{ "chunk": "game_mapGenerator6F00_74EE", "unit": "game/mapGenerator6F00", "unitLabels": { "game/mapGenerator6F00": { "750C": "startMarkerScanAtF000", "7516": "markerScanLoad", "751B": "markerScanTest", "7521": "markerScanStore", "7524": "markerScanNext", "7536": "markerTailLoop", "753B": "markerTailTest", "7544": "markerTailNext", "7569": "noRiverOnThisMap", "756A": "startRiverAtRow", "7577": "riverCellLoop", "75B9": "checkCentreRow", "75C6": "jogRiverUpOneRow", "75CB": "chooseFromCurrentSegment", "75D6": "checkUpElbow", "75DE": "chooseStraightOrJog", "75E7": "makeStraightSegment", "75EC": "rollNextSegment", "75F3": "maskSegmentType", "75F7": "rejectClosingElbow", "75FB": "clampSegmentToColumn", "7610": "forceHorizontalSegment", "7618": "storeNextSegment", "762B": "riverStepJump", "7651": "markEdgeColumnOnly", "765E": "markEdgeCellLoop", "7669": "writeBankMarkerEdge", "766D": "markEdgeCellNext", "7671": "checkRightEdgeColumn", "7688": "markOuterCellLoop", "7695": "markOuterCellNext", "7698": "markInnerCells", "769A": "markInnerCellLoop", "76A5": "writeBankMarkerInner", "76A9": "markInnerCellNext", "76B8": "drawMapAndClearName", "76BE": "mapNamePromptLoop", "76CE": "printAcceptPrompt", "7702": "redrawOverviewAfterNewMap", "7708": "acceptCurrentMap", "773A": "mapNameInputLoop", "7741": "toggleMapFlip", "7751": "checkAcceptButton", "775D": "handleTypedKey", "7771": "checkDeleteKey", "7790": "storeBlankInNameField", "7795": "lookUpKeyInAlphabet", "779B": "alphabetSearchLoop", "77A3": "keyRejected", "77A7": "storeNameCharacter", "77C2": "playKeyClick", "77C4": "playKeySound", "77CC": "checkNameComplete", "77DC": "checkRandomKeys", "77E0": "waitForMoreInput", "77E3": "checkSymmetricRandom", "77E7": "storeRandomSeed", "77F7": "packNameIntoSeed", "77F9": "clearSeedAccumulator", "77FF": "packNameCharLoop", "7804": "alphabetIndexLoop", "780E": "shiftSeedLeftFive", "7812": "shiftSeedBitLoop", "7828": "showNameAndAccept", "7838": "clearNameCharLoop", "7846": "setMapNameTerminator", "7858": "seedCharLoop", "7863": "shiftSeedRightFive", "7865": "shiftSeedRightBit", "7879": "adjustLowTileIndex", "787D": "lookUpVariantMask", "788C": "maskRandomVariant", "788E": "combineVariantWithBase", "788F": "addBaseTileCode", "7891": "restoreCallerY", "78E7": "clearRecyclerPositions", "7900": "setOwnUnitColour", "791C": "checkFilmPlayback", "7924": "startLiveGame", "7934": "requestSideFromLink", "793B": "alternateSideFromLastGame", "794C": "encodeSidePreference", "7952": "storeSidePreference", "7955": "openLinkForSession", "7962": "openLinkFresh", "7968": "resolveSidePreference", "7976": "sendSideChoice", "797C": "waitForSideAgreement", "7987": "markSetupPhase", "7991": "chooseOrAwaitGameAndMap", "79A1": "pickGameTypeAndMap", "79BF": "queueMapSeedCommand", "79C2": "afterMapSeedExchange", "79CA": "clearPendingScreenKey", "79D8": "checkOpponentVersion", "79E6": "loadTemplateAndDefaults", "79F6": "recordMapSeedLoop", "7A1E": "hideMapNameLoop", "7A24": "terminateMapName", "7A32": "storePrevGameTypeOptions", "7A3C": "compareWithPreviousMap", "7A56": "restoreMapNameLoop", "7A61": "rememberNewMap", "7A78": "saveMapNameStart", "7A7A": "saveMapNameLoop", "7A83": "checkFlipChanged", "7A93": "recordFilmHeader", "7AB7": "recordMapNameLoop", "7ABA": "recordFilmByteAndAdvance", "7ACD": "recordPlayerNamesLoop", "7AE4": "checkMirrorUnits", "7AEC": "initUnitsAndRunOptions", "7B39": "checkSetupPhaseNeeded", "7B44": "runUnitSetupPhase", "7B56": "drainOwnCommandQueue", "7B59": "checkQueueEmpty", "7B61": "syncAfterSetup", "7B64": "waitForPacketExchange", "7B6E": "mapComcenSpeedLoop", "7B86": "setBattleClock", "7B8F": "beginBattle" } }, "notes": { "74EE": { "unit": "game/mapGenerator6F00", "block": [ "Two lookup tables shared by the contour/edge pass applyContourRuleAtCell ($7444, just above this", "chunk). That routine keeps zp_48/zp_49 pointing at the top-left cell of the 3x3 block around the", "cell it is examining, so the centre cell is at offset +$29 (one row of 40 = $28, plus one column)." ], "line": "neighbour offsets NW=+$00, N=+$01, NE=+$02, W=+$28 (one row down), E=+$2A" }, "74F3": { "unit": "game/mapGenerator6F00", "line": "...SW=+$50 (two rows down), S=+$51, SE=+$52; label L_74F3 only exists because variant B has code here" }, "74F6": { "unit": "game/mapGenerator6F00", "line": "bit n of the neighbour mask built at $745B, in the same NW,N,NE,W,E,SW,S,SE order as the offsets above" }, "74FE": { "unit": "game/mapGenerator6F00", "routine": [ "clearMapMarkers - Clean-up pass of the map generator: walks all 1600 cells of the 40x40", "battlefield ($F000-$F63F) and turns every cell that still holds the reservation marker in A back", "into blank terrain $40. markRiverBanks ($764A) stamps $80 (river outskirts) and $81 (river bank)", "into empty cells so the hill/forest passes leave the river valley alone; this routine removes them", "again once those passes are done. The map is scanned as six whole pages through a self-modified", "absolute,Y load/store pair plus the 64-byte tail at $F600.", "In: A = marker byte to erase ($80 or $81); the map at $F000-$F63F", "Out: every cell equal to A becomes $40; A and Y clobbered, X untouched. Self-modifies the", " compare operands at $751C/$753C and the page bytes of the load/store at $7517-$7518 and", " $7522-$7523", "Called from: generateBattlefieldMap ($6F47 with $80, $6F5F with $81)" ], "line": "patch the marker value into the CMP #imm at $751B (main-page test)" }, "7501": { "unit": "game/mapGenerator6F00", "line": "patch the same marker into the CMP #imm at $753B (last-64-cells test)" }, "7504": { "unit": "game/mapGenerator6F00", "line": "map starts at $F000, so the low byte of both patched operands is 0" }, "7506": { "unit": "game/mapGenerator6F00", "line": "low byte of the self-modified LDA abs,Y at $7516" }, "7509": { "unit": "game/mapGenerator6F00", "line": "low byte of the self-modified STA abs,Y at $7521" }, "750C": { "unit": "game/mapGenerator6F00", "line": "first page of the map is $F0xx (label only reachable from variant B's code)" }, "750E": { "unit": "game/mapGenerator6F00", "line": "high byte of the self-modified LDA abs,Y" }, "7511": { "unit": "game/mapGenerator6F00", "line": "high byte of the self-modified STA abs,Y" }, "7514": { "unit": "game/mapGenerator6F00", "line": "start at the first cell of the page" }, "7516": { "unit": "game/mapGenerator6F00", "block": [ "Page loop: 256 cells at a time from $F000 through $F5FF. The absolute address of both the load", "and the store is the self-modified operand; the assembled placeholder is $FFFF (rendered as", "irqVectorHi), never the address actually used." ], "line": "read map cell (operand patched to the current page, $F000-$F500)" }, "7519": { "unit": "game/mapGenerator6F00", "line": "plain terrain has bit 7 clear - nothing to undo" }, "751B": { "unit": "game/mapGenerator6F00", "line": "compare against the marker being erased (operand written at $74FE)" }, "751D": { "unit": "game/mapGenerator6F00", "line": "some other bit-7 cell (a unit marker $80|index cannot occur yet) - leave it" }, "751F": { "unit": "game/mapGenerator6F00", "line": "$40 = blank terrain" }, "7521": { "unit": "game/mapGenerator6F00", "line": "write the blank back (operand patched to the current page)" }, "7524": { "unit": "game/mapGenerator6F00", "line": "next cell in this page" }, "7525": { "unit": "game/mapGenerator6F00", "line": "keep going until the page wraps back to offset 0" }, "7527": { "unit": "game/mapGenerator6F00", "line": "step the load address to the next page" }, "752A": { "unit": "game/mapGenerator6F00", "line": "step the store address with it" }, "752D": { "unit": "game/mapGenerator6F00", "line": "look at the page just reached" }, "7530": { "unit": "game/mapGenerator6F00", "line": "$F600 is past the last full page of the map" }, "7532": { "unit": "game/mapGenerator6F00", "line": "not there yet - scan the next 256 cells" }, "7534": { "unit": "game/mapGenerator6F00", "block": [ "Tail: the map is 1600 = 6*256 + 64 bytes, so the last 64 cells at $F600-$F63F are handled", "separately (backwards, so DEY/BPL can end the loop)." ], "line": "last cell of the 64-byte tail ($F63F)" }, "7536": { "unit": "game/mapGenerator6F00", "line": "read cell $F600+Y" }, "7539": { "unit": "game/mapGenerator6F00", "line": "plain terrain (bit 7 clear) - nothing to undo here" }, "753B": { "unit": "game/mapGenerator6F00", "line": "compare against the marker being erased (operand written at $7501)" }, "753D": { "unit": "game/mapGenerator6F00", "line": "not this marker - leave the cell alone" }, "753F": { "unit": "game/mapGenerator6F00", "line": "$40 = blank terrain" }, "7541": { "unit": "game/mapGenerator6F00", "line": "restore the blank cell" }, "7544": { "unit": "game/mapGenerator6F00", "line": "walk down to cell 0 of the tail" }, "7545": { "unit": "game/mapGenerator6F00", "line": "loop while the index is still positive" }, "7547": { "unit": "game/mapGenerator6F00", "line": "map is clean again" }, "7548": { "unit": "game/mapGenerator6F00", "routine": [ "generateRiver - Draws the river across the whole battlefield, left edge to right edge, as the", "first terrain feature of a generated map. A river cell is terrain code $55 + segment type", "(0-7 -> $55-$5C); the segment type also decides whether the cursor then steps right, up or down.", "Around every cell it reserves the banks with markRiverBanks so the later hill and forest passes", "cannot build on top of the water.", "In: mapGenGameFlags $032E (bit 7 = QB SNEAK, bit 6 = DEFENDER), mapSymmetryFlags $032D (bit 7 =", " point-symmetric map), scenario RNG $5A-$5C via nextScenarioRandom ($FD4A), map at $F000", "Out: river tiles $55-$5C written into the map plus $80/$81 bank markers around them; genCol", " $030F, genRow $0310, riverCurSegment $0311 and genTileType $0312 left at the right edge;", " mapSymmetryFlags bit 6 may be set by chooseNextRiverSegment. Returns with no river drawn at", " all for QB SNEAK, and with probability 1/8 for the game types other than DEFENDER", "Called from: runMapGeneratorPasses ($6F39)" ], "line": "map-style flags derived from the game type" }, "754B": { "unit": "game/mapGenerator6F00", "line": "bit 7 = QB SNEAK: that scenario is played on dry land, no river" }, "754D": { "unit": "game/mapGenerator6F00", "line": "default start row for a symmetric map: row 20, the centre line" }, "754F": { "unit": "game/mapGenerator6F00", "line": "map symmetry flags" }, "7552": { "unit": "game/mapGenerator6F00", "line": "bit 7 = point-symmetric map (seed ends in '='): keep the fixed centre row" }, "7554": { "unit": "game/mapGenerator6F00", "line": "otherwise roll for the start row" }, "7557": { "unit": "game/mapGenerator6F00", "line": "0-15..." }, "7559": { "unit": "game/mapGenerator6F00", "line": "clear carry for the add" }, "755A": { "unit": "game/mapGenerator6F00", "line": "...plus 12 = a start row of 12-27, well inside the 40-row map" }, "755C": { "unit": "game/mapGenerator6F00", "line": "keep the start row in Y" }, "755D": { "unit": "game/mapGenerator6F00", "line": "map-style flags again, this time for bit 6" }, "7560": { "unit": "game/mapGenerator6F00", "line": "bit 6 = DEFENDER: that scenario always has a river" }, "7562": { "unit": "game/mapGenerator6F00", "line": "for every other game type roll once more" }, "7565": { "unit": "game/mapGenerator6F00", "line": "3 random bits" }, "7567": { "unit": "game/mapGenerator6F00", "line": "7 chances in 8: draw the river" }, "7569": { "unit": "game/mapGenerator6F00", "line": "1 chance in 8 (and always for QB SNEAK): leave the map dry" }, "756A": { "unit": "game/mapGenerator6F00", "block": [ "Walk the river from column 0 to column 39. genTileType ($0312) holds the segment chosen for the", "*next* cell; it starts as 5, a plain horizontal straight, so the river enters the map flat." ], "line": "genRow = start row" }, "756D": { "unit": "game/mapGenerator6F00", "line": "column 0 = the left edge of the map" }, "756F": { "unit": "game/mapGenerator6F00", "line": "genCol = 0, the left edge of the map" }, "7572": { "unit": "game/mapGenerator6F00", "line": "segment type 5 = a horizontal straight variant ($5A)" }, "7574": { "unit": "game/mapGenerator6F00", "line": "genTileType = the segment to draw at the first cell" }, "7577": { "unit": "game/mapGenerator6F00", "line": "current row..." }, "757A": { "unit": "game/mapGenerator6F00", "line": "...and column of the river cursor" }, "757D": { "unit": "game/mapGenerator6F00", "line": "mapCellPtr ($48/$49) = &map[row][col] (the returned cell value is discarded)" }, "7580": { "unit": "game/mapGenerator6F00", "line": "segment type chosen for this cell" }, "7583": { "unit": "game/mapGenerator6F00", "line": "riverCurSegment = it, so markRiverBanks/advanceRiverPosition see the same segment" }, "7586": { "unit": "game/mapGenerator6F00", "line": "clear carry before the tile base is added" }, "7587": { "unit": "game/mapGenerator6F00", "line": "river terrain codes are $55 + segment type, i.e. $55-$5C" }, "7589": { "unit": "game/mapGenerator6F00", "line": "mapCellPtr already points at the cell itself" }, "758B": { "unit": "game/mapGenerator6F00", "line": "paint the river cell" }, "758D": { "unit": "game/mapGenerator6F00", "line": "decide the segment for the next cell (may also jog the cursor on a symmetric map)" }, "7590": { "unit": "game/mapGenerator6F00", "line": "reserve the 6x6 block of banks around this cell with $80/$81" }, "7593": { "unit": "game/mapGenerator6F00", "line": "step the cursor right, up or down according to riverCurSegment" }, "7596": { "unit": "game/mapGenerator6F00", "line": "column reached..." }, "7599": { "unit": "game/mapGenerator6F00", "line": "...40 = one past the right edge?" }, "759B": { "unit": "game/mapGenerator6F00", "line": "no - draw the next river cell" }, "759D": { "unit": "game/mapGenerator6F00", "line": "the river has crossed the whole map" }, "759E": { "unit": "game/mapGenerator6F00", "routine": [ "chooseNextRiverSegment - Picks the segment type of the next river cell into genTileType ($0312).", "Segment types: 0 = elbow leaving right after an up step ($55), 1 = elbow leaving downward ($56),", "2 = elbow leaving right after a down step ($57), 3 = elbow leaving upward ($58), 4-7 = horizontal", "straight variants ($59-$5C). Only types 1 and 3 move the cursor vertically, so the river runs", "flat with the occasional one-row jog. Rules: 1 is always followed by 2 and 3 by 0 (the elbow that", "turns the flow back to the right); an elbow is always followed by a straight; a straight is", "followed by another straight about half the time, otherwise by a jog. Columns 0-1 and 38-39 are", "forced flat, and column 37 may not start a jog (the elbow after it would fall off the map).", "On a point-symmetric map the river must run along row 20 and meet its own 180-degree mirror image", "in the middle, so at column 20 it steps back two columns and up one row with probability 7/8.", "In: riverCurSegment $0311, genCol $030F, genRow $0310, mapSymmetryFlags $032D, scenario RNG", "Out: genTileType $0312 = next segment 0-7; on a symmetric map genCol/genRow may be moved and", " mapSymmetryFlags bit 6 set to record that the jog was made", "Called from: generateRiver ($758D)" ], "block": [ "Symmetric maps: the river is drawn only once and the caller mirrors the map afterwards, so the", "line has to arrive at the centre of the map in a shape that joins its own rotated copy." ], "line": "column of the cell just drawn" }, "75A1": { "unit": "game/mapGenerator6F00", "line": "map symmetry flags" }, "75A4": { "unit": "game/mapGenerator6F00", "line": "bit 7 clear = ordinary random map: use the normal segment rules" }, "75A6": { "unit": "game/mapGenerator6F00", "line": "symmetric map: has the river reached the centre column 20?" }, "75A8": { "unit": "game/mapGenerator6F00", "line": "no - force a horizontal straight so it stays on row 20" }, "75AA": { "unit": "game/mapGenerator6F00", "line": "at the centre, roll for the jog" }, "75AD": { "unit": "game/mapGenerator6F00", "line": "3 random bits" }, "75AF": { "unit": "game/mapGenerator6F00", "line": "1 chance in 8: no jog, stay flat" }, "75B1": { "unit": "game/mapGenerator6F00", "line": "map symmetry flags" }, "75B4": { "unit": "game/mapGenerator6F00", "line": "bit 6 = 'the centre jog has been made' (read by the symmetry fix-up)" }, "75B6": { "unit": "game/mapGenerator6F00", "line": "write them back with the jog recorded" }, "75B9": { "unit": "game/mapGenerator6F00", "line": "current row" }, "75BC": { "unit": "game/mapGenerator6F00", "line": "only jog when the river is still on the centre row 20" }, "75BE": { "unit": "game/mapGenerator6F00", "line": "otherwise just keep it flat" }, "75C0": { "unit": "game/mapGenerator6F00", "line": "back up two columns..." }, "75C3": { "unit": "game/mapGenerator6F00", "line": "...so the two cells about to be redrawn form the joint" }, "75C6": { "unit": "game/mapGenerator6F00", "line": "and move up to row 19, above the mirror line" }, "75C9": { "unit": "game/mapGenerator6F00", "line": "always taken (row 19 is not 0) - draw a straight there" }, "75CB": { "unit": "game/mapGenerator6F00", "block": [ "Ordinary maps: the next segment follows from the current one. Elbows 1 and 3 must be closed by", "their partner elbow, everything else picks randomly between straights and jogs." ], "line": "segment just drawn" }, "75CE": { "unit": "game/mapGenerator6F00", "line": "was it the 'turn downward' elbow?" }, "75D0": { "unit": "game/mapGenerator6F00", "line": "not the downward elbow - test the next case" }, "75D2": { "unit": "game/mapGenerator6F00", "line": "yes - the cell below it must be the elbow that turns the flow right again" }, "75D4": { "unit": "game/mapGenerator6F00", "line": "always taken (A = 2)" }, "75D6": { "unit": "game/mapGenerator6F00", "line": "was it the 'turn upward' elbow?" }, "75D8": { "unit": "game/mapGenerator6F00", "line": "not the upward elbow either - fall through to the random choice" }, "75DA": { "unit": "game/mapGenerator6F00", "line": "yes - the cell above it must be elbow 0, which turns the flow right again" }, "75DC": { "unit": "game/mapGenerator6F00", "line": "always taken (A = 0)" }, "75DE": { "unit": "game/mapGenerator6F00", "line": "types 0-2 are elbows, 4-7 are straights" }, "75E0": { "unit": "game/mapGenerator6F00", "line": "current cell is a straight - it may be followed by a jog" }, "75E2": { "unit": "game/mapGenerator6F00", "line": "current cell was an elbow: the next one must be a straight" }, "75E5": { "unit": "game/mapGenerator6F00", "line": "pick one of the four straight variants..." }, "75E7": { "unit": "game/mapGenerator6F00", "line": "clear carry for the add" }, "75E8": { "unit": "game/mapGenerator6F00", "line": "...i.e. segment 4-7" }, "75EA": { "unit": "game/mapGenerator6F00", "line": "always taken (the value is 4-7)" }, "75EC": { "unit": "game/mapGenerator6F00", "line": "random byte" }, "75EF": { "unit": "game/mapGenerator6F00", "line": "random bit 7 clear: leave the value alone, so a jog stays possible" }, "75F1": { "unit": "game/mapGenerator6F00", "line": "...force bit 2, which restricts the result to a straight 4-7" }, "75F3": { "unit": "game/mapGenerator6F00", "line": "keep 3 bits: a segment type 0-7" }, "75F5": { "unit": "game/mapGenerator6F00", "line": "type 0 is an elbow that cannot start a jog - draw a straight instead" }, "75F7": { "unit": "game/mapGenerator6F00", "line": "type 2 likewise closes a jog rather than starting one" }, "75F9": { "unit": "game/mapGenerator6F00", "line": "reject it the same way (A is 0 or 2, so the retry always takes the straight path)" }, "75FB": { "unit": "game/mapGenerator6F00", "block": [ "Edge guard: a jog needs room for its closing elbow, so the first two and the last three columns", "are always drawn flat." ], "line": "column of the cell just drawn" }, "75FE": { "unit": "game/mapGenerator6F00", "line": "columns 0-1: the river must enter the map horizontally" }, "7600": { "unit": "game/mapGenerator6F00", "line": "column 0 or 1 - force a horizontal straight" }, "7602": { "unit": "game/mapGenerator6F00", "line": "is the cell in column 37, the last one that could start a jog?" }, "7604": { "unit": "game/mapGenerator6F00", "line": "columns 2-36: accept whatever was chosen" }, "7606": { "unit": "game/mapGenerator6F00", "line": "columns 38-39: force a straight so the river leaves the map horizontally" }, "7608": { "unit": "game/mapGenerator6F00", "line": "column 37: reject a downward jog..." }, "760A": { "unit": "game/mapGenerator6F00", "line": "downward jog rejected - draw a straight instead" }, "760C": { "unit": "game/mapGenerator6F00", "line": "...and an upward jog, since the closing elbow would land in column 39" }, "760E": { "unit": "game/mapGenerator6F00", "line": "not a jog - the straight that was chosen is fine in column 37" }, "7610": { "unit": "game/mapGenerator6F00", "line": "random byte" }, "7613": { "unit": "game/mapGenerator6F00", "line": "one of the four..." }, "7616": { "unit": "game/mapGenerator6F00", "line": "...horizontal straight variants 4-7" }, "7618": { "unit": "game/mapGenerator6F00", "line": "genTileType = segment type of the next river cell" }, "761B": { "unit": "game/mapGenerator6F00", "line": "back to generateRiver" }, "761C": { "unit": "game/mapGenerator6F00", "routine": [ "advanceRiverPosition - Moves the river cursor one cell according to the segment just drawn: type 1", "(elbow turning downward) steps a row down, type 3 (elbow turning upward) a row up, every other", "type one column right. Implemented as a jump through a two-part address table, so the JMP operand", "at $762C/$762D is rewritten on every call.", "In: riverCurSegment $0311, tables riverStepLo $763A / riverStepHi $7642", "Out: genCol $030F or genRow $0310 stepped by one; the operand of the JMP at $762B is self-modified", "Called from: generateRiver ($7593)" ], "line": "segment type of the cell just drawn" }, "761F": { "unit": "game/mapGenerator6F00", "line": "low byte of the step routine for that type" }, "7622": { "unit": "game/mapGenerator6F00", "line": "patch it into the JMP operand at $762C" }, "7625": { "unit": "game/mapGenerator6F00", "line": "high byte (always $76)" }, "7628": { "unit": "game/mapGenerator6F00", "line": "patch it into $762D" }, "762B": { "unit": "game/mapGenerator6F00", "line": "jump to riverStepRight/Up/Down; the assembled operand $FFFF is only a placeholder" }, "762E": { "unit": "game/mapGenerator6F00", "routine": [ "riverStepRight - Step stub for every segment type that leaves the cell to the right (0, 2 and the", "straights 4-7): advances the river cursor one column.", "In: none", "Out: genCol $030F + 1", "Called from: the patched JMP at $762B in advanceRiverPosition" ], "line": "river cursor moves one column right" }, "7631": { "unit": "game/mapGenerator6F00", "line": "back to generateRiver, which called advanceRiverPosition" }, "7632": { "unit": "game/mapGenerator6F00", "routine": [ "riverStepUp - Step stub for segment type 3, the elbow that turns the river upward: moves the", "cursor one row up (towards row 0).", "In: none", "Out: genRow $0310 - 1", "Called from: the patched JMP at $762B in advanceRiverPosition" ], "line": "river cursor moves one row up" }, "7635": { "unit": "game/mapGenerator6F00", "line": "back to generateRiver, which called advanceRiverPosition" }, "7636": { "unit": "game/mapGenerator6F00", "routine": [ "riverStepDown - Step stub for segment type 1, the elbow that turns the river downward: moves the", "cursor one row down.", "In: none", "Out: genRow $0310 + 1", "Called from: the patched JMP at $762B in advanceRiverPosition" ], "line": "river cursor moves one row down" }, "7639": { "unit": "game/mapGenerator6F00", "line": "back to generateRiver, which called advanceRiverPosition" }, "763A": { "unit": "game/mapGenerator6F00", "block": [ "Split address table of the three step stubs, indexed by segment type 0-7 and read by", "advanceRiverPosition ($761F/$7625). Only type 1 ($7636 = down) and type 3 ($7632 = up) move the", "river vertically; every other type maps to $762E (right)." ], "line": "low bytes for types 0-4: right, down, right, up, right" }, "763F": { "unit": "game/mapGenerator6F00", "line": "low bytes for types 5-7: all three straights step right" }, "7642": { "unit": "game/mapGenerator6F00", "line": "high bytes: all three stubs live in page $76" }, "764A": { "unit": "game/mapGenerator6F00", "routine": [ "markRiverBanks - Reserves the ground around the current river cell so the hill and forest passes", "that follow keep the river valley clear. Away from the map edges it addresses the 6x6 block whose", "top-left corner is (genCol & ~1) - 2, (genRow & ~1) - 2, writes $80 into every blank cell of the", "20-cell perimeter and $81 into the 16 cells of the 4x4 core (upgrading a $80 already there). Only", "cells that are still blank ($40 or lower) are touched, so terrain already placed - including the", "river itself - survives. In columns 0-1 and 38-39 only the four cells of the river's own column", "get $81. clearMapMarkers ($74FE) erases both marker values again at the end of the generator.", "In: genCol $030F, genRow $0310, map addressed through readMapCell ($25FA -> mapCellPtr zp_48/49),", " tables riverZoneOuterOffsets $7894 and riverZoneInnerOffsets $78A8", "Out: $80/$81 written into blank map cells; mapCellPtr points at the block origin; A/X/Y clobbered", "Called from: generateRiver ($7590)" ], "line": "column of the river cell just drawn" }, "764D": { "unit": "game/mapGenerator6F00", "line": "columns 0 and 1 have no room for a 6x6 block to their left" }, "764F": { "unit": "game/mapGenerator6F00", "line": "inside the map - do the full 6x6 reservation" }, "7651": { "unit": "game/mapGenerator6F00", "block": [ "Edge columns (0, 1, 38, 39): reserve only the four cells directly above and below the river in the", "river's own column, using the first four entries of riverZoneOuterOffsets ($28, $50, $78, $A0 =", "one, two, three and four rows down)." ], "line": "row of the river cell" }, "7654": { "unit": "game/mapGenerator6F00", "line": "snap it down to an even row (the generator works in 2x2 blocks)" }, "7656": { "unit": "game/mapGenerator6F00", "line": "Y = the even row" }, "7657": { "unit": "game/mapGenerator6F00", "line": "two rows above..." }, "7658": { "unit": "game/mapGenerator6F00", "line": "...the even row, so the four offsets cover evenRow-1 to evenRow+2" }, "7659": { "unit": "game/mapGenerator6F00", "line": "mapCellPtr = &map[evenRow-2][genCol] (X still holds the column)" }, "765C": { "unit": "game/mapGenerator6F00", "line": "four offsets, walked backwards" }, "765E": { "unit": "game/mapGenerator6F00", "line": "offset of the cell: +1, +2, +3 or +4 rows in the same column" }, "7661": { "unit": "game/mapGenerator6F00", "line": "read that cell" }, "7663": { "unit": "game/mapGenerator6F00", "line": "bit 7 set = already an $80/$81 reservation marker - upgrade it" }, "7665": { "unit": "game/mapGenerator6F00", "line": "$40 and below is blank ground" }, "7667": { "unit": "game/mapGenerator6F00", "line": "real terrain is already here - leave it alone" }, "7669": { "unit": "game/mapGenerator6F00", "line": "$81 = river bank, the strongest reservation" }, "766B": { "unit": "game/mapGenerator6F00", "line": "reserve the cell as river bank" }, "766D": { "unit": "game/mapGenerator6F00", "line": "next of the four offsets" }, "766E": { "unit": "game/mapGenerator6F00", "line": "loop over all four offsets" }, "7670": { "unit": "game/mapGenerator6F00", "line": "done with the edge column" }, "7671": { "unit": "game/mapGenerator6F00", "block": [ "Interior columns 2-37: build the 6x6 block, mark its 20-cell perimeter $80 and its 4x4 core $81." ], "line": "is the river within two columns of the right edge (38 or 39)?" }, "7673": { "unit": "game/mapGenerator6F00", "line": "yes - too close to the right edge for a 6x6 block" }, "7675": { "unit": "game/mapGenerator6F00", "line": "column of the river cell" }, "7676": { "unit": "game/mapGenerator6F00", "line": "snap the column down to an even one" }, "7678": { "unit": "game/mapGenerator6F00", "line": "X = the even column" }, "7679": { "unit": "game/mapGenerator6F00", "line": "row of the river cell" }, "767C": { "unit": "game/mapGenerator6F00", "line": "snap the row down to an even one" }, "767E": { "unit": "game/mapGenerator6F00", "line": "Y = the even row" }, "767F": { "unit": "game/mapGenerator6F00", "line": "step two columns left..." }, "7680": { "unit": "game/mapGenerator6F00", "line": "...to the left edge of the 6x6 block" }, "7681": { "unit": "game/mapGenerator6F00", "line": "step two rows up..." }, "7682": { "unit": "game/mapGenerator6F00", "line": "...to the top edge of the 6x6 block" }, "7683": { "unit": "game/mapGenerator6F00", "line": "mapCellPtr = &map[evenRow-2][evenCol-2]" }, "7686": { "unit": "game/mapGenerator6F00", "line": "20 perimeter offsets, walked backwards" }, "7688": { "unit": "game/mapGenerator6F00", "line": "offset of the next perimeter cell inside the 6x6 block" }, "768B": { "unit": "game/mapGenerator6F00", "line": "read it" }, "768D": { "unit": "game/mapGenerator6F00", "line": "anything above $40 - real terrain or an existing marker - is left as it is" }, "768F": { "unit": "game/mapGenerator6F00", "line": "already terrain or a marker - leave it" }, "7691": { "unit": "game/mapGenerator6F00", "line": "$80 = river outskirts, the weaker reservation" }, "7693": { "unit": "game/mapGenerator6F00", "line": "reserve the perimeter cell" }, "7695": { "unit": "game/mapGenerator6F00", "line": "next perimeter offset" }, "7696": { "unit": "game/mapGenerator6F00", "line": "loop over all 20 perimeter offsets" }, "7698": { "unit": "game/mapGenerator6F00", "block": [ "The 4x4 core of the block, i.e. the cells that actually touch the water, gets the stronger $81", "marker; an $80 written by a neighbouring river cell is upgraded to $81 here." ], "line": "16 core offsets, walked backwards" }, "769A": { "unit": "game/mapGenerator6F00", "line": "offset of the next core cell" }, "769D": { "unit": "game/mapGenerator6F00", "line": "read it" }, "769F": { "unit": "game/mapGenerator6F00", "line": "already a marker ($80 or $81) - upgrade to $81" }, "76A1": { "unit": "game/mapGenerator6F00", "line": "$40 and below is blank ground" }, "76A3": { "unit": "game/mapGenerator6F00", "line": "real terrain is already here - leave it" }, "76A5": { "unit": "game/mapGenerator6F00", "line": "$81 = river bank" }, "76A7": { "unit": "game/mapGenerator6F00", "line": "reserve the core cell as river bank" }, "76A9": { "unit": "game/mapGenerator6F00", "line": "next core offset" }, "76AA": { "unit": "game/mapGenerator6F00", "line": "loop over all 16 core offsets" }, "76AC": { "unit": "game/mapGenerator6F00", "line": "back to generateRiver" }, "76AD": { "unit": "game/mapGenerator6F00", "routine": [ "mapNameEntryScreen - The 'TYPE MAP NAME' page of the game setup. A map name is simply the game's", "24-bit map seed written in base 32 with the alphabet at $890C, so typing a name picks a", "battlefield and the two players only have to agree on those five characters. The routine draws", "the current map, then loops: enterMapName returns a new seed (C=0) - adopt it, regenerate and", "redraw the map, ask again; or the fire button (C=1) - print 'ACCEPTED' and return to the setup", "menu.", "In: mapSeed $0B95-$0B97, mapFlipFlag $0B9D, keyboard and joystick", "Out: mapSeed and mapFlipFlag updated, the map at $F000 regenerated and drawn in the overview", " window, text colour zp_3D / pad colour zp_42 = 9", "Called from: the setup menu, by JMP from $8339 (the MAP item)" ], "line": "build the 40x40 map from the current seed" }, "76B0": { "unit": "game/mapGenerator6F00", "line": "is the map shown rotated 180 degrees?" }, "76B3": { "unit": "game/mapGenerator6F00", "line": "flip flag clear - show the map as generated" }, "76B5": { "unit": "game/mapGenerator6F00", "line": "yes - rotate the map and mirror the direction-dependent terrain codes" }, "76B8": { "unit": "game/mapGenerator6F00", "line": "paint the whole map into the 20x20 overview window" }, "76BB": { "unit": "game/mapGenerator6F00", "line": "blank the five name characters $0BA9-$0BAD" }, "76BE": { "unit": "game/mapGenerator6F00", "block": [ "Prompt loop. Each pass reprints both prompts and calls enterMapName; it ends only when the", "player presses the fire button." ], "line": "colour 9 = brown, the setup-panel text colour" }, "76C0": { "unit": "game/mapGenerator6F00", "line": "text colour" }, "76C2": { "unit": "game/mapGenerator6F00", "line": "and the colour of the padding around centred text" }, "76C4": { "unit": "game/mapGenerator6F00", "line": "clear the info panel under the tactical view" }, "76C7": { "unit": "game/mapGenerator6F00", "line": "string low byte..." }, "76C9": { "unit": "game/mapGenerator6F00", "line": "...and high byte: msgTypeMapName $0677, 'TYPE MAP NAME / (F7 RANDOM) / (F5 SYM/RND)'" }, "76CB": { "unit": "game/mapGenerator6F00", "line": "print the three-line prompt" }, "76CE": { "unit": "game/mapGenerator6F00", "line": "leftmost column of the panel" }, "76D0": { "unit": "game/mapGenerator6F00", "line": "set it as the cursor column" }, "76D2": { "unit": "game/mapGenerator6F00", "line": "row 19 of the text grid" }, "76D4": { "unit": "game/mapGenerator6F00", "line": "move the cursor there" }, "76D7": { "unit": "game/mapGenerator6F00", "line": "string low byte..." }, "76D9": { "unit": "game/mapGenerator6F00", "line": "...and high byte: msgBtnToAccept $069F, 'BTN TO ACCEPT / (F 1 TO FLIP)'" }, "76DB": { "unit": "game/mapGenerator6F00", "line": "print the two-line prompt" }, "76DE": { "unit": "game/mapGenerator6F00", "line": "run the interactive name entry" }, "76E1": { "unit": "game/mapGenerator6F00", "line": "C=1: the fire button was pressed - accept the map on screen" }, "76E3": { "unit": "game/mapGenerator6F00", "line": "C=0: enterMapName left a fresh 24-bit seed in $5A-$5C" }, "76E5": { "unit": "game/mapGenerator6F00", "line": "adopt it as the map seed..." }, "76E8": { "unit": "game/mapGenerator6F00", "line": "seed byte 1..." }, "76EA": { "unit": "game/mapGenerator6F00", "line": "...into mapSeed1" }, "76ED": { "unit": "game/mapGenerator6F00", "line": "seed byte 2..." }, "76EF": { "unit": "game/mapGenerator6F00", "line": "...into mapSeed2" }, "76F2": { "unit": "game/mapGenerator6F00", "line": "wipe the map back to blank terrain $40" }, "76F5": { "unit": "game/mapGenerator6F00", "line": "colour 0" }, "76F7": { "unit": "game/mapGenerator6F00", "line": "text colour 0 while redrawing" }, "76F9": { "unit": "game/mapGenerator6F00", "line": "a freshly named map is always shown unflipped" }, "76FC": { "unit": "game/mapGenerator6F00", "line": "clear the 20x20 overview window" }, "76FF": { "unit": "game/mapGenerator6F00", "line": "generate the new battlefield from the new seed" }, "7702": { "unit": "game/mapGenerator6F00", "line": "draw it" }, "7705": { "unit": "game/mapGenerator6F00", "line": "and ask for another name" }, "7708": { "unit": "game/mapGenerator6F00", "block": [ "Accept: the map currently on screen is the one that will be played." ], "line": "clear the info panel" }, "770B": { "unit": "game/mapGenerator6F00", "line": "row 15" }, "770D": { "unit": "game/mapGenerator6F00", "line": "move the cursor to row 15" }, "7710": { "unit": "game/mapGenerator6F00", "line": "string low byte..." }, "7712": { "unit": "game/mapGenerator6F00", "line": "...and high byte: 'ACCEPTED' at $EFED in the $EC00 comm-module tail; tail-call back to the menu" }, "7714": { "unit": "game/mapGenerator6F00", "line": "centre the word in the panel and return to the setup menu" }, "7717": { "unit": "game/mapGenerator6F00", "routine": [ "enterMapName - Reads a five-character map name at column 4, row 16 and converts it into the", "24-bit map seed in $5A-$5C. The field is underlined with five $25 glyphs and the cursor cell is", "marked by writing colour $11 into the cell's colour-RAM byte. Only the 32 characters of the", "alphabet at $890C (space, A-Z, + - * / =) are accepted, five bits each, first character in the", "high bits; $88 (DEL) erases; any other key just beeps. F1 flips the displayed map, F7 takes a", "random seed from the game RNG and F5 does the same but forces the low five bits to 1 so the name", "ends in '=' - the marker for a point-symmetric map. The fire button ends entry with C=1.", "The character counter lives at $0313; the symbol commandDispatchLoop comes from the code that", "occupies $0300-$03FF in the other overlay, it has nothing to do with commands here.", "In: key events from newKeyEvent $90EA, function key requestedScreenKey zp_66, the fire button via", " checkFirePressed ($0EB1), game RNG $57-$59, alphabet $890C", "Out: C=0 - $5A-$5C hold the chosen 24-bit seed and $0BA9-$0BAD its five characters; C=1 - the fire", " button was pressed and nothing was chosen. $0313 = characters typed, mapFlipFlag $0B9D may", " have been toggled, zp_18 scratch, text cursor moved", "Called from: mapNameEntryScreen ($76DE) and the manual look-up copy protection ($09F9)" ], "line": "print the (blank) name field and leave the cursor after it" }, "771A": { "unit": "game/mapGenerator6F00", "line": "column 4 again - printMapName left the cursor on the row below the field" }, "771C": { "unit": "game/mapGenerator6F00", "line": "cursor back to column 4, the first character of the field" }, "771E": { "unit": "game/mapGenerator6F00", "line": "recompute the bitmap and colour-RAM pointers for that cell" }, "7721": { "unit": "game/mapGenerator6F00", "line": "glyph $25 = the underline character" }, "7723": { "unit": "game/mapGenerator6F00", "line": "make it the fill glyph" }, "7725": { "unit": "game/mapGenerator6F00", "line": "five character cells to underline" }, "7727": { "unit": "game/mapGenerator6F00", "line": "$C0EF is printFillChars: underline the five character cells" }, "772A": { "unit": "game/mapGenerator6F00", "line": "glyph 0 = the normal blank" }, "772C": { "unit": "game/mapGenerator6F00", "line": "restore the normal blank glyph" }, "772E": { "unit": "game/mapGenerator6F00", "line": "$0313 = number of characters typed so far = 0" }, "7731": { "unit": "game/mapGenerator6F00", "line": "clear the 24-bit seed accumulator..." }, "7733": { "unit": "game/mapGenerator6F00", "line": "seed byte 1" }, "7735": { "unit": "game/mapGenerator6F00", "line": "...all three bytes" }, "7737": { "unit": "game/mapGenerator6F00", "line": "and blank the five name characters" }, "773A": { "unit": "game/mapGenerator6F00", "block": [ "Input loop: one pass per frame. It services the opponent link, handles F1 (flip), tests the fire", "button and then consumes at most one key event." ], "line": "keep the modem/trainer exchange alive while the player types" }, "773D": { "unit": "game/mapGenerator6F00", "line": "function key from the IRQ poll: 0-3 = F1/F3/F5/F7, $FF = none" }, "773F": { "unit": "game/mapGenerator6F00", "line": "not F1 (function key code 0) - no flip" }, "7741": { "unit": "game/mapGenerator6F00", "line": "F1: flip the map end for end" }, "7744": { "unit": "game/mapGenerator6F00", "line": "toggle bit 0" }, "7746": { "unit": "game/mapGenerator6F00", "line": "store the new flip state" }, "7749": { "unit": "game/mapGenerator6F00", "line": "rotate the map 180 degrees and mirror the direction-dependent terrain codes" }, "774C": { "unit": "game/mapGenerator6F00", "line": "redraw the overview window" }, "774F": { "unit": "game/mapGenerator6F00", "line": "A = 0 so the fire test below starts from a known value (A is not used by it)" }, "7751": { "unit": "game/mapGenerator6F00", "line": "fresh press of the fire button? (returns A=0 on a new press)" }, "7754": { "unit": "game/mapGenerator6F00", "line": "no press - carry on reading keys" }, "7756": { "unit": "game/mapGenerator6F00", "line": "sound 1 = the click checkFirePressed has just played; this repeats it" }, "7758": { "unit": "game/mapGenerator6F00", "line": "a second click on top of the one checkFirePressed already played" }, "775B": { "unit": "game/mapGenerator6F00", "line": "C=1 tells the caller 'accepted, no new name'" }, "775C": { "unit": "game/mapGenerator6F00", "line": "return to the caller with 'accepted'" }, "775D": { "unit": "game/mapGenerator6F00", "block": [ "Key handling. newKeyEvent ($90EA) holds the last key the IRQ saw, $FF when there is none; it is", "reset to $FF once the key has been dealt with." ], "line": "last key event" }, "7760": { "unit": "game/mapGenerator6F00", "line": "$FF means the IRQ has not seen a key" }, "7762": { "unit": "game/mapGenerator6F00", "line": "no key this frame - go on to the completion tests" }, "7764": { "unit": "game/mapGenerator6F00", "line": "characters typed so far" }, "7767": { "unit": "game/mapGenerator6F00", "line": "not the first one - keep what is on screen" }, "7769": { "unit": "game/mapGenerator6F00", "line": "first keystroke: save the key" }, "776A": { "unit": "game/mapGenerator6F00", "line": "cursor back to the start of the field" }, "776D": { "unit": "game/mapGenerator6F00", "line": "and wipe the underlined field" }, "7770": { "unit": "game/mapGenerator6F00", "line": "restore the key" }, "7771": { "unit": "game/mapGenerator6F00", "line": "$88 = the DEL key" }, "7773": { "unit": "game/mapGenerator6F00", "line": "not DEL - try the alphabet" }, "7775": { "unit": "game/mapGenerator6F00", "line": "characters typed so far" }, "7778": { "unit": "game/mapGenerator6F00", "line": "field already empty - just beep" }, "777A": { "unit": "game/mapGenerator6F00", "line": "one character less" }, "777D": { "unit": "game/mapGenerator6F00", "line": "printChar sees $88 as a backspace: step back, erase the glyph, step back again" }, "7780": { "unit": "game/mapGenerator6F00", "line": "offset 0 = the cell the cursor has just stepped back to" }, "7782": { "unit": "game/mapGenerator6F00", "line": "colour $11 = the cursor block" }, "7784": { "unit": "game/mapGenerator6F00", "line": "mark the freed cell as the cursor (screenPtr points into colour RAM here)" }, "7786": { "unit": "game/mapGenerator6F00", "line": "offset 1 = the cell to its right" }, "7787": { "unit": "game/mapGenerator6F00", "line": "normal text colour" }, "7789": { "unit": "game/mapGenerator6F00", "line": "restore the cell to the right, which held the cursor block before the delete" }, "778B": { "unit": "game/mapGenerator6F00", "line": "index of the freed character" }, "778E": { "unit": "game/mapGenerator6F00", "line": "space" }, "7790": { "unit": "game/mapGenerator6F00", "line": "blank it in the name buffer $0BA9-$0BAD" }, "7793": { "unit": "game/mapGenerator6F00", "line": "always taken ($20 is not 0) - play the key click" }, "7795": { "unit": "game/mapGenerator6F00", "block": [ "Ordinary character: look it up in the 32-entry map-name alphabet at $890C. A key that is not in", "the alphabet is rejected with the error beep." ], "line": "keep the raw key (bit 7 may be set by the keyboard scanner)" }, "7797": { "unit": "game/mapGenerator6F00", "line": "strip bit 7 to get plain ASCII" }, "7799": { "unit": "game/mapGenerator6F00", "line": "search the alphabet backwards from index 31" }, "779B": { "unit": "game/mapGenerator6F00", "line": "mapNameAlphabet[y]: space, A-Z, +, -, *, /, =" }, "779E": { "unit": "game/mapGenerator6F00", "line": "found it - Y is the 5-bit code of the character" }, "77A0": { "unit": "game/mapGenerator6F00", "line": "try the previous alphabet entry" }, "77A1": { "unit": "game/mapGenerator6F00", "line": "keep searching down to index 0" }, "77A3": { "unit": "game/mapGenerator6F00", "line": "sound 3 = the reject beep" }, "77A5": { "unit": "game/mapGenerator6F00", "line": "always taken (A = 3) - play the reject beep" }, "77A7": { "unit": "game/mapGenerator6F00", "line": "index of the next free character" }, "77AA": { "unit": "game/mapGenerator6F00", "line": "store the character in the name buffer" }, "77AD": { "unit": "game/mapGenerator6F00", "line": "one character more" }, "77B0": { "unit": "game/mapGenerator6F00", "line": "the raw key as typed" }, "77B2": { "unit": "game/mapGenerator6F00", "line": "draw it into the field" }, "77B5": { "unit": "game/mapGenerator6F00", "line": "characters typed so far" }, "77B8": { "unit": "game/mapGenerator6F00", "line": "are all five characters of the field filled now?" }, "77BA": { "unit": "game/mapGenerator6F00", "line": "yes - no cursor block past the end of the field" }, "77BC": { "unit": "game/mapGenerator6F00", "line": "offset 0 = the cell the cursor has just advanced to" }, "77BE": { "unit": "game/mapGenerator6F00", "line": "colour $11 = the cursor block" }, "77C0": { "unit": "game/mapGenerator6F00", "line": "mark the next cell as the cursor" }, "77C2": { "unit": "game/mapGenerator6F00", "line": "sound 2 = the key click" }, "77C4": { "unit": "game/mapGenerator6F00", "line": "play it" }, "77C7": { "unit": "game/mapGenerator6F00", "line": "$FF = no key pending" }, "77C9": { "unit": "game/mapGenerator6F00", "line": "mark the key event as consumed" }, "77CC": { "unit": "game/mapGenerator6F00", "block": [ "After every frame: five characters means the name is complete, otherwise F5/F7 may still pick a", "random one. nextGameRandom is stepped every pass so the random seed depends on how long the", "player took." ], "line": "characters typed" }, "77CF": { "unit": "game/mapGenerator6F00", "line": "five = a complete map name" }, "77D1": { "unit": "game/mapGenerator6F00", "line": "pack it into the 24-bit seed" }, "77D3": { "unit": "game/mapGenerator6F00", "line": "stir the game RNG once per frame" }, "77D6": { "unit": "game/mapGenerator6F00", "line": "low byte of the new RNG state" }, "77D8": { "unit": "game/mapGenerator6F00", "line": "function key: 0-3 = F1/F3/F5/F7, $FF = none" }, "77DA": { "unit": "game/mapGenerator6F00", "line": "$FF - no function key, keep waiting" }, "77DC": { "unit": "game/mapGenerator6F00", "line": "F5 has function key code 2, F7 has 3" }, "77DE": { "unit": "game/mapGenerator6F00", "line": "one of them - take a random map" }, "77E0": { "unit": "game/mapGenerator6F00", "line": "F1 or F3 - back to the input loop" }, "77E3": { "unit": "game/mapGenerator6F00", "line": "F7 (3) gives a completely random map" }, "77E5": { "unit": "game/mapGenerator6F00", "line": "F5 (2) sets the low five bits, so the name ends in '=' = a point-symmetric map" }, "77E7": { "unit": "game/mapGenerator6F00", "line": "seed byte 0 = the RNG low byte" }, "77E9": { "unit": "game/mapGenerator6F00", "line": "RNG byte 1" }, "77EB": { "unit": "game/mapGenerator6F00", "line": "seed byte 1" }, "77ED": { "unit": "game/mapGenerator6F00", "line": "RNG byte 2" }, "77EF": { "unit": "game/mapGenerator6F00", "line": "seed byte 2" }, "77F1": { "unit": "game/mapGenerator6F00", "line": "spell the seed out as five characters in $0BA9-$0BAD (A/Y/X already hold it)" }, "77F4": { "unit": "game/mapGenerator6F00", "line": "show it and return C=0" }, "77F7": { "unit": "game/mapGenerator6F00", "block": [ "Pack the five typed characters into the 24-bit seed: index of the character in the 32-entry", "alphabet, five bits each, first character in the most significant bits." ], "line": "start at the first character, and use Y as the zero to clear the accumulator" }, "77F9": { "unit": "game/mapGenerator6F00", "line": "seed = 0..." }, "77FB": { "unit": "game/mapGenerator6F00", "line": "seed byte 1" }, "77FD": { "unit": "game/mapGenerator6F00", "line": "...all 24 bits" }, "77FF": { "unit": "game/mapGenerator6F00", "line": "character Y of the name" }, "7802": { "unit": "game/mapGenerator6F00", "line": "search the alphabet backwards from index 31" }, "7804": { "unit": "game/mapGenerator6F00", "line": "compare the character with alphabet entry X" }, "7807": { "unit": "game/mapGenerator6F00", "line": "found - X is its 5-bit code" }, "7809": { "unit": "game/mapGenerator6F00", "line": "try the previous alphabet entry" }, "780A": { "unit": "game/mapGenerator6F00", "line": "search all 32 alphabet entries" }, "780C": { "unit": "game/mapGenerator6F00", "line": "unreachable: every character in the buffer was validated when it was typed..." }, "780D": { "unit": "game/mapGenerator6F00", "line": "...so this BRK (which would crash) is really an assertion" }, "780E": { "unit": "game/mapGenerator6F00", "line": "keep the 5-bit character code" }, "7810": { "unit": "game/mapGenerator6F00", "line": "shift the accumulator five bits left" }, "7812": { "unit": "game/mapGenerator6F00", "line": "24-bit shift left by one..." }, "7814": { "unit": "game/mapGenerator6F00", "line": "carry into seed byte 1..." }, "7816": { "unit": "game/mapGenerator6F00", "line": "...and on into seed byte 2" }, "7818": { "unit": "game/mapGenerator6F00", "line": "count the five shifts" }, "7819": { "unit": "game/mapGenerator6F00", "line": "five single-bit shifts in all" }, "781B": { "unit": "game/mapGenerator6F00", "line": "low byte of the accumulator" }, "781D": { "unit": "game/mapGenerator6F00", "line": "redundant: the five ASLs already left bits 0-4 clear" }, "781F": { "unit": "game/mapGenerator6F00", "line": "merge the character code into the low five bits" }, "7821": { "unit": "game/mapGenerator6F00", "line": "store it back" }, "7823": { "unit": "game/mapGenerator6F00", "line": "next character of the name" }, "7824": { "unit": "game/mapGenerator6F00", "line": "all five characters packed?" }, "7826": { "unit": "game/mapGenerator6F00", "line": "keep packing until all five are in" }, "7828": { "unit": "game/mapGenerator6F00", "line": "print the finished name in the field" }, "782B": { "unit": "game/mapGenerator6F00", "line": "C=0: the caller gets a new seed in $5A-$5C" }, "782C": { "unit": "game/mapGenerator6F00", "line": "return to the caller with the new seed" }, "782D": { "unit": "game/mapGenerator6F00", "routine": [ "setMapNameCursor - Moves the text cursor to the start of the map-name field: column 4 of the", "current text window, row 16.", "In: the text window set up by the caller (left column zp_3B)", "Out: textCursorCol zp_3F = 4, textCursorRow zp_40 = $10, cursor pointers zp_B4-zp_B7 recomputed", "Called from: enterMapName ($776A) and printMapName ($7841)" ], "line": "the map-name field starts at column 4" }, "782F": { "unit": "game/mapGenerator6F00", "line": "set it as the cursor column" }, "7831": { "unit": "game/mapGenerator6F00", "line": "row 16" }, "7833": { "unit": "game/mapGenerator6F00", "line": "sets the row and recomputes the cell pointers" }, "7836": { "unit": "game/mapGenerator6F00", "routine": [ "clearMapNameField - Fills the five map-name characters $0BA9-$0BAD with spaces.", "In: none", "Out: mapNameText $0BA9-$0BAD = $20, Y = $FF", "Called from: mapNameEntryScreen ($76BB), enterMapName ($7737) and the manual look-up copy", " protection ($09F6)" ], "line": "five characters, index 4 down to 0" }, "7838": { "unit": "game/mapGenerator6F00", "line": "space" }, "783A": { "unit": "game/mapGenerator6F00", "line": "mapNameText[y]" }, "783D": { "unit": "game/mapGenerator6F00", "line": "walk down to character 0" }, "783E": { "unit": "game/mapGenerator6F00", "line": "until index 0 has been written" }, "7840": { "unit": "game/mapGenerator6F00", "line": "the field is blank" }, "7841": { "unit": "game/mapGenerator6F00", "routine": [ "printMapName - Prints the five-character map name at its place on the setup screen. The byte", "after the name, $0BAE, is used as the string terminator: $8D is a carriage return ($0D) with bit 7", "set, so the name is printed and the cursor drops to the next row.", "In: mapNameText $0BA9-$0BAD", "Out: mapNameTerminator $0BAE = $8D, the name drawn at column 4 row 16, cursor on row 17", "Called from: enterMapName ($7717 and $7828)" ], "line": "cursor to column 4, row 16" }, "7844": { "unit": "game/mapGenerator6F00", "line": "$8D = CR with bit 7 = 'last character of the string'" }, "7846": { "unit": "game/mapGenerator6F00", "line": "terminate the name after five characters" }, "7849": { "unit": "game/mapGenerator6F00", "line": "string low byte..." }, "784B": { "unit": "game/mapGenerator6F00", "line": "...and high byte: mapNameText $0BA9" }, "784D": { "unit": "game/mapGenerator6F00", "line": "print it" }, "7850": { "unit": "game/mapGenerator6F00", "routine": [ "seedToMapName - Spells a 24-bit map seed out as its five-character name: five times take the low", "five bits as an index into the 32-character alphabet at $890C and shift the seed right by five, so", "the last character carries the lowest bits. This is the exact inverse of the packing loop at", "$77F7, and it is why a map's name and its seed are the same number.", "In: A = seed byte 0, Y = seed byte 1, X = seed byte 2 (the same order as $5A/$5B/$5C)", "Out: mapNameText $0BA9-$0BAD; zp_18-zp_1A used as the shift register; X and Y clobbered", "Called from: runMapGeneratorPasses ($6F36, to name the map it has just built) and enterMapName", " ($77F1, after an F5/F7 random seed)" ], "line": "shift register byte 0" }, "7852": { "unit": "game/mapGenerator6F00", "line": "byte 1" }, "7854": { "unit": "game/mapGenerator6F00", "line": "byte 2" }, "7856": { "unit": "game/mapGenerator6F00", "line": "fill the name from the last character backwards" }, "7858": { "unit": "game/mapGenerator6F00", "line": "low byte of the remaining seed" }, "785A": { "unit": "game/mapGenerator6F00", "line": "the low five bits are one character" }, "785C": { "unit": "game/mapGenerator6F00", "line": "use the 5-bit code as an index into the alphabet" }, "785D": { "unit": "game/mapGenerator6F00", "line": "mapNameAlphabet: space, A-Z, +, -, *, /, =" }, "7860": { "unit": "game/mapGenerator6F00", "line": "store it in the name buffer" }, "7863": { "unit": "game/mapGenerator6F00", "line": "shift the seed right by five bits" }, "7865": { "unit": "game/mapGenerator6F00", "line": "24-bit shift right by one..." }, "7867": { "unit": "game/mapGenerator6F00", "line": "carry down into byte 1..." }, "7869": { "unit": "game/mapGenerator6F00", "line": "...and on into byte 0" }, "786B": { "unit": "game/mapGenerator6F00", "line": "count the five shifts" }, "786C": { "unit": "game/mapGenerator6F00", "line": "five single-bit shifts in all" }, "786E": { "unit": "game/mapGenerator6F00", "line": "next character to the left" }, "786F": { "unit": "game/mapGenerator6F00", "line": "loop over all five characters" }, "7871": { "unit": "game/mapGenerator6F00", "line": "the five characters are in $0BA9-$0BAD" }, "7872": { "unit": "game/mapGenerator6F00", "routine": [ "randomTileVariant - Picks a random visual variant of a terrain code so that large areas of the", "same terrain do not look tiled. The mask table at $0770 (tileVariantMaskTable, part of the", "terrain rules loaded from track 18) is indexed by tile code - $40, or tile code - $20 for the", "codes below $40, and gives 0, 1 or 3 = the number of extra variants; the result is the base code", "plus a random value masked with it. Y is preserved through a self-modified LDY #imm.", "In: A = base terrain code, tileVariantMaskTable $0770, scenario RNG", "Out: A = the code with random variant bits added; Y preserved, X untouched. Self-modifies the", " operands at $788D (AND #mask), $7890 (ADC #base) and $7892 (LDY #savedY)", "Called from: the hill/forest fill pass ($72A4) and the contour pass ($74E7)" ], "line": "leftover NOP - probably a patched-out instruction" }, "7873": { "unit": "game/mapGenerator6F00", "line": "remember the base tile code in the ADC #imm at $788F" }, "7876": { "unit": "game/mapGenerator6F00", "line": "set carry for the subtraction" }, "7877": { "unit": "game/mapGenerator6F00", "line": "terrain codes $40 and up index the mask table directly" }, "7879": { "unit": "game/mapGenerator6F00", "line": "code was $40 or higher - the index is code - $40" }, "787B": { "unit": "game/mapGenerator6F00", "line": "code below $40: add $20 back, giving an index of code - $20" }, "787D": { "unit": "game/mapGenerator6F00", "line": "save Y in the LDY #imm at $7891 so the caller's Y survives" }, "7880": { "unit": "game/mapGenerator6F00", "line": "index into the variant mask table" }, "7881": { "unit": "game/mapGenerator6F00", "line": "number of extra variants as a bit mask: 0, 1 or 3" }, "7884": { "unit": "game/mapGenerator6F00", "line": "0 = this terrain has only one look, A is already the answer" }, "7886": { "unit": "game/mapGenerator6F00", "line": "patch the mask into the AND #imm at $788C" }, "7889": { "unit": "game/mapGenerator6F00", "line": "random byte" }, "788C": { "unit": "game/mapGenerator6F00", "line": "keep only as many random bits as the terrain has variants (operand patched above)" }, "788E": { "unit": "game/mapGenerator6F00", "line": "clear carry for the add" }, "788F": { "unit": "game/mapGenerator6F00", "line": "add the base tile code back (operand patched at $7873)" }, "7891": { "unit": "game/mapGenerator6F00", "line": "restore the caller's Y (operand patched at $787D)" }, "7893": { "unit": "game/mapGenerator6F00", "line": "A is the terrain code to paint" }, "7894": { "unit": "game/mapGenerator6F00", "block": [ "The 6x6 reservation block used by markRiverBanks, expressed as offsets from its top-left cell.", "The map row stride is $28 (40 cells). Entries 0-3 are the left column (rows 1-4) and are also", "used on their own near the map edges, where they address the four cells above and below the river", "in its own column; entries 4-9 are the top row, 10-13 the right column (rows 1-4) and 14-19 the", "bottom row. Together they are the 20-cell perimeter, marked $80." ], "line": "left column, rows 1-4 ($28 = one row): also the edge-column-only case" }, "7898": { "unit": "game/mapGenerator6F00", "line": "top row, columns 0-5, then the right column rows 1-2 ($2D = row 1 col 5, $55 = row 2 col 5)" }, "78A0": { "unit": "game/mapGenerator6F00", "line": "right column rows 3-4, then the bottom row ($C8 = row 5 col 0) columns 0-5" }, "78A8": { "unit": "game/mapGenerator6F00", "block": [ "The inner 4x4 cells (rows 1-4, columns 1-4) of the same 6x6 block: the ground that actually", "touches the water, marked $81 by markRiverBanks." ], "line": "rows 1 and 2, columns 1-4" }, "78B0": { "unit": "game/mapGenerator6F00", "line": "rows 3 and 4, columns 1-4" }, "78B8": { "unit": "game/mapGenerator6F00", "block": [ "Which of the four 400-byte unit start-position templates at $F000 (+0, +400, +800, +1200) each", "game type uses, indexed by gameTypeOptions & 7: SCRIMAGE, QB SNEAK and THE BOMB share template 2,", "FACE-OFF uses 1, SLUGGERS 3, FULL WAR and DEFENDER 0." ], "line": "game type 0 SCRIMAGE -> template 2" }, "78B9": { "unit": "game/mapGenerator6F00", "line": "types 1 QB SNEAK, 2 THE BOMB -> 2; 3 FACE-OFF -> 1; 4 SLUGGERS -> 3; 5 FULL WAR, 6 DEFENDER -> 0" }, "78BF": { "unit": "game/mapGenerator6F00", "block": [ "Translates the COMCEN SPEED option (0-3, as edited by editComcenSpeed) into the engine's internal", "speed class. Applied to both entries of comcenSpeedClass $92B4/$92B5 at $7B6E." ], "line": "setting 0 -> class 4, 1 -> 0, 2 -> 1, 3 -> 5" }, "78C3": { "unit": "game/mapGenerator6F00", "block": [ "Game length in rounds for each game type (gameTypeOptions & 7), loaded into gameClock $91CB by", "setGameClockForType ($7D8B). A quarter of this value is the last-quarter warning round $92EF." ], "line": "SCRIMAGE 63, QB SNEAK 63, THE BOMB 31, FACE-OFF 127" }, "78C7": { "unit": "game/mapGenerator6F00", "line": "SLUGGERS 127, FULL WAR 254, DEFENDER 254" }, "78CA": { "unit": "game/mapGenerator6F00", "block": [ "Default gameTypeOptions byte for each of the seven items of the game-type menu, read at $828F.", "Bits 0-2 are the game type itself; bit 3 (UNIT MENUS) and bit 4 (DAMAGE) are preset for the four", "long scenarios." ], "line": "item 0 SCRIMAGE -> $00" }, "78CB": { "unit": "game/mapGenerator6F00", "line": "QB SNEAK $01, THE BOMB $02, FACE-OFF $13, SLUGGERS $14, FULL WAR $1D, DEFENDER $1E" }, "78D1": { "unit": "game/mapGenerator6F00", "routine": [ "startGameSession - The whole 'start a game' sequence, from a cleared battle state to the first", "frame of play. It resets the per-battle variables, then either branches off to the game-film", "replay path or negotiates the live game: agree which player is side 0 and which is side 1, let", "side 0 pick the game type and the map and send the map seed as command $8B (or $A6 for a custom", "map), exchange player names and check the opponent's build, load the unit start template, record", "the whole setup in the film header at $D000, generate and (for side 1) rotate the battlefield,", "run the unit deployment phase, and finally set the clock, place the units and the recyclers and", "jump into the battle.", "In: the settings block $0B95-$0BB4 (map seed, film mode, link state, side, game type, trainer", " flag), the comm module behind the $E000 jump table, the unit start templates at $F000", "Out: the complete battle state - map, units, clock, film header and message slots; playerSide", " $0B9F resolved to 0 or 1 and the side-dependent branch opcodes patched. Does not return:", " ends in JMP finaliseRecyclerSetup ($EE26) or JMP startFilmPlayback ($7CD1)", "Called from: startGameFromSetup ($0B40)" ], "block": [ "Reset everything the previous battle may have left behind. $FF is the 'none/unset' marker for", "the redraw requests, the clock, the last ordered group and both recycler positions; unitCol[0] =", "$FF additionally tells loadUnitStartTemplate ($ECF3) that the unit arrays still have to be filled", "from the template on disk." ], "line": "film recording may use the whole buffer up to $DFF0" }, "78D4": { "unit": "game/mapGenerator6F00", "line": "$FF = 'none' for everything that follows" }, "78D6": { "unit": "game/mapGenerator6F00", "line": "gamePhase != 0: not in the battle loop yet" }, "78D8": { "unit": "game/mapGenerator6F00", "line": "no group redraw pending" }, "78DB": { "unit": "game/mapGenerator6F00", "line": "no unit redraw pending" }, "78DE": { "unit": "game/mapGenerator6F00", "line": "game clock not started" }, "78E1": { "unit": "game/mapGenerator6F00", "line": "no group has been given an order yet" }, "78E4": { "unit": "game/mapGenerator6F00", "line": "unitCol[0] = $FF marks the unit arrays as 'still the disk template'" }, "78E7": { "unit": "game/mapGenerator6F00", "line": "side 0 has no recycler placed yet" }, "78EA": { "unit": "game/mapGenerator6F00", "line": "nor side 1" }, "78ED": { "unit": "game/mapGenerator6F00", "line": "50 = a comcen at full energy" }, "78EF": { "unit": "game/mapGenerator6F00", "line": "comcen status snapshot starts at full" }, "78F2": { "unit": "game/mapGenerator6F00", "line": "last-quarter warning round; overwritten with rounds/4 at $7BA3" }, "78F5": { "unit": "game/mapGenerator6F00", "line": "colour 2 = red" }, "78F7": { "unit": "game/mapGenerator6F00", "line": "the opponent's units are drawn red" }, "78F9": { "unit": "game/mapGenerator6F00", "line": "colour 9 = brown" }, "78FB": { "unit": "game/mapGenerator6F00", "line": "enemy blips on the drone radar" }, "78FE": { "unit": "game/mapGenerator6F00", "line": "colour 6 = blue" }, "7900": { "unit": "game/mapGenerator6F00", "line": "the local player's units are drawn blue" }, "7902": { "unit": "game/mapGenerator6F00", "line": "colour 11 = dark grey" }, "7904": { "unit": "game/mapGenerator6F00", "line": "own blips on the drone radar" }, "7907": { "unit": "game/mapGenerator6F00", "line": "%01010101 = all four pixels of an overview blip in multicolour pattern 1" }, "7909": { "unit": "game/mapGenerator6F00", "line": "bit pattern used for a unit in the 20x20 overview map" }, "790C": { "unit": "game/mapGenerator6F00", "line": "0 for the three variables below" }, "790E": { "unit": "game/mapGenerator6F00", "line": "no end-of-game reason yet" }, "7911": { "unit": "game/mapGenerator6F00", "line": "reset the base of the film's delta timestamps (operand of the SBC in writeFilmTimestamp)" }, "7914": { "unit": "game/mapGenerator6F00", "line": "and the matching base in the film replay decoder (operand of the ADC at $4DF3)" }, "7917": { "unit": "game/mapGenerator6F00", "line": "screen id 3" }, "7919": { "unit": "game/mapGenerator6F00", "line": "screen 3 while the game starts up" }, "791C": { "unit": "game/mapGenerator6F00", "line": "WATCH GAME FILM?" }, "791F": { "unit": "game/mapGenerator6F00", "line": "bit 7 clear - not a replay, start a live game" }, "7921": { "unit": "game/mapGenerator6F00", "line": "yes - the replay path sets everything up from the film header instead" }, "7924": { "unit": "game/mapGenerator6F00", "block": [ "Live game. First decide which side this machine plays. playerSide $0B9F is used both as a", "*request* (0 = 'I want side 0', $FF = 'I want side 1', anything else = 'no preference') and,", "after cmdChooseSide ($5511) has compared the two requests, as the answer (0 or 1)." ], "line": "solo trainer flag (bit 7)" }, "7927": { "unit": "game/mapGenerator6F00", "line": "in a trainer game the opponent's units are always visible" }, "792A": { "unit": "game/mapGenerator6F00", "line": "the engine steps once every four frames" }, "792C": { "unit": "game/mapGenerator6F00", "line": "the engine advances the battle every 4th frame" }, "792F": { "unit": "game/mapGenerator6F00", "line": "side left over from the previous game, or $80|random after a tie" }, "7932": { "unit": "game/mapGenerator6F00", "line": "a real side (0 or 1) - alternate from it" }, "7934": { "unit": "game/mapGenerator6F00", "line": "1 = 'no preference': let the tie-break value below decide" }, "7936": { "unit": "game/mapGenerator6F00", "line": "store the 'no preference' marker" }, "7939": { "unit": "game/mapGenerator6F00", "line": "always taken (A = 1)" }, "793B": { "unit": "game/mapGenerator6F00", "line": "count games played on the same setup" }, "793E": { "unit": "game/mapGenerator6F00", "line": "read the counter back" }, "7941": { "unit": "game/mapGenerator6F00", "line": "has the same setup now been played twice?" }, "7943": { "unit": "game/mapGenerator6F00", "line": "not yet - keep the same side as last time" }, "7945": { "unit": "game/mapGenerator6F00", "line": "wrap the counter to 0" }, "7947": { "unit": "game/mapGenerator6F00", "line": "restart the count" }, "794A": { "unit": "game/mapGenerator6F00", "line": "...and swap sides" }, "794C": { "unit": "game/mapGenerator6F00", "line": "is the requested side 0?" }, "794E": { "unit": "game/mapGenerator6F00", "line": "yes - ask for side 0" }, "7950": { "unit": "game/mapGenerator6F00", "line": "side 1 is requested as $FF, the highest value, so cmdChooseSide awards it side 1" }, "7952": { "unit": "game/mapGenerator6F00", "line": "this is the side we will ask for" }, "7955": { "unit": "game/mapGenerator6F00", "block": [ "Bring the link up. A session that is already running only needs the 'ready for a new game'", "handshake; otherwise the modem is opened and we wait for carrier. On the solo-trainer build both", "calls return at once." ], "line": "link session state ($FF = a session is already established)" }, "7958": { "unit": "game/mapGenerator6F00", "line": "no session yet - dial/answer" }, "795A": { "unit": "game/mapGenerator6F00", "line": "exchange the [$8C,02] READY packets with the opponent" }, "795D": { "unit": "game/mapGenerator6F00", "line": "is the comm module still live?" }, "7960": { "unit": "game/mapGenerator6F00", "line": "yes - skip the connection wait" }, "7962": { "unit": "game/mapGenerator6F00", "line": "'PICK UP PHONE THEN PRESS SPACE.' and open the link" }, "7965": { "unit": "game/mapGenerator6F00", "line": "'WAITING FOR CONNECTION...' until carrier; leaves its countdown in zp_18" }, "7968": { "unit": "game/mapGenerator6F00", "line": "did we ask for side 0?" }, "796B": { "unit": "game/mapGenerator6F00", "line": "yes - send that" }, "796D": { "unit": "game/mapGenerator6F00", "line": "or for side 1?" }, "796F": { "unit": "game/mapGenerator6F00", "line": "yes - send that" }, "7971": { "unit": "game/mapGenerator6F00", "line": "no preference: use the carrier-wait countdown as a random tie-break value" }, "7973": { "unit": "game/mapGenerator6F00", "line": "that is what we will ask for" }, "7976": { "unit": "game/mapGenerator6F00", "line": "queue command $9D with our request (also copied to $90F8 for the comparison)" }, "7979": { "unit": "game/mapGenerator6F00", "line": "push the packet out now" }, "797C": { "unit": "game/mapGenerator6F00", "block": [ "Wait until cmdChooseSide ($5511) has seen the opponent's request and written the agreed side;", "that handler sets gamePhase to $DF, clearing bit 5, which is the flag this loop watches." ], "line": "run frames until the packet exchange is idle" }, "797F": { "unit": "game/mapGenerator6F00", "line": "phase flags" }, "7981": { "unit": "game/mapGenerator6F00", "line": "bit 5 = 'side selection still running'" }, "7983": { "unit": "game/mapGenerator6F00", "line": "still not agreed - keep exchanging" }, "7985": { "unit": "game/mapGenerator6F00", "line": "$FF = setup phase, no drawing yet" }, "7987": { "unit": "game/mapGenerator6F00", "line": "gamePhase = $FF: setup, not battle" }, "7989": { "unit": "game/mapGenerator6F00", "line": "1 = a game session is now running on the link" }, "798B": { "unit": "game/mapGenerator6F00", "line": "a game session is now established on the link" }, "798E": { "unit": "game/mapGenerator6F00", "line": "patch the eleven self-modified 'is this unit mine?' branches for our side" }, "7991": { "unit": "game/mapGenerator6F00", "block": [ "Side 0 chooses the game type and the map and tells side 1 about it; side 1 just shows", "'OPPONENT PICKING GAME/MAP.' and waits for the $8B/$A6 command." ], "line": "are we side 0, the player who picks?" }, "7994": { "unit": "game/mapGenerator6F00", "line": "side 0 - we are the player who picks the game and the map" }, "7996": { "unit": "game/mapGenerator6F00", "line": "message $1A = 'OPPONENT PICKING GAME/MAP.'" }, "7998": { "unit": "game/mapGenerator6F00", "line": "keep it on screen until something replaces it" }, "799B": { "unit": "game/mapGenerator6F00", "line": "queue it for display" }, "799E": { "unit": "game/mapGenerator6F00", "line": "and wait for the map seed to arrive" }, "79A1": { "unit": "game/mapGenerator6F00", "line": "run the GAME TYPE / MAP TYPE / TYPE MAP NAME setup screens" }, "79A4": { "unit": "game/mapGenerator6F00", "line": "'WORKING...'" }, "79A7": { "unit": "game/mapGenerator6F00", "line": "map seed byte 0..." }, "79AA": { "unit": "game/mapGenerator6F00", "line": "...as command argument 0" }, "79AC": { "unit": "game/mapGenerator6F00", "line": "seed byte 1" }, "79AF": { "unit": "game/mapGenerator6F00", "line": "argument 1" }, "79B1": { "unit": "game/mapGenerator6F00", "line": "seed byte 2" }, "79B4": { "unit": "game/mapGenerator6F00", "line": "argument 2" }, "79B6": { "unit": "game/mapGenerator6F00", "line": "command $8B = set map seed" }, "79B8": { "unit": "game/mapGenerator6F00", "line": "is the map flipped?" }, "79BB": { "unit": "game/mapGenerator6F00", "line": "map not flipped - keep plain command $8B" }, "79BD": { "unit": "game/mapGenerator6F00", "line": "command $A6 = set map seed and mark it a custom/flipped map" }, "79BF": { "unit": "game/mapGenerator6F00", "line": "queue the command with its three argument bytes" }, "79C2": { "unit": "game/mapGenerator6F00", "line": "both sides wait here until gamePhase bit 7 is cleared by cmdSetMapSeed" }, "79C5": { "unit": "game/mapGenerator6F00", "line": "$FF = 'no input allowed'" }, "79C7": { "unit": "game/mapGenerator6F00", "line": "block the joystick/keyboard for the rest of the setup" }, "79CA": { "unit": "game/mapGenerator6F00", "line": "and forget any pending F1-F7 screen request" }, "79CC": { "unit": "game/mapGenerator6F00", "line": "$DB is this build's version stamp" }, "79CE": { "unit": "game/mapGenerator6F00", "line": "exchangePlayerNamesAndSettings overwrites $90F8 with the EOR of the peer's version bytes" }, "79D1": { "unit": "game/mapGenerator6F00", "line": "swap the ten-character player names and the settings block over the link" }, "79D4": { "unit": "game/mapGenerator6F00", "line": "$7F" }, "79D6": { "unit": "game/mapGenerator6F00", "line": "gamePhase $7F: setup phase, drawing enabled" }, "79D8": { "unit": "game/mapGenerator6F00", "line": "did the version handshake come back as our own stamp?" }, "79DB": { "unit": "game/mapGenerator6F00", "line": "compare it with our own version stamp" }, "79DD": { "unit": "game/mapGenerator6F00", "line": "yes - the opponent runs the same build" }, "79DF": { "unit": "game/mapGenerator6F00", "line": "string low byte..." }, "79E1": { "unit": "game/mapGenerator6F00", "line": "...and high byte: 'OPPONENT USING NON-STANDARD GAME.' at $895E" }, "79E3": { "unit": "game/mapGenerator6F00", "line": "show it plus 'PRESS SPACE WHEN READY.' and wait for the space bar" }, "79E6": { "unit": "game/mapGenerator6F00", "block": [ "Both sides now know the game type and the map, so they can build the same starting position and", "write the same setup into the film header at $D000." ], "line": "copy the unit start-position template for this game type into $F640" }, "79E9": { "unit": "game/mapGenerator6F00", "line": "load the per-side scenario parameters (drones, missiles, comcen speed, recycler mode)" }, "79EC": { "unit": "game/mapGenerator6F00", "line": "command $9E: wait until both machines have got this far" }, "79EF": { "unit": "game/mapGenerator6F00", "line": "'WORKING...'" }, "79F2": { "unit": "game/mapGenerator6F00", "line": "film header offset $2B = the map seed" }, "79F4": { "unit": "game/mapGenerator6F00", "line": "start with seed byte 0" }, "79F6": { "unit": "game/mapGenerator6F00", "line": "seed byte X" }, "79F9": { "unit": "game/mapGenerator6F00", "line": "write it into the film header" }, "79FC": { "unit": "game/mapGenerator6F00", "line": "next film header offset" }, "79FD": { "unit": "game/mapGenerator6F00", "line": "next seed byte" }, "79FE": { "unit": "game/mapGenerator6F00", "line": "all three seed bytes written?" }, "7A00": { "unit": "game/mapGenerator6F00", "line": "keep writing the seed into the film header" }, "7A02": { "unit": "game/mapGenerator6F00", "line": "build the 40x40 battlefield from the seed (this also spells out the map name)" }, "7A05": { "unit": "game/mapGenerator6F00", "line": "our side" }, "7A08": { "unit": "game/mapGenerator6F00", "line": "remember the side for the setup screens" }, "7A0B": { "unit": "game/mapGenerator6F00", "block": [ "With CUSTOM map type (gameTypeOptions bit 7) the map is not one of the maps printed in the", "manual, so its name is marked with a trailing '!' and hidden from the player who did not choose", "it - side 1 sees '#####' instead of the five characters." ], "line": "game options" }, "7A0E": { "unit": "game/mapGenerator6F00", "line": "bit 7 clear = STANDARD map type, name stays as generated" }, "7A10": { "unit": "game/mapGenerator6F00", "line": "'!' replaces the carriage return after the name" }, "7A12": { "unit": "game/mapGenerator6F00", "line": "so the name prints as five characters plus '!'" }, "7A15": { "unit": "game/mapGenerator6F00", "line": "our side" }, "7A18": { "unit": "game/mapGenerator6F00", "line": "side 0 chose the map and may see its name" }, "7A1A": { "unit": "game/mapGenerator6F00", "line": "five characters" }, "7A1C": { "unit": "game/mapGenerator6F00", "line": "'#'" }, "7A1E": { "unit": "game/mapGenerator6F00", "line": "blank out the name for the player who did not pick it" }, "7A21": { "unit": "game/mapGenerator6F00", "line": "all five characters" }, "7A22": { "unit": "game/mapGenerator6F00", "line": "loop over all five characters" }, "7A24": { "unit": "game/mapGenerator6F00", "line": "the byte after the name" }, "7A27": { "unit": "game/mapGenerator6F00", "line": "set bit 7 so the text engine stops there" }, "7A29": { "unit": "game/mapGenerator6F00", "line": "write the terminator back" }, "7A2C": { "unit": "game/mapGenerator6F00", "block": [ "Alternation bookkeeping: playsFirstFlag $0BA1 makes the two players swap sides every second game,", "but only while the setup stays the same. Changing the game type, the map seed or the flip resets", "it to 1. The previous map's name is cached at $0BAF so a repeated map keeps the name the player", "typed rather than the one derived from the seed." ], "line": "game options" }, "7A2F": { "unit": "game/mapGenerator6F00", "line": "same options as the last game?" }, "7A32": { "unit": "game/mapGenerator6F00", "line": "remember them either way" }, "7A35": { "unit": "game/mapGenerator6F00", "line": "unchanged - keep alternating" }, "7A37": { "unit": "game/mapGenerator6F00", "line": "1 = 'first game with this setup'" }, "7A39": { "unit": "game/mapGenerator6F00", "line": "options changed: restart the side alternation" }, "7A3C": { "unit": "game/mapGenerator6F00", "line": "seed byte 0..." }, "7A3F": { "unit": "game/mapGenerator6F00", "line": "...same as last game?" }, "7A42": { "unit": "game/mapGenerator6F00", "line": "no - a new map" }, "7A44": { "unit": "game/mapGenerator6F00", "line": "seed byte 1" }, "7A47": { "unit": "game/mapGenerator6F00", "line": "seed byte 1 - same as last game?" }, "7A4A": { "unit": "game/mapGenerator6F00", "line": "different - a new map" }, "7A4C": { "unit": "game/mapGenerator6F00", "line": "seed byte 2" }, "7A4F": { "unit": "game/mapGenerator6F00", "line": "seed byte 2 - same as last game?" }, "7A52": { "unit": "game/mapGenerator6F00", "line": "different - a new map" }, "7A54": { "unit": "game/mapGenerator6F00", "line": "six bytes: the five name characters plus the terminator" }, "7A56": { "unit": "game/mapGenerator6F00", "line": "same map as last time: restore the name it was given then" }, "7A59": { "unit": "game/mapGenerator6F00", "line": "into the live name buffer" }, "7A5C": { "unit": "game/mapGenerator6F00", "line": "all six bytes" }, "7A5D": { "unit": "game/mapGenerator6F00", "line": "loop over all six bytes" }, "7A5F": { "unit": "game/mapGenerator6F00", "line": "always taken" }, "7A61": { "unit": "game/mapGenerator6F00", "line": "seed byte 0" }, "7A64": { "unit": "game/mapGenerator6F00", "line": "remember the new seed..." }, "7A67": { "unit": "game/mapGenerator6F00", "line": "seed byte 1" }, "7A6A": { "unit": "game/mapGenerator6F00", "line": "store it" }, "7A6D": { "unit": "game/mapGenerator6F00", "line": "seed byte 2" }, "7A70": { "unit": "game/mapGenerator6F00", "line": "...all three bytes" }, "7A73": { "unit": "game/mapGenerator6F00", "line": "1 = 'first game with this setup'" }, "7A75": { "unit": "game/mapGenerator6F00", "line": "new map: restart the side alternation" }, "7A78": { "unit": "game/mapGenerator6F00", "line": "six bytes: name plus terminator" }, "7A7A": { "unit": "game/mapGenerator6F00", "line": "cache the name so a rematch on the same map shows it again" }, "7A7D": { "unit": "game/mapGenerator6F00", "line": "into the backup buffer $0BAF" }, "7A80": { "unit": "game/mapGenerator6F00", "line": "all six bytes" }, "7A81": { "unit": "game/mapGenerator6F00", "line": "loop over all six bytes" }, "7A83": { "unit": "game/mapGenerator6F00", "line": "map flip" }, "7A86": { "unit": "game/mapGenerator6F00", "line": "was the map flipped the same way last game?" }, "7A89": { "unit": "game/mapGenerator6F00", "line": "unchanged - keep alternating sides" }, "7A8B": { "unit": "game/mapGenerator6F00", "line": "remember the new flip" }, "7A8E": { "unit": "game/mapGenerator6F00", "line": "1 = 'first game with this setup'" }, "7A90": { "unit": "game/mapGenerator6F00", "line": "flip changed: restart the side alternation" }, "7A93": { "unit": "game/mapGenerator6F00", "block": [ "Write the setup into the film header at $D000, so a recorded game can be replayed exactly:", "+4 trainer flag, +5 side, +6..+$B map name, +$C game options, +$11..$24 both player names,", "+$2B..$2D map seed, +$2E play order and flip. startFilmPlayback ($7CD1) reads them back." ], "line": "play-order counter" }, "7A96": { "unit": "game/mapGenerator6F00", "line": "keep the play order for the end-of-game screen" }, "7A99": { "unit": "game/mapGenerator6F00", "line": "play-order counter again" }, "7A9C": { "unit": "game/mapGenerator6F00", "line": "play order in bits 1-2..." }, "7A9D": { "unit": "game/mapGenerator6F00", "line": "...and the map flip in bit 0" }, "7AA0": { "unit": "game/mapGenerator6F00", "line": "film header offset $2E" }, "7AA2": { "unit": "game/mapGenerator6F00", "line": "record it" }, "7AA5": { "unit": "game/mapGenerator6F00", "line": "film header offset 4" }, "7AA7": { "unit": "game/mapGenerator6F00", "line": "was this a solo-trainer game?" }, "7AAA": { "unit": "game/mapGenerator6F00", "line": "record it" }, "7AAD": { "unit": "game/mapGenerator6F00", "line": "offset 5" }, "7AAE": { "unit": "game/mapGenerator6F00", "line": "which side the recording player was on" }, "7AB1": { "unit": "game/mapGenerator6F00", "line": "record it" }, "7AB4": { "unit": "game/mapGenerator6F00", "line": "offset 6" }, "7AB5": { "unit": "game/mapGenerator6F00", "line": "start with the first character" }, "7AB7": { "unit": "game/mapGenerator6F00", "line": "map name character X" }, "7ABA": { "unit": "game/mapGenerator6F00", "line": "record it" }, "7ABD": { "unit": "game/mapGenerator6F00", "line": "next film header offset" }, "7ABE": { "unit": "game/mapGenerator6F00", "line": "next character" }, "7ABF": { "unit": "game/mapGenerator6F00", "line": "five characters plus the terminator" }, "7AC1": { "unit": "game/mapGenerator6F00", "line": "loop over the six name bytes" }, "7AC3": { "unit": "game/mapGenerator6F00", "line": "the game options byte" }, "7AC6": { "unit": "game/mapGenerator6F00", "line": "offset $C = the game options byte" }, "7AC9": { "unit": "game/mapGenerator6F00", "line": "offset $11" }, "7ACB": { "unit": "game/mapGenerator6F00", "line": "start with the first name byte" }, "7ACD": { "unit": "game/mapGenerator6F00", "line": "$FFDE holds both ten-character player names" }, "7AD0": { "unit": "game/mapGenerator6F00", "line": "record it" }, "7AD3": { "unit": "game/mapGenerator6F00", "line": "next film header offset" }, "7AD4": { "unit": "game/mapGenerator6F00", "line": "next name byte" }, "7AD5": { "unit": "game/mapGenerator6F00", "line": "20 bytes = both ten-character player names" }, "7AD7": { "unit": "game/mapGenerator6F00", "line": "loop over all 20 name bytes" }, "7AD9": { "unit": "game/mapGenerator6F00", "block": [ "Each player must see his own end zone at the bottom of the screen, so side 1 plays on a map that", "is rotated 180 degrees and on unit coordinates that are mirrored with it. A flipped map inverts", "that decision, which is what the EOR tests." ], "line": "our side" }, "7ADC": { "unit": "game/mapGenerator6F00", "line": "combined with the requested flip" }, "7ADF": { "unit": "game/mapGenerator6F00", "line": "side 0 on an unflipped map: leave the map as generated" }, "7AE1": { "unit": "game/mapGenerator6F00", "line": "otherwise rotate it 180 degrees and mirror the direction-dependent terrain codes" }, "7AE4": { "unit": "game/mapGenerator6F00", "line": "our side" }, "7AE7": { "unit": "game/mapGenerator6F00", "line": "side 0 keeps the template coordinates" }, "7AE9": { "unit": "game/mapGenerator6F00", "line": "side 1 mirrors all six unit coordinate arrays to match the rotated map" }, "7AEC": { "unit": "game/mapGenerator6F00", "line": "view origin to (17,28), i.e. the middle of our own end" }, "7AEF": { "unit": "game/mapGenerator6F00", "line": "reset all 100 unit records from their start positions and put them on the map" }, "7AF2": { "unit": "game/mapGenerator6F00", "line": "$FF = clock not running" }, "7AF4": { "unit": "game/mapGenerator6F00", "line": "clock stays unset until the battle starts" }, "7AF7": { "unit": "game/mapGenerator6F00", "line": "STANDARD/CUSTOM scenario banner and the custom option editors" }, "7AFA": { "unit": "game/mapGenerator6F00", "line": "0 for both variables below" }, "7AFC": { "unit": "game/mapGenerator6F00", "line": "back to text colour 0" }, "7AFE": { "unit": "game/mapGenerator6F00", "line": "'*' toggle off" }, "7B01": { "unit": "game/mapGenerator6F00", "line": "clear the info panel" }, "7B04": { "unit": "game/mapGenerator6F00", "line": "command $9E: wait until the opponent has finished his options too" }, "7B07": { "unit": "game/mapGenerator6F00", "line": "0" }, "7B09": { "unit": "game/mapGenerator6F00", "line": "no comcen alert pending" }, "7B0C": { "unit": "game/mapGenerator6F00", "line": "draw the battlefield overview" }, "7B0F": { "unit": "game/mapGenerator6F00", "line": "empty the message queue" }, "7B12": { "unit": "game/mapGenerator6F00", "block": [ "Solo trainer only: the $EC00-$EFFF tail is swapped for the trainer's opening-play chooser (track", "29 sectors 0-3), run once, and then the normal comm tail is loaded back over it." ], "line": "solo trainer?" }, "7B15": { "unit": "game/mapGenerator6F00", "line": "no - a modem game, nothing to load" }, "7B17": { "unit": "game/mapGenerator6F00", "line": "mark that a disk load is in progress (nested loads are counted)" }, "7B1A": { "unit": "game/mapGenerator6F00", "line": "the trainer setup wants the game length already set" }, "7B1D": { "unit": "game/mapGenerator6F00", "line": "'WORKING...'" }, "7B20": { "unit": "game/mapGenerator6F00", "line": "destination low byte..." }, "7B22": { "unit": "game/mapGenerator6F00", "line": "...and high byte: $EC00" }, "7B24": { "unit": "game/mapGenerator6F00", "line": "tell the fast loader where the sectors go" }, "7B27": { "unit": "game/mapGenerator6F00", "line": "track 29" }, "7B29": { "unit": "game/mapGenerator6F00", "line": "first sector 0" }, "7B2B": { "unit": "game/mapGenerator6F00", "line": "four sectors = $EC00-$EFFF" }, "7B2D": { "unit": "game/mapGenerator6F00", "line": "load the solo-trainer setup overlay" }, "7B30": { "unit": "game/mapGenerator6F00", "line": "let it pick this game's opening play" }, "7B33": { "unit": "game/mapGenerator6F00", "line": "restore the comm-module tail at $EC00 from track 34 sectors 12-15" }, "7B36": { "unit": "game/mapGenerator6F00", "line": "disk load finished" }, "7B39": { "unit": "game/mapGenerator6F00", "block": [ "Unit deployment phase. SCRIMAGE (type 0) and THE BOMB (type 2) start from the fixed template and", "skip it; every other game type lets both players drag their units around the map first. Note", "that this test looks at the game type directly and not at setupPhaseMode $92C6, which", "applyGameTypeDefaults derived from the same game type." ], "line": "the game options byte" }, "7B3C": { "unit": "game/mapGenerator6F00", "line": "bits 0-2 = the game type" }, "7B3E": { "unit": "game/mapGenerator6F00", "line": "type 0 SCRIMAGE: no deployment phase" }, "7B40": { "unit": "game/mapGenerator6F00", "line": "is the game type 2, THE BOMB?" }, "7B42": { "unit": "game/mapGenerator6F00", "line": "type 2 THE BOMB: none either" }, "7B44": { "unit": "game/mapGenerator6F00", "line": "gamePhase $3F = unit deployment" }, "7B46": { "unit": "game/mapGenerator6F00", "line": "store the deployment phase" }, "7B48": { "unit": "game/mapGenerator6F00", "line": "shuffle the unit processing order (both machines get the same order from the map seed)" }, "7B4B": { "unit": "game/mapGenerator6F00", "line": "point the '*' toggle at 'DESTROY OFF' and the 'SETUP UNITS.' prompt" }, "7B4E": { "unit": "game/mapGenerator6F00", "line": "run the battlefield screen until the player presses F1" }, "7B51": { "unit": "game/mapGenerator6F00", "line": "0 = all sprites off" }, "7B53": { "unit": "game/mapGenerator6F00", "line": "turn the cursor sprites off" }, "7B56": { "unit": "game/mapGenerator6F00", "block": [ "Do not start the battle until every order the player queued during deployment has actually been", "sent to the opponent." ], "line": "commands of ours still waiting to be sent" }, "7B59": { "unit": "game/mapGenerator6F00", "line": "queue empty - synchronise and go" }, "7B5B": { "unit": "game/mapGenerator6F00", "line": "run one more frame, which services the link" }, "7B5E": { "unit": "game/mapGenerator6F00", "line": "look again" }, "7B61": { "unit": "game/mapGenerator6F00", "line": "command $9E: both machines have finished deploying" }, "7B64": { "unit": "game/mapGenerator6F00", "block": [ "Final start-up: wait for one complete packet exchange, fix up the derived settings, snapshot the", "starting position into the film and put everything on the map." ], "line": "comm exchange flag byte $E01D" }, "7B67": { "unit": "game/mapGenerator6F00", "line": "spin until bit 6 says a full packet exchange has completed" }, "7B69": { "unit": "game/mapGenerator6F00", "line": "gameClock = the number of rounds for this game type" }, "7B6C": { "unit": "game/mapGenerator6F00", "line": "index 1 = the opponent, then 0 = us" }, "7B6E": { "unit": "game/mapGenerator6F00", "line": "COMCEN SPEED setting 0-3 for that side" }, "7B71": { "unit": "game/mapGenerator6F00", "line": "translate it into the engine speed class 4, 0, 1 or 5" }, "7B74": { "unit": "game/mapGenerator6F00", "line": "store it back over the setting" }, "7B77": { "unit": "game/mapGenerator6F00", "line": "then side 0, our own" }, "7B78": { "unit": "game/mapGenerator6F00", "line": "loop over both sides" }, "7B7A": { "unit": "game/mapGenerator6F00", "line": "take every unit and both recyclers off the map again" }, "7B7D": { "unit": "game/mapGenerator6F00", "line": "pause the comm module: the snapshot banks RAM in under the I/O area" }, "7B80": { "unit": "game/mapGenerator6F00", "line": "copy the settings and the unit arrays into the film header at $D034-$D367" }, "7B83": { "unit": "game/mapGenerator6F00", "line": "put all 100 units back on the map" }, "7B86": { "unit": "game/mapGenerator6F00", "line": "gameClock = the number of rounds, also returned in A" }, "7B89": { "unit": "game/mapGenerator6F00", "line": "redundant: setGameClockForType has already stored the value in gameClock" }, "7B8C": { "unit": "game/mapGenerator6F00", "line": "film command stream starts at $D368" }, "7B8F": { "unit": "game/mapGenerator6F00", "block": [ "Common tail, also the point the film replay path jumps back into ($7D6D). Both recyclers are now", "drawn (the replay path drew the opponent's just before jumping here), the unit order is shuffled", "one last time with gamePhase temporarily 0 so the battle-mode path of the round-order rebuild", "runs, and the last-quarter warning round is computed." ], "line": "our own side" }, "7B92": { "unit": "game/mapGenerator6F00", "line": "draw our recycler on the map" }, "7B95": { "unit": "game/mapGenerator6F00", "line": "0" }, "7B97": { "unit": "game/mapGenerator6F00", "line": "gamePhase 0 = battle, so shuffleInitialUnitOrder rebuilds the round order the battle way" }, "7B99": { "unit": "game/mapGenerator6F00", "line": "reshuffle from the map seed, identically on both machines" }, "7B9C": { "unit": "game/mapGenerator6F00", "line": "back to $FF until the battle loop clears it" }, "7B9E": { "unit": "game/mapGenerator6F00", "line": "A = the game length in rounds" }, "7BA1": { "unit": "game/mapGenerator6F00", "line": "halve..." }, "7BA2": { "unit": "game/mapGenerator6F00", "line": "divide by four" }, "7BA3": { "unit": "game/mapGenerator6F00", "line": "the last quarter of the game starts at this round ('LAST QTR' warning)" }, "7BA6": { "unit": "game/mapGenerator6F00", "line": "message slot $20" }, "7BA8": { "unit": "game/mapGenerator6F00", "line": "string low byte..." }, "7BAA": { "unit": "game/mapGenerator6F00", "line": "...and high byte: 'DRONE ALERT!' at $87ED in this overlay" }, "7BAC": { "unit": "game/mapGenerator6F00", "line": "install it as message $20" }, "7BAF": { "unit": "game/mapGenerator6F00", "line": "hand over to the comm-module tail, which finishes the recyclers and starts the battle" }, "7615": { "unit": "game/mapGenerator6F00", "line": "clear carry for the add" } }, "dataTypes": { "74EE": [ "byte", 8 ], "74F6": [ "byte", 8 ], "763A": [ "byte", 8 ], "7642": [ "byte", 8 ], "7894": [ "byte", 20 ], "78A8": [ "byte", 16 ], "78B8": [ "byte", 7 ], "78BF": [ "byte", 4 ], "78C3": [ "byte", 7 ], "78CA": [ "byte", 7 ] } }