{
 "chunk": "game_mainProgram0800_43A4",
 "unit": "game/mainProgram0800",
 "unitLabels": {
  "game/mainProgram0800": {
   "43A4": "spotEnemiesInSight",
   "43D0": "chooseFireTarget",
   "443E": "unitStepSkipFiring",
   "445C": "faceAndFireAtTarget",
   "44A3": "runStationaryUnitUpkeep",
   "4513": "finishUnitStep",
   "4537": "endUnitStep",
   "45A8": "refuseStep",
   "45AD": "chargeMovementCost",
   "4665": "handOutMovePoints",
   "46C5": "buildRoundOrder",
   "46EB": "placeUnitInRoundOrder",
   "4733": "appendToRoundOrder",
   "4748": "resetRoundCounters",
   "4783": "zoneRowSideBranch"
  }
 },
 "notes": {
  "43A4": {
   "unit": "game/mainProgram0800",
   "line": "zp_B1 = 0 only while the battle is actually running",
   "block": [
    "Spotting pass (part of processUnitStep, which starts at $4213).  Only a unit that is not cloaked",
    "and only a running battle gets here: it looks around with scanVisibleEnemies in sight mode and",
    "makes every enemy it can see visible.  The three parallel 50-entry scan lists live in the shared",
    "$0400 scratch page: $0400 = unit index ($FF = candidate rejected), $0432 = squared distance,",
    "$0464 = direction 0-3.  (The $0400 label reads 'checksumXorConstant' because the boot checksum",
    "constant lives at the same address; at run time this page is pure scratch.)"
   ]
  },
  "43A6": {
   "unit": "game/mainProgram0800",
   "line": "setup / film / menu phase: nobody spots or fires, go to the no-fire path"
  },
  "43A8": {
   "unit": "game/mainProgram0800",
   "line": "X = 0 selects the sight-range pass (see, do not shoot)"
  },
  "43AA": {
   "unit": "game/mainProgram0800",
   "line": "Y is still currentUnit: fill $0400/$0432/$0464 with the enemies in sight"
  },
  "43AD": {
   "unit": "game/mainProgram0800",
   "line": "zp_2F = index of the last list entry ($FF = nothing in sight)"
  },
  "43AF": {
   "unit": "game/mainProgram0800",
   "line": "walk the list backwards from that index"
  },
  "43B1": {
   "unit": "game/mainProgram0800",
   "line": "branch if nothing was spotted at all"
  },
  "43B3": {
   "unit": "game/mainProgram0800",
   "line": "$0400+n = unit index of scan result n",
   "block": [
    "For every candidate the scan kept: mark it seen this visibility cycle and, if it was not visible",
    "before, make it visible and draw it on the map."
   ]
  },
  "43B6": {
   "unit": "game/mainProgram0800",
   "line": "$FF = the scan rejected this candidate (out of range / no line of sight)"
  },
  "43B8": {
   "unit": "game/mainProgram0800",
   "line": "energy byte: bits 0-5 energy 0-50, bit 6 = seen this cycle, bit 7 = visible"
  },
  "43BB": {
   "unit": "game/mainProgram0800",
   "line": "bit 6: ageUnitVisibility will shift this into bit 7 at the end of the round"
  },
  "43BD": {
   "unit": "game/mainProgram0800",
   "line": "store the refreshed visibility"
  },
  "43C0": {
   "unit": "game/mainProgram0800",
   "line": "bit 7 already set: the enemy was visible before, no redraw needed"
  },
  "43C2": {
   "unit": "game/mainProgram0800",
   "line": "newly spotted: make it visible right now"
  },
  "43C4": {
   "unit": "game/mainProgram0800",
   "line": "store it"
  },
  "43C7": {
   "unit": "game/mainProgram0800",
   "line": "draw unit Y on the overview map and in the 7x5 view"
  },
  "43CA": {
   "unit": "game/mainProgram0800",
   "line": "step down to the previous list entry"
  },
  "43CC": {
   "unit": "game/mainProgram0800",
   "line": "reload the index for the LDY above"
  },
  "43CE": {
   "unit": "game/mainProgram0800",
   "line": "loop until entry 0 has been handled"
  },
  "43D0": {
   "unit": "game/mainProgram0800",
   "line": "scanVisibleEnemies wants the scanning unit in Y again",
   "block": [
    "Target selection.  Boomers keep a target of their own (selectBoomerTarget); everybody else runs a",
    "second scan in weapon-range mode and picks the nearest candidate, except that an enemy comcen is",
    "always preferred over anything else."
   ]
  },
  "43D3": {
   "unit": "game/mainProgram0800",
   "line": "$9228 = type of the unit being stepped (0 GRUNT 1 RIDER 2 BOOMER 3 SPY 4 COMCEN)"
  },
  "43D6": {
   "unit": "game/mainProgram0800",
   "line": "BOOMER?"
  },
  "43D8": {
   "unit": "game/mainProgram0800",
   "line": "boomers lock onto a target and keep it"
  },
  "43DA": {
   "unit": "game/mainProgram0800",
   "line": "X bit 7 set = weapon-range pass (only enemies that can be shot at)"
  },
  "43DC": {
   "unit": "game/mainProgram0800",
   "line": "rebuild the scan lists for firing"
  },
  "43DF": {
   "unit": "game/mainProgram0800",
   "line": "index of the last candidate"
  },
  "43E1": {
   "unit": "game/mainProgram0800",
   "line": "loop counter"
  },
  "43E3": {
   "unit": "game/mainProgram0800",
   "line": "nothing in weapon range: no shot this step"
  },
  "43E5": {
   "unit": "game/mainProgram0800",
   "line": "$FF = 'none' for all three running best values"
  },
  "43E7": {
   "unit": "game/mainProgram0800",
   "line": "$91F1 = squared distance of the best target so far"
  },
  "43EA": {
   "unit": "game/mainProgram0800",
   "line": "$91F0 = the chosen target unit"
  },
  "43ED": {
   "unit": "game/mainProgram0800",
   "line": "$1B = direction 0-3 toward the chosen target"
  },
  "43EF": {
   "unit": "game/mainProgram0800",
   "line": "current candidate index",
   "block": [
    "Loop over the candidates, keeping the nearest one; an enemy comcen (unit 49 or 99) wins",
    "immediately and cuts the loop short."
   ]
  },
  "43F1": {
   "unit": "game/mainProgram0800",
   "line": "$0400+n = the candidate's unit index"
  },
  "43F4": {
   "unit": "game/mainProgram0800",
   "line": "$FF = rejected entry, skip it"
  },
  "43F6": {
   "unit": "game/mainProgram0800",
   "line": "unit 49 = side 0 comcen"
  },
  "43F8": {
   "unit": "game/mainProgram0800",
   "line": "a comcen is taken whatever the distance"
  },
  "43FA": {
   "unit": "game/mainProgram0800",
   "line": "unit 99 = side 1 comcen"
  },
  "43FC": {
   "unit": "game/mainProgram0800",
   "line": "an ordinary unit has to win on distance"
  },
  "43FE": {
   "unit": "game/mainProgram0800",
   "line": "comcen found"
  },
  "4400": {
   "unit": "game/mainProgram0800",
   "line": "force the loop to end after this entry (DEC makes it $FF)"
  },
  "4402": {
   "unit": "game/mainProgram0800",
   "line": "always taken (A = 0): take this candidate"
  },
  "4404": {
   "unit": "game/mainProgram0800",
   "line": "$0432+n = squared distance of this candidate"
  },
  "4407": {
   "unit": "game/mainProgram0800",
   "line": "nearer than the best so far?"
  },
  "440A": {
   "unit": "game/mainProgram0800",
   "line": "no: keep the previous best"
  },
  "440C": {
   "unit": "game/mainProgram0800",
   "line": "new best distance"
  },
  "440F": {
   "unit": "game/mainProgram0800",
   "line": "take this candidate..."
  },
  "4412": {
   "unit": "game/mainProgram0800",
   "line": "...as the unit to shoot at"
  },
  "4415": {
   "unit": "game/mainProgram0800",
   "line": "$0464+n = direction 0-3 from the firing unit to that enemy"
  },
  "4418": {
   "unit": "game/mainProgram0800",
   "line": "remember it as the facing to turn to"
  },
  "441A": {
   "unit": "game/mainProgram0800",
   "line": "next candidate down"
  },
  "441C": {
   "unit": "game/mainProgram0800",
   "line": "until entry 0 (or the forced end after a comcen)"
  },
  "441E": {
   "unit": "game/mainProgram0800",
   "line": "direction of the winner"
  },
  "4420": {
   "unit": "game/mainProgram0800",
   "line": "zp_6B: the unit will be turned this way below"
  },
  "4422": {
   "unit": "game/mainProgram0800",
   "line": "join the common 'may it fire?' test"
  },
  "4425": {
   "unit": "game/mainProgram0800",
   "line": "boomer: keep or re-choose its lock, sets $91F0/$91F1/zp_6B"
  },
  "4428": {
   "unit": "game/mainProgram0800",
   "line": "the chosen target",
   "block": [
    "Decide whether the unit is allowed to shoot at the target that was just found."
   ]
  },
  "442B": {
   "unit": "game/mainProgram0800",
   "line": "$FF = nothing to shoot at"
  },
  "442D": {
   "unit": "game/mainProgram0800",
   "line": "type of the firing unit"
  },
  "4430": {
   "unit": "game/mainProgram0800",
   "line": "types 3 (SPY) and 4 (COMCEN) carry no weapon"
  },
  "4432": {
   "unit": "game/mainProgram0800",
   "line": "they never fire: drop the target"
  },
  "4434": {
   "unit": "game/mainProgram0800",
   "line": "the firing unit"
  },
  "4437": {
   "unit": "game/mainProgram0800",
   "line": "bit 7 of $F898 = the unit is cloaked"
  },
  "443A": {
   "unit": "game/mainProgram0800",
   "line": "unreachable: a cloaked unit already branched to L_443E at $43A1"
  },
  "443C": {
   "unit": "game/mainProgram0800",
   "line": "always taken: keep the target and fire below"
  },
  "443E": {
   "unit": "game/mainProgram0800",
   "line": "the unit being stepped",
   "block": [
    "unitStepSkipFiring - joined by every unit that cannot shoot this step (setup phase, cloaked, no",
    "target in range).  The unit keeps the facing it had, and a boomer that can no longer reach its",
    "locked target loses the lock."
   ]
  },
  "4441": {
   "unit": "game/mainProgram0800",
   "line": "authoritative flag byte"
  },
  "4444": {
   "unit": "game/mainProgram0800",
   "line": "bits 0-1 = facing"
  },
  "4446": {
   "unit": "game/mainProgram0800",
   "line": "zp_6B: keep looking the way it looked"
  },
  "4448": {
   "unit": "game/mainProgram0800",
   "line": "bit 7 of $F898 = cloaked"
  },
  "444B": {
   "unit": "game/mainProgram0800",
   "line": "a cloaked unit keeps its boomer lock for later"
  },
  "444D": {
   "unit": "game/mainProgram0800",
   "line": "C=1, A = boomerTargetTable entry and Y = boomer ordinal for a boomer; A = type EOR 2 (positive) otherwise"
  },
  "4450": {
   "unit": "game/mainProgram0800",
   "line": "not a boomer, or no target locked (bit 7 clear)"
  },
  "4452": {
   "unit": "game/mainProgram0800",
   "line": "clear the lock"
  },
  "4454": {
   "unit": "game/mainProgram0800",
   "line": "$91DC+ordinal: this boomer has lost sight of its target"
  },
  "4457": {
   "unit": "game/mainProgram0800",
   "line": "no shot is taken this step"
  },
  "4459": {
   "unit": "game/mainProgram0800",
   "line": "$91F0 = none"
  },
  "445C": {
   "unit": "game/mainProgram0800",
   "line": "the unit being stepped",
   "block": [
    "Turn the unit toward its target and fire.  Each unit only fires on every other round: the test is",
    "(gameClock EOR unit index) AND 1, so half of the units shoot on even rounds and half on odd ones,",
    "which spreads the work and the shot animations over two rounds."
   ]
  },
  "445F": {
   "unit": "game/mainProgram0800",
   "line": "authoritative flag byte"
  },
  "4462": {
   "unit": "game/mainProgram0800",
   "line": "clear the facing bits 0-1"
  },
  "4464": {
   "unit": "game/mainProgram0800",
   "line": "insert the direction of the target (or the old facing)"
  },
  "4466": {
   "unit": "game/mainProgram0800",
   "line": "store the new facing"
  },
  "4469": {
   "unit": "game/mainProgram0800",
   "line": "$91CB = rounds left, counts down, so its bit 0 alternates every round"
  },
  "446C": {
   "unit": "game/mainProgram0800",
   "line": "stagger the units against each other"
  },
  "446F": {
   "unit": "game/mainProgram0800",
   "line": "is this the unit's own firing round?"
  },
  "4471": {
   "unit": "game/mainProgram0800",
   "line": "no: leave the fired bit alone"
  },
  "4473": {
   "unit": "game/mainProgram0800",
   "line": "local display copy of the unit flags"
  },
  "4476": {
   "unit": "game/mainProgram0800",
   "line": "clear bit 0 = 'has fired' so the console shows READY again"
  },
  "4478": {
   "unit": "game/mainProgram0800",
   "line": "store it"
  },
  "447B": {
   "unit": "game/mainProgram0800",
   "line": "is there a target?"
  },
  "447E": {
   "unit": "game/mainProgram0800",
   "line": "no shot: go on to the standing-still upkeep"
  },
  "4480": {
   "unit": "game/mainProgram0800",
   "line": "the same parity test again"
  },
  "4483": {
   "unit": "game/mainProgram0800",
   "line": "gameClock EOR unit index"
  },
  "4486": {
   "unit": "game/mainProgram0800",
   "line": "fire only on this unit's round"
  },
  "4488": {
   "unit": "game/mainProgram0800",
   "line": "not this round"
  },
  "448A": {
   "unit": "game/mainProgram0800",
   "line": "energy/visibility byte of the firing unit"
  },
  "448D": {
   "unit": "game/mainProgram0800",
   "line": "firing gives the unit away: seen (bit 6) and visible (bit 7)"
  },
  "448F": {
   "unit": "game/mainProgram0800",
   "line": "store it"
  },
  "4492": {
   "unit": "game/mainProgram0800",
   "line": "the firing unit"
  },
  "4495": {
   "unit": "game/mainProgram0800",
   "line": "local display flags"
  },
  "4498": {
   "unit": "game/mainProgram0800",
   "line": "bit 0 = fired (console status FIRED / RELOAD)"
  },
  "449A": {
   "unit": "game/mainProgram0800",
   "line": "store it"
  },
  "449D": {
   "unit": "game/mainProgram0800",
   "line": "Y = the target unit"
  },
  "44A0": {
   "unit": "game/mainProgram0800",
   "line": "X = attacker, Y = target: damage, sound and the shot line"
  },
  "44A3": {
   "unit": "game/mainProgram0800",
   "line": "the unit being stepped",
   "block": [
    "Upkeep of a unit that is standing on its destination (bit 7 of unitDestCol set).  It stops",
    "blitzing, and if it is neither stunned nor firing it either advances its dig-in or repairs one",
    "energy point per round."
   ]
  },
  "44A6": {
   "unit": "game/mainProgram0800",
   "line": "bit 7 set = the unit has arrived / has no move order"
  },
  "44A9": {
   "unit": "game/mainProgram0800",
   "line": "still travelling: nothing to do here"
  },
  "44AB": {
   "unit": "game/mainProgram0800",
   "line": "map row 0-39"
  },
  "44AE": {
   "unit": "game/mainProgram0800",
   "line": "re-sync the path row and clear its bit 7 = blitz (a standing unit stops charging)"
  },
  "44B1": {
   "unit": "game/mainProgram0800",
   "line": "stun/dig-in byte"
  },
  "44B4": {
   "unit": "game/mainProgram0800",
   "line": "low nibble = rounds of stun left"
  },
  "44B6": {
   "unit": "game/mainProgram0800",
   "line": "a stunned unit neither digs in nor repairs"
  },
  "44B8": {
   "unit": "game/mainProgram0800",
   "line": "destination row"
  },
  "44BB": {
   "unit": "game/mainProgram0800",
   "line": "clear bit 7 = 'repairing', it is recomputed every round"
  },
  "44BD": {
   "unit": "game/mainProgram0800",
   "line": "store it back"
  },
  "44C0": {
   "unit": "game/mainProgram0800",
   "line": "destination equals position here, so this also refreshes the path row"
  },
  "44C3": {
   "unit": "game/mainProgram0800",
   "line": "local display flags"
  },
  "44C6": {
   "unit": "game/mainProgram0800",
   "line": "bit 0 = the unit fired this round"
  },
  "44C8": {
   "unit": "game/mainProgram0800",
   "line": "shooting cancels digging in and repairing"
  },
  "44CA": {
   "unit": "game/mainProgram0800",
   "line": "stun/dig-in byte"
  },
  "44CD": {
   "unit": "game/mainProgram0800",
   "line": "bit 7 = the unit is already dug in"
  },
  "44CF": {
   "unit": "game/mainProgram0800",
   "line": "bits 5-7 = dig-in progress (command $9F starts it with $20)"
  },
  "44D1": {
   "unit": "game/mainProgram0800",
   "line": "progress 0 = not digging in: try to repair instead"
  },
  "44D3": {
   "unit": "game/mainProgram0800",
   "line": "something is still happening this round..."
  },
  "44D5": {
   "unit": "game/mainProgram0800",
   "line": "...so the setup-phase clock keeps running ($92C2)"
  },
  "44D8": {
   "unit": "game/mainProgram0800",
   "line": "dig-in byte again"
  },
  "44DB": {
   "unit": "game/mainProgram0800",
   "line": "clear carry for the add"
  },
  "44DC": {
   "unit": "game/mainProgram0800",
   "line": "one more step of digging in; three steps carry into bit 7"
  },
  "44DE": {
   "unit": "game/mainProgram0800",
   "line": "store the progress"
  },
  "44E1": {
   "unit": "game/mainProgram0800",
   "line": "not finished yet"
  },
  "44E3": {
   "unit": "game/mainProgram0800",
   "line": "type byte"
  },
  "44E6": {
   "unit": "game/mainProgram0800",
   "line": "bit 6 = dug in / fortified (resolveAttack takes 25% off the damage)"
  },
  "44E8": {
   "unit": "game/mainProgram0800",
   "line": "store it"
  },
  "44EB": {
   "unit": "game/mainProgram0800",
   "line": "unit 49 = side 0 comcen"
  },
  "44ED": {
   "unit": "game/mainProgram0800",
   "line": "a comcen never repairs itself here (only the console REPAIR panel repairs it)"
  },
  "44EF": {
   "unit": "game/mainProgram0800",
   "line": "unit 99 = side 1 comcen"
  },
  "44F1": {
   "unit": "game/mainProgram0800",
   "line": "same for the other comcen"
  },
  "44F3": {
   "unit": "game/mainProgram0800",
   "line": "energy/visibility byte"
  },
  "44F6": {
   "unit": "game/mainProgram0800",
   "line": "keep the whole byte"
  },
  "44F8": {
   "unit": "game/mainProgram0800",
   "line": "bits 6-7 = seen / visible"
  },
  "44FA": {
   "unit": "game/mainProgram0800",
   "line": "save the visibility bits"
  },
  "44FC": {
   "unit": "game/mainProgram0800",
   "line": "the byte again"
  },
  "44FE": {
   "unit": "game/mainProgram0800",
   "line": "bits 0-5 = energy 0-50 (displayed as 0-100%)"
  },
  "4500": {
   "unit": "game/mainProgram0800",
   "line": "already at the maximum of 50?"
  },
  "4502": {
   "unit": "game/mainProgram0800",
   "line": "yes: nothing to repair"
  },
  "4504": {
   "unit": "game/mainProgram0800",
   "line": "+1 energy point this round (C is clear after the BCS)"
  },
  "4506": {
   "unit": "game/mainProgram0800",
   "line": "put the visibility bits back"
  },
  "4508": {
   "unit": "game/mainProgram0800",
   "line": "store the new energy"
  },
  "450B": {
   "unit": "game/mainProgram0800",
   "line": "destination row"
  },
  "450E": {
   "unit": "game/mainProgram0800",
   "line": "bit 7 = repairing, the console status word becomes REPAIR"
  },
  "4510": {
   "unit": "game/mainProgram0800",
   "line": "store it"
  },
  "4513": {
   "unit": "game/mainProgram0800",
   "line": "battle only",
   "block": [
    "End of one unit's step: give the solo trainer a look at the unit that was just moved, clear its",
    "'hit last round' marker and redraw it."
   ]
  },
  "4515": {
   "unit": "game/mainProgram0800",
   "line": "setup / film / menu: no AI hook"
  },
  "4517": {
   "unit": "game/mainProgram0800",
   "line": "$0B9B bit 7 = a game film is being replayed"
  },
  "451A": {
   "unit": "game/mainProgram0800",
   "line": "the film supplies the opponent's orders, the trainer must not run"
  },
  "451C": {
   "unit": "game/mainProgram0800",
   "line": "$0BA5 bit 7 = PRACTICE WITH SOLO TRAINER"
  },
  "451F": {
   "unit": "game/mainProgram0800",
   "line": "modem game: the opponent thinks on his own machine"
  },
  "4521": {
   "unit": "game/mainProgram0800",
   "line": "$0BA8 <> 0 = no game running"
  },
  "4524": {
   "unit": "game/mainProgram0800",
   "line": "nothing to think about"
  },
  "4526": {
   "unit": "game/mainProgram0800",
   "line": "$E0E8 in the trainer overlay: per-unit bookkeeping of the computer opponent"
  },
  "4529": {
   "unit": "game/mainProgram0800",
   "line": "the unit being stepped"
  },
  "452C": {
   "unit": "game/mainProgram0800",
   "line": "local display flags"
  },
  "452F": {
   "unit": "game/mainProgram0800",
   "line": "clear bit 1 = 'was hit during the last round' (console status PINNED)"
  },
  "4531": {
   "unit": "game/mainProgram0800",
   "line": "store it"
  },
  "4534": {
   "unit": "game/mainProgram0800",
   "line": "repaint the unit where it now stands"
  },
  "4537": {
   "unit": "game/mainProgram0800",
   "line": "$9162: the next engine step takes the following entry of unitProcessOrder",
   "block": [
    "endUnitStep - common exit of processUnitStep (dead and frozen units jump straight here from",
    "$421B).  Advances the round order and refreshes the own comcen's stun status, which is also what",
    "triggers the COMCEN STUNNED cut-scene."
   ]
  },
  "453A": {
   "unit": "game/mainProgram0800",
   "line": "$922A: 0 = comcen fine, $80|n = stunned for n rounds, $FF = knocked out"
  },
  "453D": {
   "unit": "game/mainProgram0800",
   "line": "$FF is written by applyDroneBlastToCell ($730D) when the own comcen is knocked out"
  },
  "453F": {
   "unit": "game/mainProgram0800",
   "line": "not knocked out"
  },
  "4541": {
   "unit": "game/mainProgram0800",
   "line": "$0B9B bit 7 = film playback"
  },
  "4544": {
   "unit": "game/mainProgram0800",
   "line": "the cut-scene is skipped while a film is replaying"
  },
  "4546": {
   "unit": "game/mainProgram0800",
   "line": "$0709: one blacked-out round, then the message COMCEN STUNNED!"
  },
  "4549": {
   "unit": "game/mainProgram0800",
   "line": "$9236 = 49 or 99, the local player's comcen"
  },
  "454C": {
   "unit": "game/mainProgram0800",
   "line": "its stun/dig-in byte"
  },
  "454F": {
   "unit": "game/mainProgram0800",
   "line": "low nibble = rounds of stun left"
  },
  "4551": {
   "unit": "game/mainProgram0800",
   "line": "not stunned: status byte 0"
  },
  "4553": {
   "unit": "game/mainProgram0800",
   "line": "bit 7 = the comcen is stunned (read by the console and the status line)"
  },
  "4555": {
   "unit": "game/mainProgram0800",
   "line": "publish the comcen status"
  },
  "4558": {
   "unit": "game/mainProgram0800",
   "line": "one unit of the round has been processed"
  },
  "4559": {
   "unit": "game/mainProgram0800",
   "line": "set up the Bresenham walk from ($93,$92) to ($95,$94); A = number of steps",
   "routine": [
    "tryStepTowardTarget - walks the line stepper one cell from the current cell ($93,$92) toward the",
    "target ($95,$94) and decides whether currentUnit may enter that cell and can pay for the step.",
    "A line with no steps returns C=1 and $19 = 0 (the unit is already there).  Cells outside the",
    "40x40 map are refused (C=0, X=$FF); an occupied cell may only be entered by a spy, by a cloaked",
    "unit when the occupant is cloaked too, when the occupant is on the same side, or when the",
    "occupant is a spy.  The cost is terrainMoveCostTable[class], where the class is the group's worst",
    "terrain class for a grouped unit, the class of the ground under the unit otherwise and always 0",
    "for a spy, plus 8 more for a diagonal step.",
    "In:  $92/$93 = current row/column, $94/$95 = target row/column, $90FA currentUnit, unit arrays",
    "     $F708/$F76C/$F898/$FA28/$FAF0, $91F4 groupStatusTable, terrain class table $077E",
    "Out: C=1 accepted, A = movement points left after the step, $19 = the destination cell byte,",
    "     $92/$93 advanced onto it, zp_48/$49 point at it, X = currentUnit; C=0 refused, X=$FF when",
    "     the cell is off the map or blocked and X = currentUnit when the points are not there yet;",
    "     zp_8C-$97 and zp_A9 hold the line state, $18/$19 clobbered",
    "Called from: processUnitStep $4316 (the real step) and finishRound $470D (look-ahead while the",
    "     round order is built)"
   ]
  },
  "455C": {
   "unit": "game/mainProgram0800",
   "line": "there is at least one cell to walk"
  },
  "455E": {
   "unit": "game/mainProgram0800",
   "line": "$19 = 0: there is no cell to enter (A is 0 here)"
  },
  "4560": {
   "unit": "game/mainProgram0800",
   "line": "C=1 = 'nothing in the way' - the unit is already on its destination"
  },
  "4561": {
   "unit": "game/mainProgram0800",
   "line": "done"
  },
  "4562": {
   "unit": "game/mainProgram0800",
   "line": "advance ($93,$92) by one cell; zp_A9 = 1 if the step was diagonal",
   "block": [
    "Take one step along the line and check the cell it lands on: inside the map, and either empty or",
    "shareable with the unit that stands there."
   ]
  },
  "4565": {
   "unit": "game/mainProgram0800",
   "line": "candidate column"
  },
  "4567": {
   "unit": "game/mainProgram0800",
   "line": "the battlefield is 40 columns wide"
  },
  "4569": {
   "unit": "game/mainProgram0800",
   "line": ">= 40 (or wrapped negative): off the map"
  },
  "456B": {
   "unit": "game/mainProgram0800",
   "line": "candidate row"
  },
  "456D": {
   "unit": "game/mainProgram0800",
   "line": "40 rows"
  },
  "456F": {
   "unit": "game/mainProgram0800",
   "line": "off the map"
  },
  "4571": {
   "unit": "game/mainProgram0800",
   "line": "A = the map byte of that cell, zp_48/$49 = its address"
  },
  "4574": {
   "unit": "game/mainProgram0800",
   "line": "the unit that wants to move"
  },
  "4577": {
   "unit": "game/mainProgram0800",
   "line": "$19 = the destination cell byte (bit 7 set = a unit stands there)"
  },
  "4579": {
   "unit": "game/mainProgram0800",
   "line": "type byte of the mover"
  },
  "457C": {
   "unit": "game/mainProgram0800",
   "line": "unit type 0-4"
  },
  "457E": {
   "unit": "game/mainProgram0800",
   "line": "prepare the subtraction"
  },
  "457F": {
   "unit": "game/mainProgram0800",
   "line": "gives exactly 0 for a SPY (type 3)"
  },
  "4581": {
   "unit": "game/mainProgram0800",
   "line": "$18 = 0 marks the mover as a spy"
  },
  "4583": {
   "unit": "game/mainProgram0800",
   "line": "Y = the cell byte $80|unit, used to index the -$80 biased unit tables"
  },
  "4585": {
   "unit": "game/mainProgram0800",
   "line": "bit 7 clear = plain terrain, only the movement cost is left to check"
  },
  "4587": {
   "unit": "game/mainProgram0800",
   "line": "is the mover a spy?"
  },
  "4589": {
   "unit": "game/mainProgram0800",
   "line": "a spy may walk into any occupied cell"
  },
  "458B": {
   "unit": "game/mainProgram0800",
   "line": "bit 7 of $F898 = the mover is cloaked"
  },
  "458E": {
   "unit": "game/mainProgram0800",
   "line": "not cloaked: only the side decides"
  },
  "4590": {
   "unit": "game/mainProgram0800",
   "line": "$F818 = $F898-$80, so the raw map byte indexes the occupant's cloak flag"
  },
  "4593": {
   "unit": "game/mainProgram0800",
   "line": "two cloaked units may share a cell"
  },
  "4595": {
   "unit": "game/mainProgram0800",
   "line": "$F688 = $F708-$80: flag byte of the occupant"
  },
  "4598": {
   "unit": "game/mainProgram0800",
   "line": "compare it with the mover's flags..."
  },
  "459B": {
   "unit": "game/mainProgram0800",
   "line": "...in bit 5, which is the side bit"
  },
  "459D": {
   "unit": "game/mainProgram0800",
   "line": "same side: units of one army walk through each other"
  },
  "459F": {
   "unit": "game/mainProgram0800",
   "line": "$F6EC = $F76C-$80: type byte of the occupant"
  },
  "45A2": {
   "unit": "game/mainProgram0800",
   "line": "unit type 0-4"
  },
  "45A4": {
   "unit": "game/mainProgram0800",
   "line": "an enemy SPY does not block a cell"
  },
  "45A6": {
   "unit": "game/mainProgram0800",
   "line": "step allowed"
  },
  "45A8": {
   "unit": "game/mainProgram0800",
   "line": "C=0 = step refused"
  },
  "45A9": {
   "unit": "game/mainProgram0800",
   "line": "X = $FF tells the caller 'off the map or blocked'"
  },
  "45AB": {
   "unit": "game/mainProgram0800",
   "line": "always taken (C was just cleared)"
  },
  "45AD": {
   "unit": "game/mainProgram0800",
   "line": "flag byte of the mover",
   "block": [
    "Charge the step against the unit's movement-point balance."
   ]
  },
  "45B0": {
   "unit": "game/mainProgram0800",
   "line": "bit 6 = the unit belongs to a group"
  },
  "45B2": {
   "unit": "game/mainProgram0800",
   "line": "not in a group: use its own ground"
  },
  "45B4": {
   "unit": "game/mainProgram0800",
   "line": "flag byte again"
  },
  "45B7": {
   "unit": "game/mainProgram0800",
   "line": "group key in bits 2-5 (group number 0-6 plus the side bit)"
  },
  "45B9": {
   "unit": "game/mainProgram0800",
   "line": "shift the key down..."
  },
  "45BA": {
   "unit": "game/mainProgram0800",
   "line": "...to a group index 0-15"
  },
  "45BB": {
   "unit": "game/mainProgram0800",
   "line": "index into the group table"
  },
  "45BC": {
   "unit": "game/mainProgram0800",
   "line": "$91F4+group = the group's movement byte"
  },
  "45BF": {
   "unit": "game/mainProgram0800",
   "line": "bits 3-5 = the worst terrain class any member stands on"
  },
  "45C1": {
   "unit": "game/mainProgram0800",
   "line": "right-align it..."
  },
  "45C2": {
   "unit": "game/mainProgram0800",
   "line": "...three places..."
  },
  "45C3": {
   "unit": "game/mainProgram0800",
   "line": "...to a class 0-8; a group crosses country as slowly as its worst-placed member"
  },
  "45C4": {
   "unit": "game/mainProgram0800",
   "line": "charge that class"
  },
  "45C7": {
   "unit": "game/mainProgram0800",
   "line": "terrain code hidden under the unit"
  },
  "45CA": {
   "unit": "game/mainProgram0800",
   "line": "$077E table: terrain code -> movement class 0-8"
  },
  "45CD": {
   "unit": "game/mainProgram0800",
   "line": "is the mover a spy?"
  },
  "45CF": {
   "unit": "game/mainProgram0800",
   "line": "no: use the terrain class"
  },
  "45D1": {
   "unit": "game/mainProgram0800",
   "line": "a spy always moves at class 0 (Y = 0 here)"
  },
  "45D2": {
   "unit": "game/mainProgram0800",
   "line": "Y = movement class"
  },
  "45D3": {
   "unit": "game/mainProgram0800",
   "line": "C=0 is the answer if the balance turns out to be negative"
  },
  "45D4": {
   "unit": "game/mainProgram0800",
   "line": "accumulated movement points of the unit"
  },
  "45D7": {
   "unit": "game/mainProgram0800",
   "line": "negative balance (set by recordUnitHit): the unit has to wait"
  },
  "45D9": {
   "unit": "game/mainProgram0800",
   "line": "prepare the subtraction"
  },
  "45DA": {
   "unit": "game/mainProgram0800",
   "line": "$405E: 20/65/30/40/20/40/20/20 points per class"
  },
  "45DD": {
   "unit": "game/mainProgram0800",
   "line": "not enough points saved up yet: C=0 with X = the unit index"
  },
  "45DF": {
   "unit": "game/mainProgram0800",
   "line": "zp_A9 = 1 when stepLine moved in both axes"
  },
  "45E1": {
   "unit": "game/mainProgram0800",
   "line": "orthogonal step: accepted, C=1, A = points left"
  },
  "45E3": {
   "unit": "game/mainProgram0800",
   "line": "a diagonal step costs 8 points more"
  },
  "45E5": {
   "unit": "game/mainProgram0800",
   "line": "back to the caller"
  },
  "45E6": {
   "unit": "game/mainProgram0800",
   "line": "$0BA8 <> 0 = no game is running",
   "routine": [
    "finishRound - end of a round, reached by JMP from updateGameFrame ($4210) once all 100 units have",
    "been stepped.  It ticks the game clock (in the setup phase only when something actually happened),",
    "ends the game when the clock reaches 0 and warns at the last quarter, keeps a knocked-out comcen",
    "visible for a few rounds, then - during the battle only - runs the trainer's round hook, the",
    "recycler, the group tables and the visibility ageing, hands every unit its movement points and",
    "finally builds the next round's processing order.",
    "In:  $0BA8 gameEndReason, $91CB gameClock, zp_B1 gamePhase, $92C2 exchangeActivityFlag, $92EF",
    "     lastQuarterRound, $92B2 comcenRevealTimer, $0B9B/$0BA5 opponent flags, unit arrays, $9164",
    "     unitBaseOrder",
    "Out: $91CB decremented, $92FA/message $1D at the last quarter, $F9C4 visibility, $FA28 movement",
    "     points, $91F4 group table, $90FD unitProcessOrder rebuilt, $9162 = 0, $90FC = 0, the $0400",
    "     scratch page used as round-order marks and $0464 as a stack; zp_1A/zp_1B are the stack",
    "     pointer and the base-order cursor",
    "Called from: updateGameFrame (jmp $4210); the map generator jumps into the tail at L_4657 ($7BC3)",
    "     after shuffling the initial order"
   ]
  },
  "45E9": {
   "unit": "game/mainProgram0800",
   "line": "then the clock must not move"
  },
  "45EB": {
   "unit": "game/mainProgram0800",
   "line": "$91CB = rounds left, counting down"
  },
  "45EE": {
   "unit": "game/mainProgram0800",
   "line": "already expired"
  },
  "45F0": {
   "unit": "game/mainProgram0800",
   "line": "0 = the battle is running"
  },
  "45F2": {
   "unit": "game/mainProgram0800",
   "line": "in the battle every round costs a tick"
  },
  "45F4": {
   "unit": "game/mainProgram0800",
   "line": "$92C2 = something moved, dug in or was ordered this round"
  },
  "45F7": {
   "unit": "game/mainProgram0800",
   "line": "setup phase: an idle round does not cost time"
  },
  "45F9": {
   "unit": "game/mainProgram0800",
   "line": "consume the flag..."
  },
  "45FB": {
   "unit": "game/mainProgram0800",
   "line": "...so the next setup round has to earn its tick again"
  },
  "45FE": {
   "unit": "game/mainProgram0800",
   "line": "prepare the subtraction"
  },
  "45FF": {
   "unit": "game/mainProgram0800",
   "line": "one round gone"
  },
  "4601": {
   "unit": "game/mainProgram0800",
   "line": "store the clock"
  },
  "4604": {
   "unit": "game/mainProgram0800",
   "line": "time left"
  },
  "4606": {
   "unit": "game/mainProgram0800",
   "line": "end reason 8 = the clock ran out"
  },
  "4608": {
   "unit": "game/mainProgram0800",
   "line": "record it for endGame and the score screen"
  },
  "460B": {
   "unit": "game/mainProgram0800",
   "line": "halt the units, reveal everything and show the result"
  },
  "460E": {
   "unit": "game/mainProgram0800",
   "line": "carry on with the comcen reveal timers"
  },
  "4611": {
   "unit": "game/mainProgram0800",
   "line": "$92EF = the round at which the last quarter begins"
  },
  "4614": {
   "unit": "game/mainProgram0800",
   "line": "not that round"
  },
  "4616": {
   "unit": "game/mainProgram0800",
   "line": "battle or setup?"
  },
  "4618": {
   "unit": "game/mainProgram0800",
   "line": "battle: warn the player"
  },
  "461A": {
   "unit": "game/mainProgram0800",
   "line": "setup phase reuses the same counter as a free-running timer..."
  },
  "461C": {
   "unit": "game/mainProgram0800",
   "line": "...so wrap it to 255 instead of warning"
  },
  "461F": {
   "unit": "game/mainProgram0800",
   "line": "always taken (A = $FF)"
  },
  "4621": {
   "unit": "game/mainProgram0800",
   "line": "message $1D = 'LAST QTR WARNING!'"
  },
  "4623": {
   "unit": "game/mainProgram0800",
   "line": "queue it for the status line"
  },
  "4626": {
   "unit": "game/mainProgram0800",
   "line": "bit 7 = last quarter"
  },
  "4628": {
   "unit": "game/mainProgram0800",
   "line": "$92FA: the status line prints the quarter from here on"
  },
  "462B": {
   "unit": "game/mainProgram0800",
   "line": "side 1 first, then side 0",
   "block": [
    "Per-side comcen reveal timer: endGame sets $92B2+side to 6 when that comcen is knocked out, and",
    "for those rounds the comcen is forced visible so both players can see it."
   ]
  },
  "462D": {
   "unit": "game/mainProgram0800",
   "line": "$92B2+side, counted down here"
  },
  "4630": {
   "unit": "game/mainProgram0800",
   "line": "not revealed"
  },
  "4632": {
   "unit": "game/mainProgram0800",
   "line": "one round less"
  },
  "4635": {
   "unit": "game/mainProgram0800",
   "line": "$0C8A: 49 for side 0, 99 for side 1 = that side's comcen unit"
  },
  "4638": {
   "unit": "game/mainProgram0800",
   "line": "energy/visibility byte of the comcen"
  },
  "463B": {
   "unit": "game/mainProgram0800",
   "line": "keep both visibility bits set"
  },
  "463D": {
   "unit": "game/mainProgram0800",
   "line": "store it"
  },
  "4640": {
   "unit": "game/mainProgram0800",
   "line": "next side"
  },
  "4641": {
   "unit": "game/mainProgram0800",
   "line": "loop over sides 1 and 0"
  },
  "4643": {
   "unit": "game/mainProgram0800",
   "line": "0 = the battle is running"
  },
  "4645": {
   "unit": "game/mainProgram0800",
   "line": "do the full end-of-round work"
  },
  "4647": {
   "unit": "game/mainProgram0800",
   "line": "setup phase: only reset the step counters"
  },
  "464A": {
   "unit": "game/mainProgram0800",
   "line": "$0B9B bit 7 = a film is being replayed",
   "block": [
    "Once-per-round engine work, battle only.  L_4657 is also entered by JMP from the map generator",
    "($7BC3, shuffleInitialUnitOrder) to build the very first round order, which is why the loop below",
    "tests gamePhase again before it hands out movement points."
   ]
  },
  "464D": {
   "unit": "game/mainProgram0800",
   "line": "the film already contains the opponent's orders"
  },
  "464F": {
   "unit": "game/mainProgram0800",
   "line": "$0BA5 bit 7 = solo trainer"
  },
  "4652": {
   "unit": "game/mainProgram0800",
   "line": "modem game: the opponent thinks on his own machine"
  },
  "4654": {
   "unit": "game/mainProgram0800",
   "line": "$E079: let the computer opponent plan this round"
  },
  "4657": {
   "unit": "game/mainProgram0800",
   "line": "may reveal the opponent's recycler if one of our units is close enough"
  },
  "465A": {
   "unit": "game/mainProgram0800",
   "line": "rebuild dead units at the recyclers"
  },
  "465D": {
   "unit": "game/mainProgram0800",
   "line": "recompute each group's speed and terrain class"
  },
  "4660": {
   "unit": "game/mainProgram0800",
   "line": "shift 'seen this cycle' into 'visible' and clear the seen bits"
  },
  "4663": {
   "unit": "game/mainProgram0800",
   "line": "walk the units from 99 down to 0"
  },
  "4665": {
   "unit": "game/mainProgram0800",
   "line": "0 = battle (the map generator can enter here during setup)",
   "block": [
    "handOutMovePoints - give every unit this round's movement points and clear its round-order mark",
    "in the $0400 scratch page.  A unit that is dead or standing still is pegged at 15 points; a moving",
    "unit adds speedClassRateTable[class] to its balance, saturating at +127.  The class is the unit",
    "type, or the group's slowest class for a group member, or the per-player COMCEN SPEED setting for",
    "a comcen."
   ]
  },
  "4667": {
   "unit": "game/mainProgram0800",
   "line": "setup: no points, only clear the mark"
  },
  "4669": {
   "unit": "game/mainProgram0800",
   "line": "type byte"
  },
  "466C": {
   "unit": "game/mainProgram0800",
   "line": "bit 7 = destroyed"
  },
  "466E": {
   "unit": "game/mainProgram0800",
   "line": "destination column, bit 7 = at destination / no order"
  },
  "4671": {
   "unit": "game/mainProgram0800",
   "line": "the unit still has somewhere to go: it earns points"
  },
  "4673": {
   "unit": "game/mainProgram0800",
   "line": "standing or dead: a flat 15 points"
  },
  "4675": {
   "unit": "game/mainProgram0800",
   "line": "store the balance"
  },
  "4678": {
   "unit": "game/mainProgram0800",
   "line": "always taken (A = $0F)"
  },
  "467A": {
   "unit": "game/mainProgram0800",
   "line": "A is still the type byte: bits 0-2 = the unit type, which is also the speed class"
  },
  "467C": {
   "unit": "game/mainProgram0800",
   "line": "X = speed class"
  },
  "467D": {
   "unit": "game/mainProgram0800",
   "line": "flag byte"
  },
  "4680": {
   "unit": "game/mainProgram0800",
   "line": "bit 6 = member of a group"
  },
  "4682": {
   "unit": "game/mainProgram0800",
   "line": "a group moves at one common speed"
  },
  "4684": {
   "unit": "game/mainProgram0800",
   "line": "type 4 = COMCEN"
  },
  "4686": {
   "unit": "game/mainProgram0800",
   "line": "ordinary unit: its type is its class"
  },
  "4688": {
   "unit": "game/mainProgram0800",
   "line": "$92B4 = the local player's COMCEN SPEED option"
  },
  "468B": {
   "unit": "game/mainProgram0800",
   "line": "$9236 = the local player's comcen"
  },
  "468E": {
   "unit": "game/mainProgram0800",
   "line": "yes: use the own setting"
  },
  "4690": {
   "unit": "game/mainProgram0800",
   "line": "$92B5 = the opponent's COMCEN SPEED option"
  },
  "4693": {
   "unit": "game/mainProgram0800",
   "line": "look the rate up"
  },
  "4696": {
   "unit": "game/mainProgram0800",
   "line": "flag byte"
  },
  "4699": {
   "unit": "game/mainProgram0800",
   "line": "group key in bits 2-5"
  },
  "469B": {
   "unit": "game/mainProgram0800",
   "line": "shift it down..."
  },
  "469C": {
   "unit": "game/mainProgram0800",
   "line": "...to a group index 0-15"
  },
  "469D": {
   "unit": "game/mainProgram0800",
   "line": "index the group table"
  },
  "469E": {
   "unit": "game/mainProgram0800",
   "line": "$91F4+group"
  },
  "46A1": {
   "unit": "game/mainProgram0800",
   "line": "bits 0-2 = the class of the group's slowest member"
  },
  "46A3": {
   "unit": "game/mainProgram0800",
   "line": "X = that class"
  },
  "46A4": {
   "unit": "game/mainProgram0800",
   "line": "$4066: 12/25/12/25/0 points per round for classes 0-4"
  },
  "46A7": {
   "unit": "game/mainProgram0800",
   "line": "clear carry for the addition"
  },
  "46A8": {
   "unit": "game/mainProgram0800",
   "line": "add to the balance the unit has saved up"
  },
  "46AB": {
   "unit": "game/mainProgram0800",
   "line": "no overflow past +127"
  },
  "46AD": {
   "unit": "game/mainProgram0800",
   "line": "saturate: the balance is a signed byte"
  },
  "46AF": {
   "unit": "game/mainProgram0800",
   "line": "store the new balance"
  },
  "46B2": {
   "unit": "game/mainProgram0800",
   "line": "mark 0 = this unit has not been placed in the round order yet"
  },
  "46B4": {
   "unit": "game/mainProgram0800",
   "line": "$0400+unit (the same page as the scan lists, which are finished with)"
  },
  "46B7": {
   "unit": "game/mainProgram0800",
   "line": "next unit down"
  },
  "46B8": {
   "unit": "game/mainProgram0800",
   "line": "until unit 0"
  },
  "46BA": {
   "unit": "game/mainProgram0800",
   "line": "start the new order at entry 0",
   "block": [
    "Build unitProcessOrder for the coming round out of the shuffled unitBaseOrder.  A unit whose next",
    "step would land on a unit that has not been ordered yet is pushed on a stack at $0464 and the unit",
    "in front of it is ordered first, so a queue of units all move in the same round instead of",
    "advancing one cell per round.  Marks in $0400+unit: 0 = not ordered, 1 = waiting on the stack,",
    "5 = already ordered.  zp_1A = stack pointer, zp_1B = cursor into unitBaseOrder."
   ]
  },
  "46BC": {
   "unit": "game/mainProgram0800",
   "line": "$9162 is reused here as the write index into unitProcessOrder"
  },
  "46BF": {
   "unit": "game/mainProgram0800",
   "line": "empty markers"
  },
  "46C1": {
   "unit": "game/mainProgram0800",
   "line": "$1A = stack pointer of the waiting stack ($FF = empty)"
  },
  "46C3": {
   "unit": "game/mainProgram0800",
   "line": "$1B = cursor into unitBaseOrder (the first INC gives entry 0)"
  },
  "46C5": {
   "unit": "game/mainProgram0800",
   "line": "anything waiting on the stack?"
  },
  "46C7": {
   "unit": "game/mainProgram0800",
   "line": "no: take the next unit of the base order"
  },
  "46C9": {
   "unit": "game/mainProgram0800",
   "line": "pop it"
  },
  "46CB": {
   "unit": "game/mainProgram0800",
   "line": "$0464+sp = the unit that was blocked (same buffer as the scan direction list)"
  },
  "46CE": {
   "unit": "game/mainProgram0800",
   "line": "its mark"
  },
  "46D1": {
   "unit": "game/mainProgram0800",
   "line": "prepare the subtraction"
  },
  "46D2": {
   "unit": "game/mainProgram0800",
   "line": "mark 1 (waiting) becomes 0 (unordered) so it can be placed now"
  },
  "46D4": {
   "unit": "game/mainProgram0800",
   "line": "store the mark"
  },
  "46D7": {
   "unit": "game/mainProgram0800",
   "line": "and try to place it"
  },
  "46DA": {
   "unit": "game/mainProgram0800",
   "line": "next entry of the shuffled base order"
  },
  "46DC": {
   "unit": "game/mainProgram0800",
   "line": "read the cursor"
  },
  "46DE": {
   "unit": "game/mainProgram0800",
   "line": "all 100 entries used?"
  },
  "46E0": {
   "unit": "game/mainProgram0800",
   "line": "the order is complete"
  },
  "46E2": {
   "unit": "game/mainProgram0800",
   "line": "$9164+n = a unit index"
  },
  "46E5": {
   "unit": "game/mainProgram0800",
   "line": "Y = the unit to place"
  },
  "46E6": {
   "unit": "game/mainProgram0800",
   "line": "its mark"
  },
  "46E9": {
   "unit": "game/mainProgram0800",
   "line": "already ordered or already waiting: take the next one"
  },
  "46EB": {
   "unit": "game/mainProgram0800",
   "line": "the unit we are trying to place"
  },
  "46EE": {
   "unit": "game/mainProgram0800",
   "line": "type byte"
  },
  "46F1": {
   "unit": "game/mainProgram0800",
   "line": "a dead unit blocks nothing: order it straight away"
  },
  "46F3": {
   "unit": "game/mainProgram0800",
   "line": "path column"
  },
  "46F6": {
   "unit": "game/mainProgram0800",
   "line": "drop the cloak bits 6-7"
  },
  "46F8": {
   "unit": "game/mainProgram0800",
   "line": "line stepper start column"
  },
  "46FA": {
   "unit": "game/mainProgram0800",
   "line": "path row"
  },
  "46FD": {
   "unit": "game/mainProgram0800",
   "line": "drop the blitz bit"
  },
  "46FF": {
   "unit": "game/mainProgram0800",
   "line": "line stepper start row"
  },
  "4701": {
   "unit": "game/mainProgram0800",
   "line": "destination column"
  },
  "4704": {
   "unit": "game/mainProgram0800",
   "line": "bit 7 = standing still: order it straight away"
  },
  "4706": {
   "unit": "game/mainProgram0800",
   "line": "line stepper target column"
  },
  "4708": {
   "unit": "game/mainProgram0800",
   "line": "destination row"
  },
  "470B": {
   "unit": "game/mainProgram0800",
   "line": "line stepper target row"
  },
  "470D": {
   "unit": "game/mainProgram0800",
   "line": "look one cell ahead; nothing is moved, only tested"
  },
  "4710": {
   "unit": "game/mainProgram0800",
   "line": "blocked or too few movement points: order it now"
  },
  "4712": {
   "unit": "game/mainProgram0800",
   "line": "the cell it would step onto"
  },
  "4714": {
   "unit": "game/mainProgram0800",
   "line": "free terrain: nothing to wait for"
  },
  "4716": {
   "unit": "game/mainProgram0800",
   "line": "a unit stands there: its index"
  },
  "4718": {
   "unit": "game/mainProgram0800",
   "line": "keep it"
  },
  "471A": {
   "unit": "game/mainProgram0800",
   "line": "index the marks with it"
  },
  "471B": {
   "unit": "game/mainProgram0800",
   "line": "has the blocking unit been ordered or stacked already?"
  },
  "471E": {
   "unit": "game/mainProgram0800",
   "line": "yes: then this unit can be ordered now"
  },
  "4720": {
   "unit": "game/mainProgram0800",
   "line": "push this unit..."
  },
  "4723": {
   "unit": "game/mainProgram0800",
   "line": "...onto the waiting stack"
  },
  "4725": {
   "unit": "game/mainProgram0800",
   "line": "new stack pointer"
  },
  "4727": {
   "unit": "game/mainProgram0800",
   "line": "$0464+sp = the waiting unit"
  },
  "472A": {
   "unit": "game/mainProgram0800",
   "line": "index the marks with it"
  },
  "472B": {
   "unit": "game/mainProgram0800",
   "line": "mark 1 = waiting for the unit in front of it"
  },
  "472E": {
   "unit": "game/mainProgram0800",
   "line": "now place the blocking unit first"
  },
  "4730": {
   "unit": "game/mainProgram0800",
   "line": "and repeat the same test for it"
  },
  "4733": {
   "unit": "game/mainProgram0800",
   "line": "write position in the round order"
  },
  "4736": {
   "unit": "game/mainProgram0800",
   "line": "the unit that has just been settled"
  },
  "4739": {
   "unit": "game/mainProgram0800",
   "line": "$90FD+n = the unit that will be stepped n-th next round"
  },
  "473C": {
   "unit": "game/mainProgram0800",
   "line": "one more unit ordered"
  },
  "473F": {
   "unit": "game/mainProgram0800",
   "line": "index the marks with the unit"
  },
  "4740": {
   "unit": "game/mainProgram0800",
   "line": "mark 5 = ordered"
  },
  "4742": {
   "unit": "game/mainProgram0800",
   "line": "store the mark"
  },
  "4745": {
   "unit": "game/mainProgram0800",
   "line": "back to the stack / the base order"
  },
  "4748": {
   "unit": "game/mainProgram0800",
   "line": "restart the counters"
  },
  "474A": {
   "unit": "game/mainProgram0800",
   "line": "$90FC = 0: the very next frame starts the new round"
  },
  "474D": {
   "unit": "game/mainProgram0800",
   "line": "$9162 = 0: begin at the first unit of the new order"
  },
  "4750": {
   "unit": "game/mainProgram0800",
   "line": "the round is finished"
  },
  "4751": {
   "unit": "game/mainProgram0800",
   "line": "$406E: tells processUnitStep to repaint the cell that was left",
   "routine": [
    "moveUnitToCell - puts currentUnit into the cell ($93,$92) that tryStepTowardTarget just accepted:",
    "writes $80|unit into that cell (zp_48 still points at it), restores the terrain that was hidden",
    "under the unit into the cell it leaves, updates unitCol/unitRow and saves the terrain of the new",
    "cell.  It then scores territory for the step (see the block comment at $4781).",
    "In:  $90FA currentUnit, $93/$92 = new column/row, $19 = the byte that was in the new cell,",
    "     zp_48/$49 -> that cell, $9228 scanUnitType, $92AC terrainPointsBySide, patched branch at $4783",
    "Out: both map cells rewritten, $F640/$F6A4/$FAF0/$F76C of the unit updated, $92A2/$92A4 scores,",
    "     $9208 bumped so the status line redraws, $406E unitMovedFlag and $92C2 set; zp_48 low byte is",
    "     reused as the point accumulator and left clobbered",
    "Called from: processUnitStep $42F8 (catching up with the path position) and $4345 (the normal step)"
   ]
  },
  "4754": {
   "unit": "game/mainProgram0800",
   "line": "something happened this round..."
  },
  "4756": {
   "unit": "game/mainProgram0800",
   "line": "...so the setup-phase clock may tick ($92C2)"
  },
  "4759": {
   "unit": "game/mainProgram0800",
   "line": "offset 0 for the (zp_48),Y stores"
  },
  "475B": {
   "unit": "game/mainProgram0800",
   "line": "the moving unit"
  },
  "475E": {
   "unit": "game/mainProgram0800",
   "line": "its index"
  },
  "475F": {
   "unit": "game/mainProgram0800",
   "line": "a map cell holding a unit is $80 | unit index"
  },
  "4761": {
   "unit": "game/mainProgram0800",
   "line": "zp_48 still points at the destination cell from readMapCell"
  },
  "4763": {
   "unit": "game/mainProgram0800",
   "line": "row of the cell being left"
  },
  "4766": {
   "unit": "game/mainProgram0800",
   "line": "column of the cell being left"
  },
  "4769": {
   "unit": "game/mainProgram0800",
   "line": "readMapCell wants the column in X"
  },
  "476A": {
   "unit": "game/mainProgram0800",
   "line": "point zp_48 at the old cell (A = its content, unused)"
  },
  "476D": {
   "unit": "game/mainProgram0800",
   "line": "offset 0 again"
  },
  "476F": {
   "unit": "game/mainProgram0800",
   "line": "the moving unit"
  },
  "4772": {
   "unit": "game/mainProgram0800",
   "line": "the terrain that was hidden under it"
  },
  "4775": {
   "unit": "game/mainProgram0800",
   "line": "put that terrain back into the old cell"
  },
  "4777": {
   "unit": "game/mainProgram0800",
   "line": "column the line walker stepped onto"
  },
  "4779": {
   "unit": "game/mainProgram0800",
   "line": "the unit now stands there"
  },
  "477C": {
   "unit": "game/mainProgram0800",
   "line": "row the line walker stepped onto"
  },
  "477E": {
   "unit": "game/mainProgram0800",
   "line": "store the new row"
  },
  "4781": {
   "unit": "game/mainProgram0800",
   "line": "unit index < 50 = side 0, >= 50 = side 1",
   "block": [
    "Territory scoring.  A holds the unit's new row.  For the opponent's units the row is mirrored",
    "(39-row) so that both sides are measured from their own baseline: the branch opcode at $4783 is",
    "patched by patchUnitSideBranches ($7BC6 in the map generator) with $90 = BCC when this machine",
    "plays side 0 and $B0 = BCS when it plays side 1, so 'own units' always skip the mirror.  Row < 20",
    "means the unit has crossed into the enemy half (zone 1), row < 10 means it has reached the enemy's",
    "rear (zone 2).  Each zone pays a unit only once - the receipts are bits 3 and 4 of its type byte.",
    "The value is the owner's TERRAIN PTS setting, times 16 for a comcen and times 2 for the far zone."
   ]
  },
  "4783": {
   "unit": "game/mainProgram0800",
   "line": "opcode byte patched per side ($90 BCC for side 0, $B0 BCS for side 1): own units skip the mirror"
  },
  "4785": {
   "unit": "game/mainProgram0800",
   "line": "39 - row: measure the opponent from his own end of the field"
  },
  "4788": {
   "unit": "game/mainProgram0800",
   "line": "within 10 rows of the enemy baseline?"
  },
  "478A": {
   "unit": "game/mainProgram0800",
   "line": "no"
  },
  "478C": {
   "unit": "game/mainProgram0800",
   "line": "zone 2 = the enemy's rear"
  },
  "478E": {
   "unit": "game/mainProgram0800",
   "line": "always taken"
  },
  "4790": {
   "unit": "game/mainProgram0800",
   "line": "still in the enemy half (rows 10-19)?"
  },
  "4792": {
   "unit": "game/mainProgram0800",
   "line": "no, the unit is in its own half: nothing to score"
  },
  "4794": {
   "unit": "game/mainProgram0800",
   "line": "zone 1 = the enemy half"
  },
  "4796": {
   "unit": "game/mainProgram0800",
   "line": "keep the zone number in the LDA # operand at $47C0"
  },
  "4799": {
   "unit": "game/mainProgram0800",
   "line": "index the receipt table with it"
  },
  "479A": {
   "unit": "game/mainProgram0800",
   "line": "$406B: zone 1 -> bit 3 ($08), zone 2 -> bit 4 ($10)"
  },
  "479D": {
   "unit": "game/mainProgram0800",
   "line": "has this unit already been paid for this zone?"
  },
  "47A0": {
   "unit": "game/mainProgram0800",
   "line": "yes: a zone pays only once per unit"
  },
  "47A2": {
   "unit": "game/mainProgram0800",
   "line": "index 0"
  },
  "47A4": {
   "unit": "game/mainProgram0800",
   "line": "which side does the unit belong to?"
  },
  "47A6": {
   "unit": "game/mainProgram0800",
   "line": "side 1 unit: index 0"
  },
  "47A8": {
   "unit": "game/mainProgram0800",
   "line": "side 0 unit: index 1 - both arrays are indexed by the opposing side"
  },
  "47A9": {
   "unit": "game/mainProgram0800",
   "line": "$92AC+i = that player's TERRAIN PTS setting (0 disables territory points)"
  },
  "47AC": {
   "unit": "game/mainProgram0800",
   "line": "territory scores nothing in this game"
  },
  "47AE": {
   "unit": "game/mainProgram0800",
   "line": "zp_48 doubles as the point accumulator; the cell pointer has done its work"
  },
  "47B0": {
   "unit": "game/mainProgram0800",
   "line": "type of the unit that moved"
  },
  "47B3": {
   "unit": "game/mainProgram0800",
   "line": "COMCEN?"
  },
  "47B5": {
   "unit": "game/mainProgram0800",
   "line": "ordinary unit"
  },
  "47B7": {
   "unit": "game/mainProgram0800",
   "line": "a comcen in enemy territory is worth 16 times as much..."
  },
  "47B9": {
   "unit": "game/mainProgram0800",
   "line": "...x2..."
  },
  "47BB": {
   "unit": "game/mainProgram0800",
   "line": "...x4..."
  },
  "47BD": {
   "unit": "game/mainProgram0800",
   "line": "...x8, x16"
  },
  "47BF": {
   "unit": "game/mainProgram0800",
   "line": "operand patched at $4796 = the zone number 1 or 2"
  },
  "47C1": {
   "unit": "game/mainProgram0800",
   "line": "keep the zone for the receipt below"
  },
  "47C2": {
   "unit": "game/mainProgram0800",
   "line": "the enemy's rear?"
  },
  "47C4": {
   "unit": "game/mainProgram0800",
   "line": "no"
  },
  "47C6": {
   "unit": "game/mainProgram0800",
   "line": "the far zone is worth double"
  },
  "47C8": {
   "unit": "game/mainProgram0800",
   "line": "$9208 <> gameClock forces the status line to redraw the score"
  },
  "47CB": {
   "unit": "game/mainProgram0800",
   "line": "the points earned"
  },
  "47CD": {
   "unit": "game/mainProgram0800",
   "line": "clear carry for the 16-bit add"
  },
  "47CE": {
   "unit": "game/mainProgram0800",
   "line": "$92A2+i: the score array is indexed by the losing side, so this is the mover's own score"
  },
  "47D1": {
   "unit": "game/mainProgram0800",
   "line": "store the low byte"
  },
  "47D4": {
   "unit": "game/mainProgram0800",
   "line": "$92A4+i = high byte"
  },
  "47D7": {
   "unit": "game/mainProgram0800",
   "line": "add the carry"
  },
  "47D9": {
   "unit": "game/mainProgram0800",
   "line": "store it"
  },
  "47DC": {
   "unit": "game/mainProgram0800",
   "line": "the zone number again"
  },
  "47DD": {
   "unit": "game/mainProgram0800",
   "line": "index the receipt table"
  },
  "47DE": {
   "unit": "game/mainProgram0800",
   "line": "bit 3 or bit 4"
  },
  "47E1": {
   "unit": "game/mainProgram0800",
   "line": "mark the unit as paid for this zone"
  },
  "47E4": {
   "unit": "game/mainProgram0800",
   "line": "store the type byte"
  },
  "47E7": {
   "unit": "game/mainProgram0800",
   "line": "the byte that was in the new cell (its terrain)"
  },
  "47E9": {
   "unit": "game/mainProgram0800",
   "line": "hide it under the unit so it can be restored when the unit leaves"
  },
  "47EC": {
   "unit": "game/mainProgram0800",
   "line": "the move is complete"
  },
  "47ED": {
   "unit": "game/mainProgram0800",
   "line": "leftover byte at the entry point - probably an instruction that was patched out",
   "routine": [
    "shuffleUnitOrder - exchanges two randomly chosen entries of unitBaseOrder ($9164, the 100 unit",
    "indices the round order is built from).  The indices come from randomUnitIndex, which draws on the",
    "shared scenario RNG, so both machines shuffle in exactly the same way.",
    "In:  $9164 unitBaseOrder, scenario RNG state $5A-$5C",
    "Out: two entries of unitBaseOrder exchanged, RNG advanced twice; A/X/Y clobbered",
    "Called from: processUnitStep $4229 (once per unit stepped during the battle) and the map",
    "     generator $7BBC (51 swaps at game start)"
   ]
  },
  "47EE": {
   "unit": "game/mainProgram0800",
   "line": "first slot 0-99"
  },
  "47F1": {
   "unit": "game/mainProgram0800",
   "line": "keep it in X"
  },
  "47F2": {
   "unit": "game/mainProgram0800",
   "line": "second slot 0-99"
  },
  "47F5": {
   "unit": "game/mainProgram0800",
   "line": "keep it in Y"
  },
  "47F6": {
   "unit": "game/mainProgram0800",
   "line": "entry Y..."
  },
  "47F9": {
   "unit": "game/mainProgram0800",
   "line": "...onto the stack"
  },
  "47FA": {
   "unit": "game/mainProgram0800",
   "line": "entry X..."
  },
  "47FD": {
   "unit": "game/mainProgram0800",
   "line": "...into slot Y"
  },
  "4800": {
   "unit": "game/mainProgram0800",
   "line": "the saved entry..."
  },
  "4801": {
   "unit": "game/mainProgram0800",
   "line": "...into slot X"
  },
  "4804": {
   "unit": "game/mainProgram0800",
   "line": "the two entries have been exchanged"
  },
  "4805": {
   "unit": "game/mainProgram0800",
   "line": "$FD4A: the 24-bit generator both machines keep in step",
   "routine": [
    "randomUnitIndex - returns a unit index 0-99 drawn uniformly from the scenario random generator:",
    "a 7-bit sample is rejected and redrawn while it is 100 or more, so the distribution stays flat.",
    "In:  scenario RNG state $5A-$5C",
    "Out: A = 0..99, C=0; RNG advanced (at least once)",
    "Called from: shuffleUnitOrder $47EE and $47F2"
   ]
  },
  "4808": {
   "unit": "game/mainProgram0800",
   "line": "0-127"
  },
  "480A": {
   "unit": "game/mainProgram0800",
   "line": "100 units"
  },
  "480C": {
   "unit": "game/mainProgram0800",
   "line": "reject 100-127 and draw again"
  },
  "480E": {
   "unit": "game/mainProgram0800",
   "line": "A = a unit index"
  },
  "480F": {
   "unit": "game/mainProgram0800",
   "line": "$90FB: 0 = the battlefield screen",
   "routine": [
    "followDirectedUnit - keeps the battlefield view locked on the unit the console is following.  When",
    "the battlefield screen is up and infoPanelUnit ($91D7) is the unit currently being stepped, it",
    "computes the cell under the view cursor (viewOriginCol+3, viewOriginRow+2) and, if the unit is not",
    "on it, moves sprite 0 (the tracking cursor) to the unit on the overview map, switches the sprite",
    "on and scrolls the 7x5 view onto the unit without animation.",
    "In:  $90FB currentScreen, $91D7 infoPanelUnit, $90FA currentUnit, zp_A5/zp_A6 view origin,",
    "     $F640/$F6A4 unit position",
    "Out: $91DA/$91DB = the cursor cell, $9010/$9018 sprite 0 position, $9022 sprite 0 enabled,",
    "     zp_92/zp_93 and zp_A5/zp_A6 moved by scrollViewToUnit",
    "Called from: processUnitStep $4380, after the unit has taken its step"
   ]
  },
  "4812": {
   "unit": "game/mainProgram0800",
   "line": "the console screens do not follow units"
  },
  "4814": {
   "unit": "game/mainProgram0800",
   "line": "$91D7 = the unit whose panel/menu is open ($FF = none)"
  },
  "4817": {
   "unit": "game/mainProgram0800",
   "line": "nothing is being followed"
  },
  "4819": {
   "unit": "game/mainProgram0800",
   "line": "is it the unit that is being stepped right now?"
  },
  "481C": {
   "unit": "game/mainProgram0800",
   "line": "no: leave the view alone"
  },
  "481E": {
   "unit": "game/mainProgram0800",
   "line": "the view is 7 cells wide..."
  },
  "4820": {
   "unit": "game/mainProgram0800",
   "line": "clear carry for the add"
  },
  "4821": {
   "unit": "game/mainProgram0800",
   "line": "...so its centre column is the left edge + 3"
  },
  "4823": {
   "unit": "game/mainProgram0800",
   "line": "$91DA = column of the cell under the cursor"
  },
  "4826": {
   "unit": "game/mainProgram0800",
   "line": "the view is 5 cells high..."
  },
  "4828": {
   "unit": "game/mainProgram0800",
   "line": "clear carry"
  },
  "4829": {
   "unit": "game/mainProgram0800",
   "line": "...so its centre row is the top edge + 2"
  },
  "482B": {
   "unit": "game/mainProgram0800",
   "line": "$91DB = row of the cell under the cursor"
  },
  "482E": {
   "unit": "game/mainProgram0800",
   "line": "column of the followed unit"
  },
  "4831": {
   "unit": "game/mainProgram0800",
   "line": "row of the followed unit"
  },
  "4834": {
   "unit": "game/mainProgram0800",
   "line": "readable by the compare below"
  },
  "4835": {
   "unit": "game/mainProgram0800",
   "line": "is the unit already under the cursor?"
  },
  "4838": {
   "unit": "game/mainProgram0800",
   "line": "no"
  },
  "483A": {
   "unit": "game/mainProgram0800",
   "line": "check the row too"
  },
  "483D": {
   "unit": "game/mainProgram0800",
   "line": "the view is already centred on it: nothing to do"
  },
  "483F": {
   "unit": "game/mainProgram0800",
   "line": "X/Y = sprite coordinates of that cell on the overview map"
  },
  "4842": {
   "unit": "game/mainProgram0800",
   "line": "$9010 = sprite 0 X (the tracking cursor)"
  },
  "4845": {
   "unit": "game/mainProgram0800",
   "line": "$9018 = sprite 0 Y"
  },
  "4848": {
   "unit": "game/mainProgram0800",
   "line": "mask for sprite 0"
  },
  "484A": {
   "unit": "game/mainProgram0800",
   "line": "switch it on (unless sprites are suppressed)"
  },
  "484D": {
   "unit": "game/mainProgram0800",
   "line": "the scroll starts at the current cursor cell"
  },
  "4850": {
   "unit": "game/mainProgram0800",
   "line": "line stepper start column"
  },
  "4852": {
   "unit": "game/mainProgram0800",
   "line": "cursor row"
  },
  "4855": {
   "unit": "game/mainProgram0800",
   "line": "line stepper start row"
  },
  "4857": {
   "unit": "game/mainProgram0800",
   "line": "0 ticks per step = jump there without animating"
  },
  "4859": {
   "unit": "game/mainProgram0800",
   "line": "the unit to centre on"
  },
  "485C": {
   "unit": "game/mainProgram0800",
   "line": "$1D4E: walk the view over to it"
  },
  "485F": {
   "unit": "game/mainProgram0800",
   "line": "done"
  },
  "4860": {
   "unit": "game/mainProgram0800",
   "line": "walk the units from 99...",
   "routine": [
    "updateHitFlashTimers - ages the hit markers of all 100 units.  unitHitFlashTable ($FA8C) is",
    "$80|damage while a unit is flashing (the map drawing code at $286F paints such a unit white); the",
    "low nibble counts engine steps down and the high nibble is left alone.  When the count expires the",
    "marker is cleared and the cell is repainted: a living unit is drawn again, and a destroyed one has",
    "the terrain that was under it written back into the map and drawn instead.",
    "In:  $FA8C unitHitFlashTable, $F76C unitTypeTable, $FAF0 unitTerrainUnderTable",
    "Out: $FA8C aged, map cells and screen updated for expired markers; zp_18 is the loop index",
    "Called from: updateGameFrame $41FB, once per engine step"
   ]
  },
  "4862": {
   "unit": "game/mainProgram0800",
   "line": "...down to 0 in zp_18"
  },
  "4864": {
   "unit": "game/mainProgram0800",
   "line": "current unit index"
  },
  "4866": {
   "unit": "game/mainProgram0800",
   "line": "$FA8C: 0 = no marker, else $80|damage with the countdown in bits 0-3"
  },
  "4869": {
   "unit": "game/mainProgram0800",
   "line": "this unit is not flashing"
  },
  "486B": {
   "unit": "game/mainProgram0800",
   "line": "keep the whole byte"
  },
  "486C": {
   "unit": "game/mainProgram0800",
   "line": "high nibble = the marker bit plus the top bits of the damage"
  },
  "486E": {
   "unit": "game/mainProgram0800",
   "line": "patch it into the ORA operand at $487A"
  },
  "4871": {
   "unit": "game/mainProgram0800",
   "line": "the byte again"
  },
  "4872": {
   "unit": "game/mainProgram0800",
   "line": "the countdown in the low nibble"
  },
  "4874": {
   "unit": "game/mainProgram0800",
   "line": "expired: take the marker down"
  },
  "4876": {
   "unit": "game/mainProgram0800",
   "line": "prepare the subtraction"
  },
  "4877": {
   "unit": "game/mainProgram0800",
   "line": "one engine step less"
  },
  "4879": {
   "unit": "game/mainProgram0800",
   "line": "operand patched at $486E: put the high nibble back"
  },
  "487B": {
   "unit": "game/mainProgram0800",
   "line": "store the aged marker"
  },
  "487E": {
   "unit": "game/mainProgram0800",
   "line": "next unit"
  },
  "4881": {
   "unit": "game/mainProgram0800",
   "line": "clear the marker..."
  },
  "4883": {
   "unit": "game/mainProgram0800",
   "line": "...so the unit stops flashing white"
  },
  "4886": {
   "unit": "game/mainProgram0800",
   "line": "type byte"
  },
  "4889": {
   "unit": "game/mainProgram0800",
   "line": "bit 7 = the unit was destroyed"
  },
  "488B": {
   "unit": "game/mainProgram0800",
   "line": "living unit: its index..."
  },
  "488C": {
   "unit": "game/mainProgram0800",
   "line": "...as the map byte $80|unit"
  },
  "488E": {
   "unit": "game/mainProgram0800",
   "line": "always taken (the value is >= $80)"
  },
  "4890": {
   "unit": "game/mainProgram0800",
   "line": "the terrain that was hidden under the wreck"
  },
  "4893": {
   "unit": "game/mainProgram0800",
   "line": "keep it for the redraw"
  },
  "4894": {
   "unit": "game/mainProgram0800",
   "line": "write that terrain into the map cell and free the unit's slot ($FAF0 = $FF)"
  },
  "4897": {
   "unit": "game/mainProgram0800",
   "line": "the terrain byte again"
  },
  "4898": {
   "unit": "game/mainProgram0800",
   "line": "Y = the unit whose cell is redrawn"
  },
  "489A": {
   "unit": "game/mainProgram0800",
   "line": "repaint the cell in the view and on the overview map"
  },
  "489D": {
   "unit": "game/mainProgram0800",
   "line": "next unit down"
  },
  "489F": {
   "unit": "game/mainProgram0800",
   "line": "until unit 0"
  },
  "48A1": {
   "unit": "game/mainProgram0800",
   "line": "all markers aged"
  },
  "48A2": {
   "unit": "game/mainProgram0800",
   "line": "the unit index",
   "routine": [
    "drawUnitAtPosition - redraws unit Y where it stands: builds the map byte $80|unit and falls into",
    "drawValueAtUnit.",
    "In:  Y = unit index",
    "Out: see drawValueAtUnit",
    "Called from: $3BDB (after damage), $4185/$41B1 (pending unit/group redraws), $43C7 (newly spotted",
    "     enemy) and $4534 (end of a unit step)"
   ]
  },
  "48A3": {
   "unit": "game/mainProgram0800",
   "line": "a map cell holding a unit reads $80 | index"
  },
  "48A5": {
   "unit": "game/mainProgram0800",
   "line": "keep the cell value",
   "routine": [
    "drawValueAtUnit - draws cell value A at the position of unit Y.",
    "In:  A = the cell byte to draw, Y = unit index",
    "Out: the cell is repainted in the 7x5 view and on the overview map; A/X/Y clobbered",
    "Called from: updateHitFlashTimers $489A, and by falling through from drawUnitAtPosition"
   ]
  },
  "48A6": {
   "unit": "game/mainProgram0800",
   "line": "X = the unit's map column"
  },
  "48A9": {
   "unit": "game/mainProgram0800",
   "line": "the unit's map row..."
  },
  "48AC": {
   "unit": "game/mainProgram0800",
   "line": "...into Y as drawMapCell wants it"
  },
  "48AD": {
   "unit": "game/mainProgram0800",
   "line": "the cell value again"
  },
  "48AE": {
   "unit": "game/mainProgram0800",
   "line": "$5C7C: repaint that cell everywhere it is visible"
  },
  "48B1": {
   "unit": "game/mainProgram0800",
   "line": "the unit being stepped",
   "routine": [
    "updateIdleFlag - recomputes bit 7 of unitDestCol ($F7D0) for currentUnit: it is set when the",
    "destination equals the unit's map position (nothing left to do) and cleared while the unit still",
    "has somewhere to go.  The other bits of the byte are kept.  The result is delivered in A so the",
    "caller can copy the same bit into the display flags.",
    "In:  $90FA currentUnit, $F640/$F6A4 position, $F7D0/$F834 destination",
    "Out: A = the new $F7D0 byte (bit 7 = at destination), Y = currentUnit, N reflects that bit",
    "Called from: processUnitStep $4278 (before the step) and $4383 (after it)"
   ]
  },
  "48B4": {
   "unit": "game/mainProgram0800",
   "line": "assume 'still travelling'..."
  },
  "48B6": {
   "unit": "game/mainProgram0800",
   "line": "...by clearing the ORA operand at $48D8"
  },
  "48B9": {
   "unit": "game/mainProgram0800",
   "line": "destination row"
  },
  "48BC": {
   "unit": "game/mainProgram0800",
   "line": "bits 0-5 only: bit 7 is the repair flag"
  },
  "48BE": {
   "unit": "game/mainProgram0800",
   "line": "is the unit already on that row?"
  },
  "48C1": {
   "unit": "game/mainProgram0800",
   "line": "no: it still has to move"
  },
  "48C3": {
   "unit": "game/mainProgram0800",
   "line": "destination column"
  },
  "48C6": {
   "unit": "game/mainProgram0800",
   "line": "bits 0-5 only"
  },
  "48C8": {
   "unit": "game/mainProgram0800",
   "line": "is it on that column too?"
  },
  "48CB": {
   "unit": "game/mainProgram0800",
   "line": "no: it still has to move"
  },
  "48CD": {
   "unit": "game/mainProgram0800",
   "line": "bit 7 = at destination"
  },
  "48CF": {
   "unit": "game/mainProgram0800",
   "line": "patch it into the ORA operand at $48D8"
  },
  "48D2": {
   "unit": "game/mainProgram0800",
   "line": "the destination column byte"
  },
  "48D5": {
   "unit": "game/mainProgram0800",
   "line": "drop the old flag, keep the coordinate"
  },
  "48D7": {
   "unit": "game/mainProgram0800",
   "line": "operand patched above: 0 or $80"
  },
  "48D9": {
   "unit": "game/mainProgram0800",
   "line": "store the refreshed byte"
  },
  "48DC": {
   "unit": "game/mainProgram0800",
   "line": "A = that byte, Y = currentUnit"
  },
  "48DD": {
   "unit": "game/mainProgram0800",
   "line": "16 group slots: 7 groups per side, keyed by bits 2-5 of the unit flags",
   "routine": [
    "rebuildGroupTables - recomputes the 16 entries of groupStatusTable ($91F4), one per group key",
    "(7 groups per side plus the side bit).  For every living member it works out the speed class (the",
    "unit type, or the per-player COMCEN SPEED setting for a comcen) and the terrain class of the ground",
    "it stands on (always 0 for a spy) and keeps the group's worst terrain class in bits 3-5 and the",
    "class of its slowest member in bits 0-2, so a group crosses country like its slowest member on the",
    "worst ground any member occupies.  Bits 6-7 (group blitzing / group cloaked) are carried over from",
    "the previous value for groups that still have members.  Scratch: $0400+g member count, $0410+g",
    "worst movement cost, $0420+g best movement rate, $0430+g the previous entry.",
    "In:  unit arrays $F708/$F76C/$FAF0, $92B4/$92B5 comcen speed classes, $9236 comcenUnit, tables",
    "     $405E terrainMoveCostTable, $4066 speedClassRateTable, $077E terrain classes",
    "Out: $91F4-$9203 rewritten, $0400-$043F used as scratch; zp_18/zp_19/zp_1A clobbered",
    "Called from: finishRound $465D, once per round"
   ]
  },
  "48DF": {
   "unit": "game/mainProgram0800",
   "line": "the entry as it was last round"
  },
  "48E2": {
   "unit": "game/mainProgram0800",
   "line": "$0430+g: keep it for its blitz/cloak bits"
  },
  "48E5": {
   "unit": "game/mainProgram0800",
   "line": "start from scratch"
  },
  "48E7": {
   "unit": "game/mainProgram0800",
   "line": "clear the entry"
  },
  "48EA": {
   "unit": "game/mainProgram0800",
   "line": "$0400+g = member count"
  },
  "48ED": {
   "unit": "game/mainProgram0800",
   "line": "$0410+g = worst movement cost met so far"
  },
  "48F0": {
   "unit": "game/mainProgram0800",
   "line": "worse than any real rate"
  },
  "48F2": {
   "unit": "game/mainProgram0800",
   "line": "$0420+g = best (lowest) movement rate met so far"
  },
  "48F5": {
   "unit": "game/mainProgram0800",
   "line": "next slot"
  },
  "48F6": {
   "unit": "game/mainProgram0800",
   "line": "until slot 0"
  },
  "48F8": {
   "unit": "game/mainProgram0800",
   "line": "scan the units from 99..."
  },
  "48FA": {
   "unit": "game/mainProgram0800",
   "line": "...down to 0 in zp_1A"
  },
  "48FC": {
   "unit": "game/mainProgram0800",
   "line": "current unit"
  },
  "48FE": {
   "unit": "game/mainProgram0800",
   "line": "type byte"
  },
  "4901": {
   "unit": "game/mainProgram0800",
   "line": "bit 7 = destroyed: a dead member does not slow the group down"
  },
  "4903": {
   "unit": "game/mainProgram0800",
   "line": "flag byte"
  },
  "4906": {
   "unit": "game/mainProgram0800",
   "line": "bit 6 = the unit is in a group"
  },
  "4908": {
   "unit": "game/mainProgram0800",
   "line": "not a member"
  },
  "490A": {
   "unit": "game/mainProgram0800",
   "line": "flag byte again"
  },
  "490D": {
   "unit": "game/mainProgram0800",
   "line": "group key in bits 2-5"
  },
  "490F": {
   "unit": "game/mainProgram0800",
   "line": "shift it down..."
  },
  "4910": {
   "unit": "game/mainProgram0800",
   "line": "...to a group index 0-15"
  },
  "4911": {
   "unit": "game/mainProgram0800",
   "line": "index the group tables with it"
  },
  "4912": {
   "unit": "game/mainProgram0800",
   "line": "one more member in this group"
  },
  "4915": {
   "unit": "game/mainProgram0800",
   "line": "type byte"
  },
  "4918": {
   "unit": "game/mainProgram0800",
   "line": "unit type 0-4 = speed class"
  },
  "491A": {
   "unit": "game/mainProgram0800",
   "line": "COMCEN?"
  },
  "491C": {
   "unit": "game/mainProgram0800",
   "line": "ordinary unit: its type is its class"
  },
  "491E": {
   "unit": "game/mainProgram0800",
   "line": "$92B4 = the local player's COMCEN SPEED option"
  },
  "4921": {
   "unit": "game/mainProgram0800",
   "line": "$9236 = the local player's comcen"
  },
  "4924": {
   "unit": "game/mainProgram0800",
   "line": "yes: keep the own setting"
  },
  "4926": {
   "unit": "game/mainProgram0800",
   "line": "$92B5 = the opponent's COMCEN SPEED option"
  },
  "4929": {
   "unit": "game/mainProgram0800",
   "line": "zp_18 = the member's speed class"
  },
  "492B": {
   "unit": "game/mainProgram0800",
   "line": "prepare the subtraction"
  },
  "492C": {
   "unit": "game/mainProgram0800",
   "line": "class 3 = SPY"
  },
  "492E": {
   "unit": "game/mainProgram0800",
   "line": "a spy ignores the terrain: class 0 (A is 0 here)"
  },
  "4930": {
   "unit": "game/mainProgram0800",
   "line": "terrain code hidden under the member"
  },
  "4933": {
   "unit": "game/mainProgram0800",
   "line": "index the class table with it"
  },
  "4934": {
   "unit": "game/mainProgram0800",
   "line": "$077E: terrain code -> movement class"
  },
  "4937": {
   "unit": "game/mainProgram0800",
   "line": "zp_19 = the member's terrain class"
  },
  "4939": {
   "unit": "game/mainProgram0800",
   "line": "index the cost table"
  },
  "493A": {
   "unit": "game/mainProgram0800",
   "line": "$405E: movement points that class costs per step"
  },
  "493D": {
   "unit": "game/mainProgram0800",
   "line": "worse ground than the group has met so far?"
  },
  "4940": {
   "unit": "game/mainProgram0800",
   "line": "no: leave the terrain class alone"
  },
  "4942": {
   "unit": "game/mainProgram0800",
   "line": "remember the new worst cost"
  },
  "4945": {
   "unit": "game/mainProgram0800",
   "line": "the class that caused it"
  },
  "4947": {
   "unit": "game/mainProgram0800",
   "line": "shift it..."
  },
  "4948": {
   "unit": "game/mainProgram0800",
   "line": "...into..."
  },
  "4949": {
   "unit": "game/mainProgram0800",
   "line": "...bits 3-5"
  },
  "494A": {
   "unit": "game/mainProgram0800",
   "line": "keep it"
  },
  "494C": {
   "unit": "game/mainProgram0800",
   "line": "the group entry"
  },
  "494F": {
   "unit": "game/mainProgram0800",
   "line": "keep the speed class bits 0-2"
  },
  "4951": {
   "unit": "game/mainProgram0800",
   "line": "insert the new terrain class"
  },
  "4953": {
   "unit": "game/mainProgram0800",
   "line": "store the entry"
  },
  "4956": {
   "unit": "game/mainProgram0800",
   "line": "the member's speed class again"
  },
  "4958": {
   "unit": "game/mainProgram0800",
   "line": "$4066: movement points that class earns per round"
  },
  "495B": {
   "unit": "game/mainProgram0800",
   "line": "slower than the slowest member so far?"
  },
  "495E": {
   "unit": "game/mainProgram0800",
   "line": "no: leave the speed class alone"
  },
  "4960": {
   "unit": "game/mainProgram0800",
   "line": "remember the new lowest rate"
  },
  "4963": {
   "unit": "game/mainProgram0800",
   "line": "the group entry"
  },
  "4966": {
   "unit": "game/mainProgram0800",
   "line": "keep the terrain class bits 3-5"
  },
  "4968": {
   "unit": "game/mainProgram0800",
   "line": "insert the slower class into bits 0-2"
  },
  "496A": {
   "unit": "game/mainProgram0800",
   "line": "store the entry"
  },
  "496D": {
   "unit": "game/mainProgram0800",
   "line": "next unit down"
  },
  "496F": {
   "unit": "game/mainProgram0800",
   "line": "until unit 0"
  },
  "4971": {
   "unit": "game/mainProgram0800",
   "line": "final pass over the 16 slots"
  },
  "4973": {
   "unit": "game/mainProgram0800",
   "line": "did the group have any living member?"
  },
  "4976": {
   "unit": "game/mainProgram0800",
   "line": "no: the entry stays cleared"
  },
  "4978": {
   "unit": "game/mainProgram0800",
   "line": "last round's entry"
  },
  "497B": {
   "unit": "game/mainProgram0800",
   "line": "bit 7 = group cloaked, bit 6 = group blitzing"
  },
  "497D": {
   "unit": "game/mainProgram0800",
   "line": "add them to the freshly computed classes"
  },
  "4980": {
   "unit": "game/mainProgram0800",
   "line": "store the entry"
  },
  "4983": {
   "unit": "game/mainProgram0800",
   "line": "next slot"
  },
  "4984": {
   "unit": "game/mainProgram0800",
   "line": "until slot 0"
  },
  "4986": {
   "unit": "game/mainProgram0800",
   "line": "the group table is up to date"
  },
  "4987": {
   "unit": "game/mainProgram0800",
   "line": "clear the accumulators",
   "routine": [
    "averageGroupMoveVector - averages the outstanding movement of one group.  Over all 100 units it",
    "sums (unitDestCol & $7F) - unitCol and (unitDestRow & $7F) - unitRow as two sign-extended 16-bit",
    "totals, counting only living units whose authoritative flag byte has the member bit 6 set and",
    "whose group key (bits 2-5) equals cmdParam2, and divides both totals by the member count.  Its",
    "only caller is followGroupMovement, so it runs when a unit joins a group and has to inherit the",
    "heading the group is already moving on.",
    "In:  zp_75 cmdParam2 = the group key in bits 2-5 (group number plus side bit); unit arrays $F640",
    "     column, $F6A4 row, $F708 flags, $F76C type, $F7D0/$F834 destination",
    "Out: A = member count (Z=1 when the group is empty), X = average column delta, Y = average row",
    "     delta; zp_18-zp_1C destroyed; self-modifies the sign-extension ADC operands at $49C6 and $49E3",
    "Called from: followGroupMovement $4A04"
   ]
  },
  "4989": {
   "unit": "game/mainProgram0800",
   "line": "zp_18/zp_19 = 16-bit sum of the column deltas"
  },
  "498B": {
   "unit": "game/mainProgram0800",
   "line": "high byte of that sum"
  },
  "498D": {
   "unit": "game/mainProgram0800",
   "line": "zp_1A/zp_1B = 16-bit sum of the row deltas"
  },
  "498F": {
   "unit": "game/mainProgram0800",
   "line": "high byte of that sum"
  },
  "4991": {
   "unit": "game/mainProgram0800",
   "line": "zp_1C = number of members found"
  },
  "4993": {
   "unit": "game/mainProgram0800",
   "line": "walk the units from 99 down to 0"
  },
  "4995": {
   "unit": "game/mainProgram0800",
   "line": "type byte"
  },
  "4998": {
   "unit": "game/mainProgram0800",
   "line": "bit 7 = destroyed: not counted"
  },
  "499A": {
   "unit": "game/mainProgram0800",
   "line": "flag byte"
  },
  "499D": {
   "unit": "game/mainProgram0800",
   "line": "bit 6 = the unit is in a group"
  },
  "499F": {
   "unit": "game/mainProgram0800",
   "line": "not a member"
  },
  "49A1": {
   "unit": "game/mainProgram0800",
   "line": "flag byte again"
  },
  "49A4": {
   "unit": "game/mainProgram0800",
   "line": "group key in bits 2-5"
  },
  "49A6": {
   "unit": "game/mainProgram0800",
   "line": "zp_75 holds the wanted key in the same bit positions"
  },
  "49A8": {
   "unit": "game/mainProgram0800",
   "line": "a member of some other group"
  },
  "49AA": {
   "unit": "game/mainProgram0800",
   "line": "count this member"
  },
  "49AC": {
   "unit": "game/mainProgram0800",
   "line": "sign-extension byte for a positive delta"
  },
  "49AE": {
   "unit": "game/mainProgram0800",
   "line": "destination column"
  },
  "49B1": {
   "unit": "game/mainProgram0800",
   "line": "drop bit 7 = at destination"
  },
  "49B3": {
   "unit": "game/mainProgram0800",
   "line": "prepare the subtraction"
  },
  "49B4": {
   "unit": "game/mainProgram0800",
   "line": "how far this member still has to travel sideways"
  },
  "49B7": {
   "unit": "game/mainProgram0800",
   "line": "positive: extend with 0"
  },
  "49B9": {
   "unit": "game/mainProgram0800",
   "line": "negative: extend with $FF"
  },
  "49BB": {
   "unit": "game/mainProgram0800",
   "line": "patch the sign into the ADC operand at $49C6"
  },
  "49BE": {
   "unit": "game/mainProgram0800",
   "line": "clear carry for the 16-bit add"
  },
  "49BF": {
   "unit": "game/mainProgram0800",
   "line": "add the low byte to the running total"
  },
  "49C1": {
   "unit": "game/mainProgram0800",
   "line": "store it"
  },
  "49C3": {
   "unit": "game/mainProgram0800",
   "line": "high byte of the total"
  },
  "49C5": {
   "unit": "game/mainProgram0800",
   "line": "operand patched above: add the sign extension plus the carry"
  },
  "49C7": {
   "unit": "game/mainProgram0800",
   "line": "store it"
  },
  "49C9": {
   "unit": "game/mainProgram0800",
   "line": "the same again for the row"
  },
  "49CB": {
   "unit": "game/mainProgram0800",
   "line": "destination row"
  },
  "49CE": {
   "unit": "game/mainProgram0800",
   "line": "drop bit 7 = repairing"
  },
  "49D0": {
   "unit": "game/mainProgram0800",
   "line": "prepare the subtraction"
  },
  "49D1": {
   "unit": "game/mainProgram0800",
   "line": "how far this member still has to travel vertically"
  },
  "49D4": {
   "unit": "game/mainProgram0800",
   "line": "positive: extend with 0"
  },
  "49D6": {
   "unit": "game/mainProgram0800",
   "line": "negative: extend with $FF"
  },
  "49D8": {
   "unit": "game/mainProgram0800",
   "line": "patch the sign into the ADC operand at $49E3"
  },
  "49DB": {
   "unit": "game/mainProgram0800",
   "line": "clear carry"
  },
  "49DC": {
   "unit": "game/mainProgram0800",
   "line": "add the low byte"
  },
  "49DE": {
   "unit": "game/mainProgram0800",
   "line": "store it"
  },
  "49E0": {
   "unit": "game/mainProgram0800",
   "line": "high byte of the total"
  },
  "49E2": {
   "unit": "game/mainProgram0800",
   "line": "operand patched above"
  },
  "49E4": {
   "unit": "game/mainProgram0800",
   "line": "store it"
  },
  "49E6": {
   "unit": "game/mainProgram0800",
   "line": "next unit down"
  },
  "49E7": {
   "unit": "game/mainProgram0800",
   "line": "until unit 0"
  },
  "49E9": {
   "unit": "game/mainProgram0800",
   "line": "column total, low byte"
  },
  "49EB": {
   "unit": "game/mainProgram0800",
   "line": "column total, high byte (carries the sign)"
  },
  "49ED": {
   "unit": "game/mainProgram0800",
   "line": "divide by the number of members"
  },
  "49EF": {
   "unit": "game/mainProgram0800",
   "line": "$FCEC: signed 16 by 8 division"
  },
  "49F2": {
   "unit": "game/mainProgram0800",
   "line": "keep the average column delta"
  },
  "49F3": {
   "unit": "game/mainProgram0800",
   "line": "row total, low byte"
  },
  "49F5": {
   "unit": "game/mainProgram0800",
   "line": "row total, high byte"
  },
  "49F7": {
   "unit": "game/mainProgram0800",
   "line": "the same divisor"
  },
  "49F9": {
   "unit": "game/mainProgram0800",
   "line": "average the row delta too"
  },
  "49FC": {
   "unit": "game/mainProgram0800",
   "line": "Y = average row delta"
  },
  "49FD": {
   "unit": "game/mainProgram0800",
   "line": "the column result"
  },
  "49FE": {
   "unit": "game/mainProgram0800",
   "line": "X = average column delta"
  },
  "49FF": {
   "unit": "game/mainProgram0800",
   "line": "A = member count, Z=1 when the group turned out to be empty"
  },
  "4A01": {
   "unit": "game/mainProgram0800",
   "line": "back to followGroupMovement"
  }
 },
 "dataTypes": {},
 "zpComments": {
  "1A": "general scratch: third math temp, right column of a frame box, low byte of the trainer's 16-bit scores; in finishRound the stack pointer of the pending-unit stack at $0464",
  "1B": "general scratch: bottom row of a frame box, division remainder (lo), max column returned by computeGroupBounds; in finishRound the cursor into unitBaseOrder, in processUnitStep the direction of the best fire target"
 }
}
