Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Stacks and City Garrisons

Units of one civilization on the same tile form a stack. Only one civilization can occupy a tile.

Finding the stack on a tile

Page 2 of the map storage holds an occupancy byte for every tile at (x + 160, y). Bit 3 means units are present and bits 0–2 give their owner. map_owner(x, y) returns the owner or −1. map_stack(x, y) then scans that civilization’s 128 records for the first unit at (x, y), records the owner in the_enemy, and returns the unit number. If none is found, it clears the stale occupancy byte.

put_unit() and lift_unit() in MAP.C keep the occupancy byte and the stack links up to date as units move.

A stack is a circular list. A lone unit has next = −1. stack_add() in BATTLE.C makes two units point at each other, and inserts further units after the head. stack_remove() finds the predecessor, bypasses the removed unit, and sets a unit left alone back to −1.

each_stack(civ, unit, callback) in UNITS.C calls a function for each unit in the ring, stopping when it returns to the starting unit. It stops after ten units, so every stack operation built on it (counts, strengths, and the destruction of a defeated stack) sees at most ten units. The helpers built on it are:

FunctionResult
stack_len(civ, unit, mode)Sum of cost (0), defence (1), count (2) or attack (3); mode 4 counts defenders before unit
count_u(civ, unit, type)Units of one type
stack_strength(civ, unit, role)Units of one role
stack_cap(civ, unit)Free transport capacity: ship capacity minus land units

Choosing the defender

When a stack is attacked, stack_other() picks the defender with the highest score from score_group_record():

land unit: (fortified ? 3 : 2) * defence * terrain defence * 8
other:     defence * 16
veteran:   + score / 2

Land units at sea are skipped. City Walls and fortresses do not enter the choice, although they affect the battle.

Packing garrisons into cities

Unit records are limited, so the human’s cities store part of their garrison in the city record. When a unit finishes fortifying in its home city, ai_turn() calls garrison_in() for that city. It keeps the first fortified unit homed to the city on the map and packs up to two more into townbuf[city].garrison[]. Each byte holds the unit type in bits 0–5 and the veteran flag in bit 6, and the packed units are removed from armydata. garrison_in() clears status bit 0x04 of the city, and unpacking sets it again.

When another civilization’s unit comes next to the city, unit_sight() calls unpack_garrison(). It recreates the stored units as fortified units (veterans keep their status) and clears the bytes. Both functions return immediately for cities not owned by the human. Even so, the AI’s strength tables count any garrison bytes they find.