Skip to content

Combat & Events

Two systems drive the game’s strategic layer once armies start colliding and the story starts advancing: combat (one big battle-resolution function, LAB_0A47, traced end to end) and the event system (an 8-bit campaign-progress bitfield plus a scripted-route network). Both are fully confirmed from disassembly. Full byte/instruction-level detail: docs/wime/amiga/game-logic.md and docs/wime/amiga/event-system.md in the main repo (not part of this site) — this page curates the mechanics that matter for understanding how the game actually behaves.

Correction the source doc makes explicit: an earlier pass described combat as “unit class matchups” with race-specific bonuses and cavalry beating infantry. None of that exists. The battle resolver never reads unitClass, never compares one entity’s race against another’s, and never reads the field earlier notes called “armor”. Unit class only ever selects a movement speed table — it has no combat effect at all.

One function (LAB_0A47) handles the whole thing, in order:

  1. Force aggregation — every participating entity (following its commander chain, see Characters) is assigned to a battle “slot”, and each side’s total troop strength is summed.
  2. Order assignment — the player (and the AI) gives each slot a tactical order: full attack, contribute strength only, withdraw, or charge. A slot’s order determines how much power it contributes to the fight, not just whether it fights at all.
  3. Power calculation — each slot’s contribution is based on its combat stat, current strength, and its order. A charging slot contributes its full combat × strength.
  4. Magical vs. ordinary damage pools — every slot’s power feeds one of two pools depending on combatFlags bit 0 (does this unit’s attack count as magical? Andúril, Sting, and the Dwarven hammer all set it). Entities with combatFlags bit 1 set (“warded” — 41 of 196 entities, including all major supernatural threats) can only be damaged by the magical pool; any surplus magical power left over after warded targets are accounted for demotes to the ordinary pool.
  5. Casualty resolution — each slot takes damage proportional to its own share of its side’s total strength, scaled down by its own toughness (combat × hitPoints). Armies lose troop count; lone heroes lose hit points until they die.
  6. Write-back and cleanup — casualties are subtracted from strength/hitPoints, and anything a dying figure was carrying is dropped into the same 30-slot item table the game ships pre-populated with (see Items § “Where items are found”).
  • No armor stat is ever read in combat. The field earlier notes called “armor” is actually a stamina/fatigue counter used only by movement.
  • The Ring bearer isn’t invincible or bonused in encounters. A long-standing misread had the Ring granting +20 evasion; the instruction in question actually tests for the Elven cloak, not the Ring.
  • “Morale” is never stored — see Characters for how the status screen computes it on the fly from strength/hit-point ratios instead.
  • Recruiting characters is entirely item-driven: the Red Arrow, a Dwarven Ring, a sceptre, and a silver orb each recruit one specific named leader (Théoden, Dáin, Denethor, and Thranduil respectively) by writing obedience = 99 directly to that entity’s record — see Items for the full per-item effect table.
  • The coil of rope does nothing. It shows a flavour message and has no mechanical effect on movement or terrain — confirmed absent from every movement-cost code path, not just unobserved in play.

The event system is a campaign-progress tracker: a single 8-bit bitfield (DATA+0x3E69) that records which major scripted milestones have fired, combined with a network of 86 pre-defined army routes (DATA+0x3B00) that steer reserve forces once activated.

Bit Trigger Effect
0, 1, 2 Set at game start Baseline “event system enabled” state
3 An entity reaches Isen Ford, or Denethor is recruited Saruman/Isengard branch begins
4 Day counter reaches ~149 (mid-March) “Saruman’s army is on the march!”
5 Isen Ford reached again, or Théoden is recruited Second Isengard-branch gate
6 Set after bit 7 Gates the end-game cascade
7 Day counter reaches ~169 (early April), or a non-evil entity reaches Dagorlad/Morannon, or a specific dialog choice is made “The Dark Lord’s armies march forth!” — three independent ways to trigger the same event
  • Defeat if either: an evil-aligned entity carrying the Ring reaches Barad-dûr, or 3 or more of the game’s five capital garrisons (Minas Tirith, Lórien, Thranduil’s Palace, Edoras, Hornburg) are destroyed.
  • Victory if either: the Ring bearer’s top-level commander reaches Mount Doom, or Sauron’s 9,500-strong orc host at Barad-dûr is reduced to 0 strength.
  • No named character’s death ends the game. Confirmed absent for Théodred, Brand, and Denethor by exhaustive search — losing a hero is a setback, never a loss condition by itself.

The Ring bearer’s entity index is tracked separately (DATA+0x3E6A). If the bearer dies in battle, the Ring scatters to one of a small set of nearby recovery destinations rather than simply vanishing, with special handling if Gollum is involved, and can trigger a Nazgûl to spawn in response.

Most of the 126 army entities start dormant (moveState = 1, “camped”). An entity activation function flips a dormant army to moveState = 3 (“actively moving”) and hands it a pre-assigned route slot from the 86-entry table — the same waypoint-queue mechanism described in Movement & Time. Notable route groups:

  • Routes 0–8: the Fellowship’s initial leg, Bree to Rivendell.
  • Routes 9–17: Saruman’s invasion of Rohan (Isen Ford, Hornburg, Edoras).
  • Routes 21–28: Gondor’s defensive dispositions.
  • Routes 29–39: Sauron’s invasion chain, from the Rammas forts through Minas Tirith toward Rivendell.

Commander/follower chains mean some activations are invisible until later: Sam and Pippin are set to follow Frodo from the start, and Legolas and Gimli only start following Gandalf once the Fellowship reaches Rivendell.

Two things the event-system trace didn’t resolve: what code path writes the pre-activation staging globals (DATA+0x502E/0x5030) that an activated entity’s race/state are read from, and the full body of the post-activation cleanup handler (only its jump-table slot is located, not its contents). Neither affects the confirmed mechanics above.