Atlas of Bretonnia

Workshop journal · · 8 min read

The 9 walls of porting a campaign map to Warhammer III

Porting a Warhammer I map to Warhammer III mostly means running into walls. In four days I counted nine big ones. For each: what we saw, what was really going on, how to get past it, and what I took away from it.

The campaign map in game: the forests of Athel Loren, their roads and, beyond, mountains
In-game capture: the Season map in Warhammer III.

How to read these cards

Each wall follows the format of our error log: symptom, cause, fix, lesson. The causes were found by Claude, Anthropic's AI assistant, often by reading a crash dump in a debugger. The symptoms were usually mine, spotted in game with a Warhammer I screenshot next to it.

Technical terms are explained along the way. For the full method, in order, see the tutorial.

Wall 1: the impossible startpos

The startpos is the file that freezes a campaign's starting state: factions, characters, settlements, diplomacy. No startpos, no game. The game builds it itself, from the data you give it.

  • Symptom: from the evening of 20 September until 1 am, the game crashes on every generation attempt.
  • Cause: the logical map file (map_data.esf) came out in a variant of CA's ESF format that Warhammer III doesn't read. The only difference: the width of the field giving the length of two text tables at the end of the file. Changing only the format's label just moved the crash elsewhere.
  • Fix: a real conversion, built into the pack build, and proven both ways: with the converted file, that crash goes away; with the old variant, it comes back exactly as before.
  • Lesson: a format's label names a grammar. Read the file on both sides, convert what differs, then check the result.

Two smaller walls stood behind it: our ports didn't have CA's shape, and a declared minimap didn't exist. The first startpos came out on the 21st at 12:08 pm.

Wall 2: BOB doing nothing, silently

BOB is the Assembly Kit's builder: it turns the terrain project into files the game reads.

  • Symptom: BOB runs only 6 actions out of 15. No relief, no textures, and no error. We lost an hour trying files at random.
  • Cause: a limit of the tool. For a map the game's database (the one in CA's packs) does not know, BOB runs only 6 of its 15 actions, without a message; adding the map to the kit's database or to a mod pack changes nothing.
  • The right way: a control case first, to clear our files: ChaosRobie's project, copied under another name, failed the same way. Then the community: the CAIME Discord, tw-modding. We know of no official way to lift this limit, and our guides rule out taking a CA tool apart or working around it.
  • Lesson: when a tool does nothing without an error, take three steps before touching any files: a control case known to work, the exact command, then the community.

Wall 3: Athel Loren without settlement slots

  • Symptom: the terrain is ready, and my two tests late on the 21st crash as soon as the campaign loads.
  • Cause: the day before, the 36 rows giving slots to Athel Loren's 18 settlements had been dropped on a false check: “Warhammer III declares none for its elf regions”. Yet the game looks for every settlement's primary slot. Our first fix targeted something else, and the crash came back unchanged.
  • Fix: the rows restored from Immortal Empires' templates, plus a new check comparing our startpos with one from a campaign that loads. That check finds this defect on its own.
  • Lesson: “CA has none” is proven with a query, then cross-checked from another angle: here, searching by place rather than by faction. And before fixing a crash, read in the dump what the code was looking for: here, the word primary.

Wall 4: an AI without a map, and a pack that jumps the queue

  • Symptom: a crash when the game sets up the human player. Worse, two tests were running on an old startpos, and we thought the fix didn't work.
  • Cause: three causes, one behind the other. The startpos was generated without the AI's map data, the two files it uses to find its way (hlp_data.esf and spd_data.esf). One faction had an empty AI group. And the startpos inside the pack took priority over the copy sitting next to it.
  • Fix: generate with the option that produces the AI data, and ship it; give each faction the AI group CA gives it in Immortal Empires, otherwise its culture's.
  • Lesson: a fixed order. Regenerate, copy into the project, rebuild the pack, and only then test.

