Add Claude Code settings and CK3 modding reference doc
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"env": {
|
||||
"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
|
||||
}
|
||||
}
|
||||
@@ -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/<language>/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_<language>.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 = <weight>` 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 <id> <char_id>` checks if an event can fire; `debug_event <id> <char_id>` forces it to fire
|
||||
|
||||
### Useful Console Commands
|
||||
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
| `event <id>` | Fire an event for the player character |
|
||||
| `test_event <id> <char_id>` | Check if event can trigger (prints result) |
|
||||
| `debug_event <id> <char_id>` | Force-fire event and print trigger info |
|
||||
| `add_trait <trait>` | Add a trait to the player character |
|
||||
| `remove_trait <trait>` | Remove a trait |
|
||||
| `add_gold <amount>` | Add gold |
|
||||
| `add_prestige <amount>` | Add prestige |
|
||||
| `yesmen` | AI always accepts proposals |
|
||||
| `observe` | Enter observer mode |
|
||||
| `charinfo` | Toggle character debug info |
|
||||
| `reload <file>` | 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/)
|
||||
Reference in New Issue
Block a user