Skirmish — armies and scenarios#
Summary#
Skirmish armies come from two layers:
- Embedded EXE tables — scenario indices, NPC nobles, map parameters, faction
color pairs (GoG
Lords2.exeVAs below). - External
TROOPS*.ENG/battles.eng— unit counts per preset and scenario display names, parsed at runtime intoDAT_00516ac0and name buffers.
Regenerate EXE tables:
python3 tools/ghidra/dump_skirmish_tables.py gog/Lords2.exe
Confidence: confirmed for EXE tables (dump script); likely for
TROOPS*.ENG layout (inferred from FUN_0042ac0c parser).
Preset row indexing#
Battle types index into a flat preset row array via DAT_004d49b8:
| Battle type | Base row | Count |
|---|---|---|
| 0 — field A | 0 | 10 |
| 1 — field B | 10 | 10 |
| 2 — siege | 20 | 15 |
| 3 — custom | 35 | 20 |
Formula: preset_row = *(int*)(0x004D49B8 + battle_type*4) + scenario_index
Used by FUN_0042bf46, FUN_0042ba40, and NPC lookup.
NPC noble per scenario#
Table @ 0x004D4BC8 (GoG): culture_row per preset row → L2.ENG group 7
name. See nobles/README.md.
Field A (type 0, rows 0–9)#
| Sc | Noble |
|---|---|
| 0 | Baron |
| 1 | Knight |
| 2 | Countess |
| 3 | Bishop |
| 4 | Knight |
| 5 | Countess |
| 6 | Bishop |
| 7 | Baron |
| 8 | Knight |
| 9 | Countess |
Field B (type 1, rows 10–19)#
| Sc | Noble |
|---|---|
| 0 | Baron |
| 1 | Knight |
| 2 | Countess |
| 3 | Bishop |
| 4 | Bishop |
| 5 | Countess |
| 6 | Baron |
| 7 | Knight |
| 8 | Bishop |
| 9 | Knight |
Siege (type 2, rows 20–34)#
| Sc | Noble |
|---|---|
| 0 | Countess |
| 1 | Baron |
| 2 | Bishop |
| 3 | Knight |
| 4 | Knight |
| 5 | Countess |
| 6 | Bishop |
| 7 | Baron |
| 8 | Baron |
| 9 | Countess |
| 10 | Knight |
| 11 | Countess |
| 12 | Baron |
| 13 | Baron |
| 14 | Knight |
Custom (type 3, rows 35–54)#
| Sc | Noble |
|---|---|
| 0 | Countess |
| 1 | Bishop |
| 2 | Baron |
| 3 | Countess |
| 4 | Knight |
| 5 | Bishop |
| 6 | Baron |
| 7 | Countess |
| 8 | Knight |
| 9 | Knight |
| 10 | Countess |
| 11 | Baron |
| 12 | Bishop |
| 13 | Knight |
| 14 | Countess |
| 15 | Baron |
| 16 | Countess |
| 17 | Knight |
| 18 | Knight |
| 19 | Countess |
Faction color pairs#
@ 0x004D4CA8: when SP assigns NPC colors, if human faction color equals
color_a, NPC gets color_b, else color_a.
| culture_row | color_a | color_b |
|---|---|---|
| 1 Knight | 2 | 4 |
| 2 Baron | 1 | 5 |
| 3 Countess | 5 | 1 |
| 4 Bishop | 4 | 2 |
Siege map IDs#
@ 0x004D4B58: DAT_0057c910 for siege scenarios (type 2).
| Scenario | map_id |
|---|---|
| 0–3 | 0 |
| 4–14 | 1 |
Map parameter tables#
Each DAT_0053f258 slot (0–7, wraps after 8 battles) selects a 0x20-byte
row loaded by lotr2_combat_init_battle_ui.
Preset table @ 0x004D8E18#
| Slot | map_id | field_04 | p08 | p0c | p10 | p14 | p18 | p1c |
|---|---|---|---|---|---|---|---|---|
| 0 | 17 | 0 | 5000 | 1 | 1 | 1 | 0 | 1 |
| 1 | 12 | 0 | 2500 | 1 | 1 | 1 | 0 | 2 |
| 2 | 2 | 1 | 5000 | 2 | 1 | 1 | 0 | 3 |
| 3 | 5 | 1 | 2500 | 3 | 0 | 1 | 0 | 4 |
| 4 | 0 | 2 | 5000 | 4 | 2 | 1 | 0 | 4 |
| 5 | 3 | 2 | 2500 | 4 | 1 | 1 | 0 | 4 |
| 6 | 7 | 2 | 1000 | 5 | 0 | 1 | 0 | 4 |
| 7 | 4 | 2 | 1000 | 5 | 0 | 1 | 0 | 4 |
Fields map to globals: DAT_0053f034, DAT_0053f23c, DAT_0053f278,
DAT_0053f280, DAT_0053f27c, DAT_0053f270, DAT_0053f274, DAT_0053f268.
Custom table @ 0x004D8F58 (when DAT_0053f640 == 1)#
| Slot | map_id | field_04 | p08 | p0c | p10 | p14 | p18 | p1c |
|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 4 |
| 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 4 |
| 2 | 52 | 2 | 5000 | 2 | 1 | 1 | 0 | 1 |
| 3 | 53 | 2 | 2500 | 3 | 0 | 1 | 0 | 1 |
| 4 | 45 | 2 | 2500 | 4 | 2 | 1 | 0 | 2 |
| 5 | 44 | 2 | 2500 | 4 | 1 | 1 | 0 | 3 |
| 6 | 41 | 2 | 1000 | 5 | 0 | 1 | 0 | 4 |
| 7 | 42 | 2 | 1000 | 5 | 0 | 1 | 0 | 4 |
Unit counts (TROOPS*.ENG)#
FUN_0042ac0c loads:
| Session | File | Purpose |
|---|---|---|
| SP, local side | troops2.eng |
Presets when local player attacks |
| SP, NPC side | troops3.eng |
Presets when NPC attacks |
| MP | troops.eng |
Both sides |
Format (inferred): * delimits presets; first number after * is capacity cap
(stored @ DAT_0051fae0 + preset*4); following digits are 11 unit types ×
layout dimensions:
- 0x23 (35) preset rows max
- Stride 0xdc bytes per preset in
DAT_00516ac0 - 5 faction-color rows × 2 sides × 11 unit types (types 0–10)
- Sub-offset 0x16 per color, 0x6e per side
Counts copied into army record DAT_0052f21c (+0x1a4 stride) by FUN_0042bf46,
indexed by:
base = DAT_004d49b8[battle_type] + scenario_index
offset = base * 0xdc + faction_color * 0x16 + side * 0x6e
Siege types use 7 unit columns in UI vs 11 for field (FUN_0042130f).
Clone requirement: ship or parse the three TROOPS*.ENG files from the
game asset directory; they are not in this repository.
Scenario names (battles.eng)#
Loaded once; FUN_0042ab15(index*3) seeks the nth null-terminated string for
the scenario list. Custom maps use the editable DAT_0053f5fc buffer instead.
Army record layout (skirmish battle)#
FUN_0042ba40 / FUN_0042bf46 fill two army slots:
| Field | Global | Notes |
|---|---|---|
| Attacker army slot | DAT_00568210 |
Usually 1 |
| Defender army slot | DAT_00568218 |
Usually 2 |
| Attacker player | DAT_00553efc |
1 or 2 |
| Defender player | DAT_00553f34 |
2 or 1 |
| Human slot | lotr2_game_local_player_slot |
|
| Opponent slot | DAT_0056d5cc |
1 or 2 |
Evidence#
| Item | GoG VA |
|---|---|
| Preset bases | 0x004D49B8 |
| NPC nobles | 0x004D4BC8 |
| Color pairs | 0x004D4CA8 |
| Siege map IDs | 0x004D4B58 |
| Map preset rows | 0x004D8E18 |
| Map custom rows | 0x004D8F58 |
| Runtime unit block | DAT_00516ac0 |
Dump tool: tools/ghidra/dump_skirmish_tables.py