Movement & Time
Every entity’s movement and the game’s calendar are driven by the same
function, ProcessMovement, called once per game tick to advance exactly
one entity. Full byte/instruction-level detail:
docs/wime/amiga/movement-system.md and docs/wime/amiga/timer-system.md
in the main repo (not part of this site).
The clock
Section titled “The clock”Time in War in Middle Earth has three nested levels, and time only advances once every entity has had a turn — there’s no independent real-time or per-frame clock:
1 call to ProcessMovement = try to move 1 entity151 calls (the full roster) = 1 sub-day tick (15 game-minutes)96 sub-day ticks = 1 dayThe calendar spans 8 months matching the War of the Ring timeline, September 3018 through April 3019 of the Third Age. One quirk survives into the original release: the calendar never advances past March in the shipped game — the month index clamps at March while the day count keeps climbing, producing dates like “March 102nd.” (This project’s own reimplementation fixes the day/month rollover; the original game’s bug is documented here for accuracy.)
Day/night doesn’t change movement speed — it changes whether units move
Section titled “Day/night doesn’t change movement speed — it changes whether units move”There’s no direct day/night speed penalty. Instead, during the “night” window (roughly the middle third of each day), every entity currently moving has a 1-in-10 chance, each time it’s processed, of switching to a camped/resting state. This is why units don’t all stop simultaneously at a fixed hour — camping is gradual and probabilistic, one unit at a time.
How an entity picks a direction
Section titled “How an entity picks a direction”Movement is not a global pathfinding search — there’s no “plan a route across the whole map” step. Instead, each entity’s turn does local, greedy terrain scoring:
- Compute a preferred compass heading straight at the entity’s current destination.
- 90% of the time, sample all 8 neighboring directions and terrain-score each one (scores come from the movement speed tables, 13 tables keyed by the destination tile’s low nibble and the mover’s movement class); the other 10%, just check the straight-ahead tile and commit to it if its score clears a low bar.
- Pick whichever direction scores best, with the exact-reverse direction penalized so units don’t flip-flop in place.
This local scoring is the entire explanation for behavior that looks much smarter than it is:
- Units snap onto and follow roads simply because road tiles score better than open terrain in the local comparison — there’s no explicit “prefer roads” rule, just better numbers.
- Units avoid water and use bridges the same way: a direct heading into water scores badly, so the local search steers along the bank until a bridge tile appears in the 8-direction neighborhood, at which point it wins the comparison and gets taken.
- Units route around mountains identically — poor terrain scores force local sidestepping until a pass or road tile becomes visible.
There is genuinely no global “find the nearest bridge” or “search the mountain range for a pass” algorithm anywhere in this code path. The illusion of intelligent routing comes from combining this local scoring with a second, separate layer:
Waypoint queues (the macro layer)
Section titled “Waypoint queues (the macro layer)”Above the tile-by-tile steering sits a waypoint queue: each moving
entity that’s following a route consumes queued destinations one at a
time from an 8-byte slot table, loading the next (destX, destY) once
the current one is reached. This is the same 86-route, DATA+0x3B00 table
described in Combat & Events § “Routes” — so
the full picture is: pre-authored waypoint routes provide the long-range
plan, and per-tick local terrain scoring keeps the entity on passable
ground between waypoints.
Entity fields that drive this
Section titled “Entity fields that drive this”| Field | Role |
|---|---|
posX/posY, destX/destY |
Current position and current-leg destination |
facing |
Current compass heading (0–7); also drives the compass direction shown in status text |
moveState |
0 = inactive, 1 = camped/resting, 2 = locked/busy, 3 = actively moving |
moveClass |
Which of 13 terrain-speed tables this entity uses |
moveAccum |
A fractional speed accumulator — terrain score adds to it each tick, and only once it crosses a whole-tile threshold does the entity actually move a tile, so faster units/terrain combinations can move multiple tiles in one tick |
linkedEntity |
Non-zero means “following another entity” — this entity is skipped by the normal movement logic entirely |
Status text
Section titled “Status text”The status line the game shows for a selected entity (e.g. “Frodo is
going to Rivendell.”, “Aragorn is heading north.”, “Sam is resting.”)
is assembled directly from moveState plus whether the destination is
near a named location:
moveState |
Status shown |
|---|---|
| 0 | (not displayed — inactive) |
| 1 | “resting.” |
| 2 | (context-dependent — locked/busy) |
| 3, destination near a named location | “going to <location>” |
| 3, no named location nearby | “heading <direction>” |
The game’s actual movement vocabulary is “following”, “heading”, “going to”, “passing by”, and “resting” — notably, the word “traveling” never appears anywhere in the original game’s strings.