3452 lines
No EOL
104 KiB
JSON
3452 lines
No EOL
104 KiB
JSON
{
|
|
"chunk": "game_mainProgram0800_0EF7",
|
|
"unit": "game/mainProgram0800",
|
|
"unitLabels": {
|
|
"game/mainProgram0800": {
|
|
"0F03": "loadStartupOverlays",
|
|
"1030": "ensureOverlayAResident",
|
|
"1080": "loadOverlayBIfNotResident",
|
|
"10AB": "loadUnitTemplatesAndSetup",
|
|
"131B": "blinkCursorColour",
|
|
"1412": "repairLoopCounter",
|
|
"1413": "repairTabStunCopy",
|
|
"1414": "resumeMainMenuScreen",
|
|
"1507": "selectDefaultTab",
|
|
"1535": "tabActionTable",
|
|
"14F0": "snapshotComcenStatus",
|
|
"0EF7": "fireArmOrHeld",
|
|
"1101": "irqNotBrk",
|
|
"1134": "irqBailOut",
|
|
"1137": "irqPhase2",
|
|
"1174": "irqUseScrollOffsets",
|
|
"1187": "irqSpriteLoopSetup",
|
|
"1191": "irqSpriteLoop",
|
|
"11AC": "irqWriteSpriteColour",
|
|
"11B1": "irqSpritePosition",
|
|
"11DB": "irqAfterSprites",
|
|
"11E7": "irqPollInput",
|
|
"1205": "irqStoreJoystick",
|
|
"1218": "irqIdleCounters",
|
|
"123D": "irqTimerLoop",
|
|
"124F": "irqCheckAbortHotkey",
|
|
"126E": "irqPerFrameWork",
|
|
"12B4": "bumpLinkWatchdog",
|
|
"13EF": "chatLineWriteLoop",
|
|
"1493": "menuJoyLeftRight",
|
|
"14CB": "drawSelectedTab"
|
|
}
|
|
},
|
|
"notes": {
|
|
"0EF7": {
|
|
"unit": "game/mainProgram0800",
|
|
"block": [
|
|
"Tail of isFireHeld ($0EEA): reached when the button is up, or is down and has already been seen",
|
|
"released once (fireButtonArmed set). A=0 on return means 'the player is holding fire'."
|
|
],
|
|
"line": "re-read the latched fire state: 0 = button down, 1 = button up"
|
|
},
|
|
"0EF9": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "button still down (and armed) -> return A=0 = held"
|
|
},
|
|
"0EFB": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "button is up: arm the latch so the next press counts, and return A=1 = not held"
|
|
},
|
|
"0EFD": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "back to the caller; Z=1 means fire is being held"
|
|
},
|
|
"0EFE": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"stopAllSound - Silences every SID voice by requesting sound id 0, which requestSound turns into",
|
|
"$FF/$FF/$FF/$00 in the four sound-request slots $92E7-$92EA so the IRQ dequeues 'sound 0' and the",
|
|
"player releases all three voices.",
|
|
"In: none",
|
|
"Out: $92E7-$92EA reset, all voices silenced",
|
|
"Called from: initIrqAndInputState ($0BB5) and $1AF7 (end of game)"
|
|
],
|
|
"line": "sound id 0 = the 'silence everything' request"
|
|
},
|
|
"0F00": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "tail-call the $C000 sound entry (playSound preserves X/Y and returns to our caller)"
|
|
},
|
|
"0F03": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"loadStartupOverlays - One-shot start-up loader: fast-loads track 30 sectors 0-15 into $C000-$CFFF",
|
|
"(the text/glyph engine, which replaces the boot loader that lived there), then loadOverlayA - which",
|
|
"chains the message strings and the comm tail - and falls straight into loadCommModule.",
|
|
"In: isSoloTrainer ($0BA5), read further down the chain",
|
|
"Out: $C000-$CFFF, $6F00-$87FF variant A, $8800-$89FF, $EC00-$EFFF, $E000-$EBFF, comm module initialised",
|
|
"Called from: mainStart ($0A81), once"
|
|
],
|
|
"line": "destination low byte $00 ..."
|
|
},
|
|
"0F05": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... and high byte $C0: the transfer lands at $C000"
|
|
},
|
|
"0F07": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "store both into the loader's self-modifying destination operands"
|
|
},
|
|
"0F0A": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "track $1E = 30, the text/glyph engine overlay"
|
|
},
|
|
"0F0C": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$10 = 16 sectors = 4 KB -> $C000-$CFFF"
|
|
},
|
|
"0F0E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "starting at sector 0"
|
|
},
|
|
"0F10": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "pull it in over the boot loader that is still sitting at $C000"
|
|
},
|
|
"0F13": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "then the $6F00 overlay variant A, the $8800 strings and the $EC00 comm tail"
|
|
},
|
|
"0F16": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"loadCommModule - Loads the opponent module behind the $E000 jump table and initialises it. With",
|
|
"isSoloTrainer ($0BA5) bit 7 set it disables the CIA interrupts and reads track 35 sectors 0-11 (the",
|
|
"solo trainer), then points the NMI vector at the bare RTI because the trainer never uses NMIs;",
|
|
"otherwise it falls into loadCommBuild2 for the real modem driver.",
|
|
"In: isSoloTrainer ($0BA5) bit 7",
|
|
"Out: $E000-$EBFF filled, comm module initialised, (build 1) NMI vector = irqRti",
|
|
"Called from: $0AF4 in startGameFromSetup, and by fall-through from loadStartupOverlays"
|
|
],
|
|
"line": "destination low byte $00 ..."
|
|
},
|
|
"0F18": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... high byte $E0: the module always loads at $E000"
|
|
},
|
|
"0F1A": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "arm the loader's destination"
|
|
},
|
|
"0F1D": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "which opponent did the player pick?"
|
|
},
|
|
"0F20": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "bit 7 clear = modem game -> load build 2 (the software modem)"
|
|
},
|
|
"0F22": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "solo trainer: no CIA interrupts at all while the fast loader runs"
|
|
},
|
|
"0F25": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "track $23 = 35, the solo trainer"
|
|
},
|
|
"0F27": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$0C = 12 sectors = 3 KB -> $E000-$EBFF"
|
|
},
|
|
"0F29": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "from sector 0"
|
|
},
|
|
"0F2B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "load it and run the module's init entry"
|
|
},
|
|
"0F2E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the trainer has no UART, so send NMIs straight to an RTI and return"
|
|
},
|
|
"0F31": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"loadCommBuild2 - Loads the modem-driver build of the comm module with interrupts off. Its first",
|
|
"page comes from track 18 sector 7 (on the directory track, so it is not encrypted and holds the",
|
|
"module's jump table and variable block); track 34 sectors 1-11 supply the rest. Falls into",
|
|
"loadCommFinish.",
|
|
"In: load destination already set to $E000",
|
|
"Out: $E000-$EBFF = the modem driver",
|
|
"Called from: loadCommModule ($0F20) when isSoloTrainer bit 7 is clear"
|
|
],
|
|
"line": "no interrupts during the fast-loader handshake"
|
|
},
|
|
"0F32": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "track $12 = 18, the directory track"
|
|
},
|
|
"0F34": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "sector 7 holds the driver's first page"
|
|
},
|
|
"0F36": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "just that one sector -> $E000-$E0FF"
|
|
},
|
|
"0F38": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "read it (loadSectors leaves the destination advanced to $E100)"
|
|
},
|
|
"0F3B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "track $22 = 34, the rest of the modem driver"
|
|
},
|
|
"0F3D": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "sectors 1..11 (sector 0 is filler)"
|
|
},
|
|
"0F3F": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$0B = 11 sectors -> $E100-$EBFF"
|
|
},
|
|
"0F41": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"loadCommFinish - Shared tail of the two comm-module load paths: does the final loadSectors with the",
|
|
"registers the caller set up and falls into initCommModule.",
|
|
"In: A = sector count, Y = track, X = first sector, destination from setLoadDest",
|
|
"Out: comm module loaded and initialised",
|
|
"Called from: loadCommModule ($0F2B); reached by fall-through from loadCommBuild2"
|
|
],
|
|
"line": "final transfer of the module"
|
|
},
|
|
"0F44": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"initCommModule - Cold-initialises the freshly loaded comm module and grafts the game's own keyboard",
|
|
"scanner into it: the module's keyboard vector at $E013/$E014 is patched to scanKeyboard ($0DB7), so",
|
|
"the module's $E012/$E015 entries scan the matrix with the game's routine (the KERNAL is banked out).",
|
|
"In: comm module resident at $E000",
|
|
"Out: $E013/$E014 = $0DB7, interrupts enabled",
|
|
"Called from: loadCommFinish (fall-through) and directly from $0AFC"
|
|
],
|
|
"line": "function code 1 = cold initialise the module"
|
|
},
|
|
"0F46": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "call the module's life-cycle entry $E003"
|
|
},
|
|
"0F49": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "low byte of scanKeyboard ($0DB7) ..."
|
|
},
|
|
"0F4B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... into the operand of the module's keyboard JMP"
|
|
},
|
|
"0F4E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "high byte $0D ..."
|
|
},
|
|
"0F50": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... completing the vector: $E012/$E015 now scan the game's own key matrix"
|
|
},
|
|
"0F53": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the module is live: let the raster IRQ run again"
|
|
},
|
|
"0F54": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "done"
|
|
},
|
|
"0F55": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"loadSectorsDelayed - Wrapper around loadSectors that first burns 8 raster frames through the $C000",
|
|
"frame delay, giving the drive time to settle (and the previous fast-load handshake time to finish)",
|
|
"before the next request. Every overlay, map and setup load in this file goes through it.",
|
|
"In: A = sector count, Y = track, X = first sector, destination from setLoadDest",
|
|
"Out: as loadSectors (memory filled, C=1 on error)",
|
|
"Called from: $0FD1, $1054, $105D, $106D, $1096, $109F, $10B8, $107D, $10C8 and overlay A ($7E97, $7F84)"
|
|
],
|
|
"line": "the sector count must survive the delay"
|
|
},
|
|
"0F56": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "8 frames ..."
|
|
},
|
|
"0F58": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... of raster-timed idling (Y and X are preserved by waitFrames)"
|
|
},
|
|
"0F5B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "get the sector count back"
|
|
},
|
|
"0F5C": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "now do the transfer and return to our caller"
|
|
},
|
|
"0F5F": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"suspendCommModule - Asks the comm module to pause before the game touches the disk: the fast loader",
|
|
"needs interrupts off and exact cycle timing, which a UART NMI would ruin. When the link is up it",
|
|
"writes request code $C0 into the module's suspend-request byte $E039 and spins until the module",
|
|
"acknowledges by setting bit 7 of $E03A. A is preserved across the call.",
|
|
"In: $E03B (link active flag)",
|
|
"Out: $E039 = $C0; blocks until $E03A bit 7 is set",
|
|
"Called from: suspendCommForDiskAccess ($10CB)"
|
|
],
|
|
"line": "the caller's A must survive"
|
|
},
|
|
"0F60": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "is the link actually up?"
|
|
},
|
|
"0F63": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "no link (or the solo trainer) - nothing to suspend"
|
|
},
|
|
"0F65": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$C0 = 'disable every CIA2 NMI source' request code"
|
|
},
|
|
"0F67": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "hand it to the module's request byte $E039"
|
|
},
|
|
"0F6A": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "poll the acknowledge byte $E03A ..."
|
|
},
|
|
"0F6D": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... until bit 7 says the module has parked itself"
|
|
},
|
|
"0F6F": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "restore the caller's A"
|
|
},
|
|
"0F70": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the disk may now be touched"
|
|
},
|
|
"0F71": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"resumeCommModule - Counterpart of suspendCommModule: when the link is up it clears the request byte",
|
|
"$E039 and spins until the module clears bit 7 of the acknowledge byte $E03A, i.e. until the UART",
|
|
"NMIs are running again.",
|
|
"In: $E03B (link active flag)",
|
|
"Out: $E039 = 0; blocks until $E03A bit 7 is clear",
|
|
"Called from: resumeCommAfterDiskAccess ($10D1)"
|
|
],
|
|
"line": "is the link up?"
|
|
},
|
|
"0F74": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "no link - nothing to resume"
|
|
},
|
|
"0F76": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "0 = 'no suspend request'"
|
|
},
|
|
"0F78": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "release the module"
|
|
},
|
|
"0F7B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "poll the acknowledge byte ..."
|
|
},
|
|
"0F7E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... until the module reports it is running again"
|
|
},
|
|
"0F80": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "back to normal service"
|
|
},
|
|
"0F81": {
|
|
"unit": "game/mainProgram0800",
|
|
"block": [
|
|
"Three status-line strings used by the disk routines below, each terminated by a character with",
|
|
"bit 7 set. showDiskMessageAndFail is called with A = low byte, Y = high byte ($0F)."
|
|
],
|
|
"line": "shown when the disk in the drive is not the film/data disk ('EA')"
|
|
},
|
|
"0F91": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "shown when the disk in the drive is not the game disk ('OZ')"
|
|
},
|
|
"0FA2": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "shown when the BAM read itself failed (drive error or no disk)"
|
|
},
|
|
"0FAD": {
|
|
"unit": "game/mainProgram0800",
|
|
"block": [
|
|
"diskIdTable: two 2-character disk ids indexed by X (X=0 -> 'OZ' = the game disk, X=2 -> 'EA' = the",
|
|
"film/data disk). checkDiskId reads the first character with diskIdTable,X and the second with",
|
|
"$0FAE,X and compares them against the id field of the BAM at $02A2/$02A3."
|
|
],
|
|
"line": "first character of the game-disk id 'OZ' = Ozark Softscape"
|
|
},
|
|
"0FAE": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "'Z' completes 'OZ'; 'E','A' is the data-disk id used for game films"
|
|
},
|
|
"0FB1": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"checkDiskId - Verifies which disk is in the drive. Reads the BAM (track 18 sector 0, which is not",
|
|
"encrypted) to $0200 and compares the disk id at $02A2/$02A3 with the two characters of",
|
|
"diskIdTable[X]; the two expected characters and the 'silent' flag are stuffed into instruction",
|
|
"operands rather than variables. For the game disk (X=0), outside film playback, it also copies the",
|
|
"ten bytes at BAM offset $AB - the owner name the game writes onto each player's disk - into",
|
|
"ownPlayerName ($FFDE), which buildOwnerNameString turns into the printed owner line and which is",
|
|
"exchanged with the opponent. NOTE: the read clobbers $0200-$02FF, so callers reload the setup block.",
|
|
"In: A = silent flag (bit 7 set = fail without a message), X = 0 ('OZ') or 2 ('EA')",
|
|
"Out: C=0 ok / C=1 wrong disk or drive error, diskIdIndex ($92F0), $FFDE-$FFE7, $0200-$02FF clobbered",
|
|
"Called from: waitForGameDisk ($10E3) and the film save/load code in overlay A ($7E53, $7E5C)"
|
|
],
|
|
"line": "self-modifying: the caller's silent flag becomes the operand of the LDA #$FF at $0FFE"
|
|
},
|
|
"0FB4": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "remember which id we are looking for (X is about to be destroyed)"
|
|
},
|
|
"0FB7": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "Y = expected first id character ('O' or 'E')"
|
|
},
|
|
"0FBA": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "A = expected second id character ('Z' or 'A'), from diskIdTable+1"
|
|
},
|
|
"0FBD": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "park it in X so both can be written into the compare operands"
|
|
},
|
|
"0FBE": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "self-modifying: patch the CMP #$FF at $0FDC with the expected first character"
|
|
},
|
|
"0FC1": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "self-modifying: patch the CMP #$FF at $0FE3 with the expected second character"
|
|
},
|
|
"0FC4": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "BAM destination low byte $00 ..."
|
|
},
|
|
"0FC6": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... high byte $02: the sector lands at $0200 (over the terrain rule table)"
|
|
},
|
|
"0FC8": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "arm the loader"
|
|
},
|
|
"0FCB": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "one sector"
|
|
},
|
|
"0FCD": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "track $12 = 18, the directory track"
|
|
},
|
|
"0FCF": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "sector 0 = the BAM"
|
|
},
|
|
"0FD1": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "read it with the usual 8-frame settling delay"
|
|
},
|
|
"0FD4": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "C=0: the BAM is in memory"
|
|
},
|
|
"0FD6": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "drive error / no disk -> 'DISK ERROR.' and C=1"
|
|
},
|
|
"0FD9": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "first character of the disk id in the BAM"
|
|
},
|
|
"0FDC": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "compare against the expected first character (operand patched at $0FBE)"
|
|
},
|
|
"0FDE": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "wrong disk"
|
|
},
|
|
"0FE0": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "second character of the disk id"
|
|
},
|
|
"0FE3": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "compare against the expected second character (operand patched at $0FC1)"
|
|
},
|
|
"0FE5": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "wrong disk"
|
|
},
|
|
"0FE7": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "which id were we checking?"
|
|
},
|
|
"0FEA": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "non-zero = the 'EA' data disk: nothing else to do, report success"
|
|
},
|
|
"0FEC": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "game disk: is a film being replayed?"
|
|
},
|
|
"0FEF": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "during playback the film supplies the names, so leave $FFDE alone"
|
|
},
|
|
"0FF1": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "copy 10 bytes, index 9 down to 0"
|
|
},
|
|
"0FF3": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "BAM offset $AB = the owner name EA writes into the unused tail of the BAM"
|
|
},
|
|
"0FF6": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "-> ownPlayerName ($FFDE-$FFE7), used by buildOwnerNameString and the link handshake"
|
|
},
|
|
"0FF9": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "next byte"
|
|
},
|
|
"0FFA": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "loop until index 0 has been copied"
|
|
},
|
|
"0FFC": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "always taken (X went to $FF): report success"
|
|
},
|
|
"0FFE": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "operand patched at $0FB1 with the caller's silent flag"
|
|
},
|
|
"1000": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "bit 7 set = caller wants a silent failure -> just return C=1"
|
|
},
|
|
"1002": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "low byte of msgInsertGameDisk ($0F91) ..."
|
|
},
|
|
"1004": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... and its high byte"
|
|
},
|
|
"1006": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "which id did we expect (the patched compare operand)?"
|
|
},
|
|
"1009": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "'E' means we wanted the data disk 'EA'"
|
|
},
|
|
"100B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "wanted the game disk -> keep 'INSERT GAME DISK.'"
|
|
},
|
|
"100D": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "low byte of msgNotADataDisk ($0F81) - overlay A jumps straight in here at $7E71"
|
|
},
|
|
"100F": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... and its high byte"
|
|
},
|
|
"1011": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "show it, beep, pause and return C=1"
|
|
},
|
|
"1014": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "C=0 = the expected disk is in the drive"
|
|
},
|
|
"1015": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "success return"
|
|
},
|
|
"1016": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "C=1 = wrong disk"
|
|
},
|
|
"1017": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "silent failure return"
|
|
},
|
|
"1018": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"diskErrorExit - Loads the address of msgDiskError ('DISK ERROR.') and falls into",
|
|
"showDiskMessageAndFail.",
|
|
"In: none",
|
|
"Out: message shown, C=1",
|
|
"Called from: checkDiskId ($0FD6) and overlay A ($7E9D)"
|
|
],
|
|
"line": "low byte of msgDiskError ($0FA2) ..."
|
|
},
|
|
"101A": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... and its high byte"
|
|
},
|
|
"101C": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"showDiskMessageAndFail - Common failure exit of the disk routines: error beep, put the message on",
|
|
"the centred status line for about two seconds, blank the line again and return C=1.",
|
|
"In: A = message address low byte, Y = high byte (bit-7 terminated string)",
|
|
"Out: C=1, status line restored",
|
|
"Called from: checkDiskId ($1011) and diskErrorExit by fall-through"
|
|
],
|
|
"line": "the message pointer's low byte has to survive the beep"
|
|
},
|
|
"101D": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "sound 3 = the error buzz"
|
|
},
|
|
"101F": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "queue it (playSound preserves Y, which still holds the message page)"
|
|
},
|
|
"1022": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "get the low byte back"
|
|
},
|
|
"1023": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "print the string centred on the 36-column status line"
|
|
},
|
|
"1026": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$64 = 100 frames, about 2 seconds ..."
|
|
},
|
|
"1028": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... so the player can read it"
|
|
},
|
|
"102B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "blank the status line again"
|
|
},
|
|
"102E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "C=1 = the operation failed"
|
|
},
|
|
"102F": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "back to the caller"
|
|
},
|
|
"1030": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"ensureOverlayAResident - Makes sure the $6F00-$87FF overlay variant A (map generator, setup and menu",
|
|
"code) is in memory before control leaves for handleMainMenuChoice ($7DE3). overlayVariantFlag",
|
|
"($87FF) is the identity byte carried by whichever overlay is resident: $FF = variant B, so variant A",
|
|
"must be read in full; $00 = variant A is already there and only the $8800 message strings and the",
|
|
"$EC00 comm tail (which sub-overlays borrow) need refreshing.",
|
|
"In: overlayVariantFlag ($87FF)",
|
|
"Out: variant A resident plus fresh strings/comm tail; comm module suspended and resumed around the disk access",
|
|
"Called from: $1C72, with diskLoadDepth bumped around the call"
|
|
],
|
|
"line": "park the comm module and put 'WORKING...' on the status line"
|
|
},
|
|
"1033": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "make sure the OZ disk is really in the drive first"
|
|
},
|
|
"1036": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "identity byte of the resident $6F00 overlay"
|
|
},
|
|
"1039": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$FF = variant B is resident -> the whole of variant A has to be read"
|
|
},
|
|
"103B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "variant A is already there: just refresh $8800-$89FF and $EC00-$EFFF"
|
|
},
|
|
"103E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "restart the comm module, clear the message and return"
|
|
},
|
|
"1041": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "read variant A (which chains the strings and the comm tail)"
|
|
},
|
|
"1044": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "restart the comm module, clear the message and return"
|
|
},
|
|
"1047": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"loadOverlayA - Reads the $6F00-$87FF overlay variant A: track 31 sectors 0-16 to $6F00-$7FFF and",
|
|
"track 32 sectors 0-7 to $8000-$87FF. Variant A is the random map generator, the setup phase and the",
|
|
"film menus. Falls into loadStringsAndCommTail.",
|
|
"In: none",
|
|
"Out: $6F00-$87FF = variant A (its last byte $87FF is the identity byte $00), plus $8800-$89FF and $EC00-$EFFF",
|
|
"Called from: loadStartupOverlays ($0F13) and ensureOverlayAResident ($1041)"
|
|
],
|
|
"line": "destination low byte $00 ..."
|
|
},
|
|
"1049": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... high byte $6F: the overlay starts at $6F00"
|
|
},
|
|
"104B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "arm the loader"
|
|
},
|
|
"104E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "track $1F = 31"
|
|
},
|
|
"1050": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "from sector 0"
|
|
},
|
|
"1052": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$11 = 17 sectors -> $6F00-$7FFF"
|
|
},
|
|
"1054": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "read them"
|
|
},
|
|
"1057": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "track $20 = 32"
|
|
},
|
|
"1059": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "from sector 0"
|
|
},
|
|
"105B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "8 sectors -> $8000-$87FF, ending with the identity byte at $87FF"
|
|
},
|
|
"105D": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "read them"
|
|
},
|
|
"1060": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"loadStringsAndCommTail - Reads the modem status-message string block (track 29 sectors 9-10) into",
|
|
"$8800-$89FF, then falls into loadCommTailBuild2. In a solo game the trainer overwrites this block",
|
|
"with its own per-unit tables, so it has to be reloaded whenever the strings are wanted again.",
|
|
"In: none",
|
|
"Out: $8800-$89FF strings, $EC00-$EFFF comm tail",
|
|
"Called from: ensureOverlayAResident ($103B); reached by fall-through from loadOverlayA"
|
|
],
|
|
"line": "destination low byte $00 ..."
|
|
},
|
|
"1062": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... high byte $88"
|
|
},
|
|
"1064": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "arm the loader"
|
|
},
|
|
"1067": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "track $1D = 29"
|
|
},
|
|
"1069": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "from sector 9"
|
|
},
|
|
"106B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "2 sectors -> $8800-$89FF"
|
|
},
|
|
"106D": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "read them"
|
|
},
|
|
"1070": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"loadCommTailBuild2 - Reads the last page group of the modem driver (track 34 sectors 12-15) into",
|
|
"$EC00-$EFFF. Overlay A also calls it to put the comm tail back after the $EC00 sub-overlay from",
|
|
"track 29 has temporarily occupied that space.",
|
|
"In: none",
|
|
"Out: $EC00-$EFFF = the modem driver tail",
|
|
"Called from: overlay A ($7B33); reached by fall-through from loadStringsAndCommTail"
|
|
],
|
|
"line": "destination low byte $00 ..."
|
|
},
|
|
"1072": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... high byte $EC"
|
|
},
|
|
"1074": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "arm the loader"
|
|
},
|
|
"1077": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "track $22 = 34"
|
|
},
|
|
"1079": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "from sector $0C = 12"
|
|
},
|
|
"107B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "4 sectors -> $EC00-$EFFF"
|
|
},
|
|
"107D": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "read them and return straight to our caller"
|
|
},
|
|
"1080": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"loadOverlayBIfNotResident - Loads the $6F00 overlay variant B only when it is not already in memory.",
|
|
"overlayVariantFlag ($87FF) is $00 while variant A is resident and $FF while B is, so a positive",
|
|
"value means the swap has to happen.",
|
|
"In: overlayVariantFlag ($87FF)",
|
|
"Out: see loadOverlayB, or nothing at all",
|
|
"Called from: startGameFromSetup ($0B5F)"
|
|
],
|
|
"line": "identity byte of the resident $6F00 overlay"
|
|
},
|
|
"1083": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$00 = variant A is resident -> swap variant B in"
|
|
},
|
|
"1085": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "variant B is already there, nothing to do"
|
|
},
|
|
"1086": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"loadOverlayB - Reads the $6F00-$87FF overlay variant B (the comcen missile and drone screens): track",
|
|
"33 sectors 0-16 to $6F00-$7FFF and track 32 sectors 8-15 to $8000-$87FF. Afterwards it copies the",
|
|
"byte at $206B into $750A: both are the opcode byte of a BCC/BCS that follows a 'is this unit index",
|
|
"below 50' test, i.e. the side-dependent branch the main program has already patched for this",
|
|
"player's side, propagated into the freshly loaded overlay.",
|
|
"In: $206B (the patched branch opcode), overlayVariantFlag",
|
|
"Out: $6F00-$87FF = variant B, $750A patched, comm module suspended and resumed",
|
|
"Called from: loadOverlayBIfNotResident ($1083)"
|
|
],
|
|
"line": "park the comm module and show 'WORKING...' - the fast loader needs the interrupts"
|
|
},
|
|
"1089": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "destination low byte $00 ..."
|
|
},
|
|
"108B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... high byte $6F"
|
|
},
|
|
"108D": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "arm the loader"
|
|
},
|
|
"1090": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "track $21 = 33"
|
|
},
|
|
"1092": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$11 = 17 sectors -> $6F00-$7FFF"
|
|
},
|
|
"1094": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "from sector 0"
|
|
},
|
|
"1096": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "read them"
|
|
},
|
|
"1099": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "track $20 = 32"
|
|
},
|
|
"109B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "from sector 8 (sectors 0-7 of that track belong to variant A)"
|
|
},
|
|
"109D": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "8 sectors -> $8000-$87FF"
|
|
},
|
|
"109F": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "read them"
|
|
},
|
|
"10A2": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the branch opcode ($90 BCC / $B0 BCS) that patchOwnSideBranches wrote at $206B for this player's side"
|
|
},
|
|
"10A5": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "patch the matching 'cpy #$32 / branch' in the overlay at $7508-$750A"
|
|
},
|
|
"10A8": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "restart the comm module, clear the message and return"
|
|
},
|
|
"10AB": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"loadUnitTemplatesAndSetup - Reads track 18 sectors 8-14 into $F000-$F6FF, then falls into",
|
|
"loadSetupBlock. What is on the disk there is not a battlefield: it is four 400-byte unit",
|
|
"start-position templates (columns, rows, flags and types for 100 units each) which the setup code",
|
|
"picks from and copies into the live unit arrays; the 40x40 map is generated, not loaded.",
|
|
"In: none",
|
|
"Out: $F000-$F6FF = the start-position templates, $0200-$03FF = the setup block",
|
|
"Called from: startGameFromSetup ($0B35), with diskLoadDepth bumped so the IRQ drops keypresses"
|
|
],
|
|
"line": "destination low byte $00 ..."
|
|
},
|
|
"10AD": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... high byte $F0"
|
|
},
|
|
"10AF": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "arm the loader"
|
|
},
|
|
"10B2": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "track $12 = 18, the directory track"
|
|
},
|
|
"10B4": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "from sector 8"
|
|
},
|
|
"10B6": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "7 sectors -> $F000-$F6FF (four 400-byte templates plus 192 unused bytes)"
|
|
},
|
|
"10B8": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "read them"
|
|
},
|
|
"10BB": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"loadSetupBlock - Reads the saved setup block (track 18 sectors 15-16) into $0200-$03FF: the terrain",
|
|
"tile rule table at $0200 and the persisted game settings plus the little start-up routine at $0300.",
|
|
"In: none",
|
|
"Out: $0200-$03FF",
|
|
"Called from: mainStart ($0A84); reached by fall-through from loadUnitTemplatesAndSetup"
|
|
],
|
|
"line": "destination low byte $00 ..."
|
|
},
|
|
"10BD": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... high byte $02"
|
|
},
|
|
"10BF": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "arm the loader"
|
|
},
|
|
"10C2": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "track $12 = 18"
|
|
},
|
|
"10C4": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "from sector $0F = 15"
|
|
},
|
|
"10C6": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "2 sectors -> $0200-$03FF"
|
|
},
|
|
"10C8": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "read them and return straight to our caller"
|
|
},
|
|
"10CB": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"suspendCommForDiskAccess - Standard prologue for disk access: pause the comm module, then set",
|
|
"persistentMessageId to 1 and paint message 1 ('WORKING...') on the status line so the player knows",
|
|
"the drive is busy.",
|
|
"In: none",
|
|
"Out: comm module paused, persistentMessageId ($92A1) = 1",
|
|
"Called from: ensureOverlayAResident ($1030), loadOverlayB ($1086), waitForGameDiskInserted ($10DC) and overlay A ($7B7D, $7DF7, $7F57, $815E)"
|
|
],
|
|
"line": "stop the UART NMIs so the fast loader can keep its timing"
|
|
},
|
|
"10CE": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "show the 'WORKING...' notice and return to our caller"
|
|
},
|
|
"10D1": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"resumeCommAfterDiskAccess - Epilogue for disk access: restart the comm module, forget the persistent",
|
|
"'WORKING...' message and blank the status line.",
|
|
"In: none",
|
|
"Out: comm module running, persistentMessageId ($92A1) = 0, status line cleared",
|
|
"Called from: $0B3D, $103E, $1044, $10A8 and overlay A ($7DFE, $7F95, $81A2, $81AF)"
|
|
],
|
|
"line": "let the module's NMIs run again"
|
|
},
|
|
"10D4": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "no message is being held on the line any more"
|
|
},
|
|
"10D6": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "clear the persistent message id"
|
|
},
|
|
"10D9": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "blank the status line and return to our caller"
|
|
},
|
|
"10DC": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"waitForGameDiskInserted - Blocks until the OZ game disk is in the drive. Suspends the comm module",
|
|
"(and leaves it suspended for the caller), then loops: check the disk id verbosely, and on failure",
|
|
"print 'PRESS BUTTON WHEN READY.' and wait for a fire click before trying again. Because that prompt",
|
|
"stirs the RNG while it waits, the delay also randomises the map seed.",
|
|
"In: none",
|
|
"Out: returns only with C=0 from checkDiskId; comm module left suspended",
|
|
"Called from: mainStart ($0ADC), ensureOverlayAResident ($1033) and overlay A ($81AC)"
|
|
],
|
|
"line": "pause the comm module and show 'WORKING...'"
|
|
},
|
|
"10DF": {
|
|
"unit": "game/mainProgram0800",
|
|
"block": [
|
|
"Retry loop: ask for the game disk until it is there."
|
|
],
|
|
"line": "id index 0 = the game disk 'OZ'"
|
|
},
|
|
"10E1": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "A bit 7 clear = report a mismatch on the status line"
|
|
},
|
|
"10E3": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "read the BAM and compare the id"
|
|
},
|
|
"10E6": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "C=0: the right disk is in the drive"
|
|
},
|
|
"10E8": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "wrong disk: prompt and wait for the fire button"
|
|
},
|
|
"10EB": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "then try again"
|
|
},
|
|
"10EE": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the game disk is present"
|
|
},
|
|
"10EF": {
|
|
"unit": "game/mainProgram0800",
|
|
"block": [
|
|
"spriteEnableScratch: written by the raster IRQ at $11CB with the sprite enable mask it is about to",
|
|
"put into VIC_SPR_ENA. Nothing ever reads it back (a dead store); $10F0 is unused padding before",
|
|
"the interrupt handler."
|
|
],
|
|
"line": "copy of the last sprite enable mask written by the IRQ; never read"
|
|
},
|
|
"10F1": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"rasterIrqHandler - The game's only interrupt handler, entered through the RAM vector $FFFE at raster",
|
|
"line $FA (250), installed by installRasterIrq ($0C66). A BRK is recognised from the B flag in the",
|
|
"pushed status byte and thrown away through the patchable JMP operand at $10FF/$1100 (a debug hook",
|
|
"that initInterruptVectors points at irqExit). Phase 1 acknowledges the VIC interrupt, re-arms the",
|
|
"raster line and the $FFFE/$FFFF vector from their zero-page shadows, guards against re-entry with",
|
|
"irqInProgress, copies the two VIC control registers from their shadows and services the comm module",
|
|
"($E000 with X=0 and $E00C); this half also runs while a disk load is in progress. Phase 2 copies",
|
|
"the remaining VIC shadows and the eight sprite colour/X/Y shadows (colours >= $10 hold two nibbles",
|
|
"that alternate every other frame to make a sprite flash; positions can be biased by the fine-scroll",
|
|
"offsets), bumps the 24-bit frame counter, re-enables interrupts, polls the keyboard and joystick 2,",
|
|
"maintains the idle counter, the RNG and the six frame countdowns, watches for the SHIFT+C=+F7 abort,",
|
|
"blinks the map cursor, ticks the frame timers, runs both halves of the chat and drives the sound.",
|
|
"In: VIC and CIA1 registers, the shadow block $9000-$9024, inputLockoutTimer ($0B7D), diskLoadDepth",
|
|
" ($0BA7), screenShakeTimer ($92C8), spriteScrollFineX/Y ($92F4/$92F5), comm entries $E000/$E00C",
|
|
"Out: every VIC register, frameCounter (zp_45-zp_47), joyDirection/joyFireUp and their copies,",
|
|
" requestedScreenKey, irqInProgress, the timers zp_6C-zp_71, the chat buffers and the sound state",
|
|
"Called from: the hardware IRQ vector $FFFE (and BRK)"
|
|
],
|
|
"line": "save the registers the handler is about to use"
|
|
},
|
|
"10F2": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "X ..."
|
|
},
|
|
"10F3": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... onto the stack"
|
|
},
|
|
"10F4": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "Y ..."
|
|
},
|
|
"10F5": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... onto the stack"
|
|
},
|
|
"10F6": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "S now points 6 bytes below the pushed processor status"
|
|
},
|
|
"10F7": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$0104+S = the status byte the CPU pushed when it took the interrupt"
|
|
},
|
|
"10FA": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "bit 4 = the B flag: set means this was a BRK, not a raster IRQ"
|
|
},
|
|
"10FC": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "a real interrupt - carry on"
|
|
},
|
|
"10FE": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "BRK debug hook: the operand at $10FF/$1100 is patched by initInterruptVectors to irqExit"
|
|
},
|
|
"1101": {
|
|
"unit": "game/mainProgram0800",
|
|
"block": [
|
|
"Acknowledge the VIC interrupt and re-arm both the raster line and the RAM interrupt vector; the",
|
|
"vector is rewritten every frame because the film code temporarily flips $01 to see the RAM under",
|
|
"the I/O area."
|
|
],
|
|
"line": "bit 0 = the raster interrupt latch ..."
|
|
},
|
|
"1103": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... written back to clear it"
|
|
},
|
|
"1106": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the raster line the game wants ($FA = 250, below the visible playfield)"
|
|
},
|
|
"1108": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "re-arm VIC_RASTER for the next frame"
|
|
},
|
|
"110B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "shadow of the IRQ vector low byte ..."
|
|
},
|
|
"110D": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... written back into $FFFE"
|
|
},
|
|
"1110": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "shadow of the high byte ..."
|
|
},
|
|
"1112": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... written back into $FFFF"
|
|
},
|
|
"1115": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "is a previous invocation still running? (the handler re-enables interrupts halfway through)"
|
|
},
|
|
"1117": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "yes - do nothing this frame"
|
|
},
|
|
"1119": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "mark the handler as busy"
|
|
},
|
|
"111B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "shadow of VIC_CTRL1 (screen mode, raster bit 8, Y scroll)"
|
|
},
|
|
"111E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "-> $D011"
|
|
},
|
|
"1121": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "shadow of VIC_CTRL2 (multicolour, X scroll)"
|
|
},
|
|
"1124": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "-> $D016"
|
|
},
|
|
"1127": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "function 0 = the comm module's per-frame service tick"
|
|
},
|
|
"1129": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "run the UART / trainer bit-and-byte timing"
|
|
},
|
|
"112C": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "and the suspend handshake plus the carrier-detect sampling"
|
|
},
|
|
"112F": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "how deeply nested is the current disk load?"
|
|
},
|
|
"1132": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "always taken in practice - nothing ever makes diskLoadDepth negative, so the bail-out below is effectively dead"
|
|
},
|
|
"1134": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "bail out with only the comm module serviced"
|
|
},
|
|
"1137": {
|
|
"unit": "game/mainProgram0800",
|
|
"block": [
|
|
"Phase 2: push the rest of the VIC shadow block ($9002-$9006, $9020, $9023, $9024) into the chip.",
|
|
"Keeping shadows and copying them once per frame means the game never has to worry about a partly",
|
|
"updated register being displayed."
|
|
],
|
|
"line": "shadow of VIC_MEM_PTR (bitmap at $A000, video matrix at $8C00 within VIC bank 2)"
|
|
},
|
|
"113A": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "-> $D018"
|
|
},
|
|
"113D": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "border colour shadow"
|
|
},
|
|
"1140": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "-> $D020"
|
|
},
|
|
"1143": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "background colour 0 shadow"
|
|
},
|
|
"1146": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "-> $D021"
|
|
},
|
|
"1149": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "multicolour background 1 shadow"
|
|
},
|
|
"114C": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "-> $D022"
|
|
},
|
|
"114F": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "multicolour background 2 shadow"
|
|
},
|
|
"1152": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "-> $D023"
|
|
},
|
|
"1155": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "sprite X bit-8 mask shadow"
|
|
},
|
|
"1158": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "-> $D010"
|
|
},
|
|
"115B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "sprite X expand mask shadow"
|
|
},
|
|
"115E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "-> $D01D"
|
|
},
|
|
"1161": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "sprite Y expand mask shadow"
|
|
},
|
|
"1164": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "-> $D017"
|
|
},
|
|
"1167": {
|
|
"unit": "game/mainProgram0800",
|
|
"block": [
|
|
"Sprite position bias: while screenShakeTimer is running the sprites are shifted by the current fine",
|
|
"scroll offsets so they stay glued to the smooth-scrolled bitmap; otherwise both biases are zero.",
|
|
"The two offsets are written into the ADC operands at $11B6 and $11BF."
|
|
],
|
|
"line": "is the screen being shaken / fine-scrolled?"
|
|
},
|
|
"116A": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "yes - derive the offsets from the scroll position"
|
|
},
|
|
"116C": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "no bias: patch the X adder at $11B5 with 0"
|
|
},
|
|
"116F": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "and the Y adder at $11BE with 0"
|
|
},
|
|
"1172": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "always taken (A is still 0)"
|
|
},
|
|
"1174": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "vertical fine-scroll position"
|
|
},
|
|
"1177": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "only the 0-7 pixel offset"
|
|
},
|
|
"1179": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "prepare a borrow-free subtraction"
|
|
},
|
|
"117A": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "centre it: -3..+4 pixels"
|
|
},
|
|
"117C": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "patch the Y adder operand at $11BE"
|
|
},
|
|
"117F": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "horizontal fine-scroll position"
|
|
},
|
|
"1182": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "only the 0-7 pixel offset"
|
|
},
|
|
"1184": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "patch the X adder operand at $11B5"
|
|
},
|
|
"1187": {
|
|
"unit": "game/mainProgram0800",
|
|
"block": [
|
|
"Copy the eight sprite shadows into the VIC. Y counts the sprite index 7..0 and X the register",
|
|
"offset 2*index, so $D000+X / $D001+X are that sprite's X and Y registers. A colour shadow below",
|
|
"$10 is a plain colour; $10 and above packs two nibbles which are swapped every other frame to make",
|
|
"the sprite flash between two colours."
|
|
],
|
|
"line": "start with sprite 7"
|
|
},
|
|
"1189": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$0E = 7*2, the X/Y register offset of sprite 7"
|
|
},
|
|
"118B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "free-running frame counter ..."
|
|
},
|
|
"118D": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... rotated right twice ..."
|
|
},
|
|
"118E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... so that bit 7 of the result is bit 0 of the frame counter"
|
|
},
|
|
"118F": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the flash phase: negative on every other frame"
|
|
},
|
|
"1191": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "colour shadow of sprite Y ($9008+Y)"
|
|
},
|
|
"1194": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "values 0-$0F are ordinary colours"
|
|
},
|
|
"1196": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "plain colour - write it straight out"
|
|
},
|
|
"1198": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "two packed nibbles: only swap them on the flashing frames"
|
|
},
|
|
"119A": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "off-phase frame - leave the colour register untouched"
|
|
},
|
|
"119C": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "compare the shadow with what the register currently holds"
|
|
},
|
|
"119F": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "look at the low nibble of the difference"
|
|
},
|
|
"11A1": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "C=1 when the register does not already show the shadow's low nibble"
|
|
},
|
|
"11A3": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "reload the packed shadow byte"
|
|
},
|
|
"11A6": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "register differs -> show the low nibble this time"
|
|
},
|
|
"11A8": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "otherwise shift the high nibble down ..."
|
|
},
|
|
"11A9": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... (4 shifts) ..."
|
|
},
|
|
"11AA": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... so the sprite alternates ..."
|
|
},
|
|
"11AB": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... between the two packed colours"
|
|
},
|
|
"11AC": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "only the colour bits"
|
|
},
|
|
"11AE": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "-> $D027+Y, the sprite's colour register"
|
|
},
|
|
"11B1": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "X position shadow of sprite Y ($9010+Y)"
|
|
},
|
|
"11B4": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "clear carry for the bias add"
|
|
},
|
|
"11B5": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "add the horizontal bias (operand patched at $116C or $1184)"
|
|
},
|
|
"11B7": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "-> $D000+X, the sprite's X register"
|
|
},
|
|
"11BA": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "Y position shadow of sprite Y ($9018+Y)"
|
|
},
|
|
"11BD": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "clear carry for the bias add"
|
|
},
|
|
"11BE": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "add the vertical bias (operand patched at $116F or $117C)"
|
|
},
|
|
"11C0": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "-> $D001+X, the sprite's Y register"
|
|
},
|
|
"11C3": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "step the register offset ..."
|
|
},
|
|
"11C4": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... down by two"
|
|
},
|
|
"11C5": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "next sprite"
|
|
},
|
|
"11C6": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "loop until sprite 0 has been done"
|
|
},
|
|
"11C8": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "sprite enable mask shadow"
|
|
},
|
|
"11CB": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "keep a copy at $10EF (nothing ever reads it back)"
|
|
},
|
|
"11CE": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "-> $D015, so sprites appear and disappear in step with the rest of the frame"
|
|
},
|
|
"11D1": {
|
|
"unit": "game/mainProgram0800",
|
|
"block": [
|
|
"Bump the free-running 24-bit frame counter zp_45/zp_46/zp_47."
|
|
],
|
|
"line": "low byte of the frame counter"
|
|
},
|
|
"11D3": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "no carry into the middle byte"
|
|
},
|
|
"11D5": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "middle byte"
|
|
},
|
|
"11D7": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "no carry into the high byte"
|
|
},
|
|
"11D9": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "high byte: wraps after about 77 hours"
|
|
},
|
|
"11DB": {
|
|
"unit": "game/mainProgram0800",
|
|
"block": [
|
|
"From here on the handler runs with interrupts enabled - irqInProgress keeps a second raster IRQ",
|
|
"from re-entering it. inputLockoutTimer counts frames during which the keyboard and joystick are",
|
|
"not sampled at all, so joyDirection and joyFireUp keep whatever they had."
|
|
],
|
|
"line": "everything time-critical is done; allow interrupts again"
|
|
},
|
|
"11DC": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "is input still locked out (after a screen change or an abort)?"
|
|
},
|
|
"11DF": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "no - sample the keyboard and the stick"
|
|
},
|
|
"11E1": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "count the lockout down one frame ..."
|
|
},
|
|
"11E4": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... and skip the whole input poll"
|
|
},
|
|
"11E7": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "scan the key matrix through the comm module's keyboard entry"
|
|
},
|
|
"11EA": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "default 'joystick idle' pattern in case a key is pending"
|
|
},
|
|
"11EC": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "did the poll leave a screen-select key pending (0-3 = F1/F3/F5/F7, $FF = none)?"
|
|
},
|
|
"11EE": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "yes - do not read the stick this frame"
|
|
},
|
|
"11F0": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "is a typed key waiting to be consumed?"
|
|
},
|
|
"11F3": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$FF = no key"
|
|
},
|
|
"11F5": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "a key is pending - do not read the stick this frame"
|
|
},
|
|
"11F7": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "deselect every keyboard row ..."
|
|
},
|
|
"11F9": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... so CIA1 port A shows joystick 2 instead of the matrix"
|
|
},
|
|
"11FC": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "read the port ..."
|
|
},
|
|
"11FF": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... let it settle ..."
|
|
},
|
|
"1200": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... and read it again"
|
|
},
|
|
"1203": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the two reads disagree (contact bounce) - try once more"
|
|
},
|
|
"1205": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "keep bits 0-4: up, down, left, right, fire (all active low)"
|
|
},
|
|
"1207": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "assume the button is up"
|
|
},
|
|
"1209": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "bit 4 = the fire button"
|
|
},
|
|
"120B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "bit set = button not pressed - keep Y=1"
|
|
},
|
|
"120D": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "button down -> Y=0"
|
|
},
|
|
"120E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "latch the fire state for the whole game"
|
|
},
|
|
"1210": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "second copy - nothing ever reads it (dead store)"
|
|
},
|
|
"1212": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "keep the four direction bits ($0F = centred)"
|
|
},
|
|
"1214": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "latch the direction for the whole game"
|
|
},
|
|
"1216": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "second copy - nothing ever reads it (dead store)"
|
|
},
|
|
"1218": {
|
|
"unit": "game/mainProgram0800",
|
|
"block": [
|
|
"inputIdleFrames counts consecutive frames with the stick centred and the button up, saturating at",
|
|
"$FF; anything else resets it to 0. The pause/attract logic elsewhere uses it."
|
|
],
|
|
"line": "the latched direction nibble"
|
|
},
|
|
"121A": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$0F = all four switches open = centred"
|
|
},
|
|
"121C": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the stick is being pushed"
|
|
},
|
|
"121E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "stick centred: forget any held direction ..."
|
|
},
|
|
"1220": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... by clearing the direction repeat mask"
|
|
},
|
|
"1223": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "is the fire button also up?"
|
|
},
|
|
"1225": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "yes - nothing at all is being touched"
|
|
},
|
|
"1227": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "some input is active ..."
|
|
},
|
|
"1229": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... so restart the idle counter"
|
|
},
|
|
"122C": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "always taken"
|
|
},
|
|
"122E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "frames of no input so far"
|
|
},
|
|
"1231": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "already saturated?"
|
|
},
|
|
"1233": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "yes - leave it at $FF"
|
|
},
|
|
"1235": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "another idle frame"
|
|
},
|
|
"1238": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "stir the 24-bit game RNG once per frame"
|
|
},
|
|
"123B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "index 5 down to 0 covers zp_71..zp_6C"
|
|
},
|
|
"123D": {
|
|
"unit": "game/mainProgram0800",
|
|
"block": [
|
|
"Decrement the six frame countdowns zp_6C-zp_71 (joystick repeat, fire debounce, menu blink, marker",
|
|
"blink, key repeat and one spare), each only while it is non-zero."
|
|
],
|
|
"line": "timer zp_6C+X"
|
|
},
|
|
"123F": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "already expired - leave it alone"
|
|
},
|
|
"1241": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "one frame closer to expiry"
|
|
},
|
|
"1243": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "next timer"
|
|
},
|
|
"1244": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "loop over all six"
|
|
},
|
|
"1246": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "is a disk load or overlay swap in progress?"
|
|
},
|
|
"1249": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "no - function keys may switch screens"
|
|
},
|
|
"124B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$FF = no screen requested ..."
|
|
},
|
|
"124D": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... so an F-key pressed during a load is thrown away"
|
|
},
|
|
"124F": {
|
|
"unit": "game/mainProgram0800",
|
|
"block": [
|
|
"The panic hotkey: SHIFT + C= + F7 abandons whatever is happening and returns to the main menu.",
|
|
"returnToMainMenu resets the stack pointer, so this JMP never comes back - the interrupt frame is",
|
|
"simply abandoned (interrupts were already re-enabled at $11DB)."
|
|
],
|
|
"line": "was SHIFT held during the key scan?"
|
|
},
|
|
"1252": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "no - not the abort combination"
|
|
},
|
|
"1254": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "was the Commodore key held too?"
|
|
},
|
|
"1257": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "no - not the abort combination"
|
|
},
|
|
"1259": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "which function key is pending?"
|
|
},
|
|
"125B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "3 = F7"
|
|
},
|
|
"125D": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "not F7 - carry on normally"
|
|
},
|
|
"125F": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "lock the input out ..."
|
|
},
|
|
"1261": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... by pretending a disk load is running"
|
|
},
|
|
"1264": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$FF ..."
|
|
},
|
|
"1266": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... = the longest possible input lockout"
|
|
},
|
|
"1269": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... and forget the pending F7"
|
|
},
|
|
"126B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "never returns: returnToMainMenu rebuilds the stack from scratch"
|
|
},
|
|
"126E": {
|
|
"unit": "game/mainProgram0800",
|
|
"block": [
|
|
"Per-frame housekeeping that is allowed to run with interrupts on."
|
|
],
|
|
"line": "which screen is showing?"
|
|
},
|
|
"1271": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "not the battlefield screen - no map cursor to blink"
|
|
},
|
|
"1273": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "gamePhase: bit 7 marks the phases in which there is no map cursor to blink"
|
|
},
|
|
"1275": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "gamePhase negative -> skip the blink"
|
|
},
|
|
"1277": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "toggle the map cursor sprite colour"
|
|
},
|
|
"127A": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "count the game's own frame timers down"
|
|
},
|
|
"127D": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "outgoing chat: pick up typed characters and queue them to the opponent"
|
|
},
|
|
"1280": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "incoming chat: take one received byte and add it to the message line"
|
|
},
|
|
"1283": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "take the highest-priority queued sound request into X"
|
|
},
|
|
"1286": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "X = $FF when nothing is queued"
|
|
},
|
|
"1287": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "nothing to start"
|
|
},
|
|
"1289": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "start sound A on its voices"
|
|
},
|
|
"128C": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "advance the SID sound scripts by one frame"
|
|
},
|
|
"128F": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the handler is finished ..."
|
|
},
|
|
"1291": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... so a later raster IRQ may run it again"
|
|
},
|
|
"1293": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"irqExit - Pulls Y, X and A back off the stack and falls into irqRti. It is both the normal end of",
|
|
"rasterIrqHandler and the target that initInterruptVectors patches into the BRK-exit JMP at",
|
|
"$10FF/$1100.",
|
|
"In: the register frame pushed by rasterIrqHandler",
|
|
"Out: registers restored, RTI",
|
|
"Called from: $10FE (BRK) and $1134 (early bail-out); reached by fall-through at the end of the handler"
|
|
],
|
|
"line": "Y ..."
|
|
},
|
|
"1294": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... restored"
|
|
},
|
|
"1295": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "X ..."
|
|
},
|
|
"1296": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... restored"
|
|
},
|
|
"1297": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "and A"
|
|
},
|
|
"1298": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"irqRti - A bare RTI. It is the NMI vector target for the whole game: initInterruptVectors and",
|
|
"setNmiVectorRti put $1298 into $FFFA/$FFFB and into the comm module's own NMI chain vector",
|
|
"($E031/$E032), so a stray RS-232 NMI cannot disturb the game when no modem session is running.",
|
|
"In: none",
|
|
"Out: none",
|
|
"Called from: the NMI vector; reached by fall-through from irqExit"
|
|
],
|
|
"line": "return from interrupt"
|
|
},
|
|
"1299": {
|
|
"unit": "game/mainProgram0800",
|
|
"block": [
|
|
"Three leftover bytes between irqRti and updateFrameTimers. Nothing references them and they do not",
|
|
"disassemble into anything sensible - alignment padding or the tail of an edited-out routine."
|
|
],
|
|
"line": "unreferenced padding"
|
|
},
|
|
"129C": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"updateFrameTimers - Per-frame housekeeping called from the raster IRQ. It bumps the two",
|
|
"free-running animation ticks, then runs three groups of counters: an 8-frame group (the",
|
|
"packet-exchange watchdog, the end-of-game countdown and linkWaitTimer), a 4-frame group (the",
|
|
"status-message hold timer and the link poll delay) and a per-frame group (step delay, shot line,",
|
|
"view redraw and marker sprite). Every countdown is guarded so it stops at 0.",
|
|
"In: frameCounter (zp_45), gamePhase (zp_B1)",
|
|
"Out: $92F8, $92FB, $9223, $92C9, zp_7F, zp_72, $9163, $90FC, $91C8, $9234, $923E",
|
|
"Called from: rasterIrqHandler ($127A)"
|
|
],
|
|
"line": "animation tick used by the missile screen"
|
|
},
|
|
"129F": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "animation tick used by the radar sweep"
|
|
},
|
|
"12A2": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the frame counter drives all the slower groups"
|
|
},
|
|
"12A4": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "every 8th frame ..."
|
|
},
|
|
"12A6": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... otherwise skip straight to the 4-frame group"
|
|
},
|
|
"12A8": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "which of the two 8-frame slots is this?"
|
|
},
|
|
"12AA": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "low nibble 0 = one of the two, i.e. every 16 frames"
|
|
},
|
|
"12AC": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "16-frame slot: always bump the watchdog"
|
|
},
|
|
"12AE": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the odd 8-frame slot only counts when gamePhase is not $FF ..."
|
|
},
|
|
"12B0": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... so at gamePhase $FF the watchdog runs at half speed (every 16 frames)"
|
|
},
|
|
"12B2": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "skip the watchdog this time"
|
|
},
|
|
"12B4": {
|
|
"unit": "game/mainProgram0800",
|
|
"block": [
|
|
"linkTimeoutCounter is the packet-exchange watchdog: checkLinkTimeout ($5A14) arms it with bit 7",
|
|
"set, a completed exchange clears it at $4E69, and here it counts up while negative and sticks at",
|
|
"$FF, which is how the game notices that the opponent has stopped answering."
|
|
],
|
|
"line": "the watchdog value"
|
|
},
|
|
"12B7": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "positive = not armed, nothing to do"
|
|
},
|
|
"12B9": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "clear carry for the increment"
|
|
},
|
|
"12BA": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "one more tick towards the timeout"
|
|
},
|
|
"12BC": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "already at $FF - saturate instead of wrapping to 0"
|
|
},
|
|
"12BE": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "store the advanced watchdog"
|
|
},
|
|
"12C1": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "gameEndCountdown: the delay from 'game over' to the summary screen"
|
|
},
|
|
"12C4": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "0 = not running"
|
|
},
|
|
"12C6": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "negative = it has already reached its $80 end stop"
|
|
},
|
|
"12C8": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "count it up towards $80"
|
|
},
|
|
"12CB": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "linkWaitTimer: the timeout used while waiting for the comm module"
|
|
},
|
|
"12CD": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "already expired"
|
|
},
|
|
"12CF": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "one 8-frame tick closer to zero"
|
|
},
|
|
"12D1": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the frame counter again ..."
|
|
},
|
|
"12D3": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... for the every-4-frames group"
|
|
},
|
|
"12D5": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "not a 4-frame slot"
|
|
},
|
|
"12D7": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "messageTimer: how long the status-line message stays up"
|
|
},
|
|
"12D9": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "already expired"
|
|
},
|
|
"12DB": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "count it down"
|
|
},
|
|
"12DD": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "linkPollDelay: pacing of the link status polls"
|
|
},
|
|
"12E0": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "already expired"
|
|
},
|
|
"12E2": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "count it down"
|
|
},
|
|
"12E5": {
|
|
"unit": "game/mainProgram0800",
|
|
"block": [
|
|
"The per-frame group: four independent countdowns, each frozen once it reaches 0."
|
|
],
|
|
"line": "stepDelayTimer: frames until the next unit step of the round"
|
|
},
|
|
"12E8": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "already expired"
|
|
},
|
|
"12EA": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "count it down"
|
|
},
|
|
"12ED": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "shotLineTimer: how long a shot line stays drawn in the viewport"
|
|
},
|
|
"12F0": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "already expired"
|
|
},
|
|
"12F2": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "count it down"
|
|
},
|
|
"12F5": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "viewRedrawTimer: frames until the 7x5 view is redrawn"
|
|
},
|
|
"12F8": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "already expired"
|
|
},
|
|
"12FA": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$80 is the 'frozen / redraw pending' sentinel ..."
|
|
},
|
|
"12FC": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... which must not be counted down"
|
|
},
|
|
"12FE": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "count it down"
|
|
},
|
|
"1301": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "markerSpriteTimer: how long the repair/target marker sprites stay visible"
|
|
},
|
|
"1304": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "already expired"
|
|
},
|
|
"1306": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "count it down"
|
|
},
|
|
"1309": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "back to the interrupt handler"
|
|
},
|
|
"130A": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"stepRandomSeed - Called from the IRQ every frame. If the 24-bit game RNG state has collapsed to",
|
|
"all zeroes (which would lock the LFSR up) it re-seeds the low byte from the current joystick",
|
|
"direction, so the generator both recovers and is fed a little entropy from the player, then steps",
|
|
"the LFSR once.",
|
|
"In: gameRngState0-2 (zp_57-zp_59), joyDirection (zp_5D)",
|
|
"Out: the RNG state advanced, A = the new random byte",
|
|
"Called from: rasterIrqHandler ($1238)"
|
|
],
|
|
"line": "byte 0 of the RNG state ..."
|
|
},
|
|
"130C": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... ORed with byte 1 ..."
|
|
},
|
|
"130E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... and byte 2"
|
|
},
|
|
"1310": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "any bit set - the state is fine"
|
|
},
|
|
"1312": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "all zero: take the joystick nibble as fresh entropy ..."
|
|
},
|
|
"1314": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... and drop it into byte 0 so the LFSR can run again"
|
|
},
|
|
"1316": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "advance the 24-bit LFSR in the high-memory block"
|
|
},
|
|
"1319": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "A holds the new random byte"
|
|
},
|
|
"131A": {
|
|
"unit": "game/mainProgram0800",
|
|
"block": [
|
|
"cursorBlinkTimer: the 30-frame countdown of blinkCursorColour, stored in the code stream just in",
|
|
"front of the routine that owns it."
|
|
],
|
|
"line": "counts 30..0 and then wraps; bit 7 signals 'time to toggle'"
|
|
},
|
|
"131B": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"blinkCursorColour - Blinks the map cursor. A 30-frame countdown toggles bit 0 of the sprite 0",
|
|
"colour shadow and copies the result to the sprite 2 shadow, so the two cursor sprites alternate",
|
|
"between two adjacent colours. The IRQ only calls it while currentScreen is 0 (the battlefield",
|
|
"screen) and gamePhase is not negative.",
|
|
"In: cursorBlinkTimer ($131A), spriteColourShadow ($9008)",
|
|
"Out: $131A, $9008, $900A",
|
|
"Called from: rasterIrqHandler ($1277)"
|
|
],
|
|
"line": "one frame off the blink countdown"
|
|
},
|
|
"131E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "still positive - nothing to do this frame"
|
|
},
|
|
"1320": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$1E = 30 frames until the next toggle ..."
|
|
},
|
|
"1322": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... reload the countdown"
|
|
},
|
|
"1325": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "sprite 0 colour shadow"
|
|
},
|
|
"1328": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "flip the lowest colour bit (e.g. between colours 6 and 7)"
|
|
},
|
|
"132A": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "back into the sprite 0 shadow"
|
|
},
|
|
"132D": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "and mirror it into the sprite 2 shadow so both halves of the cursor match"
|
|
},
|
|
"1330": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the IRQ picks the shadows up on the next frame"
|
|
},
|
|
"1331": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"handleChatSend - The outgoing half of the modem chat ('message to opponent'), run every frame from",
|
|
"the IRQ. chatState ($929C) is the state byte: 0 = off, $7F = 'open the typing line', and bit 7 set",
|
|
"= typing, with bits 0-5 holding the cursor position in the outgoing line buffer $9278. Typing is",
|
|
"entered by RETURN (or by another routine setting $7F) provided the module's transmit ring is empty;",
|
|
"after that each frame hands one key to the $C000 line editor and queues the accepted character to",
|
|
"the opponent. If the transmit ring fills up the line is terminated with RETURN instead.",
|
|
"In: $E03B link flag, $E02E transmit ring count, filmNameLength ($92E6), chatState ($929C), newKeyEvent ($90EA)",
|
|
"Out: chatState, the line buffer $9278.., newKeyEvent/lastTypedKey cleared, one byte queued through $E009, sounds",
|
|
"Called from: rasterIrqHandler ($127D)"
|
|
],
|
|
"line": "is the link up?"
|
|
},
|
|
"1334": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "no link - chat is impossible"
|
|
},
|
|
"1336": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "is the SAVE GAME FILM name field using the same line buffer?"
|
|
},
|
|
"1339": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "no - the chat may use it"
|
|
},
|
|
"133B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "shut the chat down ..."
|
|
},
|
|
"133D": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... by clearing the state byte"
|
|
},
|
|
"1340": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "nothing more to do this frame"
|
|
},
|
|
"1341": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the chat state byte"
|
|
},
|
|
"1344": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "bit 7 set = already typing -> go and send the next character"
|
|
},
|
|
"1346": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$7F = another routine asked for the typing line to be opened"
|
|
},
|
|
"1348": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "open it"
|
|
},
|
|
"134A": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "otherwise look at the last key"
|
|
},
|
|
"134D": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$8D = RETURN opens the chat line"
|
|
},
|
|
"134F": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "open it"
|
|
},
|
|
"1351": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "nothing to do this frame"
|
|
},
|
|
"1352": {
|
|
"unit": "game/mainProgram0800",
|
|
"block": [
|
|
"Enter typing mode - but only if the module has nothing left to transmit."
|
|
],
|
|
"line": "double-check the link is still up"
|
|
},
|
|
"1355": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "it dropped - abandon"
|
|
},
|
|
"1357": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "how many bytes are still queued for transmission?"
|
|
},
|
|
"135A": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the ring is not empty - wait until it drains"
|
|
},
|
|
"135C": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$C0 = bit 7 (typing) + bit 6, cursor position 0 ..."
|
|
},
|
|
"135E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... becomes the new chat state"
|
|
},
|
|
"1361": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$9E = the cursor glyph ..."
|
|
},
|
|
"1363": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... put at the head of the outgoing line so the player sees a caret"
|
|
},
|
|
"1366": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "swallow the key ..."
|
|
},
|
|
"1368": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... that opened the line ..."
|
|
},
|
|
"136B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... and the typed-key copy as well"
|
|
},
|
|
"136E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "sound 2 = the typing click"
|
|
},
|
|
"1370": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "requestSound is called directly (playSound is not re-entrant and this is inside the IRQ)"
|
|
},
|
|
"1373": {
|
|
"unit": "game/mainProgram0800",
|
|
"block": [
|
|
"Typing mode: bits 0-5 of chatState are the cursor position. One key per frame is fed to the",
|
|
"shared line editor and the accepted character is queued to the opponent, so the remote sees the",
|
|
"message being typed letter by letter."
|
|
],
|
|
"line": "cursor position within the 36-byte line buffer"
|
|
},
|
|
"1375": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the editor wants it in Y"
|
|
},
|
|
"1376": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "how full is the transmit ring?"
|
|
},
|
|
"1379": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$10 = 16 bytes = full"
|
|
},
|
|
"137B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "room left - edit one more character"
|
|
},
|
|
"137D": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "ring full: force the line to end ..."
|
|
},
|
|
"137E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... by setting bit 7 of the cursor position (the editor's 'RETURN' marker) ..."
|
|
},
|
|
"1380": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... back into Y"
|
|
},
|
|
"1381": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "and send RETURN instead of a character"
|
|
},
|
|
"1383": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "always taken"
|
|
},
|
|
"1385": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$A3 = max 35 characters with bit 7 = 'scroll the line left when it is full'"
|
|
},
|
|
"1387": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "let the $C000 line editor consume newKeyEvent into the buffer"
|
|
},
|
|
"138A": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "nothing was accepted this frame"
|
|
},
|
|
"138C": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "keep the accepted character"
|
|
},
|
|
"138D": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the editor's updated cursor position"
|
|
},
|
|
"138E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "toggle bit 7: a normal character leaves it set (still typing), RETURN clears it (line finished)"
|
|
},
|
|
"1390": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "bit 6 is always set so the state byte is never mistaken for 0"
|
|
},
|
|
"1392": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "store the new chat state"
|
|
},
|
|
"1395": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "get the character back"
|
|
},
|
|
"1396": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "queue it to the opponent and return to the IRQ"
|
|
},
|
|
"1399": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"receiveChatCharacter - The incoming half of the chat, called every frame from the IRQ. It pulls one",
|
|
"byte out of the comm module's receive ring and ignores anything below $80. RETURN ($8D) marks the",
|
|
"message complete, DEL ($88) backspaces by overwriting the previous character with a space, and",
|
|
"everything else is appended to the incoming message line.",
|
|
"In: the comm receive ring through $E006 (C=1 = empty), incomingChatLength ($9277)",
|
|
"Out: the $9253 buffer and the $0548 status line, $9277, messageTimer cleared, sound 5",
|
|
"Called from: rasterIrqHandler ($1280)"
|
|
],
|
|
"line": "fetch one received byte (C=1 = nothing waiting)"
|
|
},
|
|
"139C": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "nothing received this frame"
|
|
},
|
|
"139E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "chat characters always have bit 7 set ..."
|
|
},
|
|
"13A0": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... so anything below $80 is not chat text"
|
|
},
|
|
"13A2": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$8D = RETURN, the end of the opponent's message"
|
|
},
|
|
"13A4": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "not RETURN - try DEL"
|
|
},
|
|
"13A6": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$80 marks the message complete: bit 7 set, length 0 ..."
|
|
},
|
|
"13A8": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... so the next character starts a fresh message"
|
|
},
|
|
"13AB": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "always taken - go and beep"
|
|
},
|
|
"13AD": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$88 = DEL"
|
|
},
|
|
"13AF": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "an ordinary character - append it"
|
|
},
|
|
"13B1": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "how long is the message so far?"
|
|
},
|
|
"13B4": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "empty - nothing to erase"
|
|
},
|
|
"13B6": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the previous message was already complete - nothing to erase"
|
|
},
|
|
"13B8": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "step back over the last character"
|
|
},
|
|
"13BB": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "a space ..."
|
|
},
|
|
"13BD": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... written over it (this re-increments the length)"
|
|
},
|
|
"13C0": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "step back again so the next character lands on that space"
|
|
},
|
|
"13C3": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "back to the IRQ"
|
|
},
|
|
"13C4": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"appendChatCharacter - Appends character A to the 36-byte incoming message buffer at $9253 and",
|
|
"rewrites the visible status line from it. A negative incomingChatLength means the previous message",
|
|
"was finished, so the buffer restarts at 0; when the buffer is full at 35 characters it is scrolled",
|
|
"one byte left. The line is rewritten backwards from the newest character so that only that",
|
|
"character carries bit 7 - the game's string terminator convention - and the printed line therefore",
|
|
"always ends exactly where the message does.",
|
|
"In: A = character, incomingChatLength ($9277), the $9253 buffer",
|
|
"Out: $9253-$9276, $9277, the status line $0548-$056C, messageTimer = 0, sound 5",
|
|
"Called from: receiveChatCharacter ($13AF as a branch, $13BD as a call)"
|
|
],
|
|
"line": "current message length = the index of the next free byte"
|
|
},
|
|
"13C7": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "a message is in progress"
|
|
},
|
|
"13C9": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "previous message finished: start a new one ..."
|
|
},
|
|
"13CB": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... at offset 0"
|
|
},
|
|
"13CE": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$23 = 35 characters, the width of the line"
|
|
},
|
|
"13D0": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "there is still room"
|
|
},
|
|
"13D2": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the buffer is full - save the new character"
|
|
},
|
|
"13D3": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "scroll the whole buffer one byte to the left ..."
|
|
},
|
|
"13D5": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... reading from $9254 (buffer+1) ..."
|
|
},
|
|
"13D8": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... and writing to $9253"
|
|
},
|
|
"13DB": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "next byte"
|
|
},
|
|
"13DC": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$24 = 36 bytes"
|
|
},
|
|
"13DE": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "keep scrolling"
|
|
},
|
|
"13E0": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the write position moves back one"
|
|
},
|
|
"13E1": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "and so does the recorded length"
|
|
},
|
|
"13E4": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "get the new character back"
|
|
},
|
|
"13E5": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "store it without the terminator bit"
|
|
},
|
|
"13E7": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "into the buffer at the write position"
|
|
},
|
|
"13EA": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the message is one character longer"
|
|
},
|
|
"13ED": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the newest character carries the bit-7 terminator"
|
|
},
|
|
"13EF": {
|
|
"unit": "game/mainProgram0800",
|
|
"block": [
|
|
"Rewrite the whole visible line backwards, newest character first, so that exactly one byte (the",
|
|
"last one) has bit 7 set and the string printer stops there."
|
|
],
|
|
"line": "write into the status line text at $0549+index"
|
|
},
|
|
"13F2": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "walk backwards through the message"
|
|
},
|
|
"13F3": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the whole message has been written"
|
|
},
|
|
"13F5": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "earlier characters are stored plain (bit 7 clear)"
|
|
},
|
|
"13F8": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "keep going"
|
|
},
|
|
"13FB": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$1E = the leading marker glyph ..."
|
|
},
|
|
"13FD": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... at $0548, in front of the message text"
|
|
},
|
|
"1400": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "leftover test: the message queue head ..."
|
|
},
|
|
"1403": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... compared with the tail ..."
|
|
},
|
|
"1406": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... but both outcomes continue at $1408, so this compare has no effect (dead code)"
|
|
},
|
|
"1408": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "0 ..."
|
|
},
|
|
"140A": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... clears the message hold timer so the chat line is shown at once"
|
|
},
|
|
"140C": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "sound 5 = the incoming-character click"
|
|
},
|
|
"140E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "requestSound directly - this runs inside the IRQ, where playSound is not re-entrant"
|
|
},
|
|
"1411": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "back to the IRQ"
|
|
},
|
|
"1412": {
|
|
"unit": "game/mainProgram0800",
|
|
"block": [
|
|
"$1412 is a scratch byte the REPAIR tab uses as a 3..0 loop counter while it erases and redraws the",
|
|
"four comcen system markers ($184B-$187C). $1413 holds the comcenStunStatus value that was current",
|
|
"when drawRepairTab last ran ($175F), so the console loop can spot a change of stun state. The",
|
|
"$7F written into $1412 at $141F is never read: the repair code always reloads it first."
|
|
],
|
|
"line": "REPAIR tab marker loop counter; the $7F stored at $141F is a leftover dead store"
|
|
},
|
|
"1413": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "copy of comcenStunStatus taken when the REPAIR tab was last drawn"
|
|
},
|
|
"1414": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"resumeMainMenuScreen - Re-entry into the console screen (screen 3, the F7 screen with the STATS /",
|
|
"REPAIR / MISC tabs) that does not rebuild the frame: it just re-picks the default tab, clears the",
|
|
"text window and joins the console loop at its 'tab has changed' handler so the panel is redrawn.",
|
|
"Used when the comcen-stunned blackout ($0709) hands control back to whichever screen was showing.",
|
|
"In: none",
|
|
"Out: menuTabIndex ($90F9) set, the tab panel redrawn; never returns (the console loop takes over)",
|
|
"Called from: $076D, the screen dispatch at the end of runComcenStunnedBlackout"
|
|
],
|
|
"line": "pick the tab the current game state suggests"
|
|
},
|
|
"1417": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "blank the panel area under the tab bar"
|
|
},
|
|
"141A": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "draw the newly selected tab and fall into the console loop"
|
|
},
|
|
"141D": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"enterMainMenu - Full entry into the console screen (screen 3): picks the default tab, draws the",
|
|
"whole screen (tab bar and frames) and enters the console loop with that tab's panel drawn.",
|
|
"In: comcenStunStatus ($922A) and everything selectDefaultTab reads",
|
|
"Out: the console screen drawn, menuTabIndex set; never returns",
|
|
"Called from: $0706, the F7 branch of switchToRequestedScreen"
|
|
],
|
|
"line": "$7F into the REPAIR tab's scratch byte $1412 ..."
|
|
},
|
|
"141F": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... which nothing ever reads: the repair marker loops always reload it first, so this is a leftover dead store"
|
|
},
|
|
"1422": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "leftover tab pre-selection: default to tab 0 (STATS) ..."
|
|
},
|
|
"1424": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... unless the comcen is stunned ..."
|
|
},
|
|
"1427": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... (bit 7 of comcenStunStatus) ..."
|
|
},
|
|
"1429": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... in which case tab 1 (REPAIR)"
|
|
},
|
|
"142A": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "store it - but selectDefaultTab three bytes later overwrites it unconditionally, so all of $1422-$142A is dead"
|
|
},
|
|
"142D": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "really choose the tab"
|
|
},
|
|
"1430": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "draw the tab bar and both frames (it reads menuTabIndex for the text colour)"
|
|
},
|
|
"1433": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "choose the tab again - redundant, nothing showMainMenu does changes the inputs"
|
|
},
|
|
"1436": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "draw that tab's panel and fall into the console loop"
|
|
},
|
|
"1439": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"mainMenuLoop - The console screen's main loop (screen 3, tabs STATS / REPAIR / MISC). Every pass it",
|
|
"runs one frame of the game engine (the battle keeps going while the console is open), blinks the",
|
|
"selected tab, refreshes the REPAIR tab when the comcen stun state changes and the STATS tab when a",
|
|
"command exchange has been applied, and honours the function keys. The joystick moves the selection",
|
|
"left and right between the three tabs with a 20-frame repeat, and the fire button dispatches through",
|
|
"tabActionTable. The loop never returns; every path jumps back to $1439.",
|
|
"In: joyDirection (zp_5D), joyRepeatTimer (zp_6C), menuTabIndex ($90F9), comcenStunStatus ($922A), exchangeAppliedFlag ($920E)",
|
|
"Out: menuTabIndex, the console screen; runs forever",
|
|
"Called from: entered by fall-through/JMP from resumeMainMenuScreen and enterMainMenu"
|
|
],
|
|
"line": "keep the simulation running while the console is open"
|
|
},
|
|
"143C": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "toggle the selected tab between its bright and normal colour"
|
|
},
|
|
"143F": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "which tab is showing?"
|
|
},
|
|
"1442": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "1 = REPAIR"
|
|
},
|
|
"1444": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "any other tab - skip the repair refresh"
|
|
},
|
|
"1446": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "current comcen stun state ..."
|
|
},
|
|
"1449": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... against the copy taken when the tab was drawn ..."
|
|
},
|
|
"144C": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... looking only at bit 7 (stunned or not)"
|
|
},
|
|
"144E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "unchanged - no full redraw needed"
|
|
},
|
|
"1450": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the stun state flipped: redraw the whole REPAIR panel in its new colour"
|
|
},
|
|
"1453": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "refresh the comcen energy percentage (it only prints when the value changed)"
|
|
},
|
|
"1456": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "has a command exchange been applied since the STATS tab was drawn?"
|
|
},
|
|
"1459": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "no - nothing to refresh"
|
|
},
|
|
"145B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "which tab is showing?"
|
|
},
|
|
"145E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "only tab 0 (STATS) shows the numbers that just changed"
|
|
},
|
|
"1460": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "recount the units and reprint the STATS panel (it clears the flag again)"
|
|
},
|
|
"1463": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "let F1/F3/F5/F7 switch to another screen (never returns if it does)"
|
|
},
|
|
"1466": {
|
|
"unit": "game/mainProgram0800",
|
|
"block": [
|
|
"Joystick handling: left and right move between the three tabs, everything else falls through to",
|
|
"the fire-button test. joyRepeatTimer holds the auto-repeat delay so a held stick steps once every",
|
|
"20 frames."
|
|
],
|
|
"line": "is the joystick auto-repeat still counting down?"
|
|
},
|
|
"1468": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "yes - ignore the stick, only look at the button"
|
|
},
|
|
"146A": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the latched joystick direction"
|
|
},
|
|
"146C": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$0F = centred"
|
|
},
|
|
"146E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the stick is being pushed - see which way"
|
|
},
|
|
"1470": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "edge-detect a fresh fire-button press"
|
|
},
|
|
"1473": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "no press - go round again"
|
|
},
|
|
"1475": {
|
|
"unit": "game/mainProgram0800",
|
|
"block": [
|
|
"Fire on a tab: light that tab and call its handler through tabActionTable. The handler address is",
|
|
"copied into the operand of the JSR at $148D, which is why the disassembly shows 'jsr $FFFF' there."
|
|
],
|
|
"line": "the selected tab"
|
|
},
|
|
"1478": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "show it in its bright colour while its action runs"
|
|
},
|
|
"147B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "tab index ..."
|
|
},
|
|
"147E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... times two ..."
|
|
},
|
|
"147F": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... is the offset into the table of 16-bit handler addresses"
|
|
},
|
|
"1480": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "handler low byte ..."
|
|
},
|
|
"1483": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... self-modifying: into the operand of the JSR at $148D"
|
|
},
|
|
"1486": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "next table byte"
|
|
},
|
|
"1487": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "handler high byte ..."
|
|
},
|
|
"148A": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... into the high half of that operand"
|
|
},
|
|
"148D": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "call the tab's fire handler (operand patched just above; tab 0 points at the RTS at $158E)"
|
|
},
|
|
"1490": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "back to the top of the loop"
|
|
},
|
|
"1493": {
|
|
"unit": "game/mainProgram0800",
|
|
"block": [
|
|
"Left/right tab movement. The direction bits are active low, so after masking bits 2 and 3, $04",
|
|
"means right is pressed and $08 means left; $0C means neither."
|
|
],
|
|
"line": "keep the left (bit 2) and right (bit 3) switches"
|
|
},
|
|
"1495": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$0C = neither of them pressed"
|
|
},
|
|
"1497": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "up or down only - ignore it"
|
|
},
|
|
"1499": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$14 = 20 frames ..."
|
|
},
|
|
"149B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... of auto-repeat delay before the selection may move again"
|
|
},
|
|
"149D": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "remember the direction"
|
|
},
|
|
"149E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the tab we are leaving ..."
|
|
},
|
|
"14A1": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... goes back to its normal colour"
|
|
},
|
|
"14A4": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "get the direction back"
|
|
},
|
|
"14A5": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$04 = right pressed (bit 3 low)"
|
|
},
|
|
"14A7": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "not right, so it must be left"
|
|
},
|
|
"14A9": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the selected tab"
|
|
},
|
|
"14AC": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "2 = MISC, the rightmost tab"
|
|
},
|
|
"14AE": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "already at the right edge - ignore"
|
|
},
|
|
"14B0": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "move one tab to the right"
|
|
},
|
|
"14B3": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "always taken"
|
|
},
|
|
"14B5": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the selected tab"
|
|
},
|
|
"14B8": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "already at STATS, the left edge - ignore"
|
|
},
|
|
"14BA": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "move one tab to the left"
|
|
},
|
|
"14BD": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "sound 2 = the selection click"
|
|
},
|
|
"14BF": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "play it"
|
|
},
|
|
"14C2": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the newly selected tab ..."
|
|
},
|
|
"14C5": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... gets its bright colour"
|
|
},
|
|
"14C8": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "blank the panel under the tab bar ready for the new contents"
|
|
},
|
|
"14CB": {
|
|
"unit": "game/mainProgram0800",
|
|
"block": [
|
|
"Draw the panel of the currently selected tab. Entered directly by both console entry points as",
|
|
"well as after a tab change."
|
|
],
|
|
"line": "which tab?"
|
|
},
|
|
"14CE": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "not tab 0"
|
|
},
|
|
"14D0": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "STATS: the game type, rules, play order, owner names and map id"
|
|
},
|
|
"14D3": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "plus the unit counts, drones, missiles, comspeed and terrain points (in overlay B)"
|
|
},
|
|
"14D6": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "back to the loop"
|
|
},
|
|
"14D9": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "tab 1?"
|
|
},
|
|
"14DB": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "no - it must be MISC"
|
|
},
|
|
"14DD": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "REPAIR: the comcen schematic and its four system markers"
|
|
},
|
|
"14E0": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "remember the comcen status that is now on screen"
|
|
},
|
|
"14E3": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "back to the loop"
|
|
},
|
|
"14E6": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "tab 2?"
|
|
},
|
|
"14E8": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "menuTabIndex is only ever 0, 1 or 2 (every writer is in this loop), so this branch is never taken"
|
|
},
|
|
"14EA": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "MISC: print the option list (ABORT GAME, VOICE PAUSE, EXIT ...)"
|
|
},
|
|
"14ED": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "back to the loop"
|
|
},
|
|
"14F0": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"snapshotComcenStatus - Remembers what the REPAIR tab is currently showing: copies the three comcen",
|
|
"system status bytes ($9242-$9244) into the snapshot at $92D7-$92D9 and the comcen's energy (the low",
|
|
"6 bits of its entry in unitEnergyTable) into $92D6. selectDefaultTab compares the live values",
|
|
"against this snapshot to decide whether the player still has repairs to look at.",
|
|
"In: comcenSystemStatus ($9241..), comcenUnit ($9236), unitEnergyTable ($F9C4)",
|
|
"Out: comcenStatusSnapshot ($92D6-$92D9)",
|
|
"Called from: mainMenuLoop ($14E0) and the end of repairTabAction ($187E)"
|
|
],
|
|
"line": "index 3 down to 1: the battle, radar and drone system bytes"
|
|
},
|
|
"14F2": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "system status byte $9241+X"
|
|
},
|
|
"14F5": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "into the snapshot at $92D6+X"
|
|
},
|
|
"14F8": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "next system"
|
|
},
|
|
"14F9": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "stop at index 1 - slot 0 is filled from the energy below"
|
|
},
|
|
"14FB": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "this side's comcen (unit 49 or 99)"
|
|
},
|
|
"14FE": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "its energy byte"
|
|
},
|
|
"1501": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "the low 6 bits are the energy 0-50 (the top bits are flags)"
|
|
},
|
|
"1503": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "snapshot slot 0 = the comcen energy"
|
|
},
|
|
"1506": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "done"
|
|
},
|
|
"1507": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"selectDefaultTab - Chooses which console tab should be showing. If the game is over or has not",
|
|
"started (gameEndReason non-zero) it opens MISC (2), where ABORT/EXIT live. Otherwise it opens",
|
|
"REPAIR (1) when the comcen is stunned or when anything on the comcen has changed since the last",
|
|
"snapshotComcenStatus, and MISC (2) when nothing needs attention. STATS (0) is never chosen here.",
|
|
"In: gameEndReason ($0BA8), comcenStunStatus ($922A), comcenSystemStatus, comcenStatusSnapshot, comcenUnit, unitEnergyTable",
|
|
"Out: menuTabIndex ($90F9)",
|
|
"Called from: resumeMainMenuScreen ($1414) and enterMainMenu ($142D, $1433)"
|
|
],
|
|
"line": "assume tab 2 = MISC"
|
|
},
|
|
"1509": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "0 while a game is actually running"
|
|
},
|
|
"150C": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "no game in progress - MISC it is"
|
|
},
|
|
"150E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "a game is running: assume tab 0 = STATS for now"
|
|
},
|
|
"1510": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "is the comcen stunned?"
|
|
},
|
|
"1513": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "yes - the player needs the REPAIR tab"
|
|
},
|
|
"1515": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "compare the three system bytes with the snapshot, index 3 down to 1"
|
|
},
|
|
"1517": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "live system status $9241+X ..."
|
|
},
|
|
"151A": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... against the snapshot $92D6+X"
|
|
},
|
|
"151D": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "something changed - show REPAIR"
|
|
},
|
|
"151F": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "next system"
|
|
},
|
|
"1520": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "stop at index 1"
|
|
},
|
|
"1522": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "this side's comcen"
|
|
},
|
|
"1525": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "its energy byte"
|
|
},
|
|
"1528": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "keep the 0-50 energy value"
|
|
},
|
|
"152A": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "has the comcen lost energy since the snapshot?"
|
|
},
|
|
"152D": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "unchanged - nothing to repair, leave Y at 2 = MISC"
|
|
},
|
|
"152F": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "something needs attention: tab 1 = REPAIR"
|
|
},
|
|
"1531": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "store the chosen tab"
|
|
},
|
|
"1534": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "done"
|
|
},
|
|
"1535": {
|
|
"unit": "game/mainProgram0800",
|
|
"block": [
|
|
"tabActionTable: the three fire-button handlers of the console tabs, one 16-bit little-endian",
|
|
"address each, indexed by menuTabIndex*2 and copied into the JSR operand at $148D.",
|
|
" +0 tab 0 STATS -> $158E, the RTS at the end of setMenuWindowBounds, i.e. no action at all",
|
|
" +2 tab 1 REPAIR -> repairTabAction ($17DA), the 'repair which system' menu",
|
|
" +4 tab 2 MISC -> miscTabAction ($1A49), the ABORT GAME / VOICE PAUSE / EXIT option list"
|
|
],
|
|
"line": "three handler addresses, one per console tab"
|
|
},
|
|
"153B": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"showMainMenu - Builds the console screen from scratch: resets the glyph plotter's parameter block,",
|
|
"sets the background colour, draws the STATS/REPAIR/MISC tab bar and the two nested frames, and ends",
|
|
"by repainting the status message line.",
|
|
"In: none",
|
|
"Out: the whole screen 3 drawn; textDrawParams, vicBg0Shadow ($9004), cellBackgroundColour ($9226), screenBuiltFlag (zp_41)",
|
|
"Called from: returnToMainMenu ($0AC2) and enterMainMenu ($1430)"
|
|
],
|
|
"line": "0 into the four glyph-plotter parameters below"
|
|
},
|
|
"153D": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "useFixedColourFlag = 0: take the colour from the text state, not a fixed byte"
|
|
},
|
|
"1540": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "drawColourByte = 0"
|
|
},
|
|
"1543": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "blockFillFlag = 0"
|
|
},
|
|
"1546": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "blockFillChar = 0"
|
|
},
|
|
"1549": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "colour $0C = medium grey ..."
|
|
},
|
|
"154B": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... as the screen background (the IRQ copies the shadow into $D021)"
|
|
},
|
|
"154E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "0 ..."
|
|
},
|
|
"1550": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... = the cell background colour used by the tile drawing"
|
|
},
|
|
"1553": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "1 ..."
|
|
},
|
|
"1555": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... marks 'a screen has been built' (written by every screen builder, read nowhere)"
|
|
},
|
|
"1557": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "0 ..."
|
|
},
|
|
"1559": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... into blockFillFlag again - redundant, it was already cleared at $1543"
|
|
},
|
|
"155C": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "print STATS, REPAIR and MISC and colour their three tab boxes"
|
|
},
|
|
"155F": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "draw the outer and inner frames"
|
|
},
|
|
"1562": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "repaint whatever message belongs on the status line and return to our caller"
|
|
},
|
|
"1565": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"drawMenuFrame - Draws the console's two nested frames from the predefined window table: window $18",
|
|
"is the outer 40x20 box starting at row 5, window $19 the inner 38x18 box at row 6. Falls into",
|
|
"clearMenuTextWindow.",
|
|
"In: none",
|
|
"Out: the frames drawn, then the text window set and cleared",
|
|
"Called from: showMainMenu ($155F)"
|
|
],
|
|
"line": "window $18 = column 0, row 5, 40x20 cells - the outer frame"
|
|
},
|
|
"1567": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "draw it from its 9-tile frame set"
|
|
},
|
|
"156A": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "window $19 = column 1, row 6, 38x18 cells - the inner frame"
|
|
},
|
|
"156C": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "draw it too"
|
|
},
|
|
"156F": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"clearMenuTextWindow - Sets the console panel's text colour and window bounds and blanks the window.",
|
|
"In: comcenStunStatus ($922A), menuTabIndex ($90F9)",
|
|
"Out: textColour (zp_3D), the window bounds zp_39-zp_40, the panel area cleared",
|
|
"Called from: resumeMainMenuScreen ($1417), mainMenuLoop ($14C8), $1ACA, $1AD6 and overlay A ($7EA0)"
|
|
],
|
|
"line": "colour and window bounds for the panel"
|
|
},
|
|
"1572": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "blank it and return to our caller"
|
|
},
|
|
"1575": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"setMenuTextWindow - Picks the console text colour from the comcen stun state (red on the REPAIR tab",
|
|
"while the comcen is stunned) and falls into setMenuWindowBounds.",
|
|
"In: comcenStunStatus ($922A), menuTabIndex ($90F9)",
|
|
"Out: textColour (zp_3D) plus the window bounds",
|
|
"Called from: clearMenuTextWindow ($156F), $1866 and $1A80"
|
|
],
|
|
"line": "$61 normally, $21 on a stunned REPAIR tab"
|
|
},
|
|
"1578": {
|
|
"unit": "game/mainProgram0800",
|
|
"routine": [
|
|
"setMenuWindowBounds - Sets the text window that the console panels print into: rows 7 to 21, left",
|
|
"column 2, 36 characters wide, cursor homed at the top left of the window. Its final RTS at $158E",
|
|
"doubles as the do-nothing handler of the STATS tab in tabActionTable.",
|
|
"In: none",
|
|
"Out: textCursorCol=0, textWindowTop=7, textCursorRow=7, textWindowLeft=2, textWindowBottom=$16, textWindowWidth=$24",
|
|
"Called from: setMenuTextWindow by fall-through, clearMenuWindowPlain ($1593) and $19E7"
|
|
],
|
|
"line": "cursor column 0 ..."
|
|
},
|
|
"157A": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... relative to the window's left edge"
|
|
},
|
|
"157C": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "row 7 = the first line under the tab bar and frame ..."
|
|
},
|
|
"157E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... as the top of the window ..."
|
|
},
|
|
"1580": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... and as the starting cursor row"
|
|
},
|
|
"1582": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "screen column 2 ..."
|
|
},
|
|
"1584": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... is the window's left edge"
|
|
},
|
|
"1586": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$16 = row 22 is the exclusive bottom limit ..."
|
|
},
|
|
"1588": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... so the window covers rows 7-21"
|
|
},
|
|
"158A": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "$24 = 36 characters ..."
|
|
},
|
|
"158C": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "... is the window width and the wrap point"
|
|
},
|
|
"158E": {
|
|
"unit": "game/mainProgram0800",
|
|
"line": "also the STATS tab's 'do nothing' fire handler (tabActionTable entry 0)"
|
|
}
|
|
},
|
|
"dataTypes": {
|
|
"0F81": [
|
|
"text",
|
|
16
|
|
],
|
|
"0F91": [
|
|
"text",
|
|
17
|
|
],
|
|
"0FA2": [
|
|
"text",
|
|
11
|
|
],
|
|
"0FAD": [
|
|
"text",
|
|
4
|
|
],
|
|
"10EF": [
|
|
"byte",
|
|
2
|
|
],
|
|
"1299": [
|
|
"byte",
|
|
3
|
|
],
|
|
"131A": [
|
|
"byte",
|
|
1
|
|
],
|
|
"1412": [
|
|
"byte",
|
|
2
|
|
],
|
|
"1535": [
|
|
"addr",
|
|
6
|
|
]
|
|
},
|
|
"zpComments": {}
|
|
} |