From bc31c3dbfd5d71291b54afb44b179f4e2d24451d Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Sat, 7 Feb 2026 13:55:56 +0100 Subject: [PATCH] Add Claude Code settings and CK3 modding reference doc Co-Authored-By: Claude Opus 4.6 --- .claude/settings.json | 5 + docs/ck3-modding/ck3-modding-reference.md | 528 ++++++++++++++++++++++ 2 files changed, 533 insertions(+) create mode 100644 .claude/settings.json create mode 100644 docs/ck3-modding/ck3-modding-reference.md diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000..b360c69 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,5 @@ +{ + "env": { + "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1" + } +} diff --git a/docs/ck3-modding/ck3-modding-reference.md b/docs/ck3-modding/ck3-modding-reference.md new file mode 100644 index 0000000..bf29150 --- /dev/null +++ b/docs/ck3-modding/ck3-modding-reference.md @@ -0,0 +1,528 @@ +# CK3 Modding Reference + +Practical reference for developing Crusader Kings III mods, with emphasis on +total conversion considerations. Based on official wiki documentation, +community guides, and patterns from major TC mods (AGOT, Elder Kings 2, +Princes of Darkness, Atlantis template). + +## Mod Structure + +### Directory Layout + +``` +my_mod/ # Mod root folder +├── descriptor.mod # Inner descriptor (no path field) +├── thumbnail.png # Steam Workshop thumbnail +├── common/ # Game data definitions (80+ subdirs) +│ ├── bookmarks/ # Start screen scenarios +│ ├── buildings/ # Holdings and buildings +│ ├── casus_belli_types/ # War justifications +│ ├── character_interactions/ # Diplomatic actions +│ ├── council_positions/ # Council roles +│ ├── council_tasks/ # Council job actions +│ ├── culture/ # Culture definitions +│ │ ├── cultures/ # Culture entries +│ │ ├── pillars/ # Heritage, language, martial custom, etc. +│ │ └── traditions/ # Cultural traditions +│ ├── decisions/ # Player/AI decisions +│ ├── defines/ # Game constants and tunables +│ ├── dynasties/ # Dynasty definitions +│ ├── dynasty_houses/ # Cadet branches +│ ├── dynasty_legacies/ # Legacy tracks +│ ├── ethnicities/ # Portrait ethnicity definitions +│ ├── factions/ # Faction types +│ ├── governments/ # Government forms +│ ├── holdings/ # Holding types +│ ├── landed_titles/ # Title hierarchy (empire → barony) +│ ├── laws/ # Realm laws +│ ├── lifestyles/ # Lifestyle focuses and perks +│ ├── men_at_arms_types/ # Custom troop types +│ ├── modifiers/ # Static modifiers +│ ├── nicknames/ # Character nicknames +│ ├── on_action/ # Event hooks (game triggers) +│ ├── province_terrain/ # Terrain types per province +│ ├── religion/ # Religion definitions +│ │ ├── religions/ # Religion and faith entries +│ │ └── holy_sites/ # Holy site definitions +│ ├── schemes/ # Intrigue schemes +│ ├── script_values/ # Reusable numeric values +│ ├── scripted_effects/ # Reusable effect blocks +│ ├── scripted_modifiers/ # Reusable modifier blocks +│ ├── scripted_triggers/ # Reusable condition blocks +│ └── traits/ # Character traits +├── events/ # Event scripts +├── gfx/ # Graphics (icons, portraits, UI art) +│ └── interface/icons/traits/ # Trait icon DDS files +├── gui/ # UI layout overrides +├── history/ # Starting game state +│ ├── characters/ # Character definitions with dates +│ ├── provinces/ # Province culture/religion/holdings +│ └── titles/ # Title holder history +├── localization/ # Display strings +│ └── english/ # l_english.yml files +│ └── replace/ # Overrides for vanilla loc keys +└── map_data/ # Map files (TC only) + ├── default.map # Province groupings + ├── definitions.csv # Province ID → RGB mapping + ├── geographical_regions/ # Regional groupings + ├── provinces.png # Province map image + ├── rivers.png # River overlay + └── heightmap files # Terrain elevation +my_mod.mod # Outer descriptor (has path field) +``` + +### The .mod Descriptor Files + +Every mod needs two descriptor files with identical content except for the +`path` field: + +**Outer file** (`my_mod.mod`) — sits alongside the mod folder in the mod +directory. Includes the `path` field: + +``` +version="1.0.0" +tags={ + "Total Conversion" +} +name="My Mod" +supported_version="1.12.*" +path="mod/my_mod" +``` + +**Inner file** (`my_mod/descriptor.mod`) — sits inside the mod folder. +Same content but **without** the `path` field: + +``` +version="1.0.0" +tags={ + "Total Conversion" +} +name="My Mod" +supported_version="1.12.*" +``` + +#### Descriptor Fields + +| Field | Required | Description | +|---|---|---| +| `name` | Yes | Display name in the launcher | +| `version` | No | Mod version string (informational only) | +| `supported_version` | Yes | Game version compatibility (wildcards OK: `1.12.*`) | +| `path` | Outer only | Path to mod folder. **Use forward slashes only.** | +| `tags` | No | Category tags (`"Total Conversion"`, `"Gameplay"`, etc.) | +| `picture` | No | Thumbnail filename (e.g., `thumbnail.png`) | +| `remote_file_id` | No | Steam Workshop item ID (added automatically on upload) | + +### Mod Installation Paths + +| Platform | Path | +|---|---| +| Windows | `%USERPROFILE%\Documents\Paradox Interactive\Crusader Kings III\mod\` | +| Linux | `~/.local/share/Paradox Interactive/Crusader Kings III/mod/` | +| Mac | `~/Library/Application Support/Paradox Interactive/Crusader Kings III/mod/` | + +Both the `.mod` file and the mod folder live in this directory. + +## File Loading and Override Rules + +### How CK3 Loads Mod Files + +When a mod provides a file at the same path as a vanilla file, the mod's file +**replaces the entire vanilla file**. This is whole-file replacement — you +cannot partially override a file just by having the same filename. + +### LIOS — Last In, Only Served (Most Files) + +For most game data (traits, decisions, events, etc.), when multiple definitions +of the same object exist across different files, the **last loaded** definition +wins. Files load in ASCIIbetical order by filename: + +- `01_my_traits.txt` loads after and overrides objects in `00_vanilla_traits.txt` +- Within the same file, later definitions override earlier ones + +This means you can override a single vanilla object by creating a new file +that sorts after the vanilla file and redefining just that object. + +### FIOS — First In, Only Served (GUI Files) + +GUI types and templates use the opposite rule: the **first loaded** definition +wins. To override vanilla GUI, name your file to sort before the vanilla file. + +### Localization Override + +Place overriding localization files in `localization//replace/`. +Files in the `replace/` subfolder can override individual keys from vanilla +without errors. Overriding keys outside of `replace/` works but produces +log warnings. + +### Multiple Mods + +When two mods provide the same file, the mod **lower in the playset** (load +order) takes priority. + +## Localization + +### File Format + +Localization files are YAML with strict requirements: + +- **Encoding**: UTF-8 with BOM (byte order mark). Files without BOM will + silently fail to load or cause validation errors. +- **Filename**: Must end in `_l_.yml` (e.g., `mistborn_traits_l_english.yml`) +- **First line**: Must declare the language: `l_english:` + +### Entry Format + +```yaml +l_english: + key_name:0 "Display text with $VARIABLE$ substitution" + another_key:1 "Text with [concept|E] references" +``` + +The number after the colon (`:0`, `:1`) is a version number used by Paradox +for tracking translation updates. For mods, use `0` or `1`. + +### Tips + +- Copy an existing vanilla `.yml` file to inherit the correct BOM encoding +- Every trait, event option, decision, title, modifier, and event description + needs a localization entry +- Missing keys display as raw key names in-game (e.g., `trait_misting_coinshot`) + +## Events + +### Namespace Declaration + +Every event file must declare its namespace at the top: + +``` +namespace = mistborn_snapping +``` + +### Event Structure + +``` +mistborn_snapping.0001 = { + type = character_event + title = mistborn_snapping.0001.t + desc = mistborn_snapping.0001.desc + theme = intrigue + + trigger = { + # Conditions that must be true + } + + immediate = { + # Effects that run before the event displays + } + + option = { + name = mistborn_snapping.0001.a + # Effects when this option is chosen + } +} +``` + +### Event Types + +- `character_event` — Targets a character, shows a popup +- `letter_event` — Displayed as a letter/message +- `court_event` — Royal court events (DLC) + +## Traits + +### Structure + +``` +trait_name = { + index = 200 # Unique index, avoid vanilla range + + category = fame # fame, lifestyle, personality, etc. + + genetic = yes # Can be inherited + inherit_chance = 15 # Base inheritance chance (%) + both_parent_has_trait_inherit_chance = 30 + + # Stat modifiers + prowess = 3 + martial = 1 + + # Display + icon = "gfx/interface/icons/traits/trait_name.dds" + ruler_designer_cost = 50 + shown_in_ruler_designer = yes +} +``` + +- Use `index` values 200+ to avoid conflicts with vanilla traits +- `group` field makes traits mutually exclusive within that group +- `birth = ` controls random assignment at birth (0 = never) + +## Scripted Triggers and Effects + +### Triggers + +Reusable conditions that return true/false: + +``` +is_allomancer_trigger = { + OR = { + has_trait = trait_misting_coinshot + has_trait = trait_misting_lurcher + has_trait = trait_mistborn + } +} +``` + +### Effects + +Reusable blocks of game actions: + +``` +activate_allomancy_effect = { + remove_trait = trait_allomantic_potential + random_list = { + 30 = { add_trait = trait_misting_coinshot } + 30 = { add_trait = trait_misting_lurcher } + 5 = { add_trait = trait_mistborn } + } +} +``` + +## On-Actions + +Game hooks that fire events/effects when specific things happen: + +``` +on_birthday = { + events = { + mistborn_snapping.0001 # Check for natural snapping + } + effect = { + # Inline effects + } +} +``` + +Common hooks: `on_birthday`, `on_yearly_pulse`, `on_game_start`, +`on_death`, `on_war_started`, `on_title_gain`, `on_marriage`. + +## Decisions + +``` +my_decision = { + picture = "gfx/interface/illustrations/decisions/decision_something.dds" + + is_shown = { + # Conditions for the decision to appear in the list + } + + is_valid = { + # Conditions for the decision to be clickable + } + + cost = { + gold = 100 + prestige = 200 + } + + effect = { + # What happens when the player takes the decision + } + + ai_will_do = { + base = 10 # AI weight for taking this decision + } +} +``` + +## History Files + +### Characters + +``` +900001 = { + name = "Devinshae" + dynasty = dynasty_venture + religion = "steel_ministry" + culture = "noble_scadrian" + trait = trait_misting_seeker + trait = education_intrigue_4 + father = 900000 + 900.1.1 = { birth = yes } + 930.1.1 = { death = yes } +} +``` + +Dates use `yyyy.mm.dd` format. Use `birth = yes` and `death = yes` inside +date blocks. Character IDs should avoid vanilla ranges (use 900000+). + +### Titles + +``` +e_final_empire = { + 900.1.1 = { + holder = 900001 + } +} +``` + +--- + +## Total Conversion Considerations + +### The Core Challenge + +A total conversion must clear vanilla CK3 content while building an entirely +new world. This means replacing or masking: the map, all provinces and titles, +all cultures and religions, all characters and dynasties, all bookmarks. + +### Approaches to Vanilla Content + +**Option A: Replace with empty files** — Create empty files matching every +vanilla filename you want to suppress. Simple but tedious and fragile across +game updates. + +**Option B: Preserve but hide (Atlantis approach)** — Keep vanilla content as +invisible placeholders, redirect references to dummy entries, hide elements +through GUI overrides. More resilient to game patches. + +**Option C: replace_path directive** — The `replace_path` field in +descriptor.mod *should* tell the engine to ignore entire vanilla directories. +In practice this has been unreliable in CK3 (reported broken since 1.1). +Don't depend on it; use Option A or B instead. + +### Map + +Total conversions that want a custom map must provide: + +- `map_data/provinces.png` — Province boundaries (each province a unique RGB) +- `map_data/definitions.csv` — Maps province IDs to RGB colors +- `map_data/rivers.png` — River overlay +- `map_data/default.map` — Province groupings and sea zones +- `map_data/heightmap` files — Terrain elevation +- `map_data/geographical_regions/` — Regional groupings + +Broken `rivers.png` files can crash the game. Test map changes incrementally. + +If your TC doesn't need a custom map (e.g., uses abstract/minimal geography), +you can reuse the vanilla map and just reassign provinces. + +### Portraits and DNA + +- Custom portrait assets go in `gfx/portraits/` +- Ethnicities are defined in `common/ethnicities/` +- Characters without proper ethnicity/portrait setup will appear bald +- Add `has_scripted_appearance = yes` to character history to use scripted + (non-DNA) appearance +- DNA strings can be generated using the in-game portrait editor (debug mode) + +### Culture and Religion Families + +- Religion families (`family = rf_scadrial`) are auto-created on first use + but verify this works with your CK3 version +- Culture pillars (heritage, language, martial_custom, ethos) must be defined + before cultures that reference them +- File load order matters — name pillar files to sort before culture files + +### Bookmarks + +Bookmarks define the start screen scenarios. Each needs: + +- A bookmark definition in `common/bookmarks/` +- Character entries with portraits and descriptions +- Localization for all display text +- At least one playable character with a valid title + +### What Bleeds Through + +Even in a TC, vanilla content can appear unexpectedly: + +- **Decisions** — Vanilla decisions may show up if not replaced/emptied +- **Events** — Vanilla on_action hooks still fire unless overridden +- **GUI text** — Hardcoded strings and tooltips reference vanilla concepts +- **AI behavior** — AI weights reference vanilla traits, cultures, religions +- **Name lists** — Without custom name lists, characters get vanilla names + +Test thoroughly and check `error.log` for references to content you didn't +create. + +--- + +## Development Workflow + +### Setup + +1. Create your mod folder in the CK3 mod directory +2. Create both `.mod` files (outer with path, inner without) +3. Add Steam launch options: `-debug_mode -develop` +4. Create a playset in the launcher with your mod enabled +5. Reload mods in launcher: Mods → Manage All Mods → Reload Installed Mods + +### Debug Mode + +Launch with `-debug_mode` to enable: + +- **Console** — Press tilde (`~`) to open. Tab for command list. +- **error.log** — Written to `Documents/Paradox Interactive/Crusader Kings III/logs/error.log`. Check this after every launch. +- **Event testing** — `test_event ` checks if an event can fire; `debug_event ` forces it to fire + +### Useful Console Commands + +| Command | Description | +|---|---| +| `event ` | Fire an event for the player character | +| `test_event ` | Check if event can trigger (prints result) | +| `debug_event ` | Force-fire event and print trigger info | +| `add_trait ` | Add a trait to the player character | +| `remove_trait ` | Remove a trait | +| `add_gold ` | Add gold | +| `add_prestige ` | Add prestige | +| `yesmen` | AI always accepts proposals | +| `observe` | Enter observer mode | +| `charinfo` | Toggle character debug info | +| `reload ` | Hot-reload a specific file | + +### Iterative Testing + +1. Make changes to mod files +2. Launch game (or use `reload` for supported file types) +3. Check `error.log` for new errors +4. Use console to test specific events/traits/decisions +5. Fix issues, repeat + +### Publishing to Steam Workshop + +1. In the CK3 launcher, go to Mods +2. Click "Upload Mod" → select your mod +3. Set the suggested game version, add thumbnail and description +4. The launcher handles packaging and upload +5. `remote_file_id` is added to your `.mod` file automatically + +To update: make changes locally, then re-upload through the launcher. + +--- + +## Common Pitfalls + +| Issue | Cause | Fix | +|---|---|---| +| Localization not loading | Missing UTF-8 BOM encoding | Re-save files as UTF-8 with BOM | +| Traits not appearing | Wrong `index` collision or missing loc | Use unique indices 200+, add loc entries | +| Events silently failing | Namespace mismatch or missing event file | Check namespace declaration matches event prefix | +| Decision not showing | `is_shown` trigger failing | Test individual trigger conditions in console | +| Vanilla content showing | Not all vanilla files overridden | Empty/replace all relevant vanilla files | +| Characters appear bald | Missing ethnicity or portrait data | Add `has_scripted_appearance` or define ethnicities | +| Game crash on load | Broken map files or circular references | Test incrementally, check `error.log` | +| `replace_path` not working | Known CK3 bug/limitation | Use empty file replacement instead | +| Wrong trait activating | LIOS override — file sort order wrong | Name files to sort correctly (00_, 01_ prefix) | +| Mod not detected | `.mod` file path wrong or uses backslashes | Use forward slashes only in path field | + +## Resources + +- [CK3 Paradox Wiki — Modding](https://ck3.paradoxwikis.com/Modding) +- [CK3 Paradox Wiki — Mod Structure](https://ck3.paradoxwikis.com/Mod_structure) +- [CK3 Community Modding Documentation (GitHub)](https://github.com/CK3-Modding/Documentation) +- [Atlantis TC Template (GitHub)](https://github.com/bombusfrigidus/Atlantis) +- [CK3 Mod Co-op Discord](https://discord.com/invite/F7Ta5R2rFR) +- [Paradox Modding Forums](https://forum.paradoxplaza.com/forum/forums/crusader-kings-iii-modding.1080/)