Using Claude Code when modding Victoria 2.

Victoria 2 is a 2010 grand strategy game by Paradox Interactive. It's a game focused on the Victorian era from 1836 to 1936, witnessing monumental events in history such as the American Civil War, Scramble for Africa, and the First World War. For the past few years, I've been volunteering my time in the development of The Third Age, a mod that converts the game into the world of Middle Earth.

Mods for Victoria 2, like in other Paradox Interactive games, are made primarily by writing text files that overwrite the default files of the game. These text files are written in a proprietary format that the community calls Clausewitz script or Paradox script. The script offers no type checking, there are few if any linting tools available, new features often have to appear in multiple files to work correctly, and the engine gives no useful error messages when script is malformed. Testing new features involves entering the game with the mod active, a process that takes at least 30 seconds at best. All-in-all, it's a stressful coding environment.

After some experimentation over the past few months, I've come up with a few insights that make Claude Code reasonably effective within this domain.

The first thing that surprised me was how well Claude Code could actually write the script. A few years ago, I'd experimented with using ChatGPT for the same task and found it was essentially useless, but Claude rarely gets it wrong. For example, consider this commit, which contains an event written correctly by Claude within only a single prompt.

One snag that did catch Claude, however, was encoding. The localisation files, which are CSV files that map keys to the text Victoria 2 players actually see, must be saved in Windows-1252 encoding. Claude Code's built-in file editing tools write in UTF-8, which means that every time Claude edits CSV files directly, the encoding gets silently corrupted.

The fix is to have Claude write localisation entries via a Python script. Claude actually discovered this for itself during an early session, but it is important to have the fix recorded in the CLAUDE.md file, so that tokens aren't wasted in rediscovering the fix.

The Edit tool writes UTF-8 and will silently corrupt any non-ASCII characters (e.g. accented letters in party names). Always use a Python script to modify these files: ```python path = 'localisation/politics.csv' with open(path, 'rb') as f: content = f.read().decode('cp1252') anchor = 'existing_key;Existing Text;x\n' insert = 'new_key;New Text with \u00fa (u-acute);x\n' # \u00fa = cp1252 0xFA content = content.replace(anchor, anchor + insert, 1) with open(path, 'wb') as f: f.write(content.encode('cp1252')) ```

Claude Code also impressed me when it came to complex tasks. The Third Age has completely reworked the ideologies found in the base game, turning them into representations of noble families and important characters from the Lord of the Rings. To properly work in the mod, each and every new ideology has to be added in ten separate places. We're looking at creating at least a few ideologies for every one of 200-odd countries in the game, meaning potentially thousands of individual edits.

I originally vibe coded a script to confirm it was being done correctly when it was still being performed manually. But the existence of the script also enables Claude to verify the output. One thing I've noticed in other programming environments is that agents are very good at fixing code to make tests pass, and these scripts serve that same purpose here. Claude can now write new ideologies with very little oversight, managing to one-shot the fairly complex change, as seen in this commit.

I'm still learning what works. Claude is good at mechanical correctness but it isn't good at what makes mods interesting. The events and decisions that create stories for the player and the careful balance of a new mechanic against the rest of the game will still be written by humans. But automating the scaffolding means more time spent on the parts that matter. That seems like a reasonable place to end up.