{ "chunk": "game_mapGenerator6F00_6F00", "unit": "game/mapGenerator6F00", "unitLabels": { "game/mapGenerator6F00": { "6F1A": "storeMapStyleFlags", "6F2A": "storeMapSymmetryFlag", "6F89": "joinRiverClearCentre", "6F8E": "mapGeneratorDone", "6F9D": "linkServiceNotNeeded", "6FC4": "limitHillsForQbSneak", "6FCB": "storeHillSiteCount", "6FD2": "noHillSitesAtAll", "6FD5": "setRowCandidateLimit", "6FDE": "hillBlobSizeLoop", "6FF5": "hillRowCandidateLoop", "7010": "mirrorHillRowCandidates", "7027": "startSitePlacement", "702B": "tryRowCandidate", "702F": "tryJitteredLaneColumn", "7036": "jitterLaneColumn", "7061": "rowCandidateWrapTest", "706B": "hillSiteAccepted", "7072": "advanceToNextHillSite", "7085": "placeNextHillSite", "7088": "storeHillSitesPlaced", "708D": "hillSitesDone", "7096": "laneIndexDone", "709F": "rowCandidateDone", "70A5": "laneIdentityLoop", "70AC": "laneSwapLoop", "70CC": "laneColumnFillLoop", "70EA": "summitBlobLoop", "7109": "summitsDone", "7112": "lowerHillScanInit", "7122": "lowerHillRowStart", "7126": "lowerHillCellScan", "7135": "lowerHillCellOccupied", "7141": "lowerHillNorthClassTest", "714C": "lowerHillTestWest", "7161": "lowerHillTestEast", "7163": "lowerHillReadEast", "7176": "lowerHillTestSouth", "718B": "growLowerHillHere", "7194": "lowerHillNextColumn", "719F": "lowerHillNextRow", "71AA": "lowerHillScanDone", "71DC": "blobPopStack", "71E3": "blobResumeCell", "721C": "blobGrowWest", "721F": "blobTryWest", "7204": "blobMarkNorthTried", "7221": "blobStepWest", "7243": "blobTryEast", "725D": "blobTestEastBlank", "7269": "blobTrySouth", "7271": "blobSouthAlreadyTried", "728A": "blobTestSouthChance", "728F": "blobCellExhausted", "7292": "blobPaintCell", "72A1": "blobWriteTile", "72B1": "blobPushCell", "72B3": "blobSaveParentFlags", "72D3": "blobStoreColumnBias", "72D5": "blobRowBias", "72E1": "blobMergeRowBias", "72E5": "blobStoreChildFlags", "72F2": "blobExpandChild", "72F5": "blobFinished", "7300": "forestBlockTestNw", "730D": "forestBlockTestNe", "7310": "forestBlockClassNe", "7311": "forestBlockLookupNe", "7316": "forestBlockCompareNe", "731A": "forestBlockTestSw", "731E": "forestBlockClassSw", "7328": "forestBlockTestSe", "7335": "forestBlockAccept", "733D": "forestBlockAcceptRts", "733E": "forestBlockReject", "734C": "storeForestTile", "7362": "limitForestForDefender", "7369": "storeForestClusterCount", "736B": "forestClusterLoop", "736E": "forestCentreFromRandom", "7387": "forestSeedRowRetry", "7394": "forestSeedColumnRetry", "7396": "jitterForestSeedColumn", "73AC": "forestClustersDone", "73B0": "forestSeedStepEast", "73B7": "forestSeedPaintSouthEast", "73BC": "forestSeedPaintSouth", "73E4": "growForestSeedBlob", "73ED": "forestSeedOffMap", "7403": "contourScanCell", "7412": "contourReadCell", "741A": "contourCompareRingClass", "741C": "contourCellIsOldRing", "7426": "contourEraseOldRing", "742A": "contourApplyRule", "742F": "contourNextColumn", "744A": "contourNeighbourLoop", "7460": "contourNextNeighbour", "746F": "contourClipRightEdge", "7475": "contourClipTopEdge", "747B": "contourClipBottomEdge", "7481": "contourLookupRule", "749E": "contourTakeRandomBit", "74BD": "contourMaybeFillCell", "74C3": "contourFillWithInterior", "74C9": "contourBackUpScan", "74D2": "contourStoreScanCol", "74D6": "contourBackUpRow", "74DD": "contourStoreScanRow", "74E0": "contourRescanReturn", "74E1": "contourRingTileFromRule", "74E5": "contourWriteTile", "74EC": "contourLeaveCell" } }, "notes": { "6F00": { "unit": "game/mapGenerator6F00", "block": [ "laneColumnTable - the four vertical 'lanes' of the battlefield along which hill summits are", "placed: columns 6, 15, 25 and 34 of the 40-column map. shuffleLaneColumns copies them into", "$0329-$032C in a random order so successive summits land in different parts of the map.", "(The label is only marked sub_6F00 because the comcen-screens overlay has code at this address.)" ], "line": "lane columns 6, 15, 25, 34 (indexed 0-3 by the shuffled permutation)" }, "6F04": { "unit": "game/mapGenerator6F00", "routine": [ "generateBattlefieldMap - entry point of the procedural battlefield generator. Derives the", "map-style flags for the chosen game type, decides whether the map is point-symmetric, puts", "'WORKING...' on the status line, blanks all 1600 map cells to $40 and re-seeds the scenario RNG", "from the 24-bit map seed, then falls into runMapGeneratorPasses. The battlefield is never loaded", "from disk: seed + game type completely determine the terrain, which is why both machines produce", "the identical map and why a map can be named by its seed.", "In: gameTypeOptions $0BA3 bits 0-2 = game type 0-6, mapSeed $0B95-$0B97; needs the contour rule", " table at $0200 (track 18 s15) and the $EC00 comm-tail helpers resident", "Out: $032E map style, $032D symmetry flags, map $F000-$F63F built, scenario RNG $5A-$5C advanced,", " map name text $0BA9-$0BAD, generator scratch $0300-$032C, $0400-$04EF and $9025-$9028 clobbered", "Called from: manualLookupCheck ($09E0) to show the map the manual asks about, and from the setup", " screens of this overlay ($76AD map editor, $76FF, $7A02 game start, $7D23 film playback)" ], "block": [ "Choose the map style from the game type: QB SNEAK and DEFENDER get special terrain." ], "line": "gameTypeOptions from the settings block" }, "6F07": { "unit": "game/mapGenerator6F00", "line": "bits 0-2 = game type (0 SCRIMAGE .. 6 DEFENDER)" }, "6F09": { "unit": "game/mapGenerator6F00", "line": "keep the type in Y for the two comparisons below" }, "6F0A": { "unit": "game/mapGenerator6F00", "line": "type 0 (SCRIMAGE): A is already 0 = ordinary random map" }, "6F0C": { "unit": "game/mapGenerator6F00", "line": "style $40 = DEFENDER map (river always, exactly 4 hills, 1-4 forest clusters)" }, "6F0E": { "unit": "game/mapGenerator6F00", "line": "game type 6 = DEFENDER?" }, "6F10": { "unit": "game/mapGenerator6F00", "line": "yes - keep style $40" }, "6F12": { "unit": "game/mapGenerator6F00", "line": "style $80 = QB SNEAK map (no river, at most 1 hill, 10 forest clusters)" }, "6F14": { "unit": "game/mapGenerator6F00", "line": "game type 1 = QB SNEAK?" }, "6F16": { "unit": "game/mapGenerator6F00", "line": "yes - keep style $80" }, "6F18": { "unit": "game/mapGenerator6F00", "line": "every other game type: no special style" }, "6F1A": { "unit": "game/mapGenerator6F00", "line": "$032E mapGenGameFlags: bit 7 = QB SNEAK style, bit 6 = DEFENDER style" }, "6F1D": { "unit": "game/mapGenerator6F00", "block": [ "A map whose name ends in '=' (seed bits 0-4 all set) is built point-symmetric." ], "line": "assume an asymmetric map" }, "6F1F": { "unit": "game/mapGenerator6F00", "line": "low byte of the 24-bit map seed" }, "6F22": { "unit": "game/mapGenerator6F00", "line": "bits 0-4 are the last character of the 5-letter map name" }, "6F24": { "unit": "game/mapGenerator6F00", "line": "$1F = the alphabet's last symbol '='" }, "6F26": { "unit": "game/mapGenerator6F00", "line": "not a symmetric map code - leave the flag clear" }, "6F28": { "unit": "game/mapGenerator6F00", "line": "bit 7 = build a point-symmetric battlefield" }, "6F2A": { "unit": "game/mapGenerator6F00", "line": "$032D mapSymmetryFlags (bit 6 is set later if the river crosses the centre)" }, "6F2D": { "unit": "game/mapGenerator6F00", "line": "show message 1 'WORKING...' - generating the map takes several seconds" }, "6F30": { "unit": "game/mapGenerator6F00", "line": "fill the whole 40x40 map $F000-$F63F with blank terrain $40" }, "6F33": { "unit": "game/mapGenerator6F00", "line": "scenario RNG $5A-$5C := mapSeed; returns the three seed bytes in A/Y/X" }, "6F36": { "unit": "game/mapGenerator6F00", "routine": [ "runMapGeneratorPasses - the eight terrain passes, entered by fall-through from", "generateBattlefieldMap. Order: map name from the seed; river with its keep-clear markers; hill", "summit sites; summit blobs; erase the $80 markers; upper contour ring; lower hill bodies; erase", "the $81 markers; lower contour ring; forest clusters. A symmetric map is finished by copying the", "top half onto the bottom half rotated 180 degrees, with a three-cell patch that joins the two", "halves of the river at the centre. The opponent link is serviced between passes.", "In: A/Y/X = the three map seed bytes, $032D symmetry flags, $032E map style, RNG $5A-$5C", "Out: the finished map at $F000-$F63F, map name text $0BA9-$0BAD, generator scratch $0300-$032C;", " ends with JMP resetMessageQueue, which clears 'WORKING...' and returns to the caller", "Called from: nothing in this overlay (fall-through only); the JSR $7125 the XREF lists belongs to", " the comcen-screens overlay that shares this address range" ], "block": [ "Pass 1-2: name the map, then carve the river." ], "line": "write the seed as the 5-character map name at $0BA9 (A/Y/X still hold it)" }, "6F39": { "unit": "game/mapGenerator6F00", "line": "carve the river ($55-$5C) and reserve its banks with the $80/$81 markers" }, "6F3C": { "unit": "game/mapGenerator6F00", "block": [ "Pass 3-5: hill summits, then the upper slope ring around them." ], "line": "choose how many summits to place in the top half and on which lanes" }, "6F3F": { "unit": "game/mapGenerator6F00", "line": "give the modem/trainer link a turn - generation must not stall the exchange" }, "6F42": { "unit": "game/mapGenerator6F00", "line": "paint each summit as a blob of tile $65/$66" }, "6F45": { "unit": "game/mapGenerator6F00", "line": "$80 = the outer (wide) river keep-clear marker" }, "6F47": { "unit": "game/mapGenerator6F00", "line": "turn those markers back into blank $40 before the contour pass reads them" }, "6F4A": { "unit": "game/mapGenerator6F00", "line": "service the link again" }, "6F4D": { "unit": "game/mapGenerator6F00", "line": "contour offset 0: rule-table tiles are used unchanged ($41-$54)" }, "6F4F": { "unit": "game/mapGenerator6F00", "line": "$0324 = amount subtracted from every rule-table tile code" }, "6F52": { "unit": "game/mapGenerator6F00", "line": "$65 = summit tile, terrain class 6" }, "6F54": { "unit": "game/mapGenerator6F00", "line": "draw the upper slope contour $41-$54 around everything of class >= 6" }, "6F57": { "unit": "game/mapGenerator6F00", "line": "service the link" }, "6F5A": { "unit": "game/mapGenerator6F00", "block": [ "Pass 6-7: widen the hills into bodies and draw their lower contour ring." ], "line": "grow lower-hill bodies ($61-$64) beside the upper slopes" }, "6F5D": { "unit": "game/mapGenerator6F00", "line": "$81 = the inner river keep-clear marker" }, "6F5F": { "unit": "game/mapGenerator6F00", "line": "erase those markers too - the banks are now safe from the lower ring" }, "6F62": { "unit": "game/mapGenerator6F00", "line": "contour offset $20: rule tiles $41-$54 become the lower ring $21-$34" }, "6F64": { "unit": "game/mapGenerator6F00", "line": "$0324" }, "6F67": { "unit": "game/mapGenerator6F00", "line": "$61 = lower hill tile, terrain class 4" }, "6F69": { "unit": "game/mapGenerator6F00", "line": "draw the lower contour around everything of class >= 4" }, "6F6C": { "unit": "game/mapGenerator6F00", "line": "service the link" }, "6F6F": { "unit": "game/mapGenerator6F00", "block": [ "Pass 8: forest, then the optional 180-degree mirror for symmetric maps." ], "line": "scatter the forest clusters ($5D-$60)" }, "6F72": { "unit": "game/mapGenerator6F00", "line": "mapSymmetryFlags" }, "6F75": { "unit": "game/mapGenerator6F00", "line": "bit 7 clear - asymmetric map, nothing more to do" }, "6F77": { "unit": "game/mapGenerator6F00", "line": "overwrite the bottom half with the 180-degree rotation of the top half" }, "6F7A": { "unit": "game/mapGenerator6F00", "line": "bit 6 = the river jogged up to row 19 at column 20 (set by chooseNextRiverSegment)" }, "6F7D": { "unit": "game/mapGenerator6F00", "line": "the river does not meet itself at the centre - done" }, "6F7F": { "unit": "game/mapGenerator6F00", "line": "$58 = river bend left/up" }, "6F81": { "unit": "game/mapGenerator6F00", "line": "cell (19,20) = $F000 + 20*40 + 19" }, "6F84": { "unit": "game/mapGenerator6F00", "line": "$55 = river bend down/right" }, "6F86": { "unit": "game/mapGenerator6F00", "line": "cell (19,19) = $F000 + 19*40 + 19" }, "6F89": { "unit": "game/mapGenerator6F00", "line": "$40 = blank terrain" }, "6F8B": { "unit": "game/mapGenerator6F00", "line": "cell (20,20): erase the mirrored stub so the two river halves join cleanly" }, "6F8E": { "unit": "game/mapGenerator6F00", "line": "clear the 'WORKING...' message and return to generateBattlefieldMap's caller" }, "6F91": { "unit": "game/mapGenerator6F00", "routine": [ "serviceLinkWhileGenerating - lets the opponent link breathe during the long map build. Does", "nothing while a game film is being replayed (no opponent) or while the battle loop is running", "(the frame handler already services the link there); otherwise runs one command-exchange step.", "In: filmPlaybackMode $0B9B bit 7, gamePhase zp_B1 bit 7", "Out: whatever serviceCommandExchange ($4DA9) does - packets sent/received, messages updated", "Called from: runMapGeneratorPasses ($6F3F, $6F4A, $6F57, $6F6C) and the map-name screen ($773A)" ], "line": "filmPlaybackMode: bit 7 = watching a recorded game" }, "6F94": { "unit": "game/mapGenerator6F00", "line": "film playback - there is nobody on the other end" }, "6F96": { "unit": "game/mapGenerator6F00", "line": "gamePhase: bit 7 set in the setup/menu phases" }, "6F98": { "unit": "game/mapGenerator6F00", "line": "bit 7 clear = the battle loop is running and already services the link" }, "6F9A": { "unit": "game/mapGenerator6F00", "line": "exchange one round of commands with the opponent (tail call)" }, "6F9D": { "unit": "game/mapGenerator6F00", "line": "nothing to do" }, "6F9E": { "unit": "game/mapGenerator6F00", "routine": [ "pickHillSummitSites - decides how many hill summits the map gets and finds a blank cell for each.", "The count is rolled as (rnd AND 3) + (rnd AND 1), re-rolled to 1-4 if it came out exactly 1;", "DEFENDER always gets 4 and QB SNEAK at most 1. Each site gets a blob size of 2-5 cells, and four", "candidate rows in the range 7-14 are rolled. findBlankSitesOnLanes then places the top-half", "sites; afterwards the count is doubled, the candidate rows are mirrored to 39-row and the same", "routine runs again by fall-through, so every summit gets a point-mirrored twin in the bottom half.", "In: $032E map style bits 6/7, scenario RNG", "Out: $0300 = total number of sites placed, $0307[0..7] blob sizes, $0314[i]/$031C[i] site", " column/row, $0325[0..3] candidate rows, $0329-$032C lane columns; zp_18, zp_28-zp_2B", "Called from: runMapGeneratorPasses ($6F3C)" ], "block": [ "Roll the number of summits for the top half of the map." ], "line": "start the top-half pass at site 0" }, "6FA0": { "unit": "game/mapGenerator6F00", "line": "zp_2A = index of the site being placed; the first pass starts at site 0" }, "6FA2": { "unit": "game/mapGenerator6F00", "line": "DEFENDER gets exactly 4 summits" }, "6FA4": { "unit": "game/mapGenerator6F00", "line": "mapGenGameFlags" }, "6FA7": { "unit": "game/mapGenerator6F00", "line": "bit 6 (DEFENDER style) - keep the fixed count of 4" }, "6FA9": { "unit": "game/mapGenerator6F00", "line": "first roll" }, "6FAC": { "unit": "game/mapGenerator6F00", "line": "0-3" }, "6FAE": { "unit": "game/mapGenerator6F00", "line": "remember it" }, "6FB0": { "unit": "game/mapGenerator6F00", "line": "second roll" }, "6FB3": { "unit": "game/mapGenerator6F00", "line": "0-1" }, "6FB5": { "unit": "game/mapGenerator6F00", "line": "prepare the add" }, "6FB6": { "unit": "game/mapGenerator6F00", "line": "count = (rnd AND 3) + (rnd AND 1) = 0-4, biased towards 1-3" }, "6FB8": { "unit": "game/mapGenerator6F00", "line": "did it come out as a single lone summit?" }, "6FBA": { "unit": "game/mapGenerator6F00", "line": "no - keep the count" }, "6FBC": { "unit": "game/mapGenerator6F00", "line": "yes - re-roll rather than build a one-hill map" }, "6FBF": { "unit": "game/mapGenerator6F00", "line": "0-3" }, "6FC1": { "unit": "game/mapGenerator6F00", "line": "prepare the add" }, "6FC2": { "unit": "game/mapGenerator6F00", "line": "1-4 summits instead" }, "6FC4": { "unit": "game/mapGenerator6F00", "line": "mapGenGameFlags" }, "6FC7": { "unit": "game/mapGenerator6F00", "line": "bit 7 clear - not QB SNEAK, keep the count" }, "6FC9": { "unit": "game/mapGenerator6F00", "line": "QB SNEAK: 0 or 1 summit only, the field has to stay open" }, "6FCB": { "unit": "game/mapGenerator6F00", "line": "$0300 = summit count (the generator uses the $0200-$03FF setup block as scratch RAM)" }, "6FCE": { "unit": "game/mapGenerator6F00", "line": "redundant: every path above already set Z from A" }, "6FD0": { "unit": "game/mapGenerator6F00", "line": "at least one summit" }, "6FD2": { "unit": "game/mapGenerator6F00", "line": "no hills at all - store 0 through the common exit and return" }, "6FD5": { "unit": "game/mapGenerator6F00", "block": [ "Roll one blob size per site (mirrored to the twin) and four candidate rows 7-14." ], "line": "zp_28 = highest index of the candidate-row list..." }, "6FD7": { "unit": "game/mapGenerator6F00", "line": "...= count-1, so 0-3 (there are four candidate rows)" }, "6FD9": { "unit": "game/mapGenerator6F00", "line": "Y walks the top-half sites 0..count-1" }, "6FDB": { "unit": "game/mapGenerator6F00", "line": "X walks their bottom-half twins, which start at index count" }, "6FDE": { "unit": "game/mapGenerator6F00", "line": "roll the size of this summit blob" }, "6FE1": { "unit": "game/mapGenerator6F00", "line": "0-3" }, "6FE3": { "unit": "game/mapGenerator6F00", "line": "prepare the add" }, "6FE4": { "unit": "game/mapGenerator6F00", "line": "blob size 2-5 cells" }, "6FE6": { "unit": "game/mapGenerator6F00", "line": "$0307[y] = size of top-half site y" }, "6FE9": { "unit": "game/mapGenerator6F00", "line": "$0307[count+y] = the mirrored twin gets the same size" }, "6FEC": { "unit": "game/mapGenerator6F00", "line": "next top-half site" }, "6FED": { "unit": "game/mapGenerator6F00", "line": "next bottom-half twin" }, "6FEE": { "unit": "game/mapGenerator6F00", "line": "all sites given a size?" }, "6FF1": { "unit": "game/mapGenerator6F00", "line": "one size per site" }, "6FF3": { "unit": "game/mapGenerator6F00", "line": "four candidate rows, filled backwards 3..0" }, "6FF5": { "unit": "game/mapGenerator6F00", "line": "roll one candidate row" }, "6FF8": { "unit": "game/mapGenerator6F00", "line": "0-7" }, "6FFA": { "unit": "game/mapGenerator6F00", "line": "prepare the add" }, "6FFB": { "unit": "game/mapGenerator6F00", "line": "row 7-14: summits stay clear of the top edge and of the centre line" }, "6FFD": { "unit": "game/mapGenerator6F00", "line": "$0325[y] = candidate row list used by findBlankSitesOnLanes" }, "7000": { "unit": "game/mapGenerator6F00", "line": "preload $031C[y] as well so an unplaced site still holds a sane row" }, "7003": { "unit": "game/mapGenerator6F00", "line": "next candidate-row slot" }, "7004": { "unit": "game/mapGenerator6F00", "line": "four candidate rows in all" }, "7006": { "unit": "game/mapGenerator6F00", "block": [ "Place the top half, then mirror everything into the bottom half." ], "line": "resolve the top-half sites onto the four lanes" }, "7009": { "unit": "game/mapGenerator6F00", "line": "double the placed count - each site also gets a point-mirrored twin" }, "700C": { "unit": "game/mapGenerator6F00", "line": "nothing could be placed - store 0 and return" }, "700E": { "unit": "game/mapGenerator6F00", "line": "mirror the four candidate rows" }, "7010": { "unit": "game/mapGenerator6F00", "line": "row of site y (the accepted row, or the preloaded candidate)" }, "7013": { "unit": "game/mapGenerator6F00", "line": "39 - row: the same distance from the bottom edge" }, "7016": { "unit": "game/mapGenerator6F00", "line": "candidate rows 25-32 for the bottom half" }, "7019": { "unit": "game/mapGenerator6F00", "line": "next of the four candidate rows" }, "701A": { "unit": "game/mapGenerator6F00", "line": "falls into findBlankSitesOnLanes for sites count..2*count-1" }, "701C": { "unit": "game/mapGenerator6F00", "routine": [ "findBlankSitesOnLanes - gives every summit site from zp_2A to $0300-1 a column and a row. The", "four lane columns are reshuffled first; each site then takes the next lane and the next candidate", "row and tries up to 21 jittered columns (+/-6 around the lane) until it finds a blank ($40) cell.", "If a whole row fails it moves on to the next candidate row, and if every row fails the site is", "dropped ($0300 and zp_2A are decremented). Entered by JSR for the top half and by fall-through", "for the mirrored bottom half, which is why zp_2A is not reset here.", "In: zp_2A = first site index, $0300 = requested count, zp_28 = highest candidate-row index,", " $0325[] candidate rows, map at $F000", "Out: $0314[i] site column, $031C[i] site row, $0300 = sites actually placed, $0329-$032C lanes;", " zp_1D/zp_1E/zp_1F/zp_29/zp_2B scratch", "Called from: pickHillSummitSites ($7006, and by fall-through from $701A)" ], "line": "randomise the order of the four lane columns 6/15/25/34" }, "701F": { "unit": "game/mapGenerator6F00", "line": "lane index 3 = the last entry of the shuffled lane list" }, "7021": { "unit": "game/mapGenerator6F00", "line": "zp_2B = lane index; advanceLaneIndex counts down 3,2,1,0,3,..." }, "7023": { "unit": "game/mapGenerator6F00", "line": "highest valid candidate-row index (= count-1)" }, "7025": { "unit": "game/mapGenerator6F00", "line": "zp_29 = start at the top of the candidate-row list" }, "7027": { "unit": "game/mapGenerator6F00", "block": [ "Per site: try candidate rows in turn until a blank cell is found." ], "line": "current candidate-row index" }, "7029": { "unit": "game/mapGenerator6F00", "line": "zp_1F remembers which candidate row this site started with" }, "702B": { "unit": "game/mapGenerator6F00", "line": "21 column attempts per candidate row (counter $14 down through 0)" }, "702D": { "unit": "game/mapGenerator6F00", "line": "zp_1E = attempts left" }, "702F": { "unit": "game/mapGenerator6F00", "line": "current lane" }, "7031": { "unit": "game/mapGenerator6F00", "line": "its column: 6, 15, 25 or 34" }, "7034": { "unit": "game/mapGenerator6F00", "line": "Y = 3 jitter steps, i.e. an offset of 0, +/-2, +/-4 or +/-6 columns" }, "7036": { "unit": "game/mapGenerator6F00", "line": "scatter the site sideways around its lane column" }, "7039": { "unit": "game/mapGenerator6F00", "line": "still inside the 40-column map?" }, "703B": { "unit": "game/mapGenerator6F00", "line": "off the map - roll again (a rejected roll does not use up an attempt)" }, "703D": { "unit": "game/mapGenerator6F00", "line": "index of the site being placed" }, "703F": { "unit": "game/mapGenerator6F00", "line": "$0314[i] = provisional column" }, "7042": { "unit": "game/mapGenerator6F00", "line": "X = column for readMapCell" }, "7043": { "unit": "game/mapGenerator6F00", "line": "current candidate-row slot" }, "7045": { "unit": "game/mapGenerator6F00", "line": "the candidate row for this attempt" }, "7048": { "unit": "game/mapGenerator6F00", "line": "zp_1D keeps it until the cell is known to be free" }, "704A": { "unit": "game/mapGenerator6F00", "line": "Y = row for readMapCell" }, "704B": { "unit": "game/mapGenerator6F00", "line": "zp_48/49 -> map cell (column,row)" }, "704E": { "unit": "game/mapGenerator6F00", "line": "offset 0 = the cell itself" }, "7050": { "unit": "game/mapGenerator6F00", "line": "what is already there" }, "7052": { "unit": "game/mapGenerator6F00", "line": "$40 = blank terrain (the river and its markers are not)" }, "7054": { "unit": "game/mapGenerator6F00", "line": "free - take this site" }, "7056": { "unit": "game/mapGenerator6F00", "line": "one attempt used up" }, "7058": { "unit": "game/mapGenerator6F00", "line": "try another column on the same row" }, "705A": { "unit": "game/mapGenerator6F00", "line": "this row is hopeless - step to the next candidate row" }, "705D": { "unit": "game/mapGenerator6F00", "line": "the candidate row we have wrapped round to" }, "705F": { "unit": "game/mapGenerator6F00", "line": "have we cycled back to the row we started on?" }, "7061": { "unit": "game/mapGenerator6F00", "line": "no - give that row its own 21 attempts" }, "7063": { "unit": "game/mapGenerator6F00", "line": "every candidate row failed: drop this site from the count" }, "7066": { "unit": "game/mapGenerator6F00", "line": "and let the next site re-use its index" }, "7068": { "unit": "game/mapGenerator6F00", "line": "site dropped - skip the accept path" }, "706B": { "unit": "game/mapGenerator6F00", "line": "index of the site just placed" }, "706D": { "unit": "game/mapGenerator6F00", "line": "the row that worked" }, "706F": { "unit": "game/mapGenerator6F00", "line": "$031C[i] = site row" }, "7072": { "unit": "game/mapGenerator6F00", "block": [ "Advance lane and row candidate so consecutive summits are spread out." ], "line": "next site uses the next lane column" }, "7075": { "unit": "game/mapGenerator6F00", "line": "the candidate row this site started from" }, "7077": { "unit": "game/mapGenerator6F00", "line": "restore the candidate row this site started from..." }, "7079": { "unit": "game/mapGenerator6F00", "line": "...then step it once, so the next site starts on a different row" }, "707C": { "unit": "game/mapGenerator6F00", "line": "next site index" }, "707E": { "unit": "game/mapGenerator6F00", "line": "site index just used" }, "7080": { "unit": "game/mapGenerator6F00", "line": "all requested sites handled?" }, "7083": { "unit": "game/mapGenerator6F00", "line": "all sites handled - store the real count" }, "7085": { "unit": "game/mapGenerator6F00", "line": "place the next site" }, "7088": { "unit": "game/mapGenerator6F00", "line": "zp_2A = number of sites actually placed" }, "708A": { "unit": "game/mapGenerator6F00", "line": "$0300 corrected, so the painters only walk real sites" }, "708D": { "unit": "game/mapGenerator6F00", "line": "returns with $0300 = the number of sites that really exist" }, "708E": { "unit": "game/mapGenerator6F00", "routine": [ "advanceLaneIndex - steps the lane cursor zp_2B down through the four shuffled lane columns in", "$0329-$032C, wrapping 0 back to 3.", "In: zp_2B", "Out: zp_2B = next lane index 0-3", "Called from: findBlankSitesOnLanes ($7072)" ], "line": "next lane" }, "7090": { "unit": "game/mapGenerator6F00", "line": "still a valid index" }, "7092": { "unit": "game/mapGenerator6F00", "line": "lane index 3" }, "7094": { "unit": "game/mapGenerator6F00", "line": "wrap round to the last of the four lanes" }, "7096": { "unit": "game/mapGenerator6F00", "line": "return the wrapped lane index" }, "7097": { "unit": "game/mapGenerator6F00", "routine": [ "advanceRowCandidate - steps the candidate-row cursor zp_29 down through $0325[0..zp_28],", "wrapping 0 back to zp_28 (= summit count - 1).", "In: zp_29, zp_28", "Out: zp_29 = next candidate-row index", "Called from: findBlankSitesOnLanes ($705A, $7079)" ], "line": "next candidate row" }, "7099": { "unit": "game/mapGenerator6F00", "line": "still a valid index" }, "709B": { "unit": "game/mapGenerator6F00", "line": "highest candidate index" }, "709D": { "unit": "game/mapGenerator6F00", "line": "wrap round to the top of the list" }, "709F": { "unit": "game/mapGenerator6F00", "line": "return the wrapped candidate-row index" }, "70A0": { "unit": "game/mapGenerator6F00", "routine": [ "shuffleLaneColumns - builds a random permutation of 0-3 (identity, then four random transpositions)", "in the sprite build buffer $9025-$9028, which is free while the map is generated, and writes", "laneColumnTable[perm[y]] into $0329-$032C. Summits are therefore distributed over the four", "vertical lanes of the map in a different order for every map.", "In: scenario RNG, laneColumnTable $6F00", "Out: $0329-$032C = the four lane columns in random order; $9025-$9028 and zp_18 clobbered", "Called from: findBlankSitesOnLanes ($701C)" ], "line": "load the swap count" }, "70A2": { "unit": "game/mapGenerator6F00", "line": "zp_18 = swap counter: 3,2,1,0 = four swaps" }, "70A4": { "unit": "game/mapGenerator6F00", "line": "Y = 3" }, "70A5": { "unit": "game/mapGenerator6F00", "line": "A = Y" }, "70A6": { "unit": "game/mapGenerator6F00", "line": "$9025[y] = y: start from the identity permutation" }, "70A9": { "unit": "game/mapGenerator6F00", "line": "next slot" }, "70AA": { "unit": "game/mapGenerator6F00", "line": "four entries 3..0" }, "70AC": { "unit": "game/mapGenerator6F00", "line": "pick the first index..." }, "70AF": { "unit": "game/mapGenerator6F00", "line": "0-3" }, "70B1": { "unit": "game/mapGenerator6F00", "line": "Y = first slot to swap" }, "70B2": { "unit": "game/mapGenerator6F00", "line": "...and the second (may be the same, which is a no-op swap)" }, "70B5": { "unit": "game/mapGenerator6F00", "line": "0-3" }, "70B7": { "unit": "game/mapGenerator6F00", "line": "X = second slot to swap (may be the same)" }, "70B8": { "unit": "game/mapGenerator6F00", "line": "perm[y]" }, "70BB": { "unit": "game/mapGenerator6F00", "line": "save it on the stack" }, "70BC": { "unit": "game/mapGenerator6F00", "line": "perm[x]" }, "70BF": { "unit": "game/mapGenerator6F00", "line": "perm[y] = perm[x]" }, "70C2": { "unit": "game/mapGenerator6F00", "line": "the old perm[y]" }, "70C3": { "unit": "game/mapGenerator6F00", "line": "exchange perm[y] and perm[x]" }, "70C6": { "unit": "game/mapGenerator6F00", "line": "one swap done" }, "70C8": { "unit": "game/mapGenerator6F00", "line": "four swaps in all" }, "70CA": { "unit": "game/mapGenerator6F00", "line": "Y = 3: fill the lane list backwards" }, "70CC": { "unit": "game/mapGenerator6F00", "line": "permuted index 0-3" }, "70CF": { "unit": "game/mapGenerator6F00", "line": "lane column 6, 15, 25 or 34" }, "70D2": { "unit": "game/mapGenerator6F00", "line": "$0329-$032C = shuffled lane columns" }, "70D5": { "unit": "game/mapGenerator6F00", "line": "next lane slot" }, "70D6": { "unit": "game/mapGenerator6F00", "line": "four lanes" }, "70D8": { "unit": "game/mapGenerator6F00", "line": "the four lane columns are ready" }, "70D9": { "unit": "game/mapGenerator6F00", "routine": [ "paintHillSummits - paints every site chosen by pickHillSummitSites as a blob of summit tiles.", "Each blob is 2-5 cells of tile $65 (randomTileVariant may pick $66) grown from the site with a", "horizontal spread of 200/256 and a vertical spread of 32/256, so summits are wide and flat rather", "than round. Does nothing when no sites were placed.", "In: $0300 site count, $0307[] blob sizes, $0314[]/$031C[] site coordinates", "Out: summit tiles written to the map; $0301 = $65, $0304 = 0, zp_2A, zp_A7/zp_A8", "Called from: runMapGeneratorPasses ($6F42)" ], "line": "number of summit sites" }, "70DC": { "unit": "game/mapGenerator6F00", "line": "no hills on this map" }, "70DE": { "unit": "game/mapGenerator6F00", "line": "clear A for the two stores below" }, "70E0": { "unit": "game/mapGenerator6F00", "line": "$0304 blob flags = 0: no 2x2 block constraint" }, "70E3": { "unit": "game/mapGenerator6F00", "line": "start at site 0" }, "70E5": { "unit": "game/mapGenerator6F00", "line": "$65 = summit tile, terrain class 6" }, "70E7": { "unit": "game/mapGenerator6F00", "line": "$0301 = the tile growTerrainBlob paints" }, "70EA": { "unit": "game/mapGenerator6F00", "line": "index of the site being painted" }, "70EC": { "unit": "game/mapGenerator6F00", "line": "site column" }, "70EF": { "unit": "game/mapGenerator6F00", "line": "zp_A7 = blob origin column" }, "70F1": { "unit": "game/mapGenerator6F00", "line": "site row" }, "70F4": { "unit": "game/mapGenerator6F00", "line": "zp_A8 = blob origin row" }, "70F6": { "unit": "game/mapGenerator6F00", "line": "A = 2-5 cells to place" }, "70F9": { "unit": "game/mapGenerator6F00", "line": "X = horizontal spread 200/256 - summits stretch east/west" }, "70FB": { "unit": "game/mapGenerator6F00", "line": "Y = vertical spread 32/256 - and stay thin north/south" }, "70FD": { "unit": "game/mapGenerator6F00", "line": "paint this summit" }, "7100": { "unit": "game/mapGenerator6F00", "line": "next site" }, "7102": { "unit": "game/mapGenerator6F00", "line": "site index just painted" }, "7104": { "unit": "game/mapGenerator6F00", "line": "all sites painted?" }, "7107": { "unit": "game/mapGenerator6F00", "line": "every site, top-half original and mirrored twin alike" }, "7109": { "unit": "game/mapGenerator6F00", "line": "no more sites" }, "710A": { "unit": "game/mapGenerator6F00", "routine": [ "growLowerHillsBesideSlopes - second terrain layer. Scans every interior cell (column and row", "1-38) and, when a blank cell touches an upper slope tile (terrain class 5, $41-$54), grows a", "5-cell blob of lower-hill tile $61 from it. The chance is 1 in 4 for the north and south", "neighbours and 1 in 2 for west and east, so the hill bodies spread sideways like the summits.", "The first matching neighbour wins. Skipped entirely when the map has no hills.", "In: $0300 summit count, the map, terrainClassTable $077E, scenario RNG", "Out: lower-hill tiles written to the map; $0301 = $61, $0304 = 0, zp_A7/zp_A8 = the scan cell", "Called from: runMapGeneratorPasses ($6F5A)" ], "line": "were any summits placed?" }, "710D": { "unit": "game/mapGenerator6F00", "line": "there are hills to widen" }, "710F": { "unit": "game/mapGenerator6F00", "line": "no hills - nothing to widen" }, "7112": { "unit": "game/mapGenerator6F00", "line": "clear A for the two stores below" }, "7114": { "unit": "game/mapGenerator6F00", "line": "$0304 blob flags = 0: no 2x2 block constraint" }, "7117": { "unit": "game/mapGenerator6F00", "line": "clears zp_2A as a side effect; nothing in this routine reads it" }, "7119": { "unit": "game/mapGenerator6F00", "line": "$61 = lower hill tile ($61-$64 variants), terrain class 4" }, "711B": { "unit": "game/mapGenerator6F00", "line": "$0301 = the tile growTerrainBlob paints" }, "711E": { "unit": "game/mapGenerator6F00", "line": "row 1" }, "7120": { "unit": "game/mapGenerator6F00", "line": "scan starts at row 1 (the outermost ring is never used)" }, "7122": { "unit": "game/mapGenerator6F00", "block": [ "Scan loop over the interior cells. zp_A7/zp_A8 hold the cell; zp_48/49 is set to the top-left", "corner of its 3x3 block so the neighbours are at fixed offsets $01 N, $28 W, $29 self, $2A E,", "$51 S." ], "line": "column 1" }, "7124": { "unit": "game/mapGenerator6F00", "line": "each row starts at column 1" }, "7126": { "unit": "game/mapGenerator6F00", "line": "X = column..." }, "7128": { "unit": "game/mapGenerator6F00", "line": "...minus 1" }, "7129": { "unit": "game/mapGenerator6F00", "line": "Y = row..." }, "712B": { "unit": "game/mapGenerator6F00", "line": "...minus 1" }, "712C": { "unit": "game/mapGenerator6F00", "line": "zp_48/49 -> cell (col-1,row-1), the top-left of the 3x3 block" }, "712F": { "unit": "game/mapGenerator6F00", "line": "offset $29 = the cell itself" }, "7131": { "unit": "game/mapGenerator6F00", "line": "the terrain code of the scan cell" }, "7133": { "unit": "game/mapGenerator6F00", "line": "only blank cells can start a lower hill" }, "7135": { "unit": "game/mapGenerator6F00", "line": "occupied - move on" }, "7137": { "unit": "game/mapGenerator6F00", "line": "offset $01 = north neighbour (col,row-1)" }, "7139": { "unit": "game/mapGenerator6F00", "line": "north neighbour's cell" }, "713B": { "unit": "game/mapGenerator6F00", "line": "bit 7 set = a unit or a river keep-clear marker, not terrain" }, "713D": { "unit": "game/mapGenerator6F00", "line": "use the terrain code as the class-table index" }, "713E": { "unit": "game/mapGenerator6F00", "line": "terrain class of the north neighbour" }, "7141": { "unit": "game/mapGenerator6F00", "line": "class 5 = upper slope contour $41-$54" }, "7143": { "unit": "game/mapGenerator6F00", "line": "not a slope - try the west neighbour" }, "7145": { "unit": "game/mapGenerator6F00", "line": "roll for the north slope" }, "7148": { "unit": "game/mapGenerator6F00", "line": "1 chance in 4 for a north slope" }, "714A": { "unit": "game/mapGenerator6F00", "line": "won - grow a hill body here" }, "714C": { "unit": "game/mapGenerator6F00", "line": "offset $28 = west neighbour (col-1,row)" }, "714E": { "unit": "game/mapGenerator6F00", "line": "west neighbour's cell" }, "7150": { "unit": "game/mapGenerator6F00", "line": "unit or marker - skip" }, "7152": { "unit": "game/mapGenerator6F00", "line": "use the terrain code as the class-table index" }, "7153": { "unit": "game/mapGenerator6F00", "line": "terrain class of the west neighbour" }, "7156": { "unit": "game/mapGenerator6F00", "line": "upper slope?" }, "7158": { "unit": "game/mapGenerator6F00", "line": "no - try the east neighbour" }, "715A": { "unit": "game/mapGenerator6F00", "line": "roll for the west slope" }, "715D": { "unit": "game/mapGenerator6F00", "line": "1 chance in 2 for a side slope - hills widen east/west" }, "715F": { "unit": "game/mapGenerator6F00", "line": "won - grow a hill body here" }, "7161": { "unit": "game/mapGenerator6F00", "line": "offset $2A = east neighbour (col+1,row)" }, "7163": { "unit": "game/mapGenerator6F00", "line": "east neighbour's cell" }, "7165": { "unit": "game/mapGenerator6F00", "line": "unit or marker - skip" }, "7167": { "unit": "game/mapGenerator6F00", "line": "use the terrain code as the class-table index" }, "7168": { "unit": "game/mapGenerator6F00", "line": "terrain class of the east neighbour" }, "716B": { "unit": "game/mapGenerator6F00", "line": "upper slope?" }, "716D": { "unit": "game/mapGenerator6F00", "line": "no - try the south neighbour" }, "716F": { "unit": "game/mapGenerator6F00", "line": "roll for the east slope" }, "7172": { "unit": "game/mapGenerator6F00", "line": "1 chance in 2" }, "7174": { "unit": "game/mapGenerator6F00", "line": "won - grow a hill body here" }, "7176": { "unit": "game/mapGenerator6F00", "line": "offset $51 = south neighbour (col,row+1)" }, "7178": { "unit": "game/mapGenerator6F00", "line": "south neighbour's cell" }, "717A": { "unit": "game/mapGenerator6F00", "line": "unit or marker - give up on this cell" }, "717C": { "unit": "game/mapGenerator6F00", "line": "use the terrain code as the class-table index" }, "717D": { "unit": "game/mapGenerator6F00", "line": "terrain class of the south neighbour" }, "7180": { "unit": "game/mapGenerator6F00", "line": "upper slope?" }, "7182": { "unit": "game/mapGenerator6F00", "line": "no - nothing to do at this cell" }, "7184": { "unit": "game/mapGenerator6F00", "line": "roll for the south slope" }, "7187": { "unit": "game/mapGenerator6F00", "line": "1 chance in 4 (inverted test: falls through to grow)" }, "7189": { "unit": "game/mapGenerator6F00", "line": "lost the roll" }, "718B": { "unit": "game/mapGenerator6F00", "line": "X = horizontal spread 64/256" }, "718D": { "unit": "game/mapGenerator6F00", "line": "Y = vertical spread 16/256 - the body hugs the slope" }, "718F": { "unit": "game/mapGenerator6F00", "line": "A = 5 cells" }, "7191": { "unit": "game/mapGenerator6F00", "line": "zp_A7/zp_A8 already hold the scan cell = the blob origin" }, "7194": { "unit": "game/mapGenerator6F00", "line": "next column" }, "7196": { "unit": "game/mapGenerator6F00", "line": "the column just finished" }, "7198": { "unit": "game/mapGenerator6F00", "line": "columns 1-38 only" }, "719A": { "unit": "game/mapGenerator6F00", "line": "row finished" }, "719C": { "unit": "game/mapGenerator6F00", "line": "scan the next cell of this row" }, "719F": { "unit": "game/mapGenerator6F00", "line": "next row" }, "71A1": { "unit": "game/mapGenerator6F00", "line": "the row just finished" }, "71A3": { "unit": "game/mapGenerator6F00", "line": "rows 1-38 only" }, "71A5": { "unit": "game/mapGenerator6F00", "line": "whole map scanned" }, "71A7": { "unit": "game/mapGenerator6F00", "line": "scan the next row" }, "71AA": { "unit": "game/mapGenerator6F00", "line": "the whole interior has been scanned" }, "71AB": { "unit": "game/mapGenerator6F00", "block": [ "unusedBitTable71AB - $08,$04,$02,$01,$00. Dead in this overlay: nothing between $6F00 and $87FF", "reads it (the $71AC reference in XREF belongs to the comcen-screens overlay). It looks like a", "leftover direction-bit table for growTerrainBlob, which builds the same bits with immediate", "operands instead." ], "line": "unused direction-bit constants" }, "71B0": { "unit": "game/mapGenerator6F00", "routine": [ "growTerrainBlob - the generic random blob painter used by every terrain pass. Starting at", "(zp_A7,zp_A8) it performs a depth-first walk with an explicit 80-entry stack in page 4 ($0400", "columns, $0450 rows, $04A0 tried-direction flags) and paints tile $0301 - passed through", "randomTileVariant - on blank ($40) cells until A cells have been placed, the stack empties or the", "stack overflows. From each cell the four directions are tried once (flag bits 0 N, 1 W, 2 E,", "3 S in zp_6B); a neighbour is taken when it is on the map, blank, and a scenario random byte is", "below the X (west/east) or Y (north/south) threshold, so X and Y control the horizontal and", "vertical spread out of 256. A newly pushed cell has the direction back towards the origin", "pre-marked as tried, which keeps the blob growing outwards. With $0304 bit 6 set (forest) a cell", "is only painted when checkAlignedBlockForForest approves its 2x2 block.", "In: A = cells to paint, X = horizontal spread 0-255, Y = vertical spread 0-255,", " zp_A7/zp_A8 = origin, $0301 = base tile, $0304 = blob flags", "Out: map cells painted; zp_18, zp_1A, zp_6B, zp_A5/zp_A6, zp_B2 stack level, zp_B3 painted count,", " $91DA/$91DB and $0400-$04EF clobbered. NOTE: $0400-$04EF is the page that also holds the", " copy-protection answer table at $0401 - harmless, because manualLookupCheck reads its answer", " before it calls the generator", "Called from: paintHillSummits ($70FD), growLowerHillsBesideSlopes ($7191), paintForestBlobAt ($73EA)" ], "block": [ "Set up the walk: thresholds, counters and stack entry 0 = the origin cell." ], "line": "X = horizontal accept threshold, parked in the engine's currentUnitCol (free here)" }, "71B3": { "unit": "game/mapGenerator6F00", "line": "Y = vertical accept threshold, parked in currentUnitRow" }, "71B6": { "unit": "game/mapGenerator6F00", "line": "zp_18 = how many cells this blob should get" }, "71B8": { "unit": "game/mapGenerator6F00", "line": "clear A for the three stores below" }, "71BA": { "unit": "game/mapGenerator6F00", "line": "zp_B3 = cells painted so far" }, "71BC": { "unit": "game/mapGenerator6F00", "line": "$04A0[0] = tried-direction flags of the origin entry" }, "71BF": { "unit": "game/mapGenerator6F00", "line": "zp_B2 = stack fill level (index of the next free entry)" }, "71C1": { "unit": "game/mapGenerator6F00", "line": "blob flags: bit 6 = only paint inside a clean 2x2 block" }, "71C4": { "unit": "game/mapGenerator6F00", "line": "zp_6B = flags of the cell currently being expanded" }, "71C6": { "unit": "game/mapGenerator6F00", "line": "the walk starts at the blob origin" }, "71C8": { "unit": "game/mapGenerator6F00", "line": "zp_A5 = column of the current cell" }, "71CA": { "unit": "game/mapGenerator6F00", "line": "$0400[0] = origin column" }, "71CD": { "unit": "game/mapGenerator6F00", "line": "origin row" }, "71CF": { "unit": "game/mapGenerator6F00", "line": "zp_A6 = row of the current cell" }, "71D1": { "unit": "game/mapGenerator6F00", "line": "$0450[0] = origin row" }, "71D4": { "unit": "game/mapGenerator6F00", "line": "zp_48/49 -> the origin cell (copes with negative coordinates)" }, "71D7": { "unit": "game/mapGenerator6F00", "line": "offset 0 = the cell itself" }, "71D9": { "unit": "game/mapGenerator6F00", "line": "paint the origin, then push it as the first stack entry" }, "71DC": { "unit": "game/mapGenerator6F00", "block": [ "Pop the top stack entry and try its four directions in turn. zp_48/49 is aimed one row above", "the cell, so N/W/E/S are at offsets $00/$27/$29/$50." ], "line": "drop the fill level to the entry on top of the stack" }, "71DE": { "unit": "game/mapGenerator6F00", "line": "there is still an entry to expand" }, "71E0": { "unit": "game/mapGenerator6F00", "line": "stack empty - this blob is finished" }, "71E3": { "unit": "game/mapGenerator6F00", "line": "y = the entry now on top of the stack" }, "71E5": { "unit": "game/mapGenerator6F00", "line": "$04A0[y] = directions already tried from this cell" }, "71E8": { "unit": "game/mapGenerator6F00", "line": "re-apply the global blob flags (bit 6 survives every push/pop)" }, "71EB": { "unit": "game/mapGenerator6F00", "line": "zp_6B = the flags of the cell being expanded" }, "71ED": { "unit": "game/mapGenerator6F00", "line": "$0400[y] = its column" }, "71F0": { "unit": "game/mapGenerator6F00", "line": "$0450[y] = its row" }, "71F3": { "unit": "game/mapGenerator6F00", "line": "A -> Y so it can be decremented" }, "71F4": { "unit": "game/mapGenerator6F00", "line": "aim one row above the cell..." }, "71F5": { "unit": "game/mapGenerator6F00", "line": "...so the north neighbour sits at offset 0" }, "71F7": { "unit": "game/mapGenerator6F00", "line": "zp_A5 = the cell's column" }, "71F9": { "unit": "game/mapGenerator6F00", "line": "zp_48/49 -> (column, row-1)" }, "71FC": { "unit": "game/mapGenerator6F00", "line": "tried-direction flags" }, "71FE": { "unit": "game/mapGenerator6F00", "line": "bit 0 = north already tried" }, "7200": { "unit": "game/mapGenerator6F00", "line": "yes - go on to the west neighbour" }, "7202": { "unit": "game/mapGenerator6F00", "line": "tried-direction flags" }, "7204": { "unit": "game/mapGenerator6F00", "line": "bit 0 = north" }, "7206": { "unit": "game/mapGenerator6F00", "line": "mark north as tried" }, "7208": { "unit": "game/mapGenerator6F00", "line": "row-1 above the top edge of the map?" }, "720A": { "unit": "game/mapGenerator6F00", "line": "yes - try west" }, "720C": { "unit": "game/mapGenerator6F00", "line": "offset $00 = north neighbour" }, "720E": { "unit": "game/mapGenerator6F00", "line": "the north neighbour's cell" }, "7210": { "unit": "game/mapGenerator6F00", "line": "only blank terrain can be painted" }, "7212": { "unit": "game/mapGenerator6F00", "line": "not blank - cannot grow there" }, "7214": { "unit": "game/mapGenerator6F00", "line": "roll for the vertical spread" }, "7217": { "unit": "game/mapGenerator6F00", "line": "accept while the random byte is below the vertical spread" }, "721A": { "unit": "game/mapGenerator6F00", "line": "lost the roll - try west" }, "721C": { "unit": "game/mapGenerator6F00", "line": "grow into the north neighbour (zp_A5/zp_A6 and Y already point at it)" }, "721F": { "unit": "game/mapGenerator6F00", "line": "undo the -1: back to the cell's own row" }, "7221": { "unit": "game/mapGenerator6F00", "line": "step one column west" }, "7223": { "unit": "game/mapGenerator6F00", "line": "tried-direction flags" }, "7225": { "unit": "game/mapGenerator6F00", "line": "bit 1 = west already tried" }, "7227": { "unit": "game/mapGenerator6F00", "line": "west already tried from this cell" }, "7229": { "unit": "game/mapGenerator6F00", "line": "tried-direction flags" }, "722B": { "unit": "game/mapGenerator6F00", "line": "bit 1 = west" }, "722D": { "unit": "game/mapGenerator6F00", "line": "mark west as tried" }, "722F": { "unit": "game/mapGenerator6F00", "line": "column-1 off the left edge?" }, "7231": { "unit": "game/mapGenerator6F00", "line": "column -1 is off the map" }, "7233": { "unit": "game/mapGenerator6F00", "line": "offset $27 = west neighbour (-1 column, +1 row from the pointer)" }, "7235": { "unit": "game/mapGenerator6F00", "line": "the west neighbour's cell" }, "7237": { "unit": "game/mapGenerator6F00", "line": "blank?" }, "7239": { "unit": "game/mapGenerator6F00", "line": "not blank" }, "723B": { "unit": "game/mapGenerator6F00", "line": "roll for the horizontal spread" }, "723E": { "unit": "game/mapGenerator6F00", "line": "accept while the random byte is below the horizontal spread" }, "7241": { "unit": "game/mapGenerator6F00", "line": "grow into the west neighbour" }, "7243": { "unit": "game/mapGenerator6F00", "line": "back to the cell's own column..." }, "7245": { "unit": "game/mapGenerator6F00", "line": "two columns east: the cell's column + 1" }, "7247": { "unit": "game/mapGenerator6F00", "line": "tried-direction flags" }, "7249": { "unit": "game/mapGenerator6F00", "line": "bit 2 = east already tried" }, "724B": { "unit": "game/mapGenerator6F00", "line": "east already tried" }, "724D": { "unit": "game/mapGenerator6F00", "line": "tried-direction flags" }, "724F": { "unit": "game/mapGenerator6F00", "line": "bit 2 = east" }, "7251": { "unit": "game/mapGenerator6F00", "line": "mark east as tried" }, "7253": { "unit": "game/mapGenerator6F00", "line": "the column the east neighbour sits in" }, "7255": { "unit": "game/mapGenerator6F00", "line": "column 40 is off the right edge" }, "7257": { "unit": "game/mapGenerator6F00", "line": "column 40 is off the map" }, "7259": { "unit": "game/mapGenerator6F00", "line": "offset $29 = east neighbour (+1 column, +1 row)" }, "725B": { "unit": "game/mapGenerator6F00", "line": "the east neighbour's cell" }, "725D": { "unit": "game/mapGenerator6F00", "line": "blank?" }, "725F": { "unit": "game/mapGenerator6F00", "line": "not blank" }, "7261": { "unit": "game/mapGenerator6F00", "line": "roll for the horizontal spread" }, "7264": { "unit": "game/mapGenerator6F00", "line": "horizontal spread again" }, "7267": { "unit": "game/mapGenerator6F00", "line": "grow into the east neighbour" }, "7269": { "unit": "game/mapGenerator6F00", "line": "back to the cell's own column" }, "726B": { "unit": "game/mapGenerator6F00", "line": "step one row south" }, "726D": { "unit": "game/mapGenerator6F00", "line": "tried-direction flags" }, "726F": { "unit": "game/mapGenerator6F00", "line": "bit 3 = south already tried" }, "7271": { "unit": "game/mapGenerator6F00", "line": "south already tried" }, "7273": { "unit": "game/mapGenerator6F00", "line": "tried-direction flags" }, "7275": { "unit": "game/mapGenerator6F00", "line": "bit 3 = south" }, "7277": { "unit": "game/mapGenerator6F00", "line": "mark south as tried" }, "7279": { "unit": "game/mapGenerator6F00", "line": "the row the south neighbour sits in" }, "727B": { "unit": "game/mapGenerator6F00", "line": "row 40 is off the bottom edge" }, "727D": { "unit": "game/mapGenerator6F00", "line": "row 40 is off the map" }, "727F": { "unit": "game/mapGenerator6F00", "line": "offset $50 = south neighbour (+2 rows)" }, "7281": { "unit": "game/mapGenerator6F00", "line": "the south neighbour's cell" }, "7283": { "unit": "game/mapGenerator6F00", "line": "blank?" }, "7285": { "unit": "game/mapGenerator6F00", "line": "not blank" }, "7287": { "unit": "game/mapGenerator6F00", "line": "roll for the vertical spread" }, "728A": { "unit": "game/mapGenerator6F00", "line": "vertical spread again" }, "728D": { "unit": "game/mapGenerator6F00", "line": "grow into the south neighbour" }, "728F": { "unit": "game/mapGenerator6F00", "line": "all four directions used up - pop the next cell" }, "7292": { "unit": "game/mapGenerator6F00", "block": [ "Paint the accepted cell (Y = its offset from zp_48/49) and push it on the stack." ], "line": "the candidate cell" }, "7294": { "unit": "game/mapGenerator6F00", "line": "blank terrain?" }, "7296": { "unit": "game/mapGenerator6F00", "line": "not blank (only possible for the origin) - push it without painting" }, "7298": { "unit": "game/mapGenerator6F00", "line": "bit 6 = the 2x2 forest constraint" }, "729A": { "unit": "game/mapGenerator6F00", "line": "bit 6 clear - paint unconditionally" }, "729C": { "unit": "game/mapGenerator6F00", "line": "forest: the aligned 2x2 block must contain only blank and forest" }, "729F": { "unit": "game/mapGenerator6F00", "line": "block rejected - do not paint, but still expand from here" }, "72A1": { "unit": "game/mapGenerator6F00", "line": "base tile for this pass" }, "72A4": { "unit": "game/mapGenerator6F00", "line": "add a random variant (Y is preserved through a self-modified LDY at $7891+1)" }, "72A7": { "unit": "game/mapGenerator6F00", "line": "paint the cell" }, "72A9": { "unit": "game/mapGenerator6F00", "line": "one more cell of this blob placed" }, "72AB": { "unit": "game/mapGenerator6F00", "line": "cells placed so far" }, "72AD": { "unit": "game/mapGenerator6F00", "line": "reached the requested number of cells?" }, "72AF": { "unit": "game/mapGenerator6F00", "line": "yes - blob finished" }, "72B1": { "unit": "game/mapGenerator6F00", "line": "y = the parent entry that is being expanded" }, "72B3": { "unit": "game/mapGenerator6F00", "line": "the parent's flags with the direction just used marked as tried" }, "72B5": { "unit": "game/mapGenerator6F00", "line": "$04A0[parent] = its updated tried-direction flags" }, "72B8": { "unit": "game/mapGenerator6F00", "line": "the child entry goes one slot higher" }, "72B9": { "unit": "game/mapGenerator6F00", "line": "the accepted cell's column" }, "72BB": { "unit": "game/mapGenerator6F00", "line": "$0400[child] = column" }, "72BE": { "unit": "game/mapGenerator6F00", "line": "and its row" }, "72C0": { "unit": "game/mapGenerator6F00", "line": "$0450[child] = row" }, "72C3": { "unit": "game/mapGenerator6F00", "block": [ "Pre-mark the direction back towards the blob origin as already tried, so a blob never folds", "back on itself." ], "line": "clear A" }, "72C5": { "unit": "game/mapGenerator6F00", "line": "zp_1A = the child's preset flags" }, "72C7": { "unit": "game/mapGenerator6F00", "line": "$02 = 'west already tried'" }, "72C9": { "unit": "game/mapGenerator6F00", "line": "the child's column" }, "72CB": { "unit": "game/mapGenerator6F00", "line": "child column against the blob origin column" }, "72CD": { "unit": "game/mapGenerator6F00", "line": "same column - no horizontal bias" }, "72CF": { "unit": "game/mapGenerator6F00", "line": "child is east of the origin - block growth back west" }, "72D1": { "unit": "game/mapGenerator6F00", "line": "$04 = 'east already tried' (child is west of the origin)" }, "72D3": { "unit": "game/mapGenerator6F00", "line": "horizontal bias" }, "72D5": { "unit": "game/mapGenerator6F00", "line": "$01 = 'north already tried'" }, "72D7": { "unit": "game/mapGenerator6F00", "line": "the child's row" }, "72D9": { "unit": "game/mapGenerator6F00", "line": "child row against the blob origin row" }, "72DB": { "unit": "game/mapGenerator6F00", "line": "same row - no vertical bias" }, "72DD": { "unit": "game/mapGenerator6F00", "line": "child is below the origin - block growth back north" }, "72DF": { "unit": "game/mapGenerator6F00", "line": "$08 = 'south already tried' (child is above the origin)" }, "72E1": { "unit": "game/mapGenerator6F00", "line": "combine with the horizontal bias" }, "72E3": { "unit": "game/mapGenerator6F00", "line": "zp_1A = the child's preset tried-direction flags" }, "72E5": { "unit": "game/mapGenerator6F00", "line": "the child's preset tried-direction flags" }, "72E7": { "unit": "game/mapGenerator6F00", "line": "$04A0[child] = its preset flags" }, "72EA": { "unit": "game/mapGenerator6F00", "line": "point one past the child entry" }, "72EB": { "unit": "game/mapGenerator6F00", "line": "zp_B2 = new fill level = child + 1" }, "72ED": { "unit": "game/mapGenerator6F00", "line": "80 entries is all that fits ($0400/$0450/$04A0 x 80 = $0400-$04EF)" }, "72EF": { "unit": "game/mapGenerator6F00", "line": "still room on the stack" }, "72F1": { "unit": "game/mapGenerator6F00", "line": "stack full - abandon this blob" }, "72F2": { "unit": "game/mapGenerator6F00", "line": "expand the cell just pushed" }, "72F5": { "unit": "game/mapGenerator6F00", "line": "blob finished: cell count reached, or the stack ran dry" }, "72F6": { "unit": "game/mapGenerator6F00", "routine": [ "checkAlignedBlockForForest - constrains forest to whole 2x2 blocks on an even grid. It takes the", "block containing (zp_A5,zp_A6) - both coordinates rounded down to even - and returns C = 0 only if", "all four cells are terrain class 0 (blank $40) or class 2 (forest $5D-$60). On success zp_48/49", "is re-pointed at the caller's own cell with Y = 0, so the caller can store straight through it.", "Note that the river keep-clear markers $80/$81 index past terrainClassTable into the zero filler", "at $07F3, so they read as class 0 here; growTerrainBlob's own $40 test still refuses to paint them.", "In: zp_A5/zp_A6 = the cell, map, terrainClassTable $077E", "Out: C = 0 accept / C = 1 reject; zp_48/49, A/X/Y clobbered", "Called from: growTerrainBlob ($729C) when $0304 bit 6 is set" ], "line": "column of the cell about to be painted" }, "72F8": { "unit": "game/mapGenerator6F00", "line": "round the column down to the even grid" }, "72FA": { "unit": "game/mapGenerator6F00", "line": "X = block column" }, "72FB": { "unit": "game/mapGenerator6F00", "line": "its row" }, "72FD": { "unit": "game/mapGenerator6F00", "line": "round the row down as well" }, "72FF": { "unit": "game/mapGenerator6F00", "line": "Y = block row" }, "7300": { "unit": "game/mapGenerator6F00", "line": "A = the block's top-left cell, zp_48/49 -> it, Y = 0" }, "7303": { "unit": "game/mapGenerator6F00", "line": "use the terrain code as the class-table index" }, "7304": { "unit": "game/mapGenerator6F00", "line": "terrain class of that cell" }, "7307": { "unit": "game/mapGenerator6F00", "line": "class 0 = blank: acceptable" }, "7309": { "unit": "game/mapGenerator6F00", "line": "class 2 = forest: also acceptable" }, "730B": { "unit": "game/mapGenerator6F00", "line": "anything else (river, hill, contour, unit) rejects the block" }, "730D": { "unit": "game/mapGenerator6F00", "line": "offset 1 = top-right cell" }, "730E": { "unit": "game/mapGenerator6F00", "line": "the top-right cell of the block" }, "7310": { "unit": "game/mapGenerator6F00", "line": "use the terrain code as the class-table index" }, "7311": { "unit": "game/mapGenerator6F00", "line": "its terrain class" }, "7314": { "unit": "game/mapGenerator6F00", "line": "blank" }, "7316": { "unit": "game/mapGenerator6F00", "line": "or forest" }, "7318": { "unit": "game/mapGenerator6F00", "line": "not blank or forest - reject the block" }, "731A": { "unit": "game/mapGenerator6F00", "line": "offset $28 = bottom-left cell" }, "731C": { "unit": "game/mapGenerator6F00", "line": "the bottom-left cell of the block" }, "731E": { "unit": "game/mapGenerator6F00", "line": "use the terrain code as the class-table index" }, "731F": { "unit": "game/mapGenerator6F00", "line": "its terrain class" }, "7322": { "unit": "game/mapGenerator6F00", "line": "blank" }, "7324": { "unit": "game/mapGenerator6F00", "line": "or forest" }, "7326": { "unit": "game/mapGenerator6F00", "line": "not blank or forest - reject the block" }, "7328": { "unit": "game/mapGenerator6F00", "line": "offset $29 = bottom-right cell" }, "7329": { "unit": "game/mapGenerator6F00", "line": "the bottom-right cell of the block" }, "732B": { "unit": "game/mapGenerator6F00", "line": "use the terrain code as the class-table index" }, "732C": { "unit": "game/mapGenerator6F00", "line": "its terrain class" }, "732F": { "unit": "game/mapGenerator6F00", "line": "blank" }, "7331": { "unit": "game/mapGenerator6F00", "line": "or forest" }, "7333": { "unit": "game/mapGenerator6F00", "line": "not blank or forest - reject the block" }, "7335": { "unit": "game/mapGenerator6F00", "line": "the caller's own column" }, "7337": { "unit": "game/mapGenerator6F00", "line": "and row" }, "7339": { "unit": "game/mapGenerator6F00", "line": "re-point zp_48/49 at the caller's own cell (leaves Y = 0)" }, "733C": { "unit": "game/mapGenerator6F00", "line": "C = 0: this block may be forested" }, "733D": { "unit": "game/mapGenerator6F00", "line": "C = 0 from $733C" }, "733E": { "unit": "game/mapGenerator6F00", "line": "C = 1: the block holds something else" }, "733F": { "unit": "game/mapGenerator6F00", "line": "C = 1 set at $733E" }, "7340": { "unit": "game/mapGenerator6F00", "routine": [ "placeForestClusters - the last terrain pass. Rolls a number of forest clusters (3-10 normally,", "with a 1-in-32 chance of no forest at all; exactly 10 for QB SNEAK; 1-4 for DEFENDER), gives each", "cluster a random centre at column/row 4-35 and scatters 6 seed points around it (+/-16 columns,", "+/-8 rows, re-rolled while off the map). Every seed becomes a 4x2 patch of small blobs through", "paintForestClusterSeeds. Blob flags $40 make all of it respect the 2x2 forest grid.", "In: $032E map style, scenario RNG", "Out: forest tiles $5D-$60 in the map; $0301, $0302, $0304, zp_2A cluster counter, zp_2B seed", " counter, zp_92-zp_95, zp_A5/zp_A6", "Called from: runMapGeneratorPasses ($6F6F)" ], "line": "blob flag bit 6: forest only grows inside a clean aligned 2x2 block" }, "7342": { "unit": "game/mapGenerator6F00", "line": "$0304 blob flags" }, "7345": { "unit": "game/mapGenerator6F00", "line": "$41 = upper contour tile" }, "7347": { "unit": "game/mapGenerator6F00", "line": "dead store: nothing in this overlay ever reads $0302 (XREF has no reader)" }, "734A": { "unit": "game/mapGenerator6F00", "line": "$5D = forest tile ($5D-$60 variants), terrain class 2" }, "734C": { "unit": "game/mapGenerator6F00", "line": "$0301 = the tile growTerrainBlob paints" }, "734F": { "unit": "game/mapGenerator6F00", "line": "QB SNEAK: 9 -> ten clusters, a deliberately cluttered field" }, "7351": { "unit": "game/mapGenerator6F00", "line": "mapGenGameFlags" }, "7354": { "unit": "game/mapGenerator6F00", "line": "bit 7 = QB SNEAK style - keep the fixed count" }, "7356": { "unit": "game/mapGenerator6F00", "line": "roll the cluster count" }, "7359": { "unit": "game/mapGenerator6F00", "line": "0-31" }, "735B": { "unit": "game/mapGenerator6F00", "line": "1 chance in 32 of a completely bare map" }, "735D": { "unit": "game/mapGenerator6F00", "line": "0-7..." }, "735F": { "unit": "game/mapGenerator6F00", "line": "prepare the add" }, "7360": { "unit": "game/mapGenerator6F00", "line": "...+2, so 3-10 clusters in total" }, "7362": { "unit": "game/mapGenerator6F00", "line": "mapGenGameFlags" }, "7365": { "unit": "game/mapGenerator6F00", "line": "bit 6 clear - not DEFENDER" }, "7367": { "unit": "game/mapGenerator6F00", "line": "DEFENDER: at most 3, i.e. 1-4 clusters (the map has to stay open)" }, "7369": { "unit": "game/mapGenerator6F00", "line": "zp_2A = clusters left minus one" }, "736B": { "unit": "game/mapGenerator6F00", "block": [ "Per cluster: pick a centre, then scatter six seed patches around it." ], "line": "roll the cluster centre column" }, "736E": { "unit": "game/mapGenerator6F00", "line": "0-31" }, "7370": { "unit": "game/mapGenerator6F00", "line": "prepare the add" }, "7371": { "unit": "game/mapGenerator6F00", "line": "cluster centre column 4-35" }, "7373": { "unit": "game/mapGenerator6F00", "line": "zp_95 = centre column, the base for the column jitter" }, "7375": { "unit": "game/mapGenerator6F00", "line": "vestigial: growTerrainBlob overwrites zp_A6 at once, and this is a column, not a row" }, "7377": { "unit": "game/mapGenerator6F00", "line": "roll the cluster centre row" }, "737A": { "unit": "game/mapGenerator6F00", "line": "0-31" }, "737C": { "unit": "game/mapGenerator6F00", "line": "prepare the add" }, "737D": { "unit": "game/mapGenerator6F00", "line": "cluster centre row 4-35" }, "737F": { "unit": "game/mapGenerator6F00", "line": "zp_94 = centre row, the base for the row jitter" }, "7381": { "unit": "game/mapGenerator6F00", "line": "vestigial in the same way (a row written to the view-origin column)" }, "7383": { "unit": "game/mapGenerator6F00", "line": "six seeds per cluster (5 down through 0)" }, "7385": { "unit": "game/mapGenerator6F00", "line": "zp_2B = six seed points per cluster (5 down through 0)" }, "7387": { "unit": "game/mapGenerator6F00", "line": "centre row" }, "7389": { "unit": "game/mapGenerator6F00", "line": "Y = 4 jitter steps = an offset of 0, +/-2, +/-4, +/-6 or +/-8 rows" }, "738B": { "unit": "game/mapGenerator6F00", "line": "scatter the seed row around the cluster centre" }, "738E": { "unit": "game/mapGenerator6F00", "line": "still on the map?" }, "7390": { "unit": "game/mapGenerator6F00", "line": "off the map - roll the row again" }, "7392": { "unit": "game/mapGenerator6F00", "line": "zp_92 = seed row" }, "7394": { "unit": "game/mapGenerator6F00", "line": "centre column" }, "7396": { "unit": "game/mapGenerator6F00", "line": "Y = 8 jitter steps = up to +/-16 columns, so clusters are wide" }, "7398": { "unit": "game/mapGenerator6F00", "line": "scatter the seed column around the cluster centre" }, "739B": { "unit": "game/mapGenerator6F00", "line": "still on the map?" }, "739D": { "unit": "game/mapGenerator6F00", "line": "off the map - roll the column again" }, "739F": { "unit": "game/mapGenerator6F00", "line": "zp_93 = seed column" }, "73A1": { "unit": "game/mapGenerator6F00", "line": "paint the 4x2 patch of blobs around this seed" }, "73A4": { "unit": "game/mapGenerator6F00", "line": "one seed done" }, "73A6": { "unit": "game/mapGenerator6F00", "line": "six seeds per cluster" }, "73A8": { "unit": "game/mapGenerator6F00", "line": "one cluster done" }, "73AA": { "unit": "game/mapGenerator6F00", "line": "next cluster" }, "73AC": { "unit": "game/mapGenerator6F00", "line": "all forest placed" }, "73AD": { "unit": "game/mapGenerator6F00", "routine": [ "paintForestClusterSeeds - paints eight small forest blobs covering the 4x2 cell block from", "column zp_93-2 to zp_93+1 and rows zp_92 to zp_92+1, walking it in the order (c,r), (c+1,r),", "(c+1,r+1), (c,r+1), (c-2,r), (c-1,r), (c-1,r+1) and finally (c-2,r+1) by fall-through. Because", "the block is four columns wide it always covers two whole 2x2 forest blocks.", "In: zp_93 = seed column, zp_92 = seed row, $0301/$0304 from placeForestClusters", "Out: forest painted; on exit zp_93 = c-2 and zp_92 = r+1 (they are not restored - the caller", " re-rolls both for the next seed)", "Called from: placeForestClusters ($73A1)" ], "line": "seed (c,r)" }, "73B0": { "unit": "game/mapGenerator6F00", "line": "-> column c+1" }, "73B2": { "unit": "game/mapGenerator6F00", "line": "(c+1,r)" }, "73B5": { "unit": "game/mapGenerator6F00", "line": "-> row r+1" }, "73B7": { "unit": "game/mapGenerator6F00", "line": "(c+1,r+1)" }, "73BA": { "unit": "game/mapGenerator6F00", "line": "-> column c" }, "73BC": { "unit": "game/mapGenerator6F00", "line": "(c,r+1)" }, "73BF": { "unit": "game/mapGenerator6F00", "line": "-> column c-1" }, "73C1": { "unit": "game/mapGenerator6F00", "line": "-> column c-2" }, "73C3": { "unit": "game/mapGenerator6F00", "line": "-> row r" }, "73C5": { "unit": "game/mapGenerator6F00", "line": "(c-2,r)" }, "73C8": { "unit": "game/mapGenerator6F00", "line": "-> column c-1" }, "73CA": { "unit": "game/mapGenerator6F00", "line": "(c-1,r)" }, "73CD": { "unit": "game/mapGenerator6F00", "line": "-> row r+1" }, "73CF": { "unit": "game/mapGenerator6F00", "line": "(c-1,r+1)" }, "73D2": { "unit": "game/mapGenerator6F00", "line": "-> column c-2, then fall through for the eighth seed (c-2,r+1)" }, "73D4": { "unit": "game/mapGenerator6F00", "routine": [ "paintForestBlobAt - grows one 4-cell forest blob at (zp_93,zp_92) if both coordinates are inside", "the 40x40 map; out-of-range coordinates (including the $FF a DEC produced at column 0) are", "silently ignored. Spread is 220/256 in both axes, so the blobs are compact and round.", "In: zp_93 column, zp_92 row, $0301 tile, $0304 flags", "Out: up to 4 forest cells; zp_A7/zp_A8 = the blob origin", "Called from: paintForestClusterSeeds (all eight seeds, $73AD-$73D2 and by fall-through)" ], "line": "seed column" }, "73D6": { "unit": "game/mapGenerator6F00", "line": "columns 0-39 only" }, "73D8": { "unit": "game/mapGenerator6F00", "line": "off the map (or wrapped to $FF by a DEC) - ignore this seed" }, "73DA": { "unit": "game/mapGenerator6F00", "line": "zp_A7 = blob origin column" }, "73DC": { "unit": "game/mapGenerator6F00", "line": "seed row" }, "73DE": { "unit": "game/mapGenerator6F00", "line": "rows 0-39 only" }, "73E0": { "unit": "game/mapGenerator6F00", "line": "off the map - ignore" }, "73E2": { "unit": "game/mapGenerator6F00", "line": "zp_A8 = blob origin row" }, "73E4": { "unit": "game/mapGenerator6F00", "line": "Y = vertical spread 220/256" }, "73E6": { "unit": "game/mapGenerator6F00", "line": "X = horizontal spread 220/256 - forest grows evenly in all directions" }, "73E8": { "unit": "game/mapGenerator6F00", "line": "A = 4 cells per seed" }, "73EA": { "unit": "game/mapGenerator6F00", "line": "grow the blob" }, "73ED": { "unit": "game/mapGenerator6F00", "line": "seed outside the map, or blob finished" }, "73EE": { "unit": "game/mapGenerator6F00", "routine": [ "applyContourTiles - draws the contour ring around a hill layer. A is the layer's interior tile", "($65 summit or $61 lower hill); zp_8E becomes its terrain class (6 or 4) and zp_91 the class of", "its ring (5 or 3). All 1600 cells are scanned in order: a cell that already holds a ring tile of", "this layer is erased to blank and re-evaluated, cells of the interior class or higher and river", "cells (class 1) are left alone, and everything else is handed to applyContourRuleAtCell. When", "that returns C = 1 it has changed a cell that earlier cells depended on, so the scan is backed up", "two columns and two rows and continues from there until the whole map is stable.", "In: A = interior tile, $0324 = contour offset (0 for $41-$54, $20 for $21-$34), contour rule", " table at $0200, terrainClassTable $077E, map", "Out: contour tiles in the map; $0312 = interior tile, zp_8E, zp_91, zp_2D/zp_2E scan position,", " zp_8C/zp_8D random-bit state, zp_21", "Called from: runMapGeneratorPasses ($6F54 with $65, $6F69 with $61)" ], "line": "$0312 = the interior tile this pass belongs to" }, "73F1": { "unit": "game/mapGenerator6F00", "line": "use the tile code as the class-table index" }, "73F2": { "unit": "game/mapGenerator6F00", "line": "its terrain class: 6 for the summit, 4 for the lower hill" }, "73F5": { "unit": "game/mapGenerator6F00", "line": "zp_8E = the 'high ground' class for the neighbour test" }, "73F7": { "unit": "game/mapGenerator6F00", "line": "zp_91 starts as the interior class..." }, "73F9": { "unit": "game/mapGenerator6F00", "line": "zp_91 = class of this layer's contour ring (5 or 3)" }, "73FB": { "unit": "game/mapGenerator6F00", "line": "clear A for the three stores below" }, "73FD": { "unit": "game/mapGenerator6F00", "line": "zp_8C = 0: force a fresh random byte on the first irregular rule" }, "73FF": { "unit": "game/mapGenerator6F00", "line": "column 0" }, "7401": { "unit": "game/mapGenerator6F00", "line": "start the scan at cell (0,0)" }, "7403": { "unit": "game/mapGenerator6F00", "block": [ "Scan every cell of the map. zp_2E/zp_2D are the cell; zp_48/49 addresses the top-left corner of", "its 3x3 block, so the cell itself is at offset $29." ], "line": "X = scan column" }, "7405": { "unit": "game/mapGenerator6F00", "line": "Y = scan row" }, "7407": { "unit": "game/mapGenerator6F00", "line": "step back one column to the block corner" }, "7408": { "unit": "game/mapGenerator6F00", "line": "address the block corner (column-1,row-1)" }, "7409": { "unit": "game/mapGenerator6F00", "line": "zp_A5 = column-1" }, "740B": { "unit": "game/mapGenerator6F00", "line": "zp_A6 = row-1" }, "740D": { "unit": "game/mapGenerator6F00", "line": "zp_48/49 -> the corner, clipped correctly for negative coordinates" }, "7410": { "unit": "game/mapGenerator6F00", "line": "offset $29 = the cell itself" }, "7412": { "unit": "game/mapGenerator6F00", "line": "the cell's terrain code" }, "7414": { "unit": "game/mapGenerator6F00", "line": "bit 7 = a unit or a river keep-clear marker - never touched" }, "7416": { "unit": "game/mapGenerator6F00", "line": "use it as the class-table index" }, "7417": { "unit": "game/mapGenerator6F00", "line": "terrain class of the cell" }, "741A": { "unit": "game/mapGenerator6F00", "line": "is it already a ring tile of this layer?" }, "741C": { "unit": "game/mapGenerator6F00", "line": "yes - erase it so the rule table can redraw it" }, "741E": { "unit": "game/mapGenerator6F00", "line": "class above the ring = hill interior or higher - leave it" }, "7420": { "unit": "game/mapGenerator6F00", "line": "class 1 = river" }, "7422": { "unit": "game/mapGenerator6F00", "line": "not the river - run the rule" }, "7424": { "unit": "game/mapGenerator6F00", "line": "river cells are never overwritten by a contour" }, "7426": { "unit": "game/mapGenerator6F00", "line": "$40 = blank" }, "7428": { "unit": "game/mapGenerator6F00", "line": "erase the stale ring tile" }, "742A": { "unit": "game/mapGenerator6F00", "line": "let the neighbourhood rule table decide what this cell becomes" }, "742D": { "unit": "game/mapGenerator6F00", "line": "C = 1: a neighbour changed, restart from the backed-up position" }, "742F": { "unit": "game/mapGenerator6F00", "line": "next column" }, "7431": { "unit": "game/mapGenerator6F00", "line": "the column just finished" }, "7433": { "unit": "game/mapGenerator6F00", "line": "columns 0-39" }, "7435": { "unit": "game/mapGenerator6F00", "line": "not at the right edge yet" }, "7437": { "unit": "game/mapGenerator6F00", "line": "next row" }, "7439": { "unit": "game/mapGenerator6F00", "line": "column 0 of the next row" }, "743B": { "unit": "game/mapGenerator6F00", "line": "back to column 0" }, "743D": { "unit": "game/mapGenerator6F00", "line": "the row just finished" }, "743F": { "unit": "game/mapGenerator6F00", "line": "rows 0-39" }, "7441": { "unit": "game/mapGenerator6F00", "line": "not at the bottom yet" }, "7443": { "unit": "game/mapGenerator6F00", "line": "the whole map is stable" }, "7444": { "unit": "game/mapGenerator6F00", "routine": [ "applyContourRuleAtCell - decides what one cell becomes, from which of its eight neighbours are", "high ground. It builds an 8-bit mask (bit 0 NW, 1 N, 2 NE, 3 W, 4 E, 5 SW, 6 S, 7 SE) of the", "neighbours whose terrain class is >= zp_8E, clears the bits that would point off the map, and uses", "the mask as the index into the 256-byte rule table at $0200 (track 18 sector 15):", " $00 leave the cell alone, C = 0", " $01-$7F paint that tile minus the contour offset $0324, with a random variant, C = 0", " $80-$8F irregular: 50% chance (bit taken from a random byte, 7 bits per byte) to erase the", " neighbour named by the low 3 bits when it is of the interior class; otherwise fill", " the cell with the interior tile. Either way C = 1", " $90-$FE same 50% erase attempt, but if it does not fire the cell is left alone, C = 0", " $FF fill the cell with the interior tile $0312, C = 1", "C = 1 also backs the scan position zp_2E/zp_2D up by two columns and two rows (floored at 0) so", "applyContourTiles re-examines the cells around the change.", "In: zp_2E/zp_2D = the cell, zp_48/49 -> its 3x3 block corner, zp_8E interior class, $0312", " interior tile, $0324 contour offset, rule table $0200, terrainClassTable $077E", "Out: C flag, map cells changed, zp_2D/zp_2E, zp_21 mask, zp_18 rule value, zp_8C/zp_8D random bits", "Called from: applyContourTiles ($742A)" ], "block": [ "Build the high-ground neighbour mask, bit 7 (SE) down to bit 0 (NW)." ], "line": "clear the neighbour mask" }, "7446": { "unit": "game/mapGenerator6F00", "line": "zp_21 = neighbour mask" }, "7448": { "unit": "game/mapGenerator6F00", "line": "walk the eight neighbours backwards: 7 = SE .. 0 = NW" }, "744A": { "unit": "game/mapGenerator6F00", "line": "offset of neighbour X from the block corner" }, "744D": { "unit": "game/mapGenerator6F00", "line": "that neighbour's terrain code" }, "744F": { "unit": "game/mapGenerator6F00", "line": "bit 7 = unit or keep-clear marker - not high ground" }, "7451": { "unit": "game/mapGenerator6F00", "line": "use it as the class-table index" }, "7452": { "unit": "game/mapGenerator6F00", "line": "terrain class of the neighbour" }, "7455": { "unit": "game/mapGenerator6F00", "line": "high ground = class >= the interior class of this pass" }, "7457": { "unit": "game/mapGenerator6F00", "line": "lower - leave the bit clear" }, "7459": { "unit": "game/mapGenerator6F00", "line": "mask built so far" }, "745B": { "unit": "game/mapGenerator6F00", "line": "bit X: NW,N,NE,W,E,SW,S,SE = bits 0-7" }, "745E": { "unit": "game/mapGenerator6F00", "line": "zp_21 = mask so far" }, "7460": { "unit": "game/mapGenerator6F00", "line": "next neighbour" }, "7461": { "unit": "game/mapGenerator6F00", "line": "all eight neighbours" }, "7463": { "unit": "game/mapGenerator6F00", "block": [ "Clear the mask bits that point off the edge of the 40x40 map." ], "line": "the cell's own column" }, "7465": { "unit": "game/mapGenerator6F00", "line": "its row" }, "7467": { "unit": "game/mapGenerator6F00", "line": "the raw mask" }, "7469": { "unit": "game/mapGenerator6F00", "line": "on the left edge?" }, "746B": { "unit": "game/mapGenerator6F00", "line": "not on the left edge" }, "746D": { "unit": "game/mapGenerator6F00", "line": "$D6 clears bits 0/3/5 = NW, W, SW" }, "746F": { "unit": "game/mapGenerator6F00", "line": "on the right edge (column 39)?" }, "7471": { "unit": "game/mapGenerator6F00", "line": "not on the right edge" }, "7473": { "unit": "game/mapGenerator6F00", "line": "$6B clears bits 2/4/7 = NE, E, SE" }, "7475": { "unit": "game/mapGenerator6F00", "line": "on the top edge?" }, "7477": { "unit": "game/mapGenerator6F00", "line": "not on the top edge" }, "7479": { "unit": "game/mapGenerator6F00", "line": "$F8 clears bits 0/1/2 = NW, N, NE" }, "747B": { "unit": "game/mapGenerator6F00", "line": "on the bottom edge (row 39)?" }, "747D": { "unit": "game/mapGenerator6F00", "line": "not on the bottom edge" }, "747F": { "unit": "game/mapGenerator6F00", "line": "$1F clears bits 5/6/7 = SW, S, SE" }, "7481": { "unit": "game/mapGenerator6F00", "line": "zp_21 = the clipped mask" }, "7483": { "unit": "game/mapGenerator6F00", "line": "use it as the rule-table index" }, "7484": { "unit": "game/mapGenerator6F00", "block": [ "Look the neighbourhood up in the 256-byte contour rule table loaded to $0200 from track 18", "sector 15." ], "line": "rule byte for this exact neighbourhood" }, "7487": { "unit": "game/mapGenerator6F00", "line": "$00 = this neighbourhood needs no contour - leave the cell (C = 0)" }, "7489": { "unit": "game/mapGenerator6F00", "line": "$01-$7F = a contour tile code - paint it" }, "748B": { "unit": "game/mapGenerator6F00", "line": "$FF = the cell is surrounded, fill it with the hill interior" }, "748D": { "unit": "game/mapGenerator6F00", "line": "fill the cell with the interior tile and force a rescan" }, "748F": { "unit": "game/mapGenerator6F00", "line": "$80-$FE: irregular rule; zp_18 keeps the value" }, "7491": { "unit": "game/mapGenerator6F00", "line": "any random bits left in zp_8D?" }, "7493": { "unit": "game/mapGenerator6F00", "line": "yes" }, "7495": { "unit": "game/mapGenerator6F00", "line": "seven bits per random byte: counter 6 down through 0" }, "7497": { "unit": "game/mapGenerator6F00", "line": "seven bits are taken from each random byte" }, "7499": { "unit": "game/mapGenerator6F00", "line": "fetch a fresh batch of random bits" }, "749C": { "unit": "game/mapGenerator6F00", "line": "zp_8D = fresh random bits" }, "749E": { "unit": "game/mapGenerator6F00", "line": "shift out the next bit" }, "74A0": { "unit": "game/mapGenerator6F00", "line": "bit clear - do not erase a neighbour this time" }, "74A2": { "unit": "game/mapGenerator6F00", "line": "the rule value" }, "74A4": { "unit": "game/mapGenerator6F00", "line": "low 3 bits of the rule value = which neighbour it wants removed" }, "74A6": { "unit": "game/mapGenerator6F00", "line": "neighbour index 0-7" }, "74A7": { "unit": "game/mapGenerator6F00", "line": "its offset from the block corner" }, "74AA": { "unit": "game/mapGenerator6F00", "line": "that neighbour's terrain code" }, "74AC": { "unit": "game/mapGenerator6F00", "line": "unit or marker - leave it alone" }, "74AE": { "unit": "game/mapGenerator6F00", "line": "use the terrain code as the class-table index" }, "74AF": { "unit": "game/mapGenerator6F00", "line": "terrain class of that neighbour" }, "74B2": { "unit": "game/mapGenerator6F00", "line": "only a cell of the interior class may be nibbled away" }, "74B4": { "unit": "game/mapGenerator6F00", "line": "not a cell of the hill interior - leave it alone" }, "74B6": { "unit": "game/mapGenerator6F00", "line": "$40 = blank" }, "74B8": { "unit": "game/mapGenerator6F00", "line": "erase the neighbour - this is what makes hill edges irregular" }, "74BA": { "unit": "game/mapGenerator6F00", "line": "C = 1 and back the scan up" }, "74BD": { "unit": "game/mapGenerator6F00", "line": "the rule value again" }, "74BF": { "unit": "game/mapGenerator6F00", "line": "rule values $90-$FE..." }, "74C1": { "unit": "game/mapGenerator6F00", "line": "...leave the cell untouched when the erase did not fire (C = 0)" }, "74C3": { "unit": "game/mapGenerator6F00", "line": "values $80-$8F (and $FF): fill the cell with the hill interior tile" }, "74C6": { "unit": "game/mapGenerator6F00", "line": "write it into the centre cell" }, "74C9": { "unit": "game/mapGenerator6F00", "block": [ "A cell changed under the scan: back up two columns and two rows so applyContourTiles", "re-evaluates the neighbourhood, and return C = 1." ], "line": "current scan column" }, "74CB": { "unit": "game/mapGenerator6F00", "line": "prepare the subtract" }, "74CC": { "unit": "game/mapGenerator6F00", "line": "two columns back" }, "74CE": { "unit": "game/mapGenerator6F00", "line": "still positive" }, "74D0": { "unit": "game/mapGenerator6F00", "line": "but never before column 0" }, "74D2": { "unit": "game/mapGenerator6F00", "line": "zp_2E = backed-up scan column" }, "74D4": { "unit": "game/mapGenerator6F00", "line": "current scan row" }, "74D6": { "unit": "game/mapGenerator6F00", "line": "prepare the subtract" }, "74D7": { "unit": "game/mapGenerator6F00", "line": "two rows back" }, "74D9": { "unit": "game/mapGenerator6F00", "line": "still positive" }, "74DB": { "unit": "game/mapGenerator6F00", "line": "but never before row 0" }, "74DD": { "unit": "game/mapGenerator6F00", "line": "zp_2D = backed-up scan row" }, "74DF": { "unit": "game/mapGenerator6F00", "line": "C = 1: applyContourTiles restarts its scan here" }, "74E0": { "unit": "game/mapGenerator6F00", "line": "C = 1 set at $74DF" }, "74E1": { "unit": "game/mapGenerator6F00", "line": "prepare the subtract" }, "74E2": { "unit": "game/mapGenerator6F00", "line": "tile = rule value - $0324: offset 0 keeps $41-$54, offset $20 gives $21-$34" }, "74E5": { "unit": "game/mapGenerator6F00", "line": "offset $29 = the cell itself" }, "74E7": { "unit": "game/mapGenerator6F00", "line": "pick a random variant of the tile (Y is preserved)" }, "74EA": { "unit": "game/mapGenerator6F00", "line": "paint the contour tile" }, "74EC": { "unit": "game/mapGenerator6F00", "line": "C = 0: the scan carries on normally" }, "74ED": { "unit": "game/mapGenerator6F00", "line": "C = 0 set at $74EC" } }, "dataTypes": { "6F00": [ "byte", 4 ], "71AB": [ "byte", 5 ] }, "zpComments": { "1D": "general scratch: bounds mode flag of computeGroupBounds (bit 7 = use destinations), division remainder (hi); the map generator holds the candidate row of the hill site being placed", "1E": "general scratch: running terrain height in the line-of-sight walk, decimal digit index, group destination centre column; the map generator counts the column attempts left for a hill site", "1F": "general scratch: line-of-sight rise flag, divide bit counter, group destination centre row; the map generator remembers which candidate row a hill site started on", "28": "map row of point B (the centre/reference point) for distanceSquared and cellDistance; the map generator reuses it as the highest valid index of the hill row-candidate list $0325", "29": "index of the last entry written to the area-scan result lists at $0400/$0432/$0464 ($FF = empty); the map generator reuses it as the current index into the hill row-candidate list $0325", "8E": "line stepper: length of the line along its major axis, max(|dRow|,|dCol|); the contour passes reuse it as the terrain class that counts as high ground (6 summit, 4 lower hill)", "91": "line stepper: steps still to walk (0 = finished); returned in A by initLineStepper/stepLine; the contour passes reuse it as the terrain class of the ring being redrawn (5 or 3)", "B3": "high byte of glyphPtr; growTerrainBlob reuses it as the count of cells painted so far", "A5": "map column of the left edge of the 7x5 battlefield view (may be negative); the cursor cell is viewOriginCol+3; the map generator reuses it as the column of the cell being painted or scanned", "A6": "map row of the top edge of the battlefield view; the cursor cell is viewOriginRow+2; the map generator reuses it as the row of the cell being painted or scanned" } }