With that wall down, the campaign finally loaded.

It works!!!! […] the map looks like nothing, but at least it loads.

Charles, 21 September, 8:31 pm (translated)

Wall 5: the end-of-turn crash nobody saw

  • Symptom: my game on the evening of the 21st stops at the end of turn one. I didn't report it; Claude found it the next day, somewhat by chance, in the crash reports.
  • Cause: a campaign has two terrains. The second one, a battle terrain, is used from the first battle, even between two AIs. Ours had never been shipped.
  • Fix: build that battle terrain the way CA does, compile it with BOB, and have the pack build check that every declared file exists.
  • Lesson: every time you pick the work back up, read the crash reports and recent saves, even if nobody said anything.

Wall 6: “I don't recognise the map”

  • Symptom: 21 September, 10:50 pm, in game: “this is a bit of a mess”, then “I don't recognise the map” (translated).
  • Cause: Warhammer III models in place of Warhammer I's; 5,277 pieces of Chaos set dressing made visible to all by a wrong rule; the winter glade's snow wiped out, mistaken for a defect. Everything had been checked with numbers, nothing by eye.
  • Fix: Warhammer I's own files, which makes the mod strictly private; only natural set dressing visible to all; the snow redone the Warhammer III way.
  • Lesson: no visual goes out without being compared on screen with the Warhammer I screenshots. And a Warhammer I oddity gets re-rendered, not deleted.

Wall 7: stuff flying everywhere

  • Symptom: 22 September, 10:40 pm, objects floating all over the place. Claude's audits only found 45.
  • Cause: a coordinate frame. In Warhammer III, objects live in hex space, while the terrain is stored in square pixels, over a depth shorter by a factor of √3/2. Our objects had been wrongly converted: squashed 13% towards the south, they floated or sank. The audits, run in the same wrong frame, saw nothing.
  • Fix: never convert object positions, and read the terrain at row z × √3/2. Checked in Terry at 11:23 pm: the waystones were back in the ground.
  • Lesson: a coordinate frame is checked in the tool that displays it. We proved it by parking Terry's camera on precise points and seeing whether they landed on land or on sea.

Wall 8: a sea without water

  • Symptom: 23 September, 3:40 am: “by the sea there's no water, just the sandy bottom” (translated). No sea, no rivers, no lakes.
  • Cause: to smooth the coastline, the same surface had been written into both of the terrain's height maps. At CA, height holds the water surface and sea_height the seabed. Same value, zero depth: the game draws nothing. Terry, on the other hand, showed the water.
  • Fix: give each map its meaning back. The water was back at 4:06 am.
  • Lesson: before changing what a piece of data means, measure it at CA. And water is judged in game, not in the editor.

Wall 9: the new game that thought it was a save

  • Symptom: no cinematic, no “How to play”, no victory mission, and a weird camera.
  • Cause: the startpos predated the campaign scripts. Its save counter (__save_counter) only goes to 1 if the scripts run during generation. Stuck at 0, it made every new game look like a save. The Claude session in charge of scripts tracked it down.
  • Fix: regenerate the startpos after any script change, plus an automatic check that the counter is 1.
  • Lesson: the startpos is a snapshot. Anything it needs to know on turn one has to exist before the picture is taken.

What the nine walls have in common

Read together, these walls boil down to four simple rules.

  • Compare with something that works. A known-good control case settles things faster than ten hypotheses.
  • Read what the code was looking for. A crash dump tells you which data was missing; a difference between two files is only a lead.
  • Judge by eye, in game. The numbers looked fine while the map was unrecognisable.
  • Respect the order of things. The startpos is a snapshot, the pack wins over loose copies, and each change gets tested on its own.

Each of these mistakes is logged in our error journal, with the rule that prevents it. I explain how we keep it in Working with an AI on a big mod. And to see where all this is heading, the map of all Bretonnia is waiting for you.

Suggest an ideaSee the map