The 42 token programs were the last undecoded part of MUSCLE. Each now carries a token-by-token listing above its unchanged .byte data, generated by _tools/bytecode_dis.py and wired into the build as 'make pass3'. Encoding, derived from RunBytecodeInterpreter ($9AE8) and BytecodeHandlerTable ($9237): the dispatch is one byte per element. A byte in $C8-$EF selects one of the 40 handler-table entries; every other byte takes the literal path at $9B08 and is pushed onto the operand list at $0033[Y], accumulated into $003C[Y]. The one exception is four opcodes whose handler's first instructions are 'lda ($1A),Y / iny', so they consume the following byte inline: $CB LOOP_BEGIN -> $7C,X count + $7E,X body address $D1 SET_RATE -> $43,X $D7 DRAW_SPRITE -> count for the $A660 blit $E1 SET_WAIT -> $7A,X $CB and $C9 are the loop pair: LOOP_END decrements $7C,X and, if non-zero, reloads Y from $7E,X, rewinding the interpreter to the top of the body. Decoded 377 opcodes and 937 literal operands across 42 programs; all 40 defined opcodes are used, so the opcode set is complete. Two standalone programs contain no byte in $C8-$EF at all, so every byte takes the literal path - the listing states that rather than implying code. Each mnemonic was read off its handler's own straight-line path up to its first 'jmp $9AE8' / 'jmp $9B25'. Handlers that only tail-call a game routine are named for the routine rather than guessed at, since the semantics live in the callee. bytecode_dis.py inserts comment lines only; .byte data is copied through verbatim. Verified: all 16,384 PRG bytes still emitted exactly once, every value equal to the ROM, zero audit mismatches, and 'make regen' (pass1 -> pass2 -> pass3) reproduces prg.s byte-for-byte. Byte-identical ROM verified. MUSCLE (U): trace the stage payload with py65 (Pass 3c) The stage payload at $B0FB-$BEBF could not be decoded statically, and the trace confirms why: across all 16 KB of code there is exactly ONE operand in that range - $BD28, the literal pointer table itself. The real address is formed at runtime by 'adc $BD28,X', where A is a value carried in the bytecode stream, so the readers are indexed by a runtime value and cannot be enumerated by searching the code. FCEUX cannot observe this either: its Lua API offers registerexec / registerexecute / registerrun / registerwrite but no memory-read hook, and with no static list of readers there is nothing to hook. _tools/trace_stage_payload.py therefore uses py65's ObservableMemory.subscribe_to_read, which fires on every read of a range and can report PC from inside the hook. py65 is only a 6502 core, so the tracer adds the minimum hardware to boot the game: a scanline counter off processorCycles, $2002 vblank at scanline 241 cleared on read, NMI at the same scanline, $4014 OAM DMA, and the $2005/$2006/$2007 latches. Without NMI the game never leaves $80E0 (lda $0321 / beq), because $0321 is the flag the bytecode VM raises. Results over 300 frames (26.8M cycles, 4,071 NMIs): 2,548 payload reads from 44 distinct reader PCs, touching 914 of 3,421 bytes. Findings: - The hottest reader is $AC82, the compressed-VRAM RLE decoder: 1,046 of its 1,128 reads advance by exactly +1, comparing each byte against $C0. - $9B50 is a backward copy (lda ($12),Y / sta ($10),Y / dey), stepping -1. - 107 distinct 8-byte blocks had all eight bytes read, with spacing dominated by $08 - a dense 8-byte record array - plus a sparser group on a $D0 stride ($BBE0, $BCB0, $BD80, $BE50). - Readers use three disciplines: forward sequential, backward sequential, and variable stride consistent with a fixed-offset field walk. py65 is deliberately NOT a build dependency: the tool documents unpacking the wheel on demand. 'make regen' is unaffected. Byte-identical ROM verified. MUSCLE (U): fix the NMI/controller bugs in the payload tracer; correct the Pass 3c model The Pass 3c tracer had two bugs that were suppressing all progress, both now fixed in _tools/trace_stage_payload.py (previously scratch, now durable): * NMI re-armed by $2002 reads. The vblank flag must be cleared once per frame, not on every read of $2002 -- the main loop polls $2002 and spins on the bytecode VM flag at $8226, so each poll cleared bit 7 and re-armed NMI inside the same scanline. That gave 40,900 NMIs across 3,000 frames and corrupted all game state. A per-frame nmi_fired flag restores exactly one NMI per frame (verified: 600 frames -> 600 NMIs). * Input went to $4017. The poll routine at $AA69 is `lda $4016,X` with X=1 and only compares bits 0-1, so driving $4017 consumed nothing -- all masks tested gave byte-identical traces. The game consumes joy1 on $4016 and needs a real latch/shift register. With it, START matters: 47.7% coverage vs 39.0%. Match entry is two discrete START presses (title -> char select -> match). Coverage 26.3% -> 40.9%. Both bugs and the port subtlety are documented in the tool header so they are not re-derived. Corrects the Pass 3c conclusion. $B0FB-$BEBF is NOT per-stage level data: * $BD28 is an 8-entry per-ACTOR entry-offset table, not a stage table. $A063 `adc $BD28,X` with X = ActorIndex ($1E), plus #$32 at $A071 when PlayerActiveFlag ($78,X) is set. Observed actors are $00-$04. Forcing all 8 actor indices adds zero new bytes. * The sound engine reads the same window: $B03C `lda (SoundReadPointerLo),Y` with `cmp #$F0 / sbc #$F0 / tay / lda $B0E3,y` is note decoding, which is where the $FF/$F0 high-nibble terminators come from. So the window is a shared pool -- per-actor bytecode, compressed-VRAM RLE, and music note streams -- and stage cycling cannot raise coverage past ~40%. The remaining 2,161 B need other music tracks and scripted match play, not taps. Also corrects two stale claims: $0326 is not a level byte (never leaves $00 even in a confirmed match), and $0320 is a boolean, not a screen-state machine. Build unaffected: byte-identical, and `make regen` still reproduces prg.s byte-for-byte. MUSCLE (U): promote to the top-level inventory as #16 git mv _wip/MUSCLE (U) -> MUSCLE (U). The relative symlink copilot/rom.nes -> ../M.U.S.C.L.E. (U).nes survives the move untouched. * copilot/Makefile: tool paths ../../../_tools/ -> ../../_tools/ for NESDIS, PASS2 and BYTECODE. `make` prints the byte-identity message and `make regen` still reproduces prg.s byte-for-byte, both verified after the move. * MUSCLE (U)/OVERVIEW.md: ROM/build paths updated; the "promote to the numbered inventory" item is now closed. * Root OVERVIEW.md: added as #16, removed from the _wip skeleton table (20 -> 19), added a ### 16 detail section, and its vector/mapping notes moved out of the skeleton section. All 16 top-level projects verified byte-identical. Add Pass 1 verification tool; teach nesdis.py the undocumented opcodes _tools/verify_pass1.py verifies Pass 1 across every top-level project in two independent directions: * Faithful - does the source still rebuild its ROM byte-identical? * Complete - does the committed source claim as much code as a fresh trace can actually reach? The second is the one that catches real problems. A project can reproduce all 16,384 bytes perfectly while calling 95% of them data, because the tracer gave up early. Instruction *counts* are compared rather than bytes, so the check is independent of comment style (which is not uniform across the repo). Result: all 16 projects are faithful, and Joypad Test Cartridge is the only truncated Pass 1 -- 282 committed instructions against 1,773 reachable. nesdis.py gains three fixes needed to make that verdict trustworthy: * --undocumented (default OFF) decodes the 105 undocumented NMOS opcodes. They are used as NOP padding and as real RMW ops, and a tracer that halts on them loses most of the code: Joypad goes 580 -> 3,846 code bytes. Default off so MUSCLE's `make regen` still reproduces prg.s byte-for-byte. * Undocumented opcodes are emitted as explicit `.byte` with the disassembly in the comment. ca65 V2.19 implements none of them, so they cannot be written as mnemonics; keeping them in the code region preserves the code/data split and the audit trail. Official 0xEA NOP still encodes normally. * Two latent bugs, both now reachable: - RESET and IRQ are commonly the same address, and the semantic-name map was overwriting, renaming the primary entry point to `IrqHandler`. Now setdefault, in RESET/NMI/IRQ priority order. - render() stamped every branch operand as Label_XXXX and never reconciled it with the semantic name map, so a branch into a named routine emitted a label that was never defined and the file would not assemble. Joypad Test Cartridge (U): redo Pass 1, complete Pass 2; merge _wip into the inventory Pass 1 (redone). The committed split claimed 282 instructions / 580 bytes (3.5%). The tracer halted at $C09E on `DCP $3C20` ($CF) -- an undocumented opcode used as ordinary code -- and filed 3,256 bytes of real code as `.byte` data. Now 1,773 instructions / 3,836 bytes (23.4%), a 6.6x increase. Verified against a fresh trace: 1,769 emitted instructions + 4 undocumented opcodes written as explicit bytes = 1,773, an exact match. Byte accounting stays exact at 3,836 + 12,548 = 16,384. ca65 V2.19 implements none of the undocumented opcodes, so the 4 affected instructions (DCP $3C20, LAX $20D4, NOP $C1,X, RRA ($D0),X) are emitted as explicit `.byte` with the disassembly in the comment. They stay in the code region, so the split and the audit trail are both preserved. Pass 2 (complete). All 202 labels renamed; zero `Label_Cxxxx` remaining. Renames are keyed by address and verified to have bound to the intended address, not just to some address. 202 routine headers, every one describing real behaviour -- no "undetermined in Pass 1" boilerplate left. `locals.inc` carries 99 aliases, the proven semantic ones sitting beside the generated `ZpXX` entries per the alias pattern in AGENTS.md. Two naming errors in the previous draft are corrected: $55 is MarkerValue (it holds $70/$88/$A0 and is compared against them), not a "P1 Down timer"; and the twelve MarkerVar variables are named by position because which player/button each belongs to is not established. Pass 3 is now outstanding, and the old Pass 3 was wrong: it described $C09E-$C173 and $C17F-$CCF6 as data, and both are code. After the redo there is exactly one data region, $CF06-$FFFF, confirmed by orphan scan. Documentation. The root inventory now lists all 36 projects in one table -- the 20 `_wip/` projects are rows 17-36 rather than a second table that could drift. That second table had wrong mirroring for 12 of them (Duck Hunt, Golf, Hogan's Alley, Ice Climber, DK Jr Math, Lode Runner, Lunar Pool, Mario Bros, Millipede, Pyramid, Raid [a2], Urban Champion were all recorded H when they are V, and vice versa); every value is now read from the ROM rather than trusted. Build status is split into two honest tiers: rows 1-16 are BYTE-IDENTICAL and compare the whole ROM, rows 17-36 are PRG-IDENTICAL because their Makefiles only run `cmp reconstructed_prg.bin prg.bin`. Header and CHR are not proven for those. All 36 build cleanly; the WIP count was also corrected from 19 to 20. `_tools/verify_pass1.py` checks all 36 and reports none truncated. Mario Bros (JU): Pass 1 disassembly, 14.6% -> 72.2% code The skeleton prg.s was a 12-line .incbin of the whole PRG. It is now a real disassembly: 5,735 instructions, 11,829 code bytes (72.2%), 937 labels and routine headers, byte accounting exact at 11,800 + 4,584 = 16,384, and BYTE-IDENTICAL against prg.bin. Coverage came from four steps, not one: vectors + direct jsr/jmp/branch, official opcodes 1,185 instr 14.6% --undocumented (105 extra NMOS opcodes) 1,210 instr 14.9% --auto-seed (61 table-referenced entries) 4,187 instr 51.1% --extra-seed 0xC0B6,0xC5A3 5,735 instr 72.2% Almost everything sits behind computed dispatch. Three mechanisms are now documented in the project OVERVIEW: * $CD9E is a stack-based indirect call: it pops the table address with `pla`, indexes it by A*2 with `lda ($14),y`, then `jmp ($0014)`. Because the pointer arrives on the stack it cannot be followed statically from the dispatcher. * $C5A3 is a 20-entry table of `JSR` thunks ending in `rts`. Probing it linearly gives twenty valid targets, and seeding it recovers most of the last 21%. * $C0B6 is the NMI phase dispatcher, reachable only by computed dispatch. Two overlapping-decode bugs in _tools/nesdis.py had to be fixed first: * Control-flow targets must win over fall-through. `bne` at $C4BA targets $C528, but the fall-through path had decoded $C527 as a 2-byte `NOP #$A5` whose operand swallowed $C528. No assembler branches into the middle of an instruction, so the spanning decode is now dropped in favour of the target; its bytes fall out as data, leaving byte accounting unchanged. * Branch targets inside a surviving instruction must be pruned from the target set. Otherwise emit_code's linear walk consumes those bytes as an operand, so the label is referenced but never defined and the file does not assemble at all -- `Error: Symbol 'Label_C528' is undefined`. Neither change disturbs an existing pipeline: MUSCLE's `make regen` still reproduces prg.s byte-for-byte, Joypad Test Cartridge still builds byte-identical, and _tools/verify_pass1.py reports all 16 top-level projects faithful with none truncated. Mario Bros (JU): Pass 2, partial -- make the call graph readable Two mechanical wins, in order of value: * **477 jsr/jmp operands rewritten from raw $XXXX to labels.** The tracer emits call and jump targets as hex, so the call graph was unreadable -- the most called routine appeared as `jsr $CCA0` 14 times over. Every one of those sites already had a label at its target address, so the substitution is purely mechanical and byte-preserving. Zero raw hex call operands remain. * **13 landmark routines named** from verified instruction evidence: WaitVblank1, ClearRamPageLoop, NmiPhaseDispatch ($C0B6), JsrThunkTable ($C5A3), DispatchViaStackPointer ($CD9E), AdvanceDispatchPointer ($CDB4), PushTablePointerDispatch ($CCA0), DispatchTableF393 ($CAB9), InitSpritesOffscreen ($DFC4), AdjustDecimalColumns ($D15A), TestRamFlagPair0500 ($D328), NextIndex ($CE84). **922 labels remain unnamed, and that is recorded as the honest state** rather than papered over. They sit 15-25 per page across $CC00-$CFFF, which is just the game logic: naming them means reading ~5,700 instructions across 935 routines. Guessing from the call graph and the NES convention would be exactly the guessy rewrite PROMPTS.md rules out. The productive next step is more reach, not more naming. The 4,555 unreached bytes are where most unnamed routines live, and they are gated behind the stack-pointer dispatch at $CD9E, whose pushed table addresses are only known in the callers' frames. Still BYTE-IDENTICAL; all 16 top-level projects remain faithful. Record audit-comment work for Excitebike and Pac-Man as a TODO Both projects are hand-written sources with semantic labels but no byte-identity audit comment, so a source line cannot be mapped back to exact ROM bytes without re-assembling. Every other project in the repo carries one. Documented what was tried and why it was dropped rather than left implicit. Addresses from 'ca65 -l' work fine -- the listing offset indexes prg.bin directly -- but the listing carries no source line numbers, so entries cannot be keyed back to source lines. Byte values also have to come from prg.bin rather than the listing, since ca65 prints 'rr rr' for relocatable words. No tool was committed, because the one written does not work. Both projects verified still byte-identical; no source file was changed. Add TODO.md handoff; bring AGENTS.md back in line with the repo AGENTS.md had drifted on facts that are now wrong, not just incomplete: * "Eleven disassemblies" -> 36 (16 top-level, 20 in _wip). The index it points at had the same stale count. * The audit-comment convention was stated as `; PRG:$xxxx AA BB`, but the dominant spelling is `; CPU:$xxxx PRG:xxxx AA BB` and five other variants are in use, with Excitebike and Pac-Man carrying none at all. Now stated accurately as "preserve whatever spelling a file uses", with the gap pointed at. * `_tools/` was described as holding splitnes.py and chr2gif.py. It holds six tools now, including the Pass 1 tracer and the verifier. * ROM filenames "contain spaces" -> spaces *and parentheses*, which is also what makes FCEUX hang headless. Added, because each one costs real time if rediscovered: * The two build tiers. The 20 _wip projects only `cmp reconstructed_prg.bin prg.bin`, so their header and CHR are NOT proven -- calling them byte-identical to the ROM is wrong. * A promotion procedure, since that has now been done twice. * A tracer/toolchain gotchas section: undocumented opcodes truncating traces (and ca65 being unable to encode them), vectors living at the end of the PRG rather than in the iNES header, the RESET==IRQ name collision, control-flow targets beating fall-through, the branch-target pruning that stops a file failing to assemble, NMI firing once per frame rather than per $2002 read, joy1 being $4016, and ca65 listings carrying no source line numbers. TODO.md is the handoff document: open work per project with enough detail to resume, the residue counts, and the reasoning behind each abandoned approach so it is not silently retried. Nothing rebuilt or changed; all projects still verify. Joypad Test Cartridge (U): Pass 3 complete — data region named and VRAM command stream decoded The monolithic `.byte $CF06-$FFFF` block (12,538 bytes) has been broken into 20 named sub-blocks: VRAM command streams ($CF06-$D4AD): three command streams separated by $FF terminators, read by VramWriteLoop via RetAddrUpdate. Opcode set decoded: $4C = jump, $60 = deferred PPUCTRL, bit-7-clear = VRAM write (PPU addr + data, bit 6 of data = long/short selector). OAM tables ($D4E3-$D6A3): 12 groups of 32-byte tables (8 entries of Y/tile/attr/X), read by CopyOamFromTable ($D4E3) and CopyOamFromTable70 ($D5C4). Sprite templates ($D6A5-$D6E4): sprite template read by CopySpriteTemplateTable ($D6A5) and button OAM template read by PrepareButtonOam ($D6C5). Padding: $FF ROM padding ($D6E5-$FFF9) and vectors ($FFFA-$FFFF). OVERVIEW.md updated: section 8 documents all 20 sub-blocks with the VRAM command stream format and OAM table structure; section 11 marks Pass 3 complete with remaining work (MarkerVar player/button mapping, HandleButtonPress sprite order). Build verified byte-identical. Root OVERVIEW.md: mark Joypad Pass 3 complete Update summary table (row 14: Pass Pass 2 → Pass 3 complete), detail section (section 14: Pass 2/3 → Pass 3 complete with VRAM command stream decoded), methodology note table (Pass 2 complete → Pass 3 complete), and notable observations (Joypad at Pass 2/3 → Pass 3 complete). Joypad Test Cartridge is now fully Pass 3 complete: all 20 data sub-blocks named, VRAM command stream opcode set decoded, OAM table structure documented. TODO.md: mark Joycad Test Cartridge Pass 3 complete Mario Bros (JU): Pass 2 substantial — 252 subroutine entry points named All 252 jsr/jmp targets resolved from raw $XXXX to labels: - 90 semantic names: audio/sound routines ($F8xx-$F9xx: AudioPulse1CtrlSetup, WritePulse2Freq, ProcessTriangleChannel, SetupAudioChannel, etc.), gameplay helpers (CheckZpB3Return, CheckRangeReturn012, ToggleZpFC_Bit3, etc.) - 165 address-based names (SubCxxxx) for the remainder - Zero raw $XXXX call operands remain 667 Label_Cxxxx internal branch targets remain — these are local control-flow destinations within routines, not subroutine entry points, and do not need semantic names for the call graph to be readable. Build verified BYTE-IDENTICAL. Root OVERVIEW.md updated (row 26: Pass 0 skeleton → Pass 1 complete, Pass 2 substantial). TODO.md updated. Lunar Pool (U): Pass 1 complete, 57.8% code; nesdis.py opcode/emitter fixes The skeleton prg.s was a 12-line .incbin of the whole PRG. It is now a real disassembly: 4,586 instructions, 9,475 code bytes (57.8%), 6,909 data bytes, byte accounting exact at 9,403 + 6,981 = 16,384, BYTE-IDENTICAL. Coverage: vectors + direct jsr/jmp/branch reached 1,259 instructions (15.6%). --undocumented took it to 4,572 (57.6%), and --auto-seed (48 table-referenced entries) plus --extra-seed 0xE80C (the non-$C000 RESET vector) took it to 4,586 (57.8%). Three undocumented opcodes were missing from nesdis.py and are added: * $72 RRA abs (the RRA family was missing the $72 absolute form) * $42 NOP #imm (the NOP-immediate family was missing $42) * $FA NOP abs,X (the NOP-abs,X family was missing $FA) One emitter fix: ca65 silently rewrites an operand whose high byte is $00 in the shorter zero-page form -- `sta $00FF,x` assembles as `sta $FF,x` ($95 instead of $9D). render() now emits the `a:` prefix for ABS/ABSX/ABSY/IND operands with a high byte of $00, forcing the absolute form so the emitted bytes match the ROM. operand_value() strips the prefix when parsing. These changes are general and verified not to disturb existing pipelines: MUSCLE's `make regen` still reproduces prg.s byte-for-byte. Remaining gaps: 6,909 bytes (42.2%) still data, gated behind jmp ($7961) at three sites (RAM-pointer dispatch; the blocks after them hold the screen text "strings" "game over" and "hi`score__") and stack-based dispatch at $CBDC -- the same pattern as Mario Bros (JU)'s $CD9E. TODO.md: add Lunar Pool as an open item Adds comments for all lines to Pacman and Excitebike Moves Pacman 'locals' and 'symbols' definitions into the right places
14333 lines
301 KiB
Plaintext
14333 lines
301 KiB
Plaintext
;----------------------------------------------------
|
|
; NES Specific
|
|
;----------------------------------------------------
|
|
|
|
; PPU registers
|
|
PPUCTRL = $2000
|
|
PPUMASK = $2001
|
|
PPUSTATUS = $2002
|
|
OAMADDR = $2003
|
|
OAMDATA = $2004
|
|
PPUSCROLL = $2005
|
|
PPUADDR = $2006
|
|
PPUDATA = $2007
|
|
OAMDMA = $4014
|
|
JOY1 = $4016
|
|
|
|
APUPC1BASE = $4000
|
|
APUPC1SWEEP = $4001
|
|
APUPC1TLOW = $4002
|
|
APUPC1THIGH = $4003
|
|
|
|
APUPC2BASE = $4004
|
|
APUPC2SWEEP = $4005
|
|
APUPC2LOW = $4006
|
|
APUPC2HIGH = $4007
|
|
|
|
APUTRIBASE = $4008
|
|
APUTRILOW = $400A
|
|
APUTRIHIGH = $400B
|
|
|
|
APUNOISEBASE = $400C
|
|
APUNOISELOOP = $400E
|
|
APUNOISELENGTH = $400F
|
|
|
|
APUDMABASE = $4010
|
|
APUDMALOAD = $4011
|
|
APUDMAADDR = $4012
|
|
APUDMALEN = $4013
|
|
|
|
APUCTRL = $4015
|
|
APUSTATUS = $4015
|
|
APUFRAMECNT = $4017
|
|
|
|
|
|
PAD_RIGHT=$01
|
|
PAD_LEFT=$02
|
|
PAD_DOWN=$04
|
|
PAD_UP=$08
|
|
PAD_START=$10
|
|
PAD_SELECT=$20
|
|
PAD_B=$40
|
|
PAD_A=$80
|
|
PAD_HORIZONTAL=PAD_LEFT|PAD_RIGHT
|
|
PAD_VERTICAL=PAD_UP|PAD_DOWN
|
|
PAD_DPAD=PAD_HORIZONTAL|PAD_VERTICAL
|
|
PAD_MENU_INPUT=PAD_SELECT|PAD_START|PAD_VERTICAL
|
|
|
|
;----------------------------------------------------
|
|
; Pacman Specific
|
|
;----------------------------------------------------
|
|
|
|
NmiHandlerOffset = $C10E
|
|
ResetOffset = $C033
|
|
IrqHandlerOffset = $C17E
|
|
|
|
;==============================================================================
|
|
; Zero Page
|
|
;==============================================================================
|
|
|
|
;------------------------------------------------------------------------------
|
|
; General work pointers / scratch
|
|
;------------------------------------------------------------------------------
|
|
|
|
workPtr0 = $00
|
|
workPtr1 = $02
|
|
|
|
workValue0 = $04
|
|
workValue1 = $05
|
|
workValue2 = $06
|
|
workValue3 = $07
|
|
workValue4 = $08
|
|
workValue5 = $09
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Maze pathfinding / direction selection workspace
|
|
;------------------------------------------------------------------------------
|
|
|
|
pathCompareValue = $0A
|
|
pathFallbackValue = $0B
|
|
legalDirections = $0C
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Indirect dispatcher vector
|
|
;------------------------------------------------------------------------------
|
|
|
|
dispatchVector = $10
|
|
|
|
;------------------------------------------------------------------------------
|
|
; 16-bit arithmetic workspace
|
|
;------------------------------------------------------------------------------
|
|
|
|
arithmeticValue = $12
|
|
arithmeticOperand = $14
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Actor fixed-point/motion records
|
|
;
|
|
; Each actor record occupies four bytes.
|
|
;------------------------------------------------------------------------------
|
|
|
|
pacmanMotion = $1A
|
|
ghost1Motion = $1E
|
|
ghost2Motion = $22
|
|
ghost3Motion = $26
|
|
ghost4Motion = $2A
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Pac-Man maze targeting
|
|
;------------------------------------------------------------------------------
|
|
|
|
pacmanTargetRow = $2E
|
|
pacmanTargetColumn = $30
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Sprite/animation selection
|
|
;------------------------------------------------------------------------------
|
|
|
|
pacmanSpriteFrame = $32
|
|
ghostSpriteFrames = $33
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Ghost direction/control state
|
|
;------------------------------------------------------------------------------
|
|
|
|
ghostDirectionFlags = $39
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Main gameplay state
|
|
;------------------------------------------------------------------------------
|
|
|
|
gameState = $3F
|
|
|
|
;------------------------------------------------------------------------------
|
|
; PPU / player-screen state
|
|
;------------------------------------------------------------------------------
|
|
|
|
ppuCtrlShadow = $43
|
|
|
|
cocktailModeFlag = $46
|
|
activePlayerFlag = $47
|
|
gameplaySuspended = $48
|
|
|
|
frameCounter = $4B
|
|
stateTimer = $4C
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Input / Pac-Man movement
|
|
;------------------------------------------------------------------------------
|
|
|
|
currentInput = $4D
|
|
newlyPressedInput = $4E
|
|
previousInput = $4F
|
|
|
|
pacmanRequestedDirection = $50
|
|
pacmanDirection = $51
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Score / round / maze progression
|
|
;------------------------------------------------------------------------------
|
|
|
|
highScoreDigits = $61
|
|
|
|
roundNumber = $67
|
|
roundDisplayValue = $68
|
|
|
|
pelletsRemaining = $6A
|
|
extraLifeAwarded = $6B
|
|
|
|
actorStatusDisplay = $6C
|
|
|
|
playerScoreDigits = $70
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Audio Engine
|
|
;------------------------------------------------------------------------------
|
|
audioRequestPtr = $F0
|
|
audioChannelTablePtr = $F2
|
|
audioSequenceTablePtr = $F4
|
|
audioWorkPtr = $F6
|
|
audioWorkValue = $F7
|
|
audioChannelFlags = $F8
|
|
audioRequestIndex = $FC
|
|
audioChannelOffset = $FD
|
|
audioIndirectPtr = $FE
|
|
|
|
.segment "PRG"
|
|
|
|
.org $C000
|
|
|
|
CopyrightText:
|
|
.byte $43,$4F,$50,$59,$20,$52,$49,$47
|
|
.byte $48,$54,$20,$31,$39,$38,$34,$20
|
|
.byte $31,$39,$39,$33,$20,$4E,$41,$4D
|
|
.byte $43,$4F,$20,$4C,$54,$44,$2E,$20
|
|
.byte $41,$4C,$4C,$20,$52,$49,$47,$48
|
|
.byte $54,$53,$20,$52,$45,$53,$45,$52
|
|
.byte $56,$45,$44
|
|
|
|
Reset:
|
|
ldx #$00
|
|
stx PPUCTRL
|
|
sei
|
|
cld
|
|
dex
|
|
txs
|
|
nop
|
|
nop
|
|
nop
|
|
|
|
ldx #$02
|
|
|
|
@WaitForPpu:
|
|
lda #$06
|
|
sta PPUMASK
|
|
|
|
lda PPUSTATUS
|
|
|
|
@WaitVBlank:
|
|
lda PPUSTATUS
|
|
bpl @WaitVBlank
|
|
|
|
lda #$00
|
|
sta PPUSCROLL
|
|
sta PPUSCROLL
|
|
dex
|
|
bne @WaitForPpu
|
|
|
|
lda #$00
|
|
tay
|
|
|
|
@ClearLowRam:
|
|
sta $0000,y
|
|
iny
|
|
cpy #$3E
|
|
bne @ClearLowRam
|
|
|
|
ldx #$08
|
|
ldy #$87
|
|
|
|
@ClearRamPages:
|
|
sta ($00),y
|
|
iny
|
|
bne @ClearRamPages
|
|
inc $01
|
|
cpx $01
|
|
bne @ClearRamPages
|
|
|
|
lda #$06
|
|
sta PPUMASK
|
|
|
|
lda #$00
|
|
sta PPUSCROLL
|
|
sta PPUSCROLL
|
|
sta $41
|
|
sta $42
|
|
sta PPUCTRL
|
|
sta PPUMASK
|
|
tay
|
|
|
|
@CheckRamSignature:
|
|
lda RamSignature,y
|
|
cmp $0052,y
|
|
bne @InitializeRamSignature
|
|
|
|
iny
|
|
cpy #$0F
|
|
bne @CheckRamSignature
|
|
|
|
beq @SignatureAlreadyPresent
|
|
|
|
@InitializeRamSignature:
|
|
lda #$00
|
|
tay
|
|
|
|
@ClearZeroPage:
|
|
sta $0000,y
|
|
iny
|
|
bne @ClearZeroPage
|
|
|
|
ldy #$00
|
|
|
|
@CopyRamSignature:
|
|
lda RamSignature,y
|
|
sta $0052,y
|
|
iny
|
|
cpy #$0F
|
|
bne @CopyRamSignature
|
|
|
|
lda #$01
|
|
sta $64
|
|
|
|
@SignatureAlreadyPresent:
|
|
ldy #$00
|
|
sty $3F
|
|
|
|
lda #$07
|
|
sta $45
|
|
lda #$01
|
|
cmp $47
|
|
bne @SkipSwap
|
|
|
|
cmp $46
|
|
bne @SkipSwap
|
|
|
|
@SwapLoop:
|
|
lda $77,y
|
|
sta workPtr0
|
|
|
|
lda $67,y
|
|
sta $77,y
|
|
|
|
lda workPtr0
|
|
sta $67,y
|
|
|
|
iny
|
|
cpy #$10
|
|
bne @SwapLoop
|
|
|
|
@SkipSwap:
|
|
lda #$1F
|
|
sta APUCTRL
|
|
|
|
lda #$C0
|
|
sta APUFRAMECNT
|
|
|
|
jsr InitializeAudioEngine
|
|
jsr $EEB4
|
|
|
|
lda #$88
|
|
sta $43
|
|
sta PPUCTRL
|
|
|
|
lda #$FF
|
|
sta $48
|
|
sta $023F
|
|
sta $024B
|
|
|
|
jmp MainEntry
|
|
|
|
RamSignature:
|
|
.byte "HIROKI AOYAGI"
|
|
.byte $AA, $55
|
|
|
|
;==============================================================================
|
|
; $C10E-$C17E: NMI Handler
|
|
;
|
|
; Local:
|
|
; Handles the per-frame NMI. Saves the CPU registers, configures the PPU,
|
|
; performs sprite OAM DMA, calls several frame-processing routines, restores
|
|
; the current scroll and PPU control state, polls both controllers, selects
|
|
; the active controller input, and conditionally performs additional
|
|
; per-frame processing.
|
|
;
|
|
; Global:
|
|
; Primary VBlank/frame interrupt entry point. This routine ties together
|
|
; rendering updates, sprite DMA, controller polling, and other work that
|
|
; needs to occur once per video frame.
|
|
;
|
|
; Notes:
|
|
; $41/$42 are used as the two PPUSCROLL writes.
|
|
; $45 supplies the source page for OAM DMA.
|
|
; $4D/$4E receive controller 1/2 input bits.
|
|
; $4F receives the controller state selected by $46/$47.
|
|
;
|
|
; The purposes of $40-$48 and the called routines at FlushGameplayPpuUpdates
|
|
; ReadNearbyNametableTiles, UpdatePalettes, and InitializeAudioChannels will
|
|
; be refined during later passes.
|
|
;==============================================================================
|
|
|
|
NmiHandler:
|
|
pha
|
|
txa
|
|
pha
|
|
tya
|
|
pha
|
|
|
|
lda #$1E
|
|
sta PPUMASK
|
|
|
|
lda #$00
|
|
sta OAMADDR
|
|
sta $40
|
|
|
|
lda $45
|
|
sta OAMDMA
|
|
|
|
jsr FlushGameplayPpuUpdates
|
|
jsr ReadNearbyNametableTiles
|
|
jsr UpdatePalettes
|
|
|
|
; Restore the two PPU scroll components.
|
|
lda $41
|
|
sta PPUSCROLL
|
|
|
|
lda $42
|
|
sta PPUSCROLL
|
|
|
|
; Construct the PPUCTRL value for this frame.
|
|
lda $47
|
|
and $46
|
|
and #$01
|
|
asl
|
|
ora $43
|
|
sta PPUCTRL
|
|
|
|
; Strobe the controller ports.
|
|
lda #$01
|
|
sta JOY1
|
|
|
|
lda #$00
|
|
sta JOY1
|
|
|
|
; Read eight serial bits from both controllers.
|
|
ldx #$08
|
|
|
|
@ReadControllers:
|
|
lda JOY1
|
|
and #$03
|
|
cmp #$01
|
|
ror $4D
|
|
|
|
lda APUFRAMECNT
|
|
and #$03
|
|
cmp #$01
|
|
ror $4E
|
|
|
|
dex
|
|
bne @ReadControllers
|
|
|
|
; Controller 1 is the default input source.
|
|
ldx currentInput
|
|
|
|
; Under the condition controlled by $46/$47,
|
|
; use controller 2 instead.
|
|
lda cocktailModeFlag
|
|
and activePlayerFlag
|
|
beq @ControllerSelected
|
|
|
|
ldx newlyPressedInput
|
|
|
|
@ControllerSelected:
|
|
stx previousInput
|
|
|
|
; Advance a per-frame counter.
|
|
inc frameCounter
|
|
|
|
; $48 gates an additional per-frame routine.
|
|
lda $48
|
|
bne @NmiDone
|
|
|
|
jsr InitializeAudioChannels
|
|
|
|
@NmiDone:
|
|
pla
|
|
tay
|
|
pla
|
|
tax
|
|
pla
|
|
IrqHandler:
|
|
rti
|
|
|
|
UpdatePalettes:
|
|
lda $0299
|
|
cmp #$0F
|
|
bne @CheckSecondPalette
|
|
|
|
lda PPUSTATUS
|
|
lda #$3F
|
|
sta PPUADDR
|
|
lda #$00
|
|
sta PPUADDR
|
|
|
|
ldy #$00
|
|
|
|
@CopyFirstPalette:
|
|
lda $0299,y
|
|
sta PPUDATA
|
|
iny
|
|
cpy #$10
|
|
bne @CopyFirstPalette
|
|
|
|
@CheckSecondPalette:
|
|
lda $02A9
|
|
cmp #$0F
|
|
bne @CheckPaletteState
|
|
|
|
lda PPUSTATUS
|
|
lda #$3F
|
|
sta PPUADDR
|
|
lda #$10
|
|
sta PPUADDR
|
|
|
|
ldy #$00
|
|
|
|
@CopySecondPalette:
|
|
lda $02A9,y
|
|
sta PPUDATA
|
|
iny
|
|
cpy #$10
|
|
bne @CopySecondPalette
|
|
|
|
@CheckPaletteState:
|
|
lda $0299
|
|
cmp #$0F
|
|
beq @ResetPpuAddress
|
|
|
|
lda $02A9
|
|
cmp #$0F
|
|
beq @ResetPpuAddress
|
|
|
|
rts
|
|
|
|
@ResetPpuAddress:
|
|
lda #$30
|
|
sta PPUADDR
|
|
|
|
lda #$00
|
|
sta PPUADDR
|
|
sta PPUADDR
|
|
sta PPUADDR
|
|
|
|
sta $0299
|
|
sta $02A9
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $C1E7-$C266: Main Initialization and State Dispatch
|
|
;
|
|
; Local:
|
|
; Synchronizes with the NMI through $40, initializes PPU/OAM and several
|
|
; game-state variables, calls four initialization routines, initializes the
|
|
; two 16-byte palette buffers, then enters the main state-dispatch loop.
|
|
;
|
|
; The loop synchronizes with NMI again, uses $3F as an index into a table of
|
|
; five handler addresses, stores the selected address in $10/$11, and jumps
|
|
; to that handler indirectly.
|
|
;
|
|
; Global:
|
|
; This is the main program entry reached from Reset after hardware and RAM
|
|
; initialization. It transitions the game into its normal frame-driven state
|
|
; machine. NMI clears $40 each frame, allowing the foreground/main code to
|
|
; proceed through its next state-machine update.
|
|
;
|
|
; Notes:
|
|
; $40 clearly provides synchronization between foreground code and NMI.
|
|
; Writing $01 to $40 and spinning until NMI clears it forms a frame wait.
|
|
;
|
|
; $3F is used here as a state/dispatch index. Its exact semantic states will
|
|
; be named as the individual handlers are decoded.
|
|
;
|
|
; $10/$11 form a temporary indirect JMP pointer.
|
|
;
|
|
; $C267 begins the state-handler address table and is intentionally left for
|
|
; the next decoding pass.
|
|
;==============================================================================
|
|
|
|
MainEntry:
|
|
lda #$01
|
|
sta $40
|
|
|
|
@WaitForInitialNmi:
|
|
lda $40
|
|
bne @WaitForInitialNmi
|
|
|
|
lda #$08
|
|
sta PPUCTRL
|
|
sta ppuCtrlShadow
|
|
|
|
lda PPUSTATUS
|
|
|
|
lda #$00
|
|
sta PPUMASK
|
|
|
|
tax
|
|
|
|
@ClearOamPage:
|
|
sta $0700,x
|
|
inx
|
|
bne @ClearOamPage
|
|
|
|
sta cocktailModeFlag
|
|
|
|
jsr ClearGameplayNametables
|
|
jsr InitializeNametableAttributes
|
|
jsr InitializeNametableData
|
|
jsr $E419
|
|
|
|
ldy #$00
|
|
|
|
@InitializePaletteBuffers:
|
|
lda TitleScreenPalette,y
|
|
sta $0299,y
|
|
iny
|
|
cpy #$20
|
|
bne @InitializePaletteBuffers
|
|
|
|
lda #$2D
|
|
sta actorStatusDisplay
|
|
sta actorStatusDisplay+1
|
|
sta actorStatusDisplay+2
|
|
sta actorStatusDisplay+3
|
|
|
|
lda #$FF
|
|
sta $023F
|
|
sta gameplaySuspended
|
|
|
|
lda #$00
|
|
sta activePlayerFlag
|
|
sta cocktailModeFlag
|
|
sta $42
|
|
sta $41
|
|
sta stateTimer
|
|
sta $87
|
|
sta $88
|
|
|
|
lda gameState
|
|
bne @UseAlternatePpuCtrl
|
|
|
|
lda #$8A
|
|
bne @SetPpuCtrl
|
|
|
|
@UseAlternatePpuCtrl:
|
|
lda #$88
|
|
|
|
@SetPpuCtrl:
|
|
sta PPUCTRL
|
|
sta ppuCtrlShadow
|
|
|
|
MainDispatchLoop:
|
|
lda #$01
|
|
sta $40
|
|
|
|
@WaitForNmi:
|
|
lda $40
|
|
bne @WaitForNmi
|
|
|
|
ldy gameState
|
|
|
|
lda $C267,y
|
|
sta dispatchVector
|
|
|
|
lda $C268,y
|
|
sta dispatchVector+1
|
|
|
|
jmp ($0010)
|
|
|
|
;==============================================================================
|
|
; $C267-$C26E: Main State Dispatch Table
|
|
;
|
|
; Local:
|
|
; Four 16-bit addresses used by the indirect state dispatcher at the end of
|
|
; MainEntry. $3F is used directly as a byte offset into this table:
|
|
;
|
|
; lda MainStateHandlerTable,y
|
|
; sta $10
|
|
; lda MainStateHandlerTable+1,y
|
|
; sta $11
|
|
; jmp ($0010)
|
|
;
|
|
; This implies the normal state values in $3F are even byte offsets:
|
|
; $00, $02, $04, $06
|
|
;
|
|
; Global:
|
|
; Selects one of four major foreground/game-state handlers. This is the
|
|
; top-level state machine entered after Reset initialization and synchronized
|
|
; to the NMI-driven frame loop.
|
|
;
|
|
; Notes:
|
|
; The four targets are:
|
|
; InitialStateHandler
|
|
; PlayerSelectionState
|
|
; State04Handler
|
|
; TimedStateTransition
|
|
;
|
|
; Handler names remain provisional until each target is decoded.
|
|
;==============================================================================
|
|
|
|
MainStateHandlerTable:
|
|
.word InitialStateHandler
|
|
.word PlayerSelectionState
|
|
.word State04Handler
|
|
.word TimedStateTransition
|
|
|
|
;==============================================================================
|
|
; $C26F-$C279: Timed State Transition Handler
|
|
;
|
|
; Local:
|
|
; Decrements the counter at $0F once per frame. While the counter remains
|
|
; nonzero, control returns to the common NMI synchronization/dispatch loop
|
|
; at $C250.
|
|
;
|
|
; When the counter reaches zero, changes the main state offset at $3F to
|
|
; $02 and then returns to the same dispatch loop.
|
|
;
|
|
; Global:
|
|
; Implements the handler selected when the main state offset is $06.
|
|
; This appears to be a timed transitional state. Another state places a
|
|
; duration in $0F and selects state $06; this handler counts that duration
|
|
; down before advancing to state $02.
|
|
;
|
|
; Notes:
|
|
; $0F is clearly being used as a countdown timer here, but its broader use
|
|
; should be traced before assigning it a permanent global name.
|
|
;
|
|
; $3F is the byte offset into MainStateHandlerTable:
|
|
; $00 -> InitialStateHandler
|
|
; $02 -> PlayerSelectionState
|
|
; $04 -> State04Handler
|
|
; $06 -> this handler
|
|
;
|
|
; $C250 is inside MainEntry and is the common frame synchronization point.
|
|
;==============================================================================
|
|
|
|
TimedStateTransition:
|
|
dec $0F
|
|
bne MainDispatchLoop
|
|
|
|
lda #$02
|
|
sta gameState
|
|
|
|
jmp MainDispatchLoop
|
|
|
|
|
|
;==============================================================================
|
|
; $C27A-$C2A5: Initial/Input State Handler
|
|
;
|
|
; Local:
|
|
; Checks controller-1 state bits $0C. If either bit is set, selects state
|
|
; $06, initializes the countdown at $0F to $5A, and jumps back to MainEntry.
|
|
;
|
|
; Otherwise increments $42. When $42 reaches $F0, resets it to zero,
|
|
; changes the saved PPUCTRL value at $43 to $88, and selects state $06
|
|
; with the same $5A countdown.
|
|
;
|
|
; If $42 has not yet reached $F0, the initialization of state $06 is
|
|
; skipped and execution reaches the common JMP back to MainDispatchLoop.
|
|
;
|
|
; Global:
|
|
; Handler selected by main state offset $00. It appears to manage an early
|
|
; or attract/input-wait state, transitioning into the timed state either
|
|
; because of controller input or because the scrolling/progression value
|
|
; at $42 reaches $F0.
|
|
;
|
|
; Notes:
|
|
; $4D is controller-1 input assembled by NmiHandler.
|
|
; $42 is also used as the second PPUSCROLL write during NMI.
|
|
; Exact game-state semantics will be refined in later passes.
|
|
;==============================================================================
|
|
|
|
InitialStateHandler:
|
|
lda currentInput
|
|
and #$0C
|
|
beq @AdvanceScroll
|
|
|
|
lda #$06
|
|
sta gameState
|
|
|
|
lda #$5A
|
|
sta $0F
|
|
|
|
jmp MainEntry
|
|
|
|
@AdvanceScroll:
|
|
inc $42
|
|
|
|
lda #$F0
|
|
cmp $42
|
|
bne @ReturnToMainLoop
|
|
|
|
lda #$00
|
|
sta $42
|
|
|
|
lda #$88
|
|
sta ppuCtrlShadow
|
|
|
|
lda #$06
|
|
sta gameState
|
|
|
|
lda #$5A
|
|
sta $0F
|
|
|
|
@ReturnToMainLoop:
|
|
jmp MainDispatchLoop
|
|
|
|
;==============================================================================
|
|
; $C2A6-$C30A: Initialize Nametable Data
|
|
;
|
|
; Local:
|
|
; Performs two groups of PPU writes used during initial screen setup.
|
|
;
|
|
; First phase:
|
|
; - Begins at PPU address $20E5.
|
|
; - Copies $17 bytes from the ROM data at TitleScreenTileBlock
|
|
; - Repeats this for six rows.
|
|
; - Advances the destination PPU address by $20 after each row.
|
|
;
|
|
; Second phase:
|
|
; - Processes nine variable-length PPU update records beginning at $C3B0.
|
|
; - Each record supplies a two-byte PPU address followed by data bytes.
|
|
; - $FF terminates the data portion of each record.
|
|
;
|
|
; Global:
|
|
; Called from MainEntry during initial game setup. This routine constructs
|
|
; part of the initial nametable/display before normal state dispatch begins.
|
|
;
|
|
; Notes:
|
|
; $00/$01 are used here as a 16-bit PPU destination address.
|
|
; $02 counts the six repeated rows.
|
|
; $03 counts $17 bytes within each row.
|
|
;
|
|
; TitleScreenTileBlock is a repeated row of tile data.
|
|
; $C3B0 contains nine encoded PPU update records.
|
|
;
|
|
; These ROM data blocks will be named more precisely when their contents
|
|
; and resulting screen regions are decoded in later passes.
|
|
;==============================================================================
|
|
|
|
InitializeNametableData:
|
|
; Initial PPU destination = $20E5.
|
|
lda #$20
|
|
sta workPtr0
|
|
|
|
lda #$E5
|
|
sta workPtr0+1
|
|
|
|
; Write six rows.
|
|
lda #$06
|
|
sta workPtr1
|
|
|
|
ldy #$00
|
|
|
|
@WriteRow:
|
|
lda PPUSTATUS
|
|
|
|
lda workPtr0
|
|
sta PPUADDR
|
|
|
|
lda workPtr0+1
|
|
sta PPUADDR
|
|
|
|
; Each row contains $17 bytes.
|
|
lda #$17
|
|
sta workPtr1+1
|
|
|
|
@WriteRowBytes:
|
|
lda TitleScreenTileBlock,y
|
|
sta PPUDATA
|
|
|
|
iny
|
|
|
|
dec workPtr1+1
|
|
bne @WriteRowBytes
|
|
|
|
; Advance the PPU destination by $20.
|
|
lda workPtr0+1
|
|
clc
|
|
adc #$20
|
|
sta workPtr0+1
|
|
|
|
lda #$00
|
|
adc workPtr0
|
|
sta workPtr0
|
|
|
|
dec workPtr1
|
|
bne @WriteRow
|
|
|
|
; Process nine additional encoded PPU update records.
|
|
lda #$09
|
|
sta workPtr0
|
|
|
|
ldy #$00
|
|
|
|
@NextPpuRecord:
|
|
lda PPUSTATUS
|
|
|
|
; First two bytes of each record are the PPU destination address.
|
|
lda TitleScreenPpuRecords,y
|
|
sta PPUADDR
|
|
iny
|
|
|
|
lda TitleScreenPpuRecords,y
|
|
sta PPUADDR
|
|
iny
|
|
|
|
@WritePpuRecord:
|
|
lda TitleScreenPpuRecords,y
|
|
cmp #$FF
|
|
beq @EndPpuRecord
|
|
|
|
sta PPUDATA
|
|
iny
|
|
bne @WritePpuRecord
|
|
|
|
@EndPpuRecord:
|
|
iny
|
|
|
|
dec workPtr0
|
|
bne @NextPpuRecord
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $C30B-$C325: Initialize Nametable Attributes
|
|
;
|
|
; Local:
|
|
; Writes $18 bytes from TitleScreenAttributeData to PPU address $23C8.
|
|
;
|
|
; Global:
|
|
; Initializes a portion of the nametable attribute table during startup.
|
|
;==============================================================================
|
|
|
|
InitializeNametableAttributes:
|
|
lda PPUSTATUS
|
|
|
|
lda #$23
|
|
sta PPUADDR
|
|
|
|
lda #$C8
|
|
sta PPUADDR
|
|
|
|
ldy #$00
|
|
|
|
@CopyAttributes:
|
|
lda TitleScreenAttributeData,y
|
|
sta PPUDATA
|
|
|
|
iny
|
|
cpy #$18
|
|
bne @CopyAttributes
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $C326-$C3AF: Initial Nametable Tile Block
|
|
;
|
|
; Local:
|
|
; Contains six rows of $17 (23) tile indices. InitializeNametableData copies
|
|
; these rows sequentially to the PPU beginning at $20E5, advancing the PPU
|
|
; destination by $20 after each row.
|
|
;
|
|
; Destination layout:
|
|
; Row 0 -> $20E5-$20FB
|
|
; Row 1 -> $2105-$211B
|
|
; Row 2 -> $2125-$213B
|
|
; Row 3 -> $2145-$215B
|
|
; Row 4 -> $2165-$217B
|
|
; Row 5 -> $2185-$219B
|
|
;
|
|
; Global:
|
|
; Forms a rectangular portion of the initial nametable display constructed
|
|
; during MainEntry. The first and last rows consist primarily of border
|
|
; tiles, while the middle four rows contain the interior graphic/tile data.
|
|
;
|
|
; Notes:
|
|
; Each row is exactly $17 bytes.
|
|
;
|
|
; Tile values are left numeric during this pass. Their visual meanings can
|
|
; be determined later from the CHR-ROM and assigned symbolic tile names if
|
|
; useful.
|
|
;==============================================================================
|
|
|
|
TitleScreenTileBlock:
|
|
; Row 0 -> PPU $20E5-$20FB
|
|
.byte $E4,$E8,$E8,$E8,$E8,$E8,$E8,$E8
|
|
.byte $E8,$E8,$E8,$E8,$E8,$E8,$E8,$E8
|
|
.byte $E8,$E8,$E8,$E8,$E8,$E8,$E5
|
|
|
|
; Row 1 -> PPU $2105-$211B
|
|
.byte $EB,$88,$80,$81,$82,$83,$84,$85
|
|
.byte $86,$87,$88,$88,$89,$8A,$8B,$8C
|
|
.byte $8D,$8E,$8F,$90,$91,$A3,$E9
|
|
|
|
; Row 2 -> PPU $2125-$213B
|
|
.byte $EB,$88,$92,$93,$94,$95,$96,$97
|
|
.byte $98,$99,$9A,$9B,$9C,$9D,$9E,$9F
|
|
.byte $A0,$A1,$A2,$A3,$A4,$A3,$E9
|
|
|
|
; Row 3 -> PPU $2145-$215B
|
|
.byte $EB,$88,$92,$A5,$A6,$A7,$A8,$A9
|
|
.byte $AA,$AB,$AC,$AD,$AE,$A3,$AF,$D0
|
|
.byte $D1,$D2,$A3,$D3,$A4,$A3,$E9
|
|
|
|
; Row 4 -> PPU $2165-$217B
|
|
.byte $EB,$88,$D4,$D5,$D6,$D7,$D8,$D9
|
|
.byte $DA,$DB,$88,$88,$DC,$D7,$DD,$DE
|
|
.byte $DF,$E0,$E1,$E2,$E3,$A3,$E9
|
|
|
|
; Row 5 -> PPU $2185-$219B
|
|
.byte $E7,$EA,$EA,$EA,$EA,$EA,$EA,$EA
|
|
.byte $EA,$EA,$EA,$EA,$EA,$EA,$EA,$EA
|
|
.byte $EA,$EA,$EA,$EA,$EA,$EA,$E6
|
|
|
|
;==============================================================================
|
|
; $C3B0-$C43E: Initial Screen PPU Records
|
|
;
|
|
; Local:
|
|
; Nine variable-length PPU write records consumed by InitializeNametableData.
|
|
; Each record has the form:
|
|
;
|
|
; .byte PPU address high
|
|
; .byte PPU address low
|
|
; .byte tile data...
|
|
; .byte $FF
|
|
;
|
|
; InitializeNametableData processes exactly nine records. For each record it
|
|
; loads the two-byte destination into PPUADDR and copies tile values to
|
|
; PPUDATA until the $FF terminator is encountered.
|
|
;
|
|
; Global:
|
|
; Supplies additional initial-screen graphics and text after the main
|
|
; six-row tile block has been installed. These records include player-count
|
|
; selections and copyright/licensing text as represented by the ROM's
|
|
; nametable tile values.
|
|
;
|
|
; Notes:
|
|
; Many values correspond directly to ASCII character codes, but not all do.
|
|
; Preserve the original tile bytes rather than converting these records to
|
|
; assembler strings during this pass.
|
|
;
|
|
; $FF is structural and is not written to PPUDATA.
|
|
;==============================================================================
|
|
|
|
TitleScreenPpuRecords:
|
|
;------------------------------------------------------------------------------
|
|
; Record 0: $C3B0-$C3C7
|
|
; PPU destination: $2065
|
|
; Data length: $15 (21) tiles
|
|
;------------------------------------------------------------------------------
|
|
.byte $20,$65
|
|
.byte $B0,$B3,$B2,$20,$20,$20,$20
|
|
.byte $B4,$B5,$B6,$B7,$B8,$B9,$BA,$BB
|
|
.byte $20,$20,$20,$B1,$B3,$B2
|
|
.byte $FF
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Record 1: $C3C8-$C3D2
|
|
; PPU destination: $220C
|
|
; Data length: $08
|
|
;
|
|
; Visible tile values correspond to:
|
|
; "1 PLAYER"
|
|
;------------------------------------------------------------------------------
|
|
.byte $22,$0C
|
|
.byte $31,$20,$50,$4C,$41,$59,$45,$52
|
|
.byte $FF
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Record 2: $C3D3-$C3DE
|
|
; PPU destination: $224C
|
|
; Data length: $09
|
|
;
|
|
; Visible tile values correspond to:
|
|
; "2 PLAYERS"
|
|
;------------------------------------------------------------------------------
|
|
.byte $22,$4C
|
|
.byte $32,$20,$50,$4C,$41,$59,$45,$52,$53
|
|
.byte $FF
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Record 3: $C3DF-$C3FC
|
|
; PPU destination: $22E3
|
|
; Data length: $1B (27)
|
|
;
|
|
; Mostly text-like tile data containing the original copyright/date/NAMCO
|
|
; display. Special tile values are retained numerically.
|
|
;------------------------------------------------------------------------------
|
|
.byte $22,$E3
|
|
.byte $54,$4D,$20,$CC,$20,$5D
|
|
.byte $20,$31,$39,$38,$30
|
|
.byte $20,$31,$39,$39,$33
|
|
.byte $20,$4E,$41,$4D,$43,$4F
|
|
.byte $20,$4C,$54,$44,$5B
|
|
.byte $FF
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Record 4: $C3FD-$C411
|
|
; PPU destination: $2327
|
|
; Data length: $12 (18)
|
|
;
|
|
; Mostly text-like tile data containing:
|
|
; NAMCO HOMETEK ... INC
|
|
;
|
|
; Special tile values remain numeric.
|
|
;------------------------------------------------------------------------------
|
|
.byte $23,$27
|
|
.byte $4E,$41,$4D,$43,$4F,$20
|
|
.byte $48,$4F,$4D,$45,$54,$45,$4B
|
|
.byte $CD
|
|
.byte $49,$4E,$43
|
|
.byte $5B
|
|
.byte $FF
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Record 5: $C412-$C428
|
|
; PPU destination: $2366
|
|
; Data length: $14 (20)
|
|
;
|
|
; Tile values correspond to:
|
|
; "LICENSED BY NINTENDO"
|
|
;------------------------------------------------------------------------------
|
|
.byte $23,$66
|
|
.byte $4C,$49,$43,$45,$4E,$53,$45,$44
|
|
.byte $20
|
|
.byte $42,$59
|
|
.byte $20
|
|
.byte $4E,$49,$4E,$54,$45,$4E,$44,$4F
|
|
.byte $FF
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Record 6: $C429-$C42D
|
|
; PPU destination: $2293
|
|
; Data length: $02
|
|
;------------------------------------------------------------------------------
|
|
.byte $22,$93
|
|
.byte $CE,$CF
|
|
.byte $FF
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Record 7: $C42E-$C439
|
|
; PPU destination: $22AC
|
|
; Data length: $09
|
|
;------------------------------------------------------------------------------
|
|
.byte $22,$AC
|
|
.byte $23,$24,$25,$26,$27,$28,$29,$2A,$2B
|
|
.byte $FF
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Record 8: $C43A-$C43E
|
|
; PPU destination: $20FC
|
|
; Data length: $02
|
|
;------------------------------------------------------------------------------
|
|
.byte $20,$FC
|
|
.byte $0E,$0F
|
|
.byte $FF
|
|
|
|
|
|
;==============================================================================
|
|
; $C43F-$C45E: Initial Palette Data
|
|
;
|
|
; Local:
|
|
; Contains $20 bytes copied to RAM $0299-$02B8 during MainEntry. The first
|
|
; $10 bytes feed PPU palette $3F00-$3F0F and the second $10 bytes feed
|
|
; $3F10-$3F1F through UpdatePalettes.
|
|
;
|
|
; Global:
|
|
; Defines the initial background and sprite palette configuration.
|
|
;
|
|
; Notes:
|
|
; Palette values remain numeric during this pass.
|
|
;==============================================================================
|
|
|
|
TitleScreenPalette:
|
|
|
|
; Background palettes
|
|
.byte $0F,$20,$0F,$06
|
|
.byte $0F,$26,$20,$27
|
|
.byte $0F,$06,$0F,$26
|
|
.byte $0F,$06,$20,$26
|
|
|
|
; Sprite palettes
|
|
.byte $0F,$27,$20,$06
|
|
.byte $0F,$11,$20,$33
|
|
.byte $0F,$20,$20,$21
|
|
.byte $0F,$09,$20,$17
|
|
|
|
|
|
;==============================================================================
|
|
; $C45F-$C476: Initial Nametable Attribute Data
|
|
;
|
|
; Local:
|
|
; Contains $18 attribute bytes copied by InitializeNametableAttributes to
|
|
; PPU $23C8-$23DF.
|
|
;
|
|
; Global:
|
|
; Defines background-palette selections for part of the initial nametable
|
|
; display.
|
|
;
|
|
; Notes:
|
|
; Attribute bytes remain raw during this first pass.
|
|
;==============================================================================
|
|
|
|
TitleScreenAttributeData:
|
|
.byte $80,$A0,$A0,$A0,$A0,$A0,$A0,$00
|
|
.byte $00,$66,$55,$55,$55,$55,$DD,$00
|
|
.byte $08,$0A,$0A,$0A,$0A,$0A,$0A,$00
|
|
|
|
;==============================================================================
|
|
; $C477-$C506: Player Selection State Handler
|
|
;
|
|
; Local:
|
|
; Handles input and display updates for the player-count selection state.
|
|
;
|
|
; On first entry, identified by $87/$88 both being zero, copies a small
|
|
; display-data sequence from $C507 to RAM beginning at $024B and captures
|
|
; the current controller states for bits $04 and $08.
|
|
;
|
|
; $87/$88 form a 16-bit counter that advances once per frame. When its high
|
|
; byte reaches $02, the counter is reset and the main state changes to $04.
|
|
;
|
|
; During normal processing:
|
|
; - Detects changes to controller bit $04.
|
|
; - When that bit becomes active, toggles $47 between 0 and 1 and changes
|
|
; display data associated with the selected player count.
|
|
; - Detects changes to controller bit $08.
|
|
; - When bit $08 becomes active, clears $48, calls $EEB4, and jumps to
|
|
; GameModeEntry.
|
|
;
|
|
; Global:
|
|
; Handler selected by MainStateHandlerTable when $3F = $02. The surrounding PPU
|
|
; data and controller behavior strongly indicate that this state implements
|
|
; the "1 PLAYER" / "2 PLAYERS" selection screen.
|
|
;
|
|
; If no selection completes within the $87/$88 timeout, execution advances
|
|
; automatically to main state $04.
|
|
;
|
|
; Notes:
|
|
; $50 stores the previous masked state of controller bit $04.
|
|
; $51 stores the previous masked state of controller bit $08.
|
|
;
|
|
; $87/$88 act as a 16-bit frame counter in this state.
|
|
;
|
|
; $47 is toggled between 0 and 1 when the $04 input becomes active. This
|
|
; strongly suggests it represents the current 1-player/2-player selection,
|
|
; but the name should be confirmed through later consumers.
|
|
;
|
|
; $C507 begins an adjacent display-data table consumed during state entry.
|
|
;==============================================================================
|
|
|
|
PlayerSelectionState:
|
|
lda $87
|
|
ora $88
|
|
bne @AdvanceTimeout
|
|
|
|
ldy #$00
|
|
|
|
@InitializeDisplayData:
|
|
lda PlayerCountSelectionDisplayData,y
|
|
sta $024B,y
|
|
iny
|
|
cmp #$FF
|
|
bne @InitializeDisplayData
|
|
|
|
lda currentInput
|
|
and #$04
|
|
sta pacmanRequestedDirection
|
|
|
|
lda currentInput
|
|
and #$08
|
|
sta pacmanDirection
|
|
|
|
@AdvanceTimeout:
|
|
clc
|
|
lda #$01
|
|
adc $87
|
|
sta $87
|
|
|
|
lda $88
|
|
adc #$00
|
|
sta $88
|
|
|
|
cmp #$02
|
|
bne @CheckSelectionInput
|
|
|
|
lda #$00
|
|
sta $87
|
|
|
|
lda #$04
|
|
sta gameState
|
|
|
|
jmp MainDispatchLoop
|
|
|
|
@CheckSelectionInput:
|
|
lda currentInput
|
|
and #$04
|
|
cmp pacmanRequestedDirection
|
|
beq @CheckConfirmInput
|
|
|
|
sta pacmanRequestedDirection
|
|
|
|
lda #$00
|
|
sta $88
|
|
|
|
lda #$01
|
|
sta $87
|
|
|
|
lda pacmanRequestedDirection
|
|
beq @CheckConfirmInput
|
|
|
|
ldx #$00
|
|
|
|
inc activePlayerFlag
|
|
lda activePlayerFlag
|
|
and #$01
|
|
sta activePlayerFlag
|
|
beq @UseFirstSelectionData
|
|
|
|
inx
|
|
|
|
@UseFirstSelectionData:
|
|
lda $C50F,x
|
|
sta $024D
|
|
|
|
lda $C510,x
|
|
sta $0251
|
|
|
|
lda #$22
|
|
sta $024B
|
|
|
|
jmp MainDispatchLoop
|
|
|
|
@CheckConfirmInput:
|
|
lda currentInput
|
|
and #$08
|
|
cmp pacmanDirection
|
|
bne @ConfirmStateChanged
|
|
|
|
jmp MainDispatchLoop
|
|
|
|
@ConfirmStateChanged:
|
|
sta pacmanDirection
|
|
|
|
lda pacmanDirection
|
|
bne @ConfirmPressed
|
|
|
|
jmp MainDispatchLoop
|
|
|
|
@ConfirmPressed:
|
|
lda #$00
|
|
sta gameplaySuspended
|
|
|
|
jsr $EEB4
|
|
|
|
jmp GameModeEntry
|
|
|
|
;==============================================================================
|
|
; $C507-$C511: Player Selection Display Data
|
|
;
|
|
; Local:
|
|
; Contains display-update data used by PlayerSelectionState.
|
|
;
|
|
; The first eight bytes, $C507-$C50E, are copied to RAM beginning at $024B
|
|
; when the player-selection state is first entered. The copy terminates after
|
|
; the $FF byte has also been stored.
|
|
;
|
|
; The final three bytes, $C50F-$C511, form an overlapping pair table used
|
|
; when $47 toggles between its two selection values:
|
|
;
|
|
; X = 0 -> $5C, $20
|
|
; X = 1 -> $20, $5C
|
|
;
|
|
; These values are written to $024D and $0251, respectively.
|
|
;
|
|
; Global:
|
|
; Provides the display-update data for the "1 PLAYER" / "2 PLAYERS"
|
|
; selection state. The overlapping three-byte table moves a $5C tile
|
|
; between two display positions while placing $20 at the other position.
|
|
;
|
|
; Notes:
|
|
; $5C appears to be the selection-marker tile and $20 appears to clear the
|
|
; alternate position. Their exact visual appearance can be confirmed later
|
|
; against CHR-ROM.
|
|
;
|
|
; $FF terminates the initialization data copied to $024B.
|
|
;==============================================================================
|
|
|
|
PlayerCountSelectionDisplayData:
|
|
.byte $22,$0A,$5C,$00
|
|
.byte $22,$4A,$20,$FF
|
|
|
|
PlayerCountSelectionMarkerTiles:
|
|
.byte $5C,$20,$5C
|
|
|
|
|
|
;==============================================================================
|
|
; $C512-$C52D: State $04 Handler / Substate Dispatcher
|
|
;
|
|
; Local:
|
|
; Handles the top-level processing for main state $04.
|
|
;
|
|
; First checks controller-1 bits $0C. If either bit is active, changes the
|
|
; main state back to $02 and jumps to MainEntry, causing the main display
|
|
; initialization sequence to run again.
|
|
;
|
|
; Otherwise uses $87 as a byte offset into a table of 16-bit handler
|
|
; addresses beginning at $C52E. The selected address is placed in $10/$11
|
|
; and execution jumps to it indirectly.
|
|
;
|
|
; Global:
|
|
; This is the fourth major handler in MainStateHandlerTable. Unlike states $00,
|
|
; $02, and $06, state $04 contains its own secondary state machine driven
|
|
; by $87.
|
|
;
|
|
; $87 therefore has a different role depending on the current main state.
|
|
; In state $02 it participated in a 16-bit frame counter with $88. Here it
|
|
; acts as the byte offset into a secondary dispatch table.
|
|
;
|
|
; Notes:
|
|
; $87 appears to take even values because it indexes packed 16-bit addresses
|
|
; directly rather than multiplying a state number by two.
|
|
;
|
|
; The substate table begins immediately afterward at $C52E.
|
|
; We leave the individual substate handlers for following passes.
|
|
;==============================================================================
|
|
|
|
State04Handler:
|
|
lda currentInput
|
|
and #$0C
|
|
beq @DispatchSubstate
|
|
|
|
lda #$02
|
|
sta gameState
|
|
|
|
jmp MainEntry
|
|
|
|
@DispatchSubstate:
|
|
ldy $87
|
|
|
|
lda State04SubstateTable,y
|
|
sta dispatchVector
|
|
|
|
lda State04SubstateTable+1,y
|
|
sta dispatchVector+1
|
|
|
|
jmp ($0010)
|
|
|
|
;==============================================================================
|
|
; $C52E-$C545: State $04 Substate Dispatch Table
|
|
;
|
|
; Local:
|
|
; Twelve 16-bit handler addresses selected by State04Handler using $87 as
|
|
; a direct byte offset.
|
|
;
|
|
; Valid offsets observed from the table structure are:
|
|
; $00,$02,$04,$06,$08,$0A,$0C,$0E,$10,$12,$14,$16
|
|
;
|
|
; Global:
|
|
; Defines the secondary state machine used while the top-level game state
|
|
; is $04. Several intermediate substates deliberately share the same handler
|
|
; at $C573.
|
|
;
|
|
; Notes:
|
|
; Later code advances $87 using two INC instructions, confirming that $87
|
|
; is a byte offset into this table rather than an ordinal state number.
|
|
;==============================================================================
|
|
|
|
State04SubstateTable:
|
|
.word State04Initialize ; $00
|
|
.word State04TimedSubstate ; $02
|
|
.word State04TimedSubstate ; $04
|
|
.word State04TimedSubstate ; $06
|
|
.word State04TimedSubstate ; $08
|
|
.word State04TimedSubstate ; $0A
|
|
.word State04TimedSubstate ; $0C
|
|
.word State04TimedSubstate ; $0E
|
|
.word State04TimedSubstate ; $10
|
|
.word State04TimedSubstate ; $12
|
|
.word State04LongDelay ; $14
|
|
.word State04FinalPhase ; $16
|
|
|
|
;==============================================================================
|
|
; $C546-$C572: State $04 Initialization Substate
|
|
;
|
|
; Local:
|
|
; Performs the one-time initialization for state $04 when substate offset
|
|
; $87 is $00.
|
|
;
|
|
; First synchronizes with NMI using $40. It then sets PPUCTRL/$43 to $08,
|
|
; disables rendering through PPUMASK, clears $88, and calls three setup
|
|
; routines:
|
|
;
|
|
; $C5D8
|
|
; $C608
|
|
; SetSelectionFlagAndContinue
|
|
;
|
|
; After setup completes, advances $87 by two, selecting substate $02 on the
|
|
; following frame. PPUCTRL/$43 are then changed to $88 before returning to
|
|
; MainDispatchLoop.
|
|
;
|
|
; Global:
|
|
; Entry/initialization substate for the secondary state machine used by
|
|
; main state $04. It prepares the display and state-specific data before
|
|
; handing execution to the shared $C573 substate handler.
|
|
;
|
|
; Notes:
|
|
; $40 continues to act as the foreground/NMI synchronization flag.
|
|
;
|
|
; $87 is a byte offset into State04SubstateTable. The two INC instructions
|
|
; deliberately advance it from $00 to $02.
|
|
;
|
|
; The three called routines remain structurally named by address until they
|
|
; are decoded. $C5D8 and $C608 appear to perform direct PPU initialization,
|
|
; while SetSelectionFlagAndContinue operates on state/display data.
|
|
;==============================================================================
|
|
|
|
State04Initialize:
|
|
lda #$01
|
|
sta $40
|
|
|
|
@WaitForNmi:
|
|
lda $40
|
|
bne @WaitForNmi
|
|
|
|
lda #$08
|
|
sta PPUCTRL
|
|
sta ppuCtrlShadow
|
|
|
|
lda #$00
|
|
sta PPUMASK
|
|
sta $88
|
|
|
|
jsr $C5D8
|
|
jsr InitializeState04PpuData
|
|
jsr LoadState04DisplayData
|
|
|
|
inc $87
|
|
inc $87
|
|
|
|
lda #$88
|
|
sta PPUCTRL
|
|
sta ppuCtrlShadow
|
|
|
|
jmp MainDispatchLoop
|
|
|
|
;==============================================================================
|
|
; $C573-$C588: State $04 Shared Timed Substate Handler
|
|
;
|
|
; Local:
|
|
; Advances $88 once per frame. At $30 frames, clears $88, invokes the
|
|
; state-$04 display-data helper, and advances $87 by two to the next
|
|
; secondary state.
|
|
;
|
|
; Global:
|
|
; Shared timing handler used by state-$04 substates $02-$12.
|
|
;
|
|
; Notes:
|
|
; LoadState04DisplayData is kept as a raw address temporarily to guarantee
|
|
; byte identity while the overlapping $C5A6-$C5D8 region is being resolved.
|
|
;==============================================================================
|
|
|
|
State04TimedSubstate:
|
|
inc $88
|
|
|
|
lda $88
|
|
cmp #$30
|
|
bne @ReturnToMainLoop
|
|
|
|
lda #$00
|
|
sta $88
|
|
|
|
jsr $C5A6
|
|
|
|
inc $87
|
|
inc $87
|
|
|
|
@ReturnToMainLoop:
|
|
jmp MainDispatchLoop
|
|
|
|
;==============================================================================
|
|
; $C589-$C59F: State $04 Long Delay Substate
|
|
;
|
|
; Local:
|
|
; Increments $88 once per frame and waits until it reaches $80.
|
|
;
|
|
; While $88 is not $80, returns to MainDispatchLoop.
|
|
;
|
|
; When $88 reaches $80:
|
|
; - Advances $87 by two, selecting substate $16.
|
|
; - Clears $88.
|
|
; - Returns to MainDispatchLoop.
|
|
;
|
|
; Global:
|
|
; Implements substate $14 of the state $04 secondary state machine. It
|
|
; follows the series of $30-frame substates handled by
|
|
; State04TimedSubstate and introduces a longer delay before entering the
|
|
; final known substate at $16.
|
|
;
|
|
; Notes:
|
|
; $88 is the frame counter for this substate.
|
|
; $87 is the byte offset into State04SubstateTable.
|
|
;
|
|
; Unlike substates $02-$12, reaching the timeout here does not call
|
|
; SetSelectionFlagAndContinue. It simply advances from substate $14 to $16.
|
|
;==============================================================================
|
|
|
|
State04LongDelay:
|
|
inc $88
|
|
|
|
lda $88
|
|
cmp #$80
|
|
beq @AdvanceSubstate
|
|
|
|
jmp MainDispatchLoop
|
|
|
|
@AdvanceSubstate:
|
|
inc $87
|
|
inc $87
|
|
|
|
lda #$00
|
|
sta $88
|
|
|
|
jmp MainDispatchLoop
|
|
|
|
|
|
;==============================================================================
|
|
; $C59F-$C5A5: Select Alternate Player Mode and Continue
|
|
;
|
|
; Local:
|
|
; Sets $47 to $01 and tail-jumps to the routine at GameModeEntry.
|
|
;
|
|
; Global:
|
|
; Forces the same $47 flag that PlayerSelectionState toggles between $00
|
|
; and $01, then transfers control to GameModeEntry. This strongly links the routine
|
|
; to the player-count/player-mode selection logic.
|
|
;
|
|
; The exact global purpose of GameModeEntry has not yet been decoded, so the routine
|
|
; and $47 remain conservatively named during this pass.
|
|
;
|
|
; Notes:
|
|
; There is no RTS. Control is permanently transferred to GameModeEntry.
|
|
;
|
|
; $47 is known to be constrained to 0/1 by PlayerSelectionState and is also
|
|
; consulted by NmiHandler when selecting controller input and constructing
|
|
; PPUCTRL. We should trace GameModeEntry before assigning $47 a final semantic name.
|
|
;==============================================================================
|
|
|
|
SetSelectionFlagAndContinue:
|
|
lda #$01
|
|
sta activePlayerFlag
|
|
jmp GameModeEntry
|
|
|
|
|
|
;==============================================================================
|
|
; $C5A6-$C5D7: State $04 Display Data Loader
|
|
;
|
|
; Local:
|
|
; Uses $87 as a byte offset into a pointer table at $C687. The selected
|
|
; $FF-terminated stream is copied through $00/$01 into RAM beginning at
|
|
; $024B, including the $FF terminator.
|
|
;
|
|
; The byte following the terminator controls an optional secondary copy:
|
|
; nonzero -> return
|
|
; zero -> copy 16 bytes using a substate-derived offset
|
|
;
|
|
; Global:
|
|
; Supplies update/display data as the state-$04 secondary state machine
|
|
; progresses.
|
|
;
|
|
; Notes:
|
|
; $00/$01 form the temporary source pointer.
|
|
;==============================================================================
|
|
|
|
LoadState04DisplayData:
|
|
ldy $87
|
|
|
|
lda CharacterIntroDisplayDataTable,y
|
|
sta workPtr0
|
|
|
|
lda CharacterIntroDisplayDataTable+1,y
|
|
sta workPtr0+1
|
|
|
|
ldy #$00
|
|
|
|
@CopyDisplayData:
|
|
lda (workPtr0),y
|
|
sta $024B,y
|
|
|
|
iny
|
|
cmp #$FF
|
|
bne @CopyDisplayData
|
|
|
|
lda (workPtr0),y
|
|
beq @SecondaryCopy
|
|
|
|
rts
|
|
|
|
@SecondaryCopy:
|
|
lda $87
|
|
sec
|
|
sbc #$02
|
|
asl
|
|
asl
|
|
tay
|
|
|
|
ldx #$10
|
|
|
|
@CopySecondaryData:
|
|
lda CharacterIntroSpriteData,y
|
|
sta $0760,y
|
|
|
|
iny
|
|
dex
|
|
bne @CopySecondaryData
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $C5D8-$C607: Initialize Playfield Area
|
|
;
|
|
; Local:
|
|
; Sets the PPU destination to $20C0 and fills 24 complete 32-tile nametable
|
|
; rows.
|
|
;
|
|
; Each row consists of:
|
|
; 2 x $2D
|
|
; 28 x $20
|
|
; 2 x $2D
|
|
;
|
|
; The inner count at $01 is reinitialized to $1C at the beginning of every
|
|
; row. $00 begins at $17 and counts rows down through zero.
|
|
;
|
|
; Global:
|
|
; Called during State04Initialize with rendering disabled. Builds the large
|
|
; rectangular background area used by state $04.
|
|
;
|
|
; Notes:
|
|
; The BPL at $C605 intentionally returns to $C5E6, not directly to the first
|
|
; tile write. This reloads $01 with $1C for every row and must be preserved
|
|
; for byte identity.
|
|
;==============================================================================
|
|
|
|
InitializePlayfieldArea:
|
|
lda #$20
|
|
sta PPUADDR
|
|
|
|
lda #$C0
|
|
sta PPUADDR
|
|
|
|
lda #$17
|
|
sta workPtr0
|
|
|
|
@NextRow:
|
|
lda #$1C
|
|
sta workPtr0+1
|
|
|
|
lda #$2D
|
|
sta PPUDATA
|
|
sta PPUDATA
|
|
|
|
lda #$20
|
|
|
|
@ClearRowInterior:
|
|
sta PPUDATA
|
|
dec workPtr0+1
|
|
bne @ClearRowInterior
|
|
|
|
lda #$2D
|
|
sta PPUDATA
|
|
sta PPUDATA
|
|
|
|
dec workPtr0
|
|
bpl @NextRow
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $C608-$C666: Initialize State $04 PPU Data
|
|
;
|
|
; Local:
|
|
; Performs three groups of PPU initialization:
|
|
;
|
|
; 1. Writes $24 (36) bytes from $C76E to PPUDATA beginning at PPU $23C8.
|
|
;
|
|
; 2. Processes a sequence of variable-length PPU write records beginning
|
|
; at $C69B. Each record contains a two-byte PPU destination followed by
|
|
; data bytes terminated by $FF.
|
|
;
|
|
; 3. Writes a full $20-byte palette table from CharacterIntroPalette to PPU palette RAM
|
|
; beginning at $3F00.
|
|
;
|
|
; After the palette transfer, resets PPUADDR away from palette space and
|
|
; returns.
|
|
;
|
|
; Global:
|
|
; Called by State04Initialize while rendering is disabled. Together with
|
|
; InitializePlayfieldArea, this routine constructs the PPU state needed by
|
|
; the state-$04 display sequence.
|
|
;
|
|
; Notes:
|
|
; Unlike InitializeNametableData, the PPU-record loop at $C61D does not
|
|
; contain an explicit record count. The encoded data and Y wrap behavior
|
|
; determine when processing terminates. We should decode $C69B before
|
|
; assigning a more precise description to that stream.
|
|
;
|
|
; CharacterIntroPalette begins the 32-byte palette table.
|
|
; $C76E is the source of the 36-byte attribute-data transfer.
|
|
;==============================================================================
|
|
|
|
InitializeState04PpuData:
|
|
; Set PPU destination to $23C8.
|
|
lda #$23
|
|
sta PPUADDR
|
|
|
|
lda #$C8
|
|
sta PPUADDR
|
|
|
|
; Copy $24 bytes of attribute data.
|
|
ldy #$00
|
|
|
|
@CopyAttributeData:
|
|
lda $C76E,y
|
|
sta PPUDATA
|
|
|
|
iny
|
|
cpy #$24
|
|
bne @CopyAttributeData
|
|
|
|
; Process encoded PPU write data from $C69B.
|
|
ldy #$00
|
|
|
|
@NextPpuRecord:
|
|
lda CharacterNicknameHeaderData,y
|
|
sta PPUADDR
|
|
iny
|
|
|
|
lda CharacterNicknameHeaderData,y
|
|
sta PPUADDR
|
|
iny
|
|
|
|
@CopyPpuRecord:
|
|
lda CharacterNicknameHeaderData,y
|
|
cmp #$FF
|
|
beq @EndPpuRecord
|
|
|
|
sta PPUDATA
|
|
iny
|
|
bne @CopyPpuRecord
|
|
|
|
@EndPpuRecord:
|
|
lda PPUSTATUS
|
|
|
|
; Upload the complete 32-byte palette directly.
|
|
lda #$3F
|
|
sta PPUADDR
|
|
|
|
lda #$00
|
|
sta PPUADDR
|
|
|
|
ldy #$00
|
|
|
|
@CopyPalette:
|
|
lda CharacterIntroPalette,y
|
|
sta PPUDATA
|
|
|
|
iny
|
|
cpy #$20
|
|
bne @CopyPalette
|
|
|
|
; Reset the PPU address following palette access.
|
|
lda #$3F
|
|
sta PPUADDR
|
|
|
|
lda #$00
|
|
sta PPUADDR
|
|
sta PPUADDR
|
|
sta PPUADDR
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $C667-$C686: State $04 Palette Data
|
|
;
|
|
; Local:
|
|
; Complete 32-byte palette uploaded directly to PPU $3F00-$3F1F by
|
|
; InitializeState04PpuData.
|
|
;
|
|
; Global:
|
|
; Defines the background and sprite colors used by the state-$04 display.
|
|
;
|
|
; Notes:
|
|
; First 16 bytes are the four background palettes.
|
|
; Second 16 bytes are the four sprite palettes.
|
|
;==============================================================================
|
|
CharacterIntroPalette:
|
|
; Background palettes
|
|
.byte $0F,$20,$0F,$06
|
|
.byte $0F,$06,$0F,$33
|
|
.byte $0F,$33,$0F,$27
|
|
.byte $0F,$17,$0F,$21
|
|
|
|
; Sprite palettes
|
|
.byte $0F,$27,$20,$06
|
|
.byte $0F,$11,$20,$33
|
|
.byte $0F,$20,$20,$21
|
|
.byte $0F,$09,$20,$17
|
|
|
|
;==============================================================================
|
|
; $C687-$C69A: State $04 Display Data Pointer Table
|
|
;
|
|
; Local:
|
|
; Contains ten 16-bit pointers to display/update data streams. The helper at
|
|
; $C5A6 uses $87 directly as a byte offset into this table:
|
|
;
|
|
; ldy $87
|
|
; lda CharacterIntroDisplayDataTable,y
|
|
; sta $00
|
|
; lda CharacterIntroDisplayDataTable+1,y
|
|
; sta $01
|
|
;
|
|
; The valid table offsets are therefore:
|
|
; $00,$02,$04,$06,$08,$0A,$0C,$0E,$10,$12
|
|
;
|
|
; Global:
|
|
; Selects the display data used as the state-$04 secondary state machine
|
|
; progresses. State04Initialize uses offset $00, while the successive timed
|
|
; substates use offsets $02 through $12.
|
|
;
|
|
; Notes:
|
|
; Each target begins a $FF-terminated display/update stream copied into RAM
|
|
; at $024B by LoadState04DisplayData.
|
|
;
|
|
; Several streams contain an additional control byte following $FF. The
|
|
; helper uses that byte to decide whether to perform its secondary copy.
|
|
;==============================================================================
|
|
|
|
CharacterIntroDisplayDataTable:
|
|
.word CharacterNicknameHeaderData ; $87 = $00 Character; NICKNAME
|
|
.word ShadowNameData ; $87 = $02 : SHADOW
|
|
.word BlinkyNameData ; $87 = $04 _BLINKY_
|
|
.word SpeedyNameData ; $87 = $06 : SPEEDY
|
|
.word PinkyNameData ; $87 = $08 _PINKY_
|
|
.word CharacterIntroGraphicData0 ; $87 = $0A
|
|
.word CharacterIntroGraphicData1 ; $87 = $0C
|
|
.word PokeyNameData ; $87 = $0E
|
|
.word ClydeNameData ; $87 = $10
|
|
.word ScoringLegendData ; $87 = $12
|
|
|
|
;==============================================================================
|
|
; $C69B-$C72D: State $04 Display Update Streams
|
|
;
|
|
; Local:
|
|
; Contains ten display/update streams selected through
|
|
; CharacterIntroDisplayDataTable according to the state-$04 substate offset $87.
|
|
;
|
|
; LoadState04DisplayData copies the selected stream into RAM beginning at
|
|
; $024B until it encounters $FF. The $FF byte itself is also copied.
|
|
;
|
|
; For several streams, the byte immediately following $FF is $00. The
|
|
; loader examines this byte and uses it to trigger its optional secondary
|
|
; data copy.
|
|
;
|
|
; Global:
|
|
; Supplies the sequence of text and display changes shown during the timed
|
|
; state-$04 sequence. The data reveals that this portion of the attract/
|
|
; information display introduces game characters and later installs
|
|
; scoring/instruction-related display data.
|
|
;
|
|
; Notes:
|
|
; Many tile values correspond directly to ASCII-like character tiles, but
|
|
; special tile values are retained numerically.
|
|
;
|
|
; $00 bytes appearing after $FF belong to the control mechanism used by
|
|
; LoadState04DisplayData. They are not part of the $FF-terminated portion
|
|
; copied to $024B.
|
|
;
|
|
; The final stream at $C707 is structurally different: it contains multiple
|
|
; apparent PPU/update command groups before the final $FF.
|
|
;==============================================================================
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $C69B-$C6B2
|
|
; State04 substate offset: $00
|
|
;
|
|
; Destination prefix: $20E6
|
|
;
|
|
; Tile data corresponds approximately to:
|
|
; "CHARACTER ; NICKNAME"
|
|
;
|
|
; No explicit $00 control byte follows this stream before the next record.
|
|
;------------------------------------------------------------------------------
|
|
|
|
CharacterNicknameHeaderData:
|
|
.byte $20,$E6
|
|
.byte $43,$48,$41,$52,$41,$43,$54,$45,$52
|
|
.byte $20,$3B,$20,$20
|
|
.byte $4E,$49,$43,$4B,$4E,$41,$4D,$45
|
|
.byte $FF
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $C6B3-$C6BD
|
|
; State04 substate offset: $02
|
|
;
|
|
; Destination prefix: $2148
|
|
;
|
|
; Text-like tile data:
|
|
; ":SHADOW"
|
|
;
|
|
; $00 after $FF selects the loader's secondary-copy path.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ShadowNameData:
|
|
.byte $21,$48
|
|
.byte $3A,$53,$48,$41,$44,$4F,$57
|
|
.byte $FF
|
|
.byte $00
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $C6BE-$C6C8
|
|
; State04 substate offset: $04
|
|
;
|
|
; Destination prefix: $2153
|
|
;
|
|
; Text-like tile data:
|
|
; "_BLINKY_"
|
|
;
|
|
; No trailing $00 before the next stream.
|
|
;------------------------------------------------------------------------------
|
|
|
|
BlinkyNameData:
|
|
.byte $21,$53
|
|
.byte $5F,$42,$4C,$49,$4E,$4B,$59,$5F
|
|
.byte $FF
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $C6C9-$C6D3
|
|
; State04 substate offset: $06
|
|
;
|
|
; Destination prefix: $21A8
|
|
;
|
|
; Text-like tile data:
|
|
; ":SPEEDY"
|
|
;
|
|
; $00 after $FF selects the loader's secondary-copy path.
|
|
;------------------------------------------------------------------------------
|
|
SpeedyNameData:
|
|
.byte $21,$A8
|
|
.byte $3A,$53,$50,$45,$45,$44,$59
|
|
.byte $FF
|
|
.byte $00
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $C6D4-$C6DD
|
|
; State04 substate offset: $08
|
|
;
|
|
; Destination prefix: $21B3
|
|
;
|
|
; Text-like tile data:
|
|
; "_PINKY_"
|
|
;------------------------------------------------------------------------------
|
|
PinkyNameData:
|
|
.byte $21,$B3
|
|
.byte $5F,$50,$49,$4E,$4B,$59,$5F
|
|
.byte $FF
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $C6DE-$C6E9
|
|
; State04 substate offset: $0A
|
|
;
|
|
; Destination prefix: $2208
|
|
;
|
|
; Contains graphical/special tile values rather than plain character codes.
|
|
; $00 after $FF selects the loader's secondary-copy path.
|
|
;------------------------------------------------------------------------------
|
|
CharacterIntroGraphicData0:
|
|
.byte $22,$08
|
|
.byte $B6,$C1,$C3,$B7,$B4,$C2,$B3,$C4
|
|
.byte $FF
|
|
.byte $00
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $C6EA-$C6F2
|
|
; State04 substate offset: $0C
|
|
;
|
|
; Destination prefix: $2213
|
|
;
|
|
; Contains another set of special graphical tile values.
|
|
;------------------------------------------------------------------------------
|
|
CharacterIntroGraphicData1:
|
|
.byte $22,$13
|
|
.byte $C8,$B5,$C5,$C0,$C6,$C8
|
|
.byte $FF
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $C6F3-$C6FC
|
|
; State04 substate offset: $0E
|
|
;
|
|
; Destination prefix: $2268
|
|
;
|
|
; Text-like tile data:
|
|
; ":POKEY"
|
|
;
|
|
; $00 after $FF selects the loader's secondary-copy path.
|
|
;------------------------------------------------------------------------------
|
|
PokeyNameData:
|
|
.byte $22,$68
|
|
.byte $3A,$50,$4F,$4B,$45,$59
|
|
.byte $FF
|
|
.byte $00
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $C6FD-$C706
|
|
; State04 substate offset: $10
|
|
;
|
|
; Destination prefix: $2273
|
|
;
|
|
; Text-like tile data:
|
|
; "_CLYDE_"
|
|
;------------------------------------------------------------------------------
|
|
ClydeNameData:
|
|
.byte $22,$73
|
|
.byte $5F,$43,$4C,$59,$44,$45,$5F
|
|
.byte $FF
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $C707-$C72D
|
|
; State04 substate offset: $12
|
|
;
|
|
; Final composite display stream. Unlike the earlier simple records, this
|
|
; contains several apparent update groups separated by $00 bytes before the
|
|
; final $FF.
|
|
;
|
|
; Visible character-like portions include:
|
|
; "10 PTS"
|
|
; "50 PTS"
|
|
;
|
|
; The special tile values $CE,$CF and $23-$2B are preserved numerically.
|
|
;------------------------------------------------------------------------------
|
|
ScoringLegendData:
|
|
.byte $22,$AD
|
|
.byte $03,$20,$31,$30,$20,$50,$54,$53
|
|
.byte $00
|
|
|
|
.byte $22,$ED
|
|
.byte $01,$20,$35,$30,$20,$50,$54,$53
|
|
.byte $00
|
|
|
|
.byte $23,$34
|
|
.byte $CE,$CF
|
|
.byte $00
|
|
|
|
.byte $23,$4D
|
|
.byte $23,$24,$25,$26,$27,$28,$29,$2A,$2B
|
|
.byte $FF
|
|
|
|
|
|
;==============================================================================
|
|
; $C72E-$C76D: State $04 Secondary Object/Sprite Data
|
|
;
|
|
; Local:
|
|
; Contains 64 bytes of secondary display data used by
|
|
; LoadState04DisplayData.
|
|
;
|
|
; When a state-$04 display stream requests the secondary-copy path, the
|
|
; loader calculates:
|
|
;
|
|
; Y = ($87 - $02) * 4
|
|
;
|
|
; It then copies $10 (16) bytes from:
|
|
;
|
|
; CharacterIntroSpriteData,Y
|
|
;
|
|
; to:
|
|
;
|
|
; $0760,Y
|
|
;
|
|
; Because state-$04 substates advance by two, Y advances by eight bytes:
|
|
;
|
|
; $87 = $02 -> Y = $00
|
|
; $87 = $04 -> Y = $08
|
|
; $87 = $06 -> Y = $10
|
|
; $87 = $08 -> Y = $18
|
|
; ...
|
|
;
|
|
; The 16-byte transfers therefore intentionally overlap by eight bytes.
|
|
;
|
|
; Global:
|
|
; Supplies progressively updated object/sprite-related state during the
|
|
; state-$04 timed display sequence. The destination lies in RAM page $07,
|
|
; which is also used as an OAM DMA source elsewhere in the program.
|
|
;
|
|
; The repeated four-byte patterns strongly suggest sprite/OAM-style records,
|
|
; but exact field semantics should be confirmed against the code that
|
|
; consumes $0760 and the active OAM page before assigning field names.
|
|
;
|
|
; Notes:
|
|
; The table is safest to represent as 16 four-byte records during this pass.
|
|
; This preserves its natural repeated structure while allowing the loader's
|
|
; overlapping 16-byte windows to remain obvious.
|
|
;==============================================================================
|
|
|
|
CharacterIntroSpriteData:
|
|
; $C72E - record $00
|
|
.byte $48,$1C,$40,$26
|
|
|
|
; $C732 - record $01
|
|
.byte $48,$1B,$40,$2E
|
|
|
|
; $C736 - record $02
|
|
.byte $50,$1F,$40,$26
|
|
|
|
; $C73A - record $03
|
|
.byte $50,$1D,$40,$2E
|
|
|
|
; $C73E - record $04
|
|
.byte $60,$1C,$41,$26
|
|
|
|
; $C742 - record $05
|
|
.byte $60,$1B,$41,$2E
|
|
|
|
; $C746 - record $06
|
|
.byte $68,$1F,$41,$26
|
|
|
|
; $C74A - record $07
|
|
.byte $68,$1D,$41,$2E
|
|
|
|
; $C74E - record $08
|
|
.byte $78,$1C,$42,$26
|
|
|
|
; $C752 - record $09
|
|
.byte $78,$1B,$42,$2E
|
|
|
|
; $C756 - record $0A
|
|
.byte $80,$1F,$42,$26
|
|
|
|
; $C75A - record $0B
|
|
.byte $80,$1D,$42,$2E
|
|
|
|
; $C75E - record $0C
|
|
.byte $90,$1C,$43,$26
|
|
|
|
; $C762 - record $0D
|
|
.byte $90,$1B,$43,$2E
|
|
|
|
; $C766 - record $0E
|
|
.byte $98,$1F,$43,$26
|
|
|
|
; $C76A - record $0F
|
|
.byte $98,$1D,$43,$2E
|
|
|
|
|
|
;==============================================================================
|
|
; $C76E-$C791: State $04 Nametable Attribute Data
|
|
;
|
|
; Local:
|
|
; Contains $24 (36) bytes copied directly to PPUDATA by
|
|
; InitializeState04PpuData.
|
|
;
|
|
; The destination begins at PPU $23C8, so the complete transfer covers:
|
|
;
|
|
; $23C8-$23EB
|
|
;
|
|
; Global:
|
|
; Defines background palette selection attributes used by the state-$04
|
|
; display. The highly regular $00/$55/$AA/$FF pattern assigns repeating
|
|
; palette selections across large regions of the nametable.
|
|
;
|
|
; Notes:
|
|
; These are NES attribute-table bytes rather than tile indices.
|
|
;
|
|
; Each attribute byte contains four 2-bit palette selections. Values such
|
|
; as $00, $55, $AA and $FF therefore select the same palette throughout all
|
|
; four quadrants covered by that attribute byte:
|
|
;
|
|
; $00 -> palette 0 in all four quadrants
|
|
; $55 -> palette 1 in all four quadrants
|
|
; $AA -> palette 2 in all four quadrants
|
|
; $FF -> palette 3 in all four quadrants
|
|
;
|
|
; The final $22 mixes palette selections within its attribute regions.
|
|
;==============================================================================
|
|
|
|
CharacterIntroAttributeData:
|
|
.byte $00,$00,$00,$00,$00,$00,$00,$00
|
|
.byte $55,$55,$55,$55,$55,$55,$55,$55
|
|
.byte $AA,$AA,$AA,$AA,$AA,$AA,$AA,$AA
|
|
.byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
|
|
.byte $AA,$AA,$AA,$22
|
|
|
|
;==============================================================================
|
|
; $C792-$C7A0: State $04 Final-Phase Dispatcher
|
|
;
|
|
; Local:
|
|
; Uses $88 as a direct byte offset into a four-entry table of 16-bit
|
|
; addresses beginning at $C7A1.
|
|
;
|
|
; The selected address is stored in the temporary pointer $10/$11 and
|
|
; execution is transferred to it using an indirect JMP.
|
|
;
|
|
; Global:
|
|
; Implements state-$04 substate offset $16. Rather than performing the work
|
|
; directly, this substate introduces another secondary state machine.
|
|
;
|
|
; At this stage:
|
|
;
|
|
; $3F = $04 main state
|
|
; $87 = $16 state-$04 substate
|
|
; $88 final-phase dispatch offset
|
|
;
|
|
; This provides another level of progression within the final state-$04
|
|
; phase.
|
|
;
|
|
; Notes:
|
|
; $88 is used directly as a byte offset, so normal values are expected to
|
|
; advance by two:
|
|
;
|
|
; $00, $02, $04, $06
|
|
;
|
|
; The individual target handlers will be named as they are decoded.
|
|
;==============================================================================
|
|
State04FinalPhase:
|
|
ldy $88
|
|
|
|
lda State04FinalPhaseTable,y
|
|
sta dispatchVector
|
|
|
|
lda State04FinalPhaseTable+1,y
|
|
sta dispatchVector+1
|
|
|
|
jmp ($0010)
|
|
|
|
;==============================================================================
|
|
; $C7A1-$C7A6: State $04 Final-Phase Dispatch Table
|
|
;
|
|
; Local:
|
|
; Three 16-bit handler addresses indexed by $88.
|
|
;
|
|
; Global:
|
|
; Selects the processing stage used during State04FinalPhase.
|
|
;
|
|
; Notes:
|
|
; Valid byte offsets established by the table are $00, $02 and $04.
|
|
; $C7A7 is executable code and is not part of the pointer table.
|
|
;==============================================================================
|
|
|
|
State04FinalPhaseTable:
|
|
.word State04FinalPhaseInitialize ; $88 = $00
|
|
.word State04FinalPhaseActive ; $88 = $02
|
|
.word State04FinalPhaseComplete ; $88 = $04
|
|
|
|
;==============================================================================
|
|
; $C7A7-$C7F1: State $04 Final-Phase Initialization
|
|
;
|
|
; Local:
|
|
; Initializes the first stage of State04FinalPhase.
|
|
;
|
|
; Copies a $FF-terminated display/update stream from State04FinalDisplayData
|
|
; into RAM at $024B, including the terminator.
|
|
;
|
|
; Initializes several state variables and object/display values, clears
|
|
; $001E-$0031 and $0278-$028B, calls the helper at $DAF1, then advances
|
|
; $88 by two to select final-phase offset $02.
|
|
;
|
|
; Global:
|
|
; First handler selected by State04FinalPhase when $88 = $00. It prepares
|
|
; the RAM and display state required by the next final-phase handler at
|
|
; $C7F2.
|
|
;
|
|
; Notes:
|
|
; $1A is initialized to $FF.
|
|
; $1B, $89 and $8A are initialized to $00.
|
|
;
|
|
; $0274 = $F4
|
|
; $0276 = $A8
|
|
; $028C = $01
|
|
; $0292 = $20
|
|
;
|
|
; The exact semantics of these locations will be refined after tracing
|
|
; their consumers.
|
|
;
|
|
; State04FinalDisplayData is a display/update stream in the same general RAM
|
|
; command area used elsewhere through $024B.
|
|
;==============================================================================
|
|
|
|
State04FinalPhaseInitialize:
|
|
ldy #$00
|
|
|
|
@CopyDisplayData:
|
|
lda State04FinalDisplayData,y
|
|
sta $024B,y
|
|
iny
|
|
cmp #$FF
|
|
bne @CopyDisplayData
|
|
|
|
lda #$FF
|
|
sta pacmanMotion
|
|
|
|
lda #$00
|
|
sta $1B
|
|
sta $89
|
|
sta $8A
|
|
|
|
lda #$F4
|
|
sta $0274
|
|
|
|
lda #$A8
|
|
sta $0276
|
|
|
|
lda #$01
|
|
sta $028C
|
|
|
|
lda #$20
|
|
sta $0292
|
|
|
|
lda #$00
|
|
tay
|
|
|
|
@ClearLowRamBlock:
|
|
sta $001E,y
|
|
iny
|
|
cpy #$14
|
|
bne @ClearLowRamBlock
|
|
|
|
tay
|
|
|
|
@ClearObjectRamBlock:
|
|
sta $0278,y
|
|
iny
|
|
cpy #$14
|
|
bne @ClearObjectRamBlock
|
|
|
|
jsr $DAF1
|
|
|
|
inc $88
|
|
inc $88
|
|
|
|
jmp MainDispatchLoop
|
|
|
|
;==============================================================================
|
|
; $C7F2-$C856: State $04 Final-Phase Active Handler
|
|
;
|
|
; Local:
|
|
; Calls two per-frame helpers at UpdateState04Objects and
|
|
; AnimateState04DisplayPattern, then examines $0274.
|
|
;
|
|
; When $0274 equals one of:
|
|
;
|
|
; $E0
|
|
; $D1
|
|
; $C2
|
|
; $B3
|
|
;
|
|
; the routine calls InitializeState04ObjectSlot.
|
|
;
|
|
; Processing otherwise continues until $0274 reaches $40. While it has not
|
|
; reached $40, control returns to MainDispatchLoop.
|
|
;
|
|
; When $0274 reaches $40, the routine:
|
|
;
|
|
; - Initializes four 4-byte structures beginning at $001E.
|
|
; - Sets $1A = $01 and $1B = $50.
|
|
; - Sets $0293-$0296 to $01.
|
|
; - Clears $89.
|
|
; - Writes a short display/update sequence at $024B/$024D.
|
|
; - Advances $88 by two, selecting final-phase offset $04.
|
|
;
|
|
; Global:
|
|
; Active middle stage of State04FinalPhase. The handler appears to drive
|
|
; an animated sequence by calling UpdateState04Objects/AnimateState04DisplayPattern
|
|
; each frame and reacting when $0274 reaches several specific values.
|
|
;
|
|
; The milestone values $E0,$D1,$C2,$B3 invoke InitializeState04ObjectSlot. The exact meaning of
|
|
; those milestones should be assigned after the movement/update helpers are
|
|
; decoded.
|
|
;
|
|
; Notes:
|
|
; $0274 was initialized to $F4 by State04FinalPhaseInitialize, so the
|
|
; descending milestone tests strongly suggest $0274 is modified by one of
|
|
; the per-frame helper routines.
|
|
;
|
|
; The four low-RAM structures are $001E/$0022/$0026/$002A. Each receives
|
|
; $00 in its first byte and $C0 in its second byte. The remaining two bytes
|
|
; are not changed by this loop.
|
|
;==============================================================================
|
|
|
|
State04FinalPhaseActive:
|
|
jsr UpdateState04Objects
|
|
jsr AnimateState04DisplayPattern
|
|
|
|
lda $0274
|
|
|
|
cmp #$E0
|
|
beq @RunMilestoneUpdate
|
|
|
|
cmp #$D1
|
|
beq @RunMilestoneUpdate
|
|
|
|
cmp #$C2
|
|
beq @RunMilestoneUpdate
|
|
|
|
cmp #$B3
|
|
bne @CheckForCompletion
|
|
|
|
@RunMilestoneUpdate:
|
|
jsr InitializeState04ObjectSlot
|
|
|
|
@CheckForCompletion:
|
|
lda $0274
|
|
cmp #$40
|
|
beq @CompletePhase
|
|
|
|
jmp MainDispatchLoop
|
|
|
|
@CompletePhase:
|
|
ldy #$00
|
|
|
|
@InitializeStructures:
|
|
lda #$00
|
|
sta ghost1Motion,y
|
|
|
|
lda #$C0
|
|
sta ghost1Motion+1,y
|
|
|
|
iny
|
|
iny
|
|
iny
|
|
iny
|
|
|
|
cpy #$10
|
|
bne @InitializeStructures
|
|
|
|
lda #$01
|
|
sta pacmanMotion
|
|
|
|
lda #$50
|
|
sta pacmanMotion+1
|
|
|
|
lda #$01
|
|
sta $0293
|
|
sta $0294
|
|
sta $0295
|
|
sta $0296
|
|
|
|
lda #$00
|
|
sta $89
|
|
|
|
lda #$22
|
|
sta $024B
|
|
|
|
lda #$20
|
|
sta $024D
|
|
|
|
inc $88
|
|
inc $88
|
|
|
|
jmp MainDispatchLoop
|
|
|
|
;==============================================================================
|
|
; $C857-$C8A7: State $04 Final-Phase Completion Handler
|
|
;
|
|
; Local:
|
|
; Final handler for final-phase offset $88 = $04.
|
|
;
|
|
; If $8A is nonzero, calls RotateState04ObjectSlots and decrements the countdown. When the
|
|
; countdown reaches zero, scans status entries beginning at $028D until an
|
|
; entry with one or more upper-three status bits set is found.
|
|
;
|
|
; The matching entry and associated state are cleared. If $89 has reached
|
|
; $04, the routine sets $47 to $01 and transfers control to GameModeEntry.
|
|
;
|
|
; When $8A is already zero on entry, calls $C8DC and returns to the common
|
|
; main dispatch loop.
|
|
;
|
|
; Global:
|
|
; Final processing stage of the nested state-$04 sequence:
|
|
;
|
|
; $3F = $04
|
|
; $87 = $16
|
|
; $88 = $04
|
|
;
|
|
; The eventual transfer to GameModeEntry appears to leave this attract/display
|
|
; sequence and enter another major portion of the program.
|
|
;
|
|
; Notes:
|
|
; $8A acts as a countdown here.
|
|
; $89 is tested against $04 for completion.
|
|
;
|
|
; The scan at $028D looks for the first entry satisfying:
|
|
;
|
|
; ($028D,Y & $E0) != 0
|
|
;
|
|
; Exact object/state semantics remain for a later pass.
|
|
;==============================================================================
|
|
|
|
State04FinalPhaseComplete:
|
|
lda $8A
|
|
beq @RunRegularUpdate
|
|
|
|
jsr RotateState04ObjectSlots
|
|
|
|
dec $8A
|
|
beq @CountdownComplete
|
|
|
|
jmp MainDispatchLoop
|
|
|
|
@CountdownComplete:
|
|
ldy #$00
|
|
|
|
@FindEntry:
|
|
lda $028D,y
|
|
and #$E0
|
|
bne @EntryFound
|
|
|
|
iny
|
|
bne @FindEntry
|
|
|
|
@EntryFound:
|
|
lda #$00
|
|
sta $028D,y
|
|
|
|
lda #$00
|
|
sta $0293,y
|
|
|
|
tya
|
|
asl
|
|
asl
|
|
tay
|
|
|
|
lda #$00
|
|
sta $0278,y
|
|
sta $027A,y
|
|
sta ghost1Motion,y
|
|
sta ghost1Motion+1,y
|
|
|
|
lda #$A8
|
|
sta $0276
|
|
|
|
lda $89
|
|
cmp #$04
|
|
beq @FinishSequence
|
|
|
|
jmp MainDispatchLoop
|
|
|
|
@FinishSequence:
|
|
lda #$01
|
|
sta activePlayerFlag
|
|
|
|
jmp GameModeEntry
|
|
|
|
@RunRegularUpdate:
|
|
jsr UpdateState04Objects
|
|
|
|
jmp MainDispatchLoop
|
|
|
|
;==============================================================================
|
|
; $C8A8-$C8DB: Allocate/Initialize State $04 Object Slot
|
|
;
|
|
; Local:
|
|
; Searches four 4-byte structures beginning at $0278 for the first slot
|
|
; whose first byte is zero.
|
|
;
|
|
; During the search, $00 tracks the logical slot number while Y advances
|
|
; by four bytes per structure.
|
|
;
|
|
; Once a free slot is found, initializes that structure:
|
|
;
|
|
; +0 = $F4
|
|
; +2 = $A8
|
|
;
|
|
; It also initializes corresponding four-byte-strided zero-page state:
|
|
;
|
|
; $001E+Y = $FF
|
|
; $001F+Y = $00
|
|
;
|
|
; The logical slot number saved in $00 is then used to index two separate
|
|
; per-slot arrays:
|
|
;
|
|
; $0293+slot = current $89 value
|
|
; $028D+slot = $0C
|
|
;
|
|
; Finally increments $89 and returns.
|
|
;
|
|
; Global:
|
|
; Called by State04FinalPhaseActive whenever $0274 reaches the milestone
|
|
; values $E0, $D1, $C2, or $B3.
|
|
;
|
|
; This strongly suggests that the routine activates one additional object
|
|
; at each milestone during the state-$04 final sequence. Four slots are
|
|
; available, matching the four milestone values.
|
|
;
|
|
; Notes:
|
|
; $0278 appears to be the first field of a four-byte structure array.
|
|
; $027A is the third field of the same structure.
|
|
;
|
|
; $001E/$001F are parallel four-byte-strided state fields.
|
|
;
|
|
; $028D and $0293 are indexed by logical slot number rather than the
|
|
; four-byte structure offset.
|
|
;
|
|
; Exact object semantics remain deliberately unnamed until UpdateState04Objects
|
|
; and RotateState04ObjectSlots reveal how these structures are updated.
|
|
;==============================================================================
|
|
|
|
InitializeState04ObjectSlot:
|
|
ldy #$00
|
|
sty workPtr0
|
|
|
|
@FindFreeSlot:
|
|
lda $0278,y
|
|
beq @InitializeSlot
|
|
|
|
inc workPtr0
|
|
|
|
iny
|
|
iny
|
|
iny
|
|
iny
|
|
|
|
bne @FindFreeSlot
|
|
|
|
@InitializeSlot:
|
|
lda #$F4
|
|
sta $0278,y
|
|
|
|
lda #$A8
|
|
sta $027A,y
|
|
|
|
lda #$FF
|
|
sta ghost1Motion,y
|
|
|
|
lda #$00
|
|
sta $001F,y
|
|
|
|
ldy workPtr0
|
|
|
|
lda $89
|
|
sta $0293,y
|
|
|
|
lda #$0C
|
|
sta $028D,y
|
|
|
|
inc $89
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $C8DC-$C8EA: State $04 Per-Frame Object Update Coordinator
|
|
;
|
|
; Local:
|
|
; Runs four update stages in sequence:
|
|
;
|
|
; UpdateTransitionObjectPositions
|
|
; RotateState04ObjectSlots
|
|
; UpdateState04ObjectStatus
|
|
; CheckState04ObjectTrigger
|
|
;
|
|
; After those return, tail-jumps to $DAF1 rather than returning directly.
|
|
;
|
|
; Global:
|
|
; Called once per frame during portions of the state-$04 final sequence.
|
|
; This routine coordinates the lower-level movement/object/display work
|
|
; associated with that sequence.
|
|
;
|
|
; It is called from both State04FinalPhaseActive and
|
|
; State04FinalPhaseComplete.
|
|
;
|
|
; Notes:
|
|
; The exact responsibilities of $EA19, $C92E, $C9FA, CheckState04ObjectTrigger
|
|
; and $DAF1 will be refined as those routines are decoded.
|
|
;
|
|
; The JMP to $DAF1 is a tail call: $DAF1 ultimately returns directly to
|
|
; the original caller of this routine.
|
|
;==============================================================================
|
|
UpdateState04Objects:
|
|
jsr UpdateTransitionObjectPositions
|
|
jsr RotateState04ObjectSlots
|
|
jsr UpdateState04ObjectStatus
|
|
jsr CheckState04ObjectTrigger
|
|
jmp BuildEntitySpriteBuffer
|
|
|
|
;==============================================================================
|
|
; $C8EB-$C92D: Check State $04 Object Trigger
|
|
;
|
|
; Local:
|
|
; Returns immediately when $1A is negative.
|
|
;
|
|
; Otherwise computes:
|
|
;
|
|
; threshold = $0274 + $08
|
|
;
|
|
; and scans four 4-byte structures beginning at $0278.
|
|
;
|
|
; For each active structure, compares its first byte against the threshold.
|
|
; When a qualifying structure is found, uses $89 as an index into a ROM
|
|
; table at $C9EE, installs the resulting value into a per-slot status array,
|
|
; clears a related slot value, initializes $8A to $40, and clears $028C and
|
|
; $0276.
|
|
;
|
|
; Global:
|
|
; Part of UpdateState04Objects. Appears to detect when one of the active
|
|
; state-$04 objects crosses a position threshold relative to the primary
|
|
; value at $0274, then initiates a $40-frame/countdown event through $8A.
|
|
;
|
|
; Notes:
|
|
; $00 holds the comparison threshold ($0274 + $08).
|
|
; $01 tracks the logical object slot while Y steps through four-byte
|
|
; structures.
|
|
;
|
|
; $89 is incremented as part of the event setup.
|
|
;
|
|
; $C9EE is a small ROM lookup table that remains to be decoded.
|
|
;==============================================================================
|
|
|
|
CheckState04ObjectTrigger:
|
|
lda pacmanMotion
|
|
bpl @Continue
|
|
|
|
rts
|
|
|
|
@Continue:
|
|
lda $0274
|
|
clc
|
|
adc #$08
|
|
sta workPtr0
|
|
|
|
ldy #$00
|
|
sty workPtr0+1
|
|
|
|
@ScanObjects:
|
|
lda $0278,y
|
|
beq @NextObject
|
|
|
|
cmp workPtr0
|
|
bcc @TriggerEvent
|
|
|
|
@NextObject:
|
|
inc workPtr0+1
|
|
|
|
iny
|
|
iny
|
|
iny
|
|
iny
|
|
|
|
cpy #$10
|
|
bne @ScanObjects
|
|
|
|
rts
|
|
|
|
@TriggerEvent:
|
|
ldy $89
|
|
inc $89
|
|
|
|
lda #$40
|
|
sta $8A
|
|
|
|
lda $C9EE,y
|
|
|
|
ldy workPtr0+1
|
|
sta $028D,y
|
|
|
|
lda #$00
|
|
sta $0293,y
|
|
|
|
lda #$00
|
|
sta $028C
|
|
sta $0276
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $C92E-$C9B7: Rotate State $04 Object Slots
|
|
;
|
|
; Local:
|
|
; Rotates four related object/state entries across several parallel arrays.
|
|
;
|
|
; The routine operates on:
|
|
;
|
|
; $001E/$001F four-byte-strided zero-page structures
|
|
; $0278-$0287 four 4-byte object structures
|
|
; $028D-$0290 four object/status bytes
|
|
; $0293-$0296 four object/index bytes
|
|
;
|
|
; For each array, the first entry is saved temporarily, entries 1-3 are
|
|
; shifted toward entry 0, and the saved entry 0 is moved to entry 3.
|
|
;
|
|
; Global:
|
|
; Called by UpdateState04Objects every frame, and also directly from
|
|
; State04FinalPhaseComplete while its $8A countdown is active.
|
|
;
|
|
; This appears to cycle the four state-$04 object slots through a fixed
|
|
; ordering while keeping their parallel state/status arrays synchronized.
|
|
;
|
|
; Notes:
|
|
; $00-$03 are temporary storage.
|
|
;
|
|
; The zero-page structures use a four-byte stride but only the first two
|
|
; bytes of each structure are moved here.
|
|
;
|
|
; The $0278 array moves all four bytes of each structure.
|
|
;
|
|
; $028D-$0290 and $0293-$0296 are simple four-entry byte arrays.
|
|
;==============================================================================
|
|
RotateState04ObjectSlots:
|
|
; -------------------------------------------------------------------------
|
|
; Rotate the first two bytes of the four-byte-strided zero-page structures.
|
|
;
|
|
; Entries:
|
|
; 0 -> $001E/$001F
|
|
; 1 -> $0022/$0023
|
|
; 2 -> $0026/$0027
|
|
; 3 -> $002A/$002B
|
|
; -------------------------------------------------------------------------
|
|
|
|
lda ghost1Motion
|
|
sta workPtr0
|
|
|
|
lda ghost1Motion+1
|
|
sta workPtr0+1
|
|
|
|
ldy #$00
|
|
|
|
@ShiftLowRamStructures:
|
|
lda ghost2Motion,y
|
|
sta ghost1Motion,y
|
|
|
|
lda ghost2Motion+1,y
|
|
sta ghost1Motion+1,y
|
|
|
|
iny
|
|
iny
|
|
iny
|
|
iny
|
|
|
|
cpy #$0C
|
|
bne @ShiftLowRamStructures
|
|
|
|
lda workPtr0
|
|
sta ghost4Motion
|
|
|
|
lda workPtr0+1
|
|
sta ghost4Motion+1
|
|
|
|
; -------------------------------------------------------------------------
|
|
; Rotate four complete 4-byte structures at $0278-$0287.
|
|
; -------------------------------------------------------------------------
|
|
|
|
lda $0278
|
|
sta workPtr0
|
|
|
|
lda $0279
|
|
sta workPtr0+1
|
|
|
|
lda $027A
|
|
sta workPtr1
|
|
|
|
lda $027B
|
|
sta workPtr1+1
|
|
|
|
ldy #$00
|
|
|
|
@ShiftObjectStructures:
|
|
lda $027C,y
|
|
sta $0278,y
|
|
|
|
iny
|
|
cpy #$0C
|
|
bne @ShiftObjectStructures
|
|
|
|
lda workPtr0
|
|
sta $0284
|
|
|
|
lda workPtr0+1
|
|
sta $0285
|
|
|
|
lda workPtr1
|
|
sta $0286
|
|
|
|
lda workPtr1+1
|
|
sta $0287
|
|
|
|
; -------------------------------------------------------------------------
|
|
; Rotate the four status bytes at $028D-$0290.
|
|
; -------------------------------------------------------------------------
|
|
|
|
lda $028D
|
|
sta workPtr0
|
|
|
|
ldy #$00
|
|
|
|
@ShiftStatusArray:
|
|
lda $028E,y
|
|
sta $028D,y
|
|
|
|
iny
|
|
cpy #$03
|
|
bne @ShiftStatusArray
|
|
|
|
lda workPtr0
|
|
sta $0290
|
|
|
|
; -------------------------------------------------------------------------
|
|
; Rotate the four associated index/state bytes at $0293-$0296.
|
|
; -------------------------------------------------------------------------
|
|
|
|
lda $0293
|
|
sta workPtr0
|
|
|
|
ldy #$00
|
|
|
|
@ShiftIndexArray:
|
|
lda $0294,y
|
|
sta $0293,y
|
|
|
|
iny
|
|
cpy #$03
|
|
bne @ShiftIndexArray
|
|
|
|
lda workPtr0
|
|
sta $0296
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $C9B8-$C9D7: Animate State $04 Display Pattern
|
|
;
|
|
; Local:
|
|
; Uses the frame counter at $4B to periodically copy one of two four-byte
|
|
; patterns into RAM $024B-$024E.
|
|
;
|
|
; The routine runs only when the low three bits of $4B are zero:
|
|
;
|
|
; ($4B & $07) == 0
|
|
;
|
|
; so the display data is updated once every eight frames.
|
|
;
|
|
; Bit 3 of $4B selects between two adjacent four-byte patterns beginning
|
|
; at $C9F2:
|
|
;
|
|
; bit 3 = 0 -> source $C9F2-$C9F5
|
|
; bit 3 = 1 -> source $C9F6-$C9F9
|
|
;
|
|
; Global:
|
|
; Called by State04FinalPhaseActive once per frame. Provides a simple
|
|
; two-frame animation/blink effect by updating the command/display buffer
|
|
; at $024B according to the NMI-driven frame counter $4B.
|
|
;
|
|
; Notes:
|
|
; $4B is incremented by NmiHandler once per frame.
|
|
;
|
|
; The source data at $C9F2 overlaps the tail of nearby ROM data. We should
|
|
; decode the surrounding $C9D8-$C9F9 region before assigning a more
|
|
; specific visual meaning to the two animation frames.
|
|
;==============================================================================
|
|
AnimateState04DisplayPattern:
|
|
lda frameCounter
|
|
and #$07
|
|
beq @UpdatePattern
|
|
|
|
rts
|
|
|
|
@UpdatePattern:
|
|
ldx #$00
|
|
ldy #$00
|
|
|
|
lda frameCounter
|
|
and #$08
|
|
beq @CopyPattern
|
|
|
|
ldy #$04
|
|
|
|
@CopyPattern:
|
|
lda State04AnimationFrames,y
|
|
sta $024B,x
|
|
|
|
inx
|
|
iny
|
|
|
|
cpx #$04
|
|
bne @CopyPattern
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $C9D8-$C9ED: State $04 Final Display Data
|
|
;==============================================================================
|
|
|
|
State04FinalDisplayData:
|
|
.byte $22,$AD
|
|
.byte $2D,$2D,$2D,$2D,$2D,$2D,$2D,$2D
|
|
.byte $00
|
|
|
|
.byte $22,$ED
|
|
.byte $2D,$2D,$2D,$2D,$2D,$2D,$2D,$2D
|
|
.byte $FF
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $C9EE-$C9F1: Adjacent data, purpose not yet resolved.
|
|
;------------------------------------------------------------------------------
|
|
|
|
State04UnknownData:
|
|
.byte $2D,$2F,$32,$34
|
|
|
|
|
|
;==============================================================================
|
|
; $C9F2-$C9F9: State $04 Animation Frames
|
|
;
|
|
; Two four-byte animation/update frames.
|
|
;
|
|
; $4B bit 3 = 0 -> frame 0
|
|
; $4B bit 3 = 1 -> frame 1
|
|
;==============================================================================
|
|
|
|
State04AnimationFrames:
|
|
.byte $22,$C7,$20,$FF
|
|
.byte $22,$C7,$01,$FF
|
|
|
|
;==============================================================================
|
|
; $C9FA-$CA3F: Update State $04 Object Status Animation
|
|
;
|
|
; Local:
|
|
; Selects an animation/status value from a ROM table at State04ObjectStatusTable and writes
|
|
; the value into active entries of $028D-$0290.
|
|
;
|
|
; The selected table range depends on $1A:
|
|
;
|
|
; $1A negative -> base offset $00
|
|
; $1A nonnegative -> base offset $0A
|
|
;
|
|
; $B7 is incremented each call and its low three bits select an entry from
|
|
; the first lookup range. The resulting value is written to $028C.
|
|
;
|
|
; The routine then updates the four status entries $028D-$0290 only once
|
|
; every eight frames. Bit 3 of $4B selects between two animation phases.
|
|
;
|
|
; Global:
|
|
; Called by UpdateState04Objects during the active state-$04 final sequence.
|
|
; Provides periodic animation/status changes for the four object slots
|
|
; maintained in $028D-$0290.
|
|
;
|
|
; Notes:
|
|
; $B7 behaves as an additional animation counter here.
|
|
;
|
|
; $4B is the NMI-driven frame counter.
|
|
;
|
|
; $028C is updated on every call, while $028D-$0290 are changed only when
|
|
; ($4B & $07) == 0.
|
|
;
|
|
; The table beginning at State04ObjectStatusTable follows this routine immediately and can be
|
|
; decoded separately.
|
|
;==============================================================================
|
|
|
|
UpdateState04ObjectStatus:
|
|
ldx #$00
|
|
|
|
lda $1A
|
|
bmi @UseTableBase
|
|
|
|
ldx #$0A
|
|
|
|
@UseTableBase:
|
|
stx workPtr0
|
|
|
|
inc $B7
|
|
|
|
lda $B7
|
|
and #$07
|
|
clc
|
|
adc workPtr0
|
|
tay
|
|
|
|
lda State04ObjectStatusTable,y
|
|
sta $028C
|
|
|
|
; Only update the four object entries once every eight frames.
|
|
lda $4B
|
|
and #$07
|
|
beq @UpdateObjectEntries
|
|
|
|
rts
|
|
|
|
@UpdateObjectEntries:
|
|
lda frameCounter
|
|
and #$08
|
|
beq @SelectTableValue
|
|
|
|
lda #$01
|
|
|
|
@SelectTableValue:
|
|
clc
|
|
adc workPtr0
|
|
adc #$08
|
|
tay
|
|
|
|
lda State04ObjectStatusTable,y
|
|
sta workPtr0
|
|
|
|
ldy #$00
|
|
|
|
@UpdateStatusEntries:
|
|
lda $028D,y
|
|
beq @NextStatusEntry
|
|
|
|
lda workPtr0
|
|
sta $028D,y
|
|
|
|
@NextStatusEntry:
|
|
iny
|
|
cpy #$04
|
|
bne @UpdateStatusEntries
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $CA40-$CA53: State $04 Object Status/Animation Lookup
|
|
;
|
|
; Local:
|
|
; Twenty-byte lookup table used by UpdateState04ObjectStatus.
|
|
;
|
|
; The routine selects one of two 10-byte groups:
|
|
;
|
|
; $1A negative -> group at offset $00
|
|
; $1A nonnegative -> group at offset $0A
|
|
;
|
|
; Within each group:
|
|
;
|
|
; bytes 0-7 are selected by ($B7 & $07)
|
|
; bytes 8-9 are selected by the slower frame-animation state
|
|
;
|
|
; Global:
|
|
; Supplies animation/status values for the four objects used during the
|
|
; final state-$04 sequence.
|
|
;
|
|
; Notes:
|
|
; Exact meanings of the individual values remain intentionally unnamed
|
|
; until the consumers of $028C and $028D-$0290 are better understood.
|
|
;==============================================================================
|
|
State04ObjectStatusTable:
|
|
; Group 0, selected while $1A is negative.
|
|
.byte $04,$04,$04,$05,$05,$04,$01,$01
|
|
.byte $0C,$0D
|
|
|
|
; Group 1, selected while $1A is nonnegative.
|
|
.byte $08,$08,$08,$09,$09,$08,$01,$01
|
|
.byte $1E,$1F
|
|
|
|
;==============================================================================
|
|
; $CA54-$CAD6: Main Game/Mode Initialization and Dispatch Loop
|
|
;
|
|
; Local:
|
|
; Reconfigures the PPU, waits for VBlank, disables rendering, clears several
|
|
; state variables, and invokes three initialization helpers.
|
|
;
|
|
; Depending on $48, initializes or preserves parts of two parallel RAM
|
|
; regions beginning at $67 and $77. It then initializes additional state,
|
|
; re-enables NMI through PPUCTRL=$88, and synchronizes with NMI via $40.
|
|
;
|
|
; After initialization, enters a persistent foreground loop that:
|
|
;
|
|
; - optionally watches controller bits $0C and returns to MainEntry,
|
|
; - services the countdown at $4C,
|
|
; - uses $3F as a byte offset into an eight-entry dispatch table at $CAD7,
|
|
; - indirect-jumps through $10/$11 to the selected handler.
|
|
;
|
|
; Global:
|
|
; Multiple earlier state-machine paths converge here, making this a major
|
|
; transition point out of the initial/state-$04 sequence and into another
|
|
; top-level game-mode state machine.
|
|
;
|
|
; The routine contains both one-time initialization and the common dispatch
|
|
; loop used by the handlers selected from $CAD7.
|
|
;
|
|
; Notes:
|
|
; $3F is reused as a byte offset into this new dispatch table.
|
|
;
|
|
; $40 continues to provide foreground/NMI synchronization.
|
|
;
|
|
; $4C acts as a countdown/delay gate in the dispatch loop.
|
|
;
|
|
; The exact semantics of $48, $46, $67-$86 and the new dispatch states will
|
|
; be refined as their handlers are decoded.
|
|
;==============================================================================
|
|
GameModeEntry:
|
|
lda #$08
|
|
sta PPUCTRL
|
|
sta ppuCtrlShadow
|
|
|
|
@WaitForVBlank:
|
|
lda PPUSTATUS
|
|
bpl @WaitForVBlank
|
|
|
|
lda #$00
|
|
sta PPUMASK
|
|
sta gameState
|
|
sta cocktailModeFlag
|
|
sta $69
|
|
sta $4A
|
|
|
|
jsr ClearGameplayNametables
|
|
jsr DrawGameplayHudLabels
|
|
jsr DrawGameplayScoreFields
|
|
|
|
lda gameplaySuspended
|
|
beq @ClearPlayerState
|
|
|
|
lda #$01
|
|
sta roundNumber
|
|
|
|
bne @InitializeCommonState
|
|
|
|
@ClearPlayerState:
|
|
lda #$00
|
|
tay
|
|
|
|
@ClearPlayerStateLoop:
|
|
sta roundNumber,y
|
|
iny
|
|
cpy #$20
|
|
bne @ClearPlayerStateLoop
|
|
|
|
lda #$03
|
|
sta roundNumber
|
|
sta $77
|
|
|
|
sta $0600
|
|
sta $0601
|
|
|
|
@InitializeCommonState:
|
|
lda #$FF
|
|
sta roundDisplayValue
|
|
sta $78
|
|
sta $0245
|
|
|
|
lda #$88
|
|
sta ppuCtrlShadow
|
|
sta PPUCTRL
|
|
|
|
GameModeFrameSync:
|
|
@WaitForNextFrame:
|
|
lda #$01
|
|
sta $40
|
|
|
|
@WaitForNmi:
|
|
lda $40
|
|
bne @WaitForNmi
|
|
|
|
@DispatchLoop:
|
|
lda gameplaySuspended
|
|
beq @ProcessDelay
|
|
|
|
lda currentInput
|
|
and #$0C
|
|
beq @ProcessDelay
|
|
|
|
lda #$02 ; TODO: what is state $02?
|
|
sta gameState
|
|
|
|
jmp MainEntry
|
|
|
|
@ProcessDelay:
|
|
lda stateTimer
|
|
beq @DispatchState
|
|
|
|
dec stateTimer
|
|
bne @WaitForNextFrame
|
|
|
|
@DispatchState:
|
|
ldy gameState
|
|
|
|
lda GameModeStateTable,y
|
|
sta dispatchVector
|
|
|
|
lda GameModeStateTable+1,y
|
|
sta dispatchVector+1
|
|
|
|
jmp ($0010)
|
|
|
|
;==============================================================================
|
|
; $CAD7-$CAE6: Game Mode State Dispatch Table
|
|
;
|
|
; Local:
|
|
; Eight 16-bit handler addresses selected by GameModeEntry using $3F as a
|
|
; direct byte offset.
|
|
;
|
|
; Global:
|
|
; Defines the next major foreground state machine entered through GameModeEntry.
|
|
;
|
|
; Notes:
|
|
; Since $3F indexes raw bytes rather than words, expected state offsets are:
|
|
;
|
|
; $00,$02,$04,$06,$08,$0A,$0C,$0E
|
|
;
|
|
; Handler names remain unresolved until each target is decoded.
|
|
;==============================================================================
|
|
|
|
GameModeStateTable:
|
|
.word GameModeState00 ; $3F = $00
|
|
.word GameModeState02 ; $3F = $02
|
|
.word GameModeState04 ; $3F = $04
|
|
.word GameModeState06 ; $3F = $06
|
|
.word GameModeState08 ; $3F = $08
|
|
.word GameModeState0A ; $3F = $0A
|
|
.word GameModeState0C ; $3F = $0C
|
|
.word InitializeGameplayTransitionState
|
|
; $3F = $0E
|
|
|
|
;==============================================================================
|
|
; $CAE7-$CAE8: Game-Mode Auxiliary Pointer
|
|
;
|
|
; Local:
|
|
; Two-byte little-endian ROM value containing $E7BF.
|
|
;
|
|
; Global:
|
|
; Sits immediately between GameModeStateTable and the $3F=$04 handler.
|
|
; Its consumer has not yet been established during this pass.
|
|
;
|
|
; Notes:
|
|
; Keep this as data rather than attempting to decode it as 6502 code.
|
|
;==============================================================================
|
|
|
|
GameModeAuxPointer:
|
|
.word $E7BF
|
|
|
|
;==============================================================================
|
|
; $CAE9-$CB5A: Game-Mode State $04 / Pause and Per-Frame Processing
|
|
;
|
|
; Local:
|
|
; First checks $060F. If nonzero, immediately returns to the common
|
|
; NMI/frame synchronization point at $CAA7.
|
|
;
|
|
; Otherwise performs edge detection on controller bit $08 using $49 as
|
|
; the stored previous state.
|
|
;
|
|
; On a new active $08 input:
|
|
; - increments $4A,
|
|
; - installs a short update command at $024B onward,
|
|
; - selects between two command variants according to $47 & $46,
|
|
; - uses bit 0 of $4A to alternate the displayed data,
|
|
; - optionally clears $060F.
|
|
;
|
|
; When no new pause/input edge is being handled, and bit 0 of $4A is clear,
|
|
; calls a sequence of gameplay/update helpers before returning to the common
|
|
; frame synchronization point.
|
|
;
|
|
; Global:
|
|
; Handler selected when GameModeStateTable offset $3F = $04.
|
|
;
|
|
; The adjacent data beginning at $CB5B contains the tile values for the word
|
|
; "PAUSE", strongly indicating that this handler manages pause-state input
|
|
; and display updates while also running the normal per-frame gameplay
|
|
; helper chain when not paused.
|
|
;
|
|
; Notes:
|
|
; $49 stores the previous masked state of controller bit $08.
|
|
; $4A is incremented on each newly detected active edge and bit 0 is used
|
|
; here as a pause/run toggle.
|
|
;
|
|
; $060F is consulted as another gate associated with this handler.
|
|
;
|
|
; Helper routines remain address-named during this pass.
|
|
;==============================================================================
|
|
|
|
GameModeState04:
|
|
lda $060F
|
|
beq @CheckPauseInput
|
|
|
|
jmp GameModeFrameSync
|
|
|
|
@CheckPauseInput:
|
|
lda currentInput
|
|
and #$08
|
|
cmp $49
|
|
beq @ProcessCurrentMode
|
|
|
|
sta $49
|
|
|
|
lda $49
|
|
beq @ProcessCurrentMode
|
|
|
|
inc $4A
|
|
|
|
ldx #$22
|
|
|
|
lda activePlayerFlag
|
|
and cocktailModeFlag
|
|
beq @SetCommandAddress
|
|
|
|
ldx #$2A
|
|
|
|
@SetCommandAddress:
|
|
stx $024B
|
|
|
|
lda #$37
|
|
sta $024C
|
|
|
|
ldx #$06
|
|
ldy #$00
|
|
|
|
lda $4A
|
|
and #$01
|
|
beq @CopyPauseData
|
|
|
|
ldx #$00
|
|
sta $060F
|
|
|
|
@CopyPauseData:
|
|
lda PauseDisplayData,x
|
|
sta $024D,y
|
|
|
|
inx
|
|
iny
|
|
|
|
cpy #$06
|
|
bne @CopyPauseData
|
|
|
|
jmp GameModeFrameSync
|
|
|
|
@ProcessCurrentMode:
|
|
lda $4A
|
|
and #$01
|
|
beq @RunFrameUpdates
|
|
|
|
jmp GameModeFrameSync
|
|
|
|
@RunFrameUpdates:
|
|
jsr UpdateGameplayTimers
|
|
jsr UpdateGameplayTileState
|
|
jsr UpdatePlayerMovement
|
|
jsr UpdatePlayerDirectionAnimation
|
|
jsr UpdateGameplayEntities
|
|
jsr UpdateEntitySpriteStates
|
|
jsr UpdateEntityStatusFlags
|
|
jsr UpdatePeriodicFourEntryState
|
|
jsr CheckGameplayProximity
|
|
jsr CheckEntityCollisions
|
|
|
|
jmp GameModeFrameSync
|
|
|
|
;==============================================================================
|
|
; $CB5B-$CB66: Pause Display Data
|
|
;
|
|
; Local:
|
|
; Two six-byte display strings selected by GameModeState04.
|
|
;
|
|
; Offset $00:
|
|
; "PAUSE",$FF
|
|
;
|
|
; Offset $06:
|
|
; five $2D tiles followed by $FF, used to replace/clear the pause text.
|
|
;
|
|
; Global:
|
|
; Provides the visible pause-state update controlled by $4A bit 0.
|
|
;==============================================================================
|
|
|
|
PauseDisplayData:
|
|
.byte $50,$41,$55,$53,$45,$FF
|
|
.byte $2D,$2D,$2D,$2D,$2D,$FF
|
|
|
|
|
|
;==============================================================================
|
|
; $CB67-$CC9B: Game-Mode State $02 Handler
|
|
;
|
|
; Local:
|
|
; Implements a multi-phase initialization/progression state.
|
|
;
|
|
; When $87 is zero, constructs structured data in RAM page $07 using several
|
|
; ROM lookup tables. The construction is influenced by $48, $47, $46,
|
|
; $68 and $69.
|
|
;
|
|
; Once $87 is nonzero, it advances once per frame. At $87=$78, initializes
|
|
; a new group of RAM state and prepares display/update data in $024B-$0254.
|
|
;
|
|
; At $87=$C0, checks $0600/$0601. If both are zero, clears a large area of
|
|
; page $07 and advances the main game-mode state to $04.
|
|
;
|
|
; Global:
|
|
; Handler selected by GameModeStateTable when $3F=$02. This appears to be
|
|
; a substantial setup/transition state between game-mode phases, preparing
|
|
; object/OAM-related RAM, display command data, and other game state before
|
|
; handing control to GameModeState04.
|
|
;
|
|
; Notes:
|
|
; $87 serves as the phase timer/progression value.
|
|
;
|
|
; $00/$01 initially form a pointer to $0760 during the page-$07 build.
|
|
; The same locations are reused later as temporary display-address values.
|
|
;
|
|
; ROM tables $CC9C-$CCD8 immediately follow this routine and should be
|
|
; decoded next.
|
|
;==============================================================================
|
|
|
|
GameModeState02:
|
|
lda $87
|
|
beq @BuildInitialData
|
|
|
|
jmp @AdvancePhase
|
|
|
|
@BuildInitialData:
|
|
lda #$60
|
|
sta workPtr0
|
|
|
|
lda #$07
|
|
sta workPtr0+1
|
|
|
|
lda $48
|
|
bne @AdvancePhase
|
|
|
|
lda #$02
|
|
sta workValue0
|
|
|
|
ldy #$00
|
|
sty workValue1
|
|
sty workValue2
|
|
sty workValue3
|
|
|
|
@BuildOuterLoop:
|
|
ldx workValue2
|
|
|
|
lda State02PositionTable,x
|
|
sta workPtr1
|
|
|
|
lda State02PositionTable + 1,x
|
|
sta workPtr1+1
|
|
|
|
ldx workValue3
|
|
|
|
lda State02EntryCounts,x
|
|
sta workValue4
|
|
|
|
@BuildInnerLoop:
|
|
lda workPtr1+1
|
|
sta ($00),y
|
|
|
|
ldx workValue1
|
|
|
|
lda State02ValueTableA,x
|
|
iny
|
|
sta (workPtr0),y
|
|
|
|
lda State02ValueTableB,x
|
|
iny
|
|
sta (workPtr0),y
|
|
|
|
lda workPtr1
|
|
iny
|
|
sta ($00),y
|
|
|
|
lda workPtr1
|
|
clc
|
|
adc #$08
|
|
sta workPtr1
|
|
|
|
iny
|
|
inc workValue1
|
|
|
|
dec workValue4
|
|
bne @BuildInnerLoop
|
|
|
|
inc workValue2
|
|
inc workValue2
|
|
inc workValue3
|
|
|
|
lda $69
|
|
bne @ContinueBuild
|
|
|
|
lda roundDisplayValue
|
|
bne @AdvancePhase
|
|
|
|
@ContinueBuild:
|
|
dec workValue0
|
|
beq @CheckPlayerMode
|
|
|
|
bpl @BuildOuterLoop
|
|
bmi @AdvancePhase
|
|
|
|
@CheckPlayerMode:
|
|
lda activePlayerFlag
|
|
beq @AdvancePhase
|
|
|
|
lda cocktailModeFlag
|
|
beq @BuildOuterLoop
|
|
|
|
inc workValue1
|
|
inc workValue1
|
|
inc workValue1
|
|
|
|
bne @BuildOuterLoop
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $CBE4
|
|
; Frame-based progression portion of the same state.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@AdvancePhase:
|
|
lda $87
|
|
cmp #$C0
|
|
bne @IncrementPhase
|
|
|
|
jmp $CC7C
|
|
|
|
@IncrementPhase:
|
|
inc $87
|
|
|
|
lda $87
|
|
cmp #$78
|
|
beq @InitializeMidPhase
|
|
|
|
jmp $CC99
|
|
|
|
@InitializeMidPhase:
|
|
lda #$A8
|
|
sta $1C
|
|
|
|
lda #$60
|
|
sta pacmanMotion
|
|
sta ghost1Motion
|
|
sta ghost2Motion
|
|
|
|
lda #$58
|
|
sta ghost3Motion
|
|
sta $20
|
|
|
|
lda #$68
|
|
sta ghost4Motion
|
|
|
|
lda #$70
|
|
sta $24
|
|
sta $28
|
|
sta $2C
|
|
|
|
lda #$00
|
|
tay
|
|
|
|
@ClearOamRegion:
|
|
sta $0778,y
|
|
iny
|
|
cpy #$24
|
|
bne @ClearOamRegion
|
|
|
|
lda activePlayerFlag
|
|
and cocktailModeFlag
|
|
beq @NoPlayerOffset
|
|
|
|
lda #$08
|
|
|
|
@NoPlayerOffset:
|
|
sta $00
|
|
|
|
lda $67
|
|
sec
|
|
sbc #$01
|
|
asl
|
|
tay
|
|
|
|
lda State02DisplayAddressTable,y
|
|
clc
|
|
adc workPtr0
|
|
sta workPtr0
|
|
|
|
lda State02DisplayAddressTable+1,y
|
|
sta workPtr0+1
|
|
|
|
lda workPtr0
|
|
sta $024B
|
|
|
|
lda workPtr0+1
|
|
sta $024C
|
|
|
|
lda #$2D
|
|
sta $024D
|
|
sta $024E
|
|
|
|
lda #$00
|
|
sta $024F
|
|
|
|
lda $00
|
|
sta $0250
|
|
|
|
lda $01
|
|
clc
|
|
adc #$20
|
|
sta $0251
|
|
|
|
lda #$2D
|
|
sta $0252
|
|
sta $0253
|
|
|
|
lda #$FF
|
|
sta $0254
|
|
|
|
jsr UpdatePlayerDirectionAnimation
|
|
jsr UpdateEntitySpriteStates
|
|
jsr $DA40
|
|
|
|
jmp $CC99
|
|
|
|
@CheckCompletion:
|
|
lda $0600
|
|
ora $0601
|
|
bne $CC99
|
|
|
|
lda $48
|
|
bne @AdvanceMainState
|
|
|
|
lda #$00
|
|
sta $69
|
|
tay
|
|
|
|
@ClearPage07Region:
|
|
sta $0760,y
|
|
iny
|
|
cpy #$A0
|
|
bne @ClearPage07Region
|
|
|
|
@AdvanceMainState:
|
|
lda #$04
|
|
sta $3F
|
|
|
|
@ReturnToFrameLoop:
|
|
jmp GameModeFrameSync
|
|
|
|
;==============================================================================
|
|
; $CC9C-$CCD8: Game-Mode State $02 Lookup Tables
|
|
;
|
|
; Local:
|
|
; Collection of lookup tables consumed by GameModeState02 while constructing
|
|
; page-$07 object/display data and preparing the update command at $024B.
|
|
;
|
|
; Global:
|
|
; Supplies the tile/status/position/count/address parameters used by the
|
|
; state-$02 setup sequence.
|
|
;
|
|
; Notes:
|
|
; The tables are separated according to the exact addresses referenced by
|
|
; GameModeState02. Names remain structural during this first pass.
|
|
;==============================================================================
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $CC9C-$CCAD: State $02 tile/value table
|
|
;
|
|
; Indexed through $05:
|
|
;
|
|
; lda State02ValueTableA,x
|
|
;
|
|
; Written as the second byte of each 4-byte structure generated at $0760+.
|
|
; Length: $12 (18) bytes.
|
|
;------------------------------------------------------------------------------
|
|
|
|
State02ValueTableA:
|
|
.byte $C6,$C3,$C1,$BA,$C7,$BB
|
|
.byte $B0,$B1,$B2,$B3,$B4,$B5
|
|
.byte $B6,$B7,$B4,$B8,$B9,$B6
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $CCAE-$CCBF: State $02 secondary value table
|
|
;
|
|
; Indexed through the same $05 value as State02ValueTableA.
|
|
;
|
|
; Written as the third byte of each generated 4-byte structure.
|
|
; Length: $12 (18) bytes.
|
|
;------------------------------------------------------------------------------
|
|
|
|
State02ValueTableB:
|
|
.byte $00,$00,$00,$00,$00,$00
|
|
.byte $02,$02,$02,$02,$02,$02
|
|
.byte $02,$02,$02,$02,$02,$02
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $CCC0-$CCC5: State $02 position/parameter pairs
|
|
;
|
|
; GameModeState02 accesses this table as overlapping little groups:
|
|
;
|
|
; lda State02PositionTable,x
|
|
; lda State02PositionTable+1,x
|
|
;
|
|
; $06 advances by 2 each outer pass.
|
|
;
|
|
; Therefore the natural structure is three 2-byte pairs.
|
|
;------------------------------------------------------------------------------
|
|
|
|
State02PositionTable:
|
|
.byte $44,$88
|
|
.byte $44,$60
|
|
.byte $50,$70
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $CCC6-$CCC8: State $02 entry-count table
|
|
;
|
|
; Indexed by $07. Determines how many four-byte structures are emitted by
|
|
; each inner construction loop.
|
|
;------------------------------------------------------------------------------
|
|
|
|
State02EntryCounts:
|
|
.byte $06,$06,$03
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $CCC9-$CCD0: Additional state-$02 values
|
|
;
|
|
; No direct reference has yet been established in the portion decoded so far.
|
|
; Keep this data structurally separated until its consumer is found.
|
|
;------------------------------------------------------------------------------
|
|
|
|
State02UnknownData:
|
|
.byte $C0,$C1,$C2,$C3,$C4,$C5,$C3,$C6
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $CCD1-$CCD8: Display-address table
|
|
;
|
|
; Indexed by:
|
|
;
|
|
; ($67 - 1) * 2
|
|
;
|
|
; and read as two-byte values:
|
|
;
|
|
; lda State02DisplayAddressTable,y
|
|
; lda State02DisplayAddressTable+1,y
|
|
;
|
|
; The bytes form four PPU-style address pairs:
|
|
;
|
|
; $2317
|
|
; $2319
|
|
; $231B
|
|
; $2357
|
|
;
|
|
; When $47 & $46 is nonzero, $08 is added to the low byte before the command
|
|
; is placed into $024B/$024C.
|
|
;------------------------------------------------------------------------------
|
|
|
|
State02DisplayAddressTable:
|
|
.byte $23,$17
|
|
.byte $23,$19
|
|
.byte $23,$1B
|
|
.byte $23,$57
|
|
|
|
;==============================================================================
|
|
; $CCD9-$CD05: Game-Mode State $06 Handler
|
|
;
|
|
; Local:
|
|
; Increments $DA each frame. Normally falls through to a group of four
|
|
; per-frame update routines.
|
|
;
|
|
; When $DA reaches $28, resets $DA to $02, changes the main game-mode state
|
|
; to $04, finds an even-indexed entry in $B8+X containing $08, and changes
|
|
; that entry to $06 before continuing through the same update routines.
|
|
;
|
|
; Global:
|
|
; Handler selected by GameModeStateTable when $3F = $06. Implements a timed
|
|
; transition back to game-mode state $04 while continuing normal frame
|
|
; processing throughout the delay.
|
|
;
|
|
; Notes:
|
|
; $DA is used as a frame/progression counter.
|
|
; The $B8 array is searched only at even offsets.
|
|
;==============================================================================
|
|
|
|
GameModeState06:
|
|
inc $DA
|
|
|
|
lda #$28
|
|
cmp $DA
|
|
bne @RunFrameUpdates
|
|
|
|
lda #$02
|
|
sta $DA
|
|
|
|
lda #$04
|
|
sta $3F
|
|
|
|
lda #$08
|
|
|
|
ldx #$FE
|
|
|
|
@FindStateEntry:
|
|
inx
|
|
inx
|
|
cmp $B8,x
|
|
bne @FindStateEntry
|
|
|
|
lda #$06
|
|
sta $B8,x
|
|
|
|
@RunFrameUpdates:
|
|
jsr UpdatePeriodicFourEntryState
|
|
jsr UpdateEntityMovementStates
|
|
jsr UpdateEntitySpriteStates
|
|
jsr $DA40
|
|
|
|
jmp GameModeFrameSync
|
|
|
|
|
|
;==============================================================================
|
|
; $CD06-$CDAF: Game-Mode State $08 Handler
|
|
;
|
|
; Local:
|
|
; Multi-phase timed state using $87, $DB, and $32.
|
|
;
|
|
; During the initial phase, $DB counts down. When it expires, $87 advances,
|
|
; $DB and $0603 are initialized to $0A, and $001E-$0031 are cleared.
|
|
;
|
|
; During the active phase, $DB periodically advances $32 until $32 reaches
|
|
; $1E. The completion logic then updates the two parallel 16-byte state
|
|
; blocks at $67-$76 and $77-$86 and selects the next game-mode state.
|
|
;
|
|
; Global:
|
|
; Handler selected by GameModeStateTable when $3F = $08.
|
|
;
|
|
; Notes:
|
|
; $DB acts as a short-period timer.
|
|
; $87 distinguishes the initial and active phases.
|
|
; $67-$76 and $77-$86 are interchangeable 16-byte state structures.
|
|
;
|
|
; A few cross-flow destinations are kept as raw addresses during this pass
|
|
; to preserve the original control flow exactly.
|
|
;==============================================================================
|
|
|
|
GameModeState08:
|
|
lda $87
|
|
bne @ActivePhase
|
|
|
|
dec $DB
|
|
bne @InitialFrameUpdates
|
|
|
|
inc $87
|
|
|
|
lda #$0A
|
|
sta $DB
|
|
sta $0603
|
|
|
|
lda #$00
|
|
tax
|
|
|
|
@ClearLowRamState:
|
|
sta $1E,x
|
|
inx
|
|
cpx #$14
|
|
bne @ClearLowRamState
|
|
|
|
@InitialFrameUpdates:
|
|
jsr UpdatePeriodicFourEntryState
|
|
jsr UpdateEntitySpriteStates
|
|
jsr $DA40
|
|
|
|
jmp GameModeFrameSync
|
|
|
|
@ActivePhase:
|
|
dec $DB
|
|
bpl @ActiveFrameUpdates
|
|
|
|
lda #$0A
|
|
sta $DB
|
|
|
|
lda $32
|
|
clc
|
|
adc #$01
|
|
sta $32
|
|
|
|
cmp #$1E
|
|
beq @PhaseComplete
|
|
|
|
@ActiveFrameUpdates:
|
|
jsr UpdatePeriodicFourEntryState
|
|
jsr $DA40
|
|
|
|
jmp GameModeFrameSync
|
|
|
|
@PhaseComplete:
|
|
lda $48
|
|
bne @SinglePlayerRestart
|
|
|
|
dec $67
|
|
bne @ContinuePlayerHandling
|
|
|
|
lda #$00
|
|
sta $87
|
|
sta $69
|
|
|
|
lda #$0A
|
|
sta $3F
|
|
|
|
jmp GameModeFrameSync
|
|
|
|
@ContinuePlayerHandling:
|
|
lda #$00
|
|
sta $3F
|
|
|
|
lda #$01
|
|
sta $69
|
|
|
|
lda $47
|
|
beq @CheckPrimaryBlock
|
|
|
|
lda $77
|
|
bne @SwapBlocksAndToggle
|
|
|
|
@CheckPrimaryBlock:
|
|
lda $67
|
|
bne $CDAD
|
|
|
|
sta $69
|
|
|
|
lda $46
|
|
beq @SinglePlayerRestart
|
|
|
|
ldx #$0F
|
|
|
|
@SwapBlocksForMainEntry:
|
|
lda $67,x
|
|
sta $00
|
|
|
|
lda $77,x
|
|
sta $67,x
|
|
|
|
lda $00
|
|
sta $77,x
|
|
|
|
dex
|
|
bpl @SwapBlocksForMainEntry
|
|
|
|
@SinglePlayerRestart:
|
|
lda #$00
|
|
sta $46
|
|
|
|
lda #$00
|
|
sta $3F
|
|
|
|
jmp MainEntry
|
|
|
|
|
|
@SwapBlocksAndToggle:
|
|
ldx #$0F
|
|
|
|
@SwapBlocks:
|
|
lda $67,x
|
|
sta $00
|
|
|
|
lda $77,x
|
|
sta $67,x
|
|
|
|
lda $00
|
|
sta $77,x
|
|
|
|
dex
|
|
bpl @SwapBlocks
|
|
|
|
inc $46
|
|
|
|
lda $46
|
|
and #$01
|
|
sta $46
|
|
|
|
jmp GameModeFrameSync
|
|
|
|
|
|
;==============================================================================
|
|
; $CDB0-$CE1E: Game-Mode State $0C Handler
|
|
;
|
|
; Local:
|
|
; Uses $87 as a frame/progression counter.
|
|
;
|
|
; On first entry ($87 == 0):
|
|
; - Clears $001E-$0031.
|
|
; - Increments $87.
|
|
; - Initializes $32 to $01.
|
|
;
|
|
; On subsequent frames, processing is throttled by the low three bits of
|
|
; the NMI-driven frame counter $4B. Only once every eight frames does the
|
|
; handler:
|
|
;
|
|
; - Alternate a value written to $029E according to bit 0 of $87.
|
|
; - Set $0299 to $0F.
|
|
; - Increment $87.
|
|
;
|
|
; When $87 reaches $10, the routine clears $1A/$1C/$87 and selects a new
|
|
; main game-mode state according to the value at $68.
|
|
;
|
|
; Global:
|
|
; Handler selected by GameModeStateTable when $3F = $0C.
|
|
;
|
|
; This appears to implement a short visual/timed transition. The write of
|
|
; $0F to $0299 interacts directly with the palette-update mechanism decoded
|
|
; earlier, while $029E lies inside that first 16-byte palette/update buffer.
|
|
;
|
|
; Notes:
|
|
; $4B is the NMI-driven frame counter.
|
|
;
|
|
; $87 advances only once every eight frames after initialization.
|
|
;
|
|
; $68 controls which state is selected when the sequence completes.
|
|
;==============================================================================
|
|
|
|
GameModeState0C:
|
|
lda $87
|
|
bne @TimedPhase
|
|
|
|
ldx #$00
|
|
|
|
@ClearLowRam:
|
|
sta $1E,x
|
|
inx
|
|
cpx #$14
|
|
bne @ClearLowRam
|
|
|
|
inc $87
|
|
|
|
lda #$01
|
|
sta $32
|
|
|
|
bne @RunFrameUpdates
|
|
|
|
|
|
@TimedPhase:
|
|
lda $4B
|
|
and #$07
|
|
bne @RunFrameUpdates
|
|
|
|
ldx #$11
|
|
|
|
lda $87
|
|
and #$01
|
|
bne @SetPaletteValue
|
|
|
|
ldx #$20
|
|
|
|
@SetPaletteValue:
|
|
stx $029E
|
|
|
|
lda #$0F
|
|
sta $0299
|
|
|
|
inc $87
|
|
|
|
lda #$10
|
|
cmp $87
|
|
bne @RunFrameUpdates
|
|
|
|
lda #$00
|
|
sta $1A
|
|
sta $1C
|
|
sta $87
|
|
|
|
lda $68
|
|
cmp #$01
|
|
beq @SelectState0E
|
|
|
|
inc $87
|
|
inc $87
|
|
|
|
cmp #$04
|
|
beq @SelectState0E
|
|
|
|
inc $87
|
|
inc $87
|
|
|
|
cmp #$08
|
|
beq @SelectState0E
|
|
|
|
cmp #$0C
|
|
beq @SelectState0E
|
|
|
|
cmp #$10
|
|
bne @SelectState00
|
|
|
|
|
|
@SelectState0E:
|
|
lda #$0E
|
|
sta $3F
|
|
|
|
jmp @RunFrameUpdates
|
|
|
|
|
|
@SelectState00:
|
|
lda #$00
|
|
sta $3F
|
|
|
|
|
|
@RunFrameUpdates:
|
|
jsr UpdatePeriodicFourEntryState
|
|
jsr $DA40
|
|
|
|
jmp GameModeFrameSync
|
|
|
|
|
|
;==============================================================================
|
|
; $CE1F-$CEBE: Game-Mode State $0A Handler
|
|
;
|
|
; Local:
|
|
; Uses $87 to distinguish between initialization and subsequent processing.
|
|
;
|
|
; On initial entry:
|
|
; - Fills $0700-$075F with $FF.
|
|
; - Initializes $00/$01 as a pointer to $0760.
|
|
; - Builds structured four-byte records in page $07 from several ROM
|
|
; lookup tables beginning at $CEBF.
|
|
;
|
|
; The builder uses:
|
|
;
|
|
; $00/$01 destination pointer ($0760)
|
|
; $02/$03 per-group values
|
|
; $04 outer pass counter, initially $03
|
|
; $05 shared table index
|
|
; $06 index into the value-pair table
|
|
; $07 index into the entry-count table
|
|
; $08 inner record counter
|
|
;
|
|
; Player/mode variables $47, $77, and $46 influence whether passes repeat
|
|
; and whether the lookup index is advanced.
|
|
;
|
|
; After the construction phase, $87 is incremented. A later entry either
|
|
; clears $0760-$07FF and transitions to the code at $CD5E, or simply
|
|
; returns to the common frame loop.
|
|
;
|
|
; Global:
|
|
; Handler selected by GameModeStateTable when $3F = $0A.
|
|
;
|
|
; Structurally this is closely related to GameModeState02, but uses a
|
|
; different set of ROM tables and first clears $0700-$075F to $FF. Both
|
|
; handlers construct arrays of four-byte records in page $07.
|
|
;
|
|
; Notes:
|
|
; The tables at $CEBF-$CEF2 are decoded immediately after this routine.
|
|
; Semantic object names are deferred until the page-$07 consumers are
|
|
; understood more completely.
|
|
;==============================================================================
|
|
|
|
GameModeState0A:
|
|
lda $87
|
|
beq @Initialize
|
|
|
|
jmp $CEAA
|
|
|
|
@Initialize:
|
|
ldy #$00
|
|
|
|
lda #$FF
|
|
|
|
@FillPage07Prefix:
|
|
sta $0700,y
|
|
iny
|
|
cpy #$60
|
|
bne @FillPage07Prefix
|
|
|
|
lda #$60
|
|
sta $00
|
|
|
|
lda #$07
|
|
sta $01
|
|
|
|
lda #$03
|
|
sta $04
|
|
|
|
ldy #$00
|
|
sty $05
|
|
sty $06
|
|
sty $07
|
|
|
|
@BuildOuterLoop:
|
|
ldx $06
|
|
|
|
lda State0AParameterPairs,x
|
|
sta $02
|
|
|
|
lda State0AParameterPairs+1,x
|
|
sta $03
|
|
|
|
ldx $07
|
|
|
|
lda State0AEntryCounts,x
|
|
sta $08
|
|
|
|
|
|
@BuildInnerLoop:
|
|
lda $03
|
|
sta ($00),y
|
|
|
|
ldx $05
|
|
|
|
lda State0AValueTableA,x
|
|
iny
|
|
sta ($00),y
|
|
|
|
lda State0AValueTableB,x
|
|
iny
|
|
sta ($00),y
|
|
|
|
lda $02
|
|
iny
|
|
sta ($00),y
|
|
|
|
lda $02
|
|
clc
|
|
adc #$08
|
|
sta $02
|
|
|
|
iny
|
|
inc $05
|
|
|
|
dec $08
|
|
bne @BuildInnerLoop
|
|
|
|
inc $06
|
|
inc $06
|
|
|
|
inc $07
|
|
|
|
lda $47
|
|
beq @ContinueOuterPass
|
|
|
|
lda $77
|
|
bne @ContinueOuterPass
|
|
|
|
lda $04
|
|
cmp #$02
|
|
beq $CEAA
|
|
|
|
|
|
@ContinueOuterPass:
|
|
dec $04
|
|
beq @CheckPlayerMode
|
|
|
|
bpl @BuildOuterLoop
|
|
bmi @FinishInitialization
|
|
|
|
|
|
@CheckPlayerMode:
|
|
lda $47
|
|
beq @FinishInitialization
|
|
|
|
lda $46
|
|
beq @BuildOuterLoop
|
|
|
|
|
|
@AdjustTableIndex:
|
|
inc $05
|
|
inc $05
|
|
inc $05
|
|
|
|
bne @BuildOuterLoop
|
|
|
|
|
|
@FinishInitialization:
|
|
inc $87
|
|
bne @ReturnToFrameLoop
|
|
|
|
|
|
@PostInitialization:
|
|
lda #$00
|
|
tay
|
|
|
|
@ClearPage07Region:
|
|
sta $0760,y
|
|
iny
|
|
cpy #$A0
|
|
bne @ClearPage07Region
|
|
|
|
jmp $CD5E
|
|
|
|
|
|
@ReturnToFrameLoop:
|
|
jmp GameModeFrameSync
|
|
|
|
|
|
;==============================================================================
|
|
; $CEBF-$CEF2: Game-Mode State $0A Lookup Tables
|
|
;
|
|
; Local:
|
|
; Lookup data used by GameModeState0A to construct four-byte records in
|
|
; page $07.
|
|
;
|
|
; Global:
|
|
; Provides the object/tile/value and layout parameters for state $0A.
|
|
;==============================================================================
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $CEBF-$CED2: Primary value table
|
|
; Length: $14 (20) bytes
|
|
;------------------------------------------------------------------------------
|
|
|
|
State0AValueTableA:
|
|
.byte $BC,$B2,$BD,$B4,$B6,$BE,$B4,$B5
|
|
.byte $B0,$B1,$B2,$B3,$B4,$B5,$B6,$B7
|
|
.byte $B4,$B8,$B9,$B6
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $CED3-$CEE6: Secondary value table
|
|
; Length: $14 (20) bytes
|
|
;------------------------------------------------------------------------------
|
|
|
|
State0AValueTableB:
|
|
.byte $00,$00,$00,$00,$00,$00,$00,$00
|
|
.byte $02,$02,$02,$02,$02,$02,$02,$02
|
|
.byte $02,$02,$02,$02
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $CEE7-$CEEE: Parameter-pair table
|
|
;
|
|
; $06 advances by two, so represent this as four 2-byte pairs.
|
|
;------------------------------------------------------------------------------
|
|
|
|
State0AParameterPairs:
|
|
.byte $38,$88
|
|
.byte $60,$88
|
|
.byte $44,$60
|
|
.byte $50,$70
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $CEEF-$CEF2: Inner-loop entry counts
|
|
;------------------------------------------------------------------------------
|
|
|
|
State0AEntryCounts:
|
|
.byte $04,$04,$06,$03
|
|
|
|
;==============================================================================
|
|
; $CEF3-$D0AA: Game-Mode State $00 Initialization
|
|
;
|
|
; Local:
|
|
; Performs the main initialization for the game-mode state machine:
|
|
;
|
|
; - Synchronizes with NMI and disables rendering.
|
|
; - Clears working RAM $87-$EF.
|
|
; - Clears page $0700-$07FF.
|
|
; - Copies a 32-byte palette table from GameplayPaletteData to $0299-$02B8.
|
|
; - Selects game-mode state $02.
|
|
; - Initializes gameplay/state variables and invokes several setup helpers.
|
|
; - Loads numerous parameters from ROM lookup tables.
|
|
; - Initializes arrays and display/update data.
|
|
; - Re-enables NMI with PPUCTRL=$88.
|
|
; - Returns to GameModeFrameSync.
|
|
;
|
|
; Global:
|
|
; Primary initialization handler for GameModeStateTable offset $00.
|
|
; Establishes the working state used by the later $02/$04/etc. handlers.
|
|
;
|
|
; Notes:
|
|
; Many ROM tables referenced from $EBxx/$ECxx are intentionally left raw
|
|
; during this pass and will be named when those regions are reached.
|
|
;==============================================================================
|
|
|
|
GameModeState00:
|
|
lda #$01
|
|
sta $40
|
|
|
|
@WaitForNmi:
|
|
lda $40
|
|
bne @WaitForNmi
|
|
|
|
lda #$08
|
|
sta PPUCTRL
|
|
sta $43
|
|
|
|
lda #$00
|
|
sta PPUMASK
|
|
|
|
ldx #$00
|
|
|
|
@ClearWorkingRam:
|
|
sta $87,x
|
|
inx
|
|
cpx #$69
|
|
bne @ClearWorkingRam
|
|
|
|
tax
|
|
|
|
@ClearPage07:
|
|
sta $0700,x
|
|
inx
|
|
bne @ClearPage07
|
|
|
|
ldy #$00
|
|
|
|
@LoadPalette:
|
|
lda GameplayPaletteData,y
|
|
sta $0299,y
|
|
iny
|
|
cpy #$20
|
|
bne @LoadPalette
|
|
|
|
lda #$02
|
|
sta $3F
|
|
|
|
lda $69
|
|
bne $CF4A
|
|
|
|
sta $8B
|
|
|
|
lda #$01
|
|
sta $6C
|
|
sta $6D
|
|
sta $6E
|
|
sta $6F
|
|
|
|
lda #$C0
|
|
sta $6A
|
|
|
|
lda $68
|
|
cmp #$16
|
|
beq @SkipIncrement68
|
|
|
|
inc $68
|
|
|
|
@SkipIncrement68:
|
|
jsr InitializeGameplayAttributes
|
|
jsr DrawMazeNametable
|
|
jsr DrawGameplayScoreFields
|
|
jsr InitializeGameNametableRegion
|
|
jsr DrawLevelProgressMarkers
|
|
jsr $E5C1
|
|
jsr DrawGameplayHudLabels
|
|
|
|
@ContinueSetup:
|
|
ldx $68
|
|
|
|
lda #$00
|
|
clc
|
|
|
|
@MultiplyBy6:
|
|
dex
|
|
bmi @MultiplyBy6Done
|
|
|
|
adc #$06
|
|
bne @MultiplyBy6
|
|
|
|
@MultiplyBy6Done:
|
|
sta $00
|
|
tax
|
|
|
|
lda $EBB6,x
|
|
tax
|
|
|
|
lda #$00
|
|
clc
|
|
|
|
@MultiplyBy22:
|
|
dex
|
|
bmi @MultiplyBy22Done
|
|
|
|
adc #$16
|
|
bne @MultiplyBy22
|
|
|
|
@MultiplyBy22Done:
|
|
tay
|
|
|
|
ldx #$00
|
|
|
|
@CopyGameParameters:
|
|
lda $EC40,y
|
|
sta $9F,x
|
|
inx
|
|
iny
|
|
cpx #$16
|
|
bne @CopyGameParameters
|
|
|
|
ldx $00
|
|
|
|
lda $EBB6,x
|
|
asl
|
|
asl
|
|
asl
|
|
tax
|
|
|
|
ldy #$00
|
|
sty $D0
|
|
|
|
; Save the first selected table value separately.
|
|
lda $ECAE,x
|
|
sta $CF
|
|
|
|
@CopyTableECae:
|
|
lda $ECAE,x
|
|
sta $0097,y
|
|
|
|
inx
|
|
iny
|
|
cpy #$08
|
|
bne @CopyTableECae
|
|
|
|
inc $00
|
|
|
|
ldx $00
|
|
lda $EBB6,x
|
|
sta $8C
|
|
|
|
inc $00
|
|
|
|
ldx $00
|
|
lda $EBB6,x
|
|
asl
|
|
tax
|
|
|
|
lda $ECCE,x
|
|
sta $8D
|
|
inx
|
|
lda $ECCE,x
|
|
sta $8E
|
|
|
|
inc $00
|
|
|
|
lda $69
|
|
beq @UseAlternateData
|
|
|
|
ldx #$0C
|
|
ldy #$00
|
|
|
|
lda $ECDC,x
|
|
sta $008F,y
|
|
|
|
iny
|
|
inx
|
|
|
|
lda #$C0
|
|
sec
|
|
sbc $6A
|
|
sta $01
|
|
|
|
@CopyOffsetData:
|
|
lda $01
|
|
clc
|
|
adc $ECDC,x
|
|
sta $008F,y
|
|
|
|
iny
|
|
inx
|
|
|
|
cpy #$04
|
|
bne @CopyOffsetData
|
|
|
|
beq @InitializeArray
|
|
|
|
@UseAlternateData:
|
|
ldx $00
|
|
|
|
lda $EBB6,x
|
|
asl
|
|
asl
|
|
tax
|
|
|
|
ldy #$00
|
|
|
|
@CopyAlternateData:
|
|
lda $ECDC,x
|
|
sta $008F,y
|
|
|
|
inx
|
|
iny
|
|
cpy #$04
|
|
bne @CopyAlternateData
|
|
|
|
|
|
@InitializeArray:
|
|
lda #$04
|
|
sta $B8
|
|
|
|
lda #$01
|
|
sta $B9
|
|
|
|
lda $8F
|
|
sta $01
|
|
|
|
ldx #$00
|
|
|
|
@InitializeArrayLoop:
|
|
dec $01
|
|
beq @InitializeArrayTail
|
|
|
|
lda #$02
|
|
sta $BA,x
|
|
|
|
lda #$00
|
|
sta $BB,x
|
|
|
|
inx
|
|
inx
|
|
bne @InitializeArrayLoop
|
|
|
|
|
|
@InitializeArrayTail:
|
|
lda #$00
|
|
|
|
@ClearRemainingArray:
|
|
cpx #$06
|
|
beq @ContinueFinalSetup
|
|
|
|
sta $BA,x
|
|
sta $BB,x
|
|
|
|
inx
|
|
inx
|
|
bne @ClearRemainingArray
|
|
|
|
|
|
@ContinueFinalSetup:
|
|
lda $90
|
|
sta $D3
|
|
|
|
inc $00
|
|
|
|
ldx $00
|
|
lda $EBB6,x
|
|
sta $93
|
|
|
|
inc $00
|
|
|
|
ldx $00
|
|
lda $EBB6,x
|
|
sta $96
|
|
|
|
lda $A5
|
|
sta $B5
|
|
|
|
lda $A6
|
|
sta $B6
|
|
|
|
lda $AF
|
|
sta $C4
|
|
sta $C6
|
|
sta $C8
|
|
sta $CA
|
|
|
|
lda $B0
|
|
sta $C5
|
|
sta $C7
|
|
sta $C9
|
|
sta $CB
|
|
|
|
lda #$01
|
|
sta $50
|
|
sta $51
|
|
|
|
ldy #$00
|
|
ldx #$00
|
|
|
|
lda $46
|
|
and $47
|
|
beq @CopyDisplayInit
|
|
|
|
ldy #$09
|
|
|
|
@CopyDisplayInit:
|
|
lda GameDisplayInitialData,y
|
|
sta $026B,x
|
|
|
|
iny
|
|
inx
|
|
cpx #$09
|
|
bne @CopyDisplayInit
|
|
|
|
ldy #$00
|
|
|
|
@CopyStateData:
|
|
lda GameStateInitialValues,y
|
|
sta $0032,y
|
|
iny
|
|
cpy #$0C
|
|
bne @CopyStateData
|
|
|
|
ldy #$00
|
|
|
|
@NormalizeValues:
|
|
lda $006C,y
|
|
cmp #$02
|
|
bne @NextNormalizeValue
|
|
|
|
lda #$01
|
|
sta $006C,y
|
|
|
|
@NextNormalizeValue:
|
|
iny
|
|
cpy #$04
|
|
bne @NormalizeValues
|
|
|
|
sty $C0
|
|
|
|
lda #$FF
|
|
sta $89
|
|
|
|
lda #$88
|
|
sta PPUCTRL
|
|
sta $43
|
|
|
|
jmp GameModeFrameSync
|
|
|
|
;==============================================================================
|
|
; $D0AB-$D0F2: Initialize/Clear Repeated Nametable Region
|
|
;
|
|
; Local:
|
|
; Selects an initial PPU destination based on ($46 & $47):
|
|
;
|
|
; zero -> $2256
|
|
; nonzero -> $2A56
|
|
;
|
|
; It then performs 10 iterations. For each iteration:
|
|
;
|
|
; - Sets PPUADDR to the current destination.
|
|
; - Writes six $20 tiles.
|
|
; - Writes two $2D tiles.
|
|
; - Advances the destination address by $20.
|
|
;
|
|
; Global:
|
|
; Called from GameModeState00 during game/round initialization while
|
|
; rendering is disabled. This prepares the same rectangular display region
|
|
; in one of two nametable locations depending on the current player/mode
|
|
; state represented by $46/$47.
|
|
;
|
|
; Notes:
|
|
; $00/$01 form the current 16-bit PPU destination address.
|
|
; $02 counts 10 rows.
|
|
; $03 counts the six $20 tile writes in each row.
|
|
;
|
|
; $20 and $2D are retained as raw tile IDs during this pass.
|
|
;==============================================================================
|
|
|
|
InitializeGameNametableRegion:
|
|
ldy #$22
|
|
|
|
lda $46
|
|
and $47
|
|
beq @SetDestination
|
|
|
|
ldy #$2A
|
|
|
|
@SetDestination:
|
|
sty $00
|
|
|
|
lda #$56
|
|
sta $01
|
|
|
|
lda #$0A
|
|
sta $02
|
|
|
|
@NextRow:
|
|
lda PPUSTATUS
|
|
|
|
lda $00
|
|
sta PPUADDR
|
|
|
|
lda $01
|
|
sta PPUADDR
|
|
|
|
lda #$06
|
|
sta $03
|
|
|
|
lda #$20
|
|
|
|
@WriteInterior:
|
|
sta PPUDATA
|
|
|
|
dec $03
|
|
bne @WriteInterior
|
|
|
|
lda #$2D
|
|
sta PPUDATA
|
|
sta PPUDATA
|
|
|
|
; Advance the destination by one full nametable row ($20 bytes).
|
|
lda $01
|
|
clc
|
|
adc #$20
|
|
sta $01
|
|
|
|
lda $00
|
|
adc #$00
|
|
sta $00
|
|
|
|
dec $02
|
|
bne @NextRow
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $D0F3-$D130: Game-Mode State $00 Initialization Data
|
|
;
|
|
; Local:
|
|
; Contains three adjacent data blocks consumed during GameModeState00:
|
|
;
|
|
; $D0F3-$D0FE 12-byte state initialization table
|
|
; $D0FF-$D110 18-byte display/update table
|
|
; $D111-$D130 32-byte palette table
|
|
;
|
|
; Global:
|
|
; Supplies initial state, display-command, and palette data used when
|
|
; GameModeState00 prepares a new game/round state.
|
|
;
|
|
; Notes:
|
|
; The display table is intentionally kept as raw tile/command bytes during
|
|
; this pass. GameModeState00 selects either offset $00 or $09 from this
|
|
; table and copies nine bytes to $026B-$0273.
|
|
;
|
|
; The palette table is copied in full to $0299-$02B8.
|
|
;==============================================================================
|
|
|
|
|
|
;==============================================================================
|
|
; $D0F3-$D0FE: Game State Initialization Values
|
|
;
|
|
; Local:
|
|
; 12 bytes copied directly to zero-page RAM $32-$3D:
|
|
;
|
|
; ROM $D0F3-$D0FE -> RAM $0032-$003D
|
|
;
|
|
; Global:
|
|
; Establishes a compact block of initial game-state values during
|
|
; GameModeState00.
|
|
;
|
|
; Notes:
|
|
; Individual fields remain unnamed until their consumers are traced.
|
|
;==============================================================================
|
|
|
|
GameStateInitialValues:
|
|
.byte $04,$0C,$0A,$0A
|
|
.byte $0A,$00,$00,$00
|
|
.byte $01,$02,$03,$00
|
|
|
|
|
|
;==============================================================================
|
|
; $D0FF-$D110: Game Display Initialization Data
|
|
;
|
|
; Local:
|
|
; Contains two 9-byte records. GameModeState00 selects the first record when
|
|
; ($46 & $47) is zero and the second record when it is nonzero.
|
|
;
|
|
; The selected nine bytes are copied to RAM $026B-$0273.
|
|
;
|
|
; Global:
|
|
; Provides alternate display/update initialization according to the active
|
|
; player/mode state.
|
|
;
|
|
; Notes:
|
|
; These bytes appear to mix PPU/update-command values and tile IDs.
|
|
; Preserve them numerically until the consumer of $026B is decoded.
|
|
;==============================================================================
|
|
GameDisplayInitialData:
|
|
|
|
; Record 0, selected when ($46 & $47) == 0.
|
|
; $D0FF-$D107
|
|
.byte $21,$36,$20,$F7,$B0,$B3,$B2,$20,$B6
|
|
|
|
; Record 1, selected when ($46 & $47) != 0.
|
|
; $D108-$D110
|
|
.byte $29,$B6,$29,$77,$B1,$B3,$B2,$28,$B6
|
|
|
|
|
|
;==============================================================================
|
|
; $D111-$D130: Initial Gameplay Palette
|
|
;
|
|
; Local:
|
|
; Complete 32-byte palette copied to RAM $0299-$02B8 by GameModeState00.
|
|
; The NMI palette-update mechanism later transfers these buffers into PPU
|
|
; palette RAM.
|
|
;
|
|
; Global:
|
|
; Defines the initial background and sprite color palettes used for normal
|
|
; gameplay/game-mode initialization.
|
|
;
|
|
; Notes:
|
|
; $D111-$D120 contains four background palettes.
|
|
; $D121-$D130 contains four sprite palettes.
|
|
;
|
|
; Palette values are retained as NES color indices.
|
|
;==============================================================================
|
|
GameplayPaletteData:
|
|
; Background palette 0
|
|
.byte $0F,$20,$0F,$06
|
|
|
|
; Background palette 1
|
|
.byte $0F,$11,$0F,$27
|
|
|
|
; Background palette 2
|
|
.byte $0F,$16,$26,$06
|
|
|
|
; Background palette 3
|
|
.byte $0F,$19,$17,$12
|
|
|
|
; Sprite palette 0
|
|
.byte $0F,$27,$20,$06
|
|
|
|
; Sprite palette 1
|
|
.byte $0F,$11,$20,$33
|
|
|
|
; Sprite palette 2
|
|
.byte $0F,$21,$20,$21
|
|
|
|
; Sprite palette 3
|
|
.byte $0F,$09,$20,$17
|
|
|
|
;==============================================================================
|
|
; $D131-$D15F: Initialize Gameplay Nametable Attributes
|
|
;
|
|
; Local:
|
|
; Copies the 64-byte attribute table at $D160 to two PPU destinations:
|
|
;
|
|
; pass 1 -> PPU $23C0-$23FF
|
|
; pass 2 -> PPU $2BC0-$2BFF
|
|
;
|
|
; The first pass uses X=$01. After copying all $40 bytes, X is decremented.
|
|
; Since X becomes zero, execution falls through into the setup for the
|
|
; second destination at $2BC0.
|
|
;
|
|
; After the second copy, X decrements from $00 to $FF and the routine
|
|
; returns.
|
|
;
|
|
; Global:
|
|
; Called by GameModeState00 during game/round initialization. Initializes
|
|
; complete attribute tables for two nametables using identical palette-
|
|
; selection data.
|
|
;
|
|
; Notes:
|
|
; The branch at $D15E intentionally jumps back into the shared copy loop
|
|
; after selecting PPU address $2BC0.
|
|
;
|
|
; $D160 begins the 64-byte attribute source table and is not executable.
|
|
;==============================================================================
|
|
|
|
InitializeGameplayAttributes:
|
|
lda PPUSTATUS
|
|
|
|
lda #$23
|
|
sta PPUADDR
|
|
|
|
lda #$C0
|
|
sta PPUADDR
|
|
|
|
ldx #$01
|
|
|
|
@CopyAttributeTable:
|
|
ldy #$00
|
|
|
|
@CopyAttributeBytes:
|
|
lda GameplayAttributeData,y
|
|
sta PPUDATA
|
|
|
|
iny
|
|
cpy #$40
|
|
bne @CopyAttributeBytes
|
|
|
|
dex
|
|
beq @SetupSecondNametable
|
|
|
|
rts
|
|
|
|
@SetupSecondNametable:
|
|
lda PPUSTATUS
|
|
|
|
lda #$2B
|
|
sta PPUADDR
|
|
|
|
lda #$C0
|
|
sta PPUADDR
|
|
|
|
bne @CopyAttributeTable
|
|
|
|
;==============================================================================
|
|
; $D160-$D19F: Gameplay Nametable Attribute Data
|
|
;
|
|
; Local:
|
|
; Complete 64-byte NES attribute table copied to both PPU $23C0-$23FF and
|
|
; $2BC0-$2BFF by InitializeGameplayAttributes.
|
|
;
|
|
; Global:
|
|
; Defines background-palette selections for the gameplay nametables.
|
|
;
|
|
; Notes:
|
|
; Common values:
|
|
;
|
|
; $00 -> palette 0 in all four attribute quadrants
|
|
; $55 -> palette 1 in all four quadrants
|
|
;
|
|
; Values such as $11, $51, $50 and $05 combine different palette selections
|
|
; within the four quadrants of an attribute byte.
|
|
;==============================================================================
|
|
|
|
GameplayAttributeData:
|
|
.byte $55,$55,$55,$55,$55,$11,$00,$00
|
|
.byte $55,$55,$55,$55,$55,$11,$00,$00
|
|
.byte $55,$55,$55,$55,$55,$11,$00,$00
|
|
.byte $55,$55,$55,$55,$55,$51,$50,$50
|
|
.byte $55,$55,$55,$55,$55,$11,$05,$05
|
|
.byte $55,$55,$55,$55,$55,$11,$00,$00
|
|
.byte $55,$55,$55,$55,$55,$55,$55,$55
|
|
.byte $55,$55,$55,$55,$55,$55,$55,$55
|
|
|
|
;==============================================================================
|
|
; $D1A0-$D289: Gameplay Timers and State Progression
|
|
;
|
|
; Local:
|
|
; Updates several gameplay timers, palette-animation values, progression
|
|
; counters, and state variables.
|
|
;
|
|
; Global:
|
|
; Called once per active gameplay frame from GameModeState04. Coordinates
|
|
; several independent timing and progression systems.
|
|
;
|
|
; Notes:
|
|
; Address-based local labels are used during this pass to make the original
|
|
; branch destinations explicit and simplify byte-identical verification.
|
|
;==============================================================================
|
|
|
|
UpdateGameplayTimers:
|
|
lda $89
|
|
bmi @D1E1
|
|
|
|
inc $8A
|
|
|
|
lda #$3C
|
|
cmp $8A
|
|
bne @D1C9
|
|
|
|
lda #$00
|
|
sta $8A
|
|
|
|
dec $89
|
|
bpl @D1C9
|
|
|
|
sta $88
|
|
|
|
ldx #$00
|
|
|
|
@D1B7:
|
|
lda $39,x
|
|
and #$FC
|
|
sta $00
|
|
|
|
txa
|
|
ora $00
|
|
sta $39,x
|
|
|
|
inx
|
|
cpx #$04
|
|
bne @D1B7
|
|
|
|
@D1C9:
|
|
lda $89
|
|
cmp #$02
|
|
bcs @D1E1
|
|
|
|
ldx #$11
|
|
|
|
lda $8A
|
|
and #$08
|
|
bne @D1D9
|
|
|
|
ldx #$20
|
|
|
|
@D1D9:
|
|
stx $02AE
|
|
|
|
lda #$0F
|
|
sta $02A9
|
|
|
|
|
|
@D1E1:
|
|
lda $88
|
|
bne @D213
|
|
|
|
lda $CF
|
|
cmp #$FF
|
|
beq @D213
|
|
|
|
inc $D1
|
|
|
|
lda $D1
|
|
cmp #$3C
|
|
bne @D213
|
|
|
|
lda #$00
|
|
sta $D1
|
|
|
|
dec $CF
|
|
bpl @D213
|
|
|
|
inc $D0
|
|
|
|
lda $D0
|
|
and #$01
|
|
beq @D209
|
|
|
|
jsr $E08E
|
|
|
|
lda #$0F
|
|
bne @D20B
|
|
|
|
@D209:
|
|
lda $D2
|
|
|
|
@D20B:
|
|
sta $87
|
|
|
|
ldx $D0
|
|
lda $97,x
|
|
sta $CF
|
|
|
|
|
|
@D213:
|
|
lda $D3
|
|
beq @D236
|
|
|
|
clc
|
|
adc $6A
|
|
cmp #$C0
|
|
bne @D236
|
|
|
|
jsr ActivateNextStateEntry
|
|
|
|
lda $D3
|
|
ldx #$00
|
|
|
|
@D225:
|
|
cmp $8F,x
|
|
bne @D231
|
|
|
|
inx
|
|
lda $8F,x
|
|
sta $D3
|
|
|
|
jmp @D236
|
|
|
|
@D231:
|
|
inx
|
|
cpx #$04
|
|
bne @D225
|
|
|
|
|
|
@D236:
|
|
inc $D6
|
|
|
|
lda #$60
|
|
cmp $D6
|
|
bne @D251
|
|
|
|
lda #$00
|
|
sta $D6
|
|
|
|
inc $D5
|
|
|
|
lda $D5
|
|
cmp $96
|
|
bne @D251
|
|
|
|
lda #$00
|
|
sta $D5
|
|
|
|
jsr ActivateNextStateEntry
|
|
|
|
|
|
@D251:
|
|
ldx $D4
|
|
|
|
cpx #$02
|
|
beq @D26E
|
|
|
|
lda $8D,x
|
|
cmp $6A
|
|
bne @D26E
|
|
|
|
inc $D4
|
|
|
|
lda #$01
|
|
sta $D2
|
|
|
|
txa
|
|
asl
|
|
tax
|
|
|
|
lda $AB,x
|
|
sta $CA
|
|
|
|
lda $AC,x
|
|
sta $CB
|
|
|
|
|
|
@D26E:
|
|
ora $D7
|
|
ora $D8
|
|
beq @D289
|
|
|
|
dec $D8
|
|
bne @D289
|
|
|
|
lda $D7
|
|
beq @D283
|
|
|
|
dec $D7
|
|
|
|
lda #$3C
|
|
sta $D8
|
|
|
|
rts
|
|
|
|
|
|
@D283:
|
|
sta $2E
|
|
sta $30
|
|
sta $8B
|
|
|
|
|
|
@D289:
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $D28A-$D29B: Activate First Available State Entry
|
|
;
|
|
; Local:
|
|
; Searches the even-indexed entries at $BA, $BC, and $BE for the first
|
|
; zero value.
|
|
;
|
|
; When a zero entry is found, replaces it with $02 and returns.
|
|
;
|
|
; If all three entries are already nonzero, returns without modifying them.
|
|
;
|
|
; Global:
|
|
; Called by UpdateGameplayTimers when certain progression timers expire.
|
|
; This appears to activate the next available entry in a three-element
|
|
; state array.
|
|
;
|
|
; Notes:
|
|
; Only the even addresses $BA/$BC/$BE are examined. The interleaved bytes
|
|
; $BB/$BD/$BF form a parallel field initialized elsewhere.
|
|
;
|
|
; The meaning of state value $02 will be refined when the consumers of
|
|
; $BA-$BF are decoded.
|
|
;==============================================================================
|
|
ActivateNextStateEntry:
|
|
ldx #$00
|
|
|
|
@FindAvailableEntry:
|
|
lda $BA,x
|
|
bne @NextEntry
|
|
|
|
lda #$02
|
|
sta $BA,x
|
|
|
|
rts
|
|
|
|
@NextEntry:
|
|
inx
|
|
inx
|
|
|
|
cpx #$06
|
|
bne @FindAvailableEntry
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $D29C-$D2A3: Sequential Tile/Value Table
|
|
;
|
|
; Local:
|
|
; Eight sequential values from $24 through $2B.
|
|
;
|
|
; Global:
|
|
; Consumer has not yet been decoded during this pass. Given the sequential
|
|
; values and the surrounding graphics-oriented code, this may represent
|
|
; tile IDs or animation values.
|
|
;
|
|
; Notes:
|
|
; Keep the table generically named until a direct reference establishes its
|
|
; exact purpose.
|
|
;==============================================================================
|
|
|
|
SequentialValueTableD29C:
|
|
.byte $24,$25,$26,$27,$28,$29,$2A,$2B
|
|
|
|
|
|
|
|
;==============================================================================
|
|
; $D2A4-$D36B: Gameplay Proximity / State Transition Handler
|
|
;
|
|
; Local:
|
|
; Returns immediately when $6A is zero.
|
|
;
|
|
; Otherwise scans even-indexed state entries beginning at $B8. Entries whose
|
|
; state value is $04 undergo two proximity tests using the four-byte
|
|
; structures beginning at $001E.
|
|
;
|
|
; $02 is shifted once for each scanned entry and acts as a candidate bitmask.
|
|
; When a qualifying entry is found, the routine selects one of several state
|
|
; transition paths based on X and ($02 & $88).
|
|
;
|
|
; Global:
|
|
; Called during normal gameplay processing from GameModeState04. This
|
|
; routine appears to detect proximity/collision conditions and initiate
|
|
; corresponding gameplay-state transitions.
|
|
;
|
|
; Notes:
|
|
; $00/$01 form a temporary pointer, initially $001E.
|
|
; $02 is a shifting bitmask.
|
|
; $03 is temporary storage for distance/index calculations.
|
|
;
|
|
; Lookup tables begin at ProximityCandidateValues and will be decoded separately.
|
|
;==============================================================================
|
|
CheckGameplayProximity:
|
|
lda $6A
|
|
bne @Start
|
|
|
|
rts
|
|
|
|
@Start:
|
|
lda #$1E
|
|
sta $00
|
|
|
|
lda #$00
|
|
sta $01
|
|
|
|
lda #$01
|
|
sta $02
|
|
|
|
ldx #$00
|
|
|
|
@ScanEntries:
|
|
lda $B8,x
|
|
cmp #$04
|
|
bne @NextEntry
|
|
|
|
ldy #$00
|
|
|
|
lda $1A
|
|
cmp ($00),y
|
|
bcs @FirstAxisReverse
|
|
|
|
lda ($00),y
|
|
sec
|
|
sbc $1A
|
|
bcs @CheckFirstAxisDistance
|
|
|
|
@FirstAxisReverse:
|
|
sbc ($00),y
|
|
|
|
@CheckFirstAxisDistance:
|
|
cmp #$0A
|
|
bcs @NextEntry
|
|
|
|
sta $03
|
|
|
|
ldy #$02
|
|
|
|
lda $1C
|
|
cmp ($00),y
|
|
bcs @SecondAxisReverse
|
|
|
|
lda ($00),y
|
|
sec
|
|
sbc $1C
|
|
bcs @CheckSecondAxisDistance
|
|
|
|
@SecondAxisReverse:
|
|
sbc ($00),y
|
|
|
|
@CheckSecondAxisDistance:
|
|
cmp #$0A
|
|
bcs @NextEntry
|
|
|
|
adc $03
|
|
cmp #$05
|
|
bcc @CandidateFound
|
|
|
|
|
|
@NextEntry:
|
|
inx
|
|
inx
|
|
|
|
lda $00
|
|
clc
|
|
adc #$04
|
|
sta $00
|
|
|
|
asl $02
|
|
|
|
cpx #$0A
|
|
bne @ScanEntries
|
|
|
|
rts
|
|
|
|
|
|
@CandidateFound:
|
|
cpx #$08
|
|
beq @ProcessSecondaryState
|
|
|
|
lda $02
|
|
and $88
|
|
beq @SpecialCandidate
|
|
|
|
txa
|
|
lsr
|
|
sta $03
|
|
|
|
ldy $D9
|
|
|
|
lda ProximityCandidateValues,y
|
|
|
|
ldy $03
|
|
sta $0033,y
|
|
|
|
lda #$00
|
|
sta $32
|
|
|
|
ldy $D9
|
|
|
|
lda ProximityDDValues,y
|
|
sta $DD
|
|
|
|
lda ProximityDEValues,y
|
|
sta $DE
|
|
|
|
inc $D9
|
|
|
|
lda #$08
|
|
sta $B8,x
|
|
sta $0607
|
|
|
|
lda #$06
|
|
sta $3F
|
|
|
|
jmp $E0E6
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D337
|
|
; Candidate path selected when ($02 & $88) == 0.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@SpecialCandidate:
|
|
lda #$08
|
|
sta $3F
|
|
|
|
lda #$12
|
|
sta $32
|
|
|
|
lda #$80
|
|
sta $DB
|
|
|
|
lda #$00
|
|
sta $87
|
|
|
|
rts
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D348
|
|
; Special path selected when X == $08.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@ProcessSecondaryState:
|
|
lda $8B
|
|
beq @InitializeSecondaryState
|
|
|
|
rts
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D34D
|
|
; Initialize secondary state.
|
|
;------------------------------------------------------------------------------
|
|
@InitializeSecondaryState:
|
|
sta $D7
|
|
|
|
lda #$80
|
|
sta $D8
|
|
sta $8B
|
|
sta $0606
|
|
|
|
ldy $93
|
|
|
|
lda SecondaryStateDDValues,y
|
|
sta $DD
|
|
|
|
lda SecondaryStateDEValues,y
|
|
sta $DE
|
|
|
|
lda SecondaryState37Values,y
|
|
sta $37
|
|
|
|
jmp $E0E6
|
|
|
|
;==============================================================================
|
|
; $D36C-$D38F: Gameplay Proximity / Transition Lookup Data
|
|
;
|
|
; Local:
|
|
; Lookup data used by CheckGameplayProximity when a qualifying proximity
|
|
; condition triggers a gameplay-state transition.
|
|
;
|
|
; Global:
|
|
; Supplies values written to $33+, $37, $DD and $DE during the different
|
|
; transition paths handled by CheckGameplayProximity.
|
|
;
|
|
; Notes:
|
|
; $D370 is intentionally a label inside the table beginning at $D36C.
|
|
; No bytes are duplicated.
|
|
;==============================================================================
|
|
ProximityCandidateValues:
|
|
; $D36C-$D36F
|
|
.byte $2D,$2F,$32,$34
|
|
|
|
SecondaryState37Values:
|
|
; $D370-$D373
|
|
; Also forms bytes 4-7 of ProximityCandidateValues.
|
|
.byte $2C,$2E,$30,$31
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D374-$D377
|
|
; Consumer not yet established.
|
|
;------------------------------------------------------------------------------
|
|
ProximityUnknownTableD374:
|
|
.byte $33,$35,$36,$37
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D378-$D37B
|
|
; Indexed by $D9 and loaded into $DE.
|
|
;------------------------------------------------------------------------------
|
|
ProximityDEValues:
|
|
.byte $00,$00,$00,$01
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D37C-$D37F
|
|
; Indexed by $D9 and loaded into $DD.
|
|
;------------------------------------------------------------------------------
|
|
ProximityDDValues:
|
|
.byte $02,$04,$08,$06
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D380-$D387
|
|
; Indexed by $93 and loaded into $DD.
|
|
;------------------------------------------------------------------------------
|
|
SecondaryStateDDValues:
|
|
.byte $01,$03,$05,$07
|
|
.byte $00,$00,$00,$00
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D388-$D38F
|
|
; Indexed by $93 and loaded into $DE.
|
|
;------------------------------------------------------------------------------
|
|
SecondaryStateDEValues:
|
|
.byte $00,$00,$00,$00
|
|
.byte $01,$02,$03,$05
|
|
|
|
;==============================================================================
|
|
; $D390-...: Gameplay Direction / Movement Processing
|
|
;
|
|
; Local:
|
|
; Processes directional controller input, validates a requested direction
|
|
; against the current map/tile state, and selects movement parameters.
|
|
;
|
|
; Global:
|
|
; Called during normal gameplay processing from GameModeState04.
|
|
;
|
|
; Notes:
|
|
; Address-derived labels are retained during this pass to make branch
|
|
; targets explicit while maintaining byte identity.
|
|
;==============================================================================
|
|
|
|
UpdatePlayerMovement:
|
|
lda $48
|
|
beq @D397
|
|
|
|
jmp $D506
|
|
|
|
@D397:
|
|
lda $4F
|
|
and #$F0
|
|
beq @D3D2
|
|
|
|
ldx #$FF
|
|
|
|
@D39F:
|
|
inx
|
|
asl
|
|
bcc @D39F
|
|
|
|
lda InputDirectionTable,x
|
|
sta $50
|
|
|
|
clc
|
|
adc #$02
|
|
and #$03
|
|
cmp $51
|
|
bne @D3C9
|
|
|
|
lda $1A
|
|
ora $1C
|
|
and #$07
|
|
bne @D3C2
|
|
|
|
ldy $50
|
|
|
|
lda $022B,y
|
|
and #$F0
|
|
bne @D3C9
|
|
|
|
|
|
@D3C2:
|
|
lda $50
|
|
sta $51
|
|
|
|
jmp @D3D6
|
|
|
|
|
|
@D3C9:
|
|
ldx $50
|
|
|
|
lda $022B,x
|
|
and #$F0
|
|
beq @D3D6
|
|
|
|
|
|
@D3D2:
|
|
lda $51
|
|
sta $50
|
|
|
|
|
|
@D3D6:
|
|
ldx #$04
|
|
|
|
lda $88
|
|
bne @D3DE
|
|
|
|
ldx #$0A
|
|
|
|
@D3DE:
|
|
lda $022A
|
|
cmp #$01
|
|
beq @D3F4
|
|
|
|
cmp #$02
|
|
beq @D3F4
|
|
|
|
dex
|
|
dex
|
|
|
|
cmp #$03
|
|
beq @D3F4
|
|
|
|
cmp #$09
|
|
beq @D3F4
|
|
|
|
dex
|
|
dex
|
|
|
|
|
|
@D3F4:
|
|
lda $9F,x
|
|
sta $B5
|
|
|
|
lda $A0,x
|
|
sta $B6
|
|
|
|
lda $51
|
|
asl
|
|
tay
|
|
|
|
lda MovementArithmeticTable,y
|
|
sta $10
|
|
|
|
lda MovementArithmeticTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
;==============================================================================
|
|
; $D40E-$D415: Movement Arithmetic Dispatch Table
|
|
;
|
|
; Local:
|
|
; Four 16-bit handlers selected using the internal direction value in $51.
|
|
;
|
|
; Global:
|
|
; Dispatches into direction-specific coordinate arithmetic used by
|
|
; UpdatePlayerMovement.
|
|
;
|
|
; Notes:
|
|
; Direction semantics remain unnamed during this pass.
|
|
;==============================================================================
|
|
MovementArithmeticTable:
|
|
.word $D416
|
|
.word $D41A
|
|
.word $D435
|
|
.word $D431
|
|
;==============================================================================
|
|
; $D416-$D443: Direction-Specific Movement Arithmetic
|
|
;
|
|
; Local:
|
|
; Four entry points selected by MovementArithmeticTable converge into two
|
|
; shared arithmetic paths.
|
|
;
|
|
; $D416/$D41A select the coordinate component and enter subtraction.
|
|
; $D431/$D435 select the coordinate component and enter addition.
|
|
;
|
|
; Global:
|
|
; Computes the fixed-point movement result used by the second direction
|
|
; dispatch beginning at MovementApplyResult.
|
|
;
|
|
; Notes:
|
|
; Shared labels are deliberately non-local because multiple entry-point
|
|
; labels must branch into the same code.
|
|
;==============================================================================
|
|
|
|
MovementArithmeticD416:
|
|
ldx #$02
|
|
bne MovementSubtract
|
|
|
|
MovementArithmeticD41A:
|
|
ldx #$00
|
|
|
|
MovementSubtract:
|
|
lda $1B,x
|
|
sec
|
|
sbc $B5
|
|
sta $1B,x
|
|
|
|
lda #$00
|
|
bcs MovementSubtractNoBorrow
|
|
|
|
lda #$01
|
|
|
|
MovementSubtractNoBorrow:
|
|
clc
|
|
adc $B6
|
|
sta $CC
|
|
|
|
jmp MovementApplyResult
|
|
|
|
|
|
MovementArithmeticD431:
|
|
ldx #$00
|
|
beq MovementAdd
|
|
|
|
|
|
MovementArithmeticD435:
|
|
ldx #$02
|
|
|
|
|
|
MovementAdd:
|
|
lda $1B,x
|
|
clc
|
|
adc $B5
|
|
sta $1B,x
|
|
|
|
lda #$00
|
|
adc $B6
|
|
sta $CC
|
|
|
|
;==============================================================================
|
|
; $D444-$D459: Apply Movement Result and Dispatch Direction Handler
|
|
;
|
|
; Local:
|
|
; Decrements the movement accumulator $CC. If it becomes negative, returns
|
|
; immediately.
|
|
;
|
|
; Otherwise uses the current direction value at $51 as a byte offset into a
|
|
; four-entry handler table beginning at $D45A.
|
|
;
|
|
; Global:
|
|
; Second stage of UpdatePlayerMovement. After the fixed-point arithmetic
|
|
; performed by the $D416-$D443 handlers, this dispatches to the actual
|
|
; direction-specific coordinate/tile movement code.
|
|
;
|
|
; Notes:
|
|
; $51 is multiplied by two before indexing the pointer table.
|
|
;==============================================================================
|
|
|
|
MovementApplyResult:
|
|
dec $CC
|
|
bpl @D449
|
|
|
|
rts
|
|
|
|
|
|
@D449:
|
|
lda $51
|
|
asl
|
|
tay
|
|
|
|
lda MovementDirectionTable,y
|
|
sta $10
|
|
|
|
lda MovementDirectionTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
;==============================================================================
|
|
; $D45A-$D461: Direction-Specific Movement Dispatch Table
|
|
;
|
|
; Local:
|
|
; Four handlers selected according to the internal direction value in $51.
|
|
;
|
|
; Notes:
|
|
; Handler names remain address-based until coordinate effects are fully
|
|
; mapped to semantic direction names.
|
|
;==============================================================================
|
|
|
|
MovementDirectionTable:
|
|
.word MovementDirectionD49A
|
|
.word MovementDirectionD490
|
|
.word MovementDirectionD46C
|
|
.word MovementDirectionD462
|
|
|
|
;==============================================================================
|
|
; $D462-$D501: Direction-Specific Movement Handlers
|
|
;
|
|
; Local:
|
|
; Four entry points selected by MovementDirectionTable.
|
|
;
|
|
; $D462 and $D46C enter the increment path.
|
|
; $D490 and $D49A enter the decrement path.
|
|
;
|
|
; X selects which coordinate component at $1A/$1C is modified. $00 and $01
|
|
; preserve working indexes used for collision/tile checks against $022B.
|
|
;
|
|
; After movement, the shared tail handles coordinate wrapping/state flags
|
|
; and, when aligned to an 8-unit boundary, commits a requested direction
|
|
; change from $50 to $51.
|
|
;
|
|
; Global:
|
|
; Final stage of UpdatePlayerMovement. Applies movement to the player's
|
|
; coordinate state and reconciles requested direction changes.
|
|
;
|
|
; Notes:
|
|
; Entry points intentionally share code. Use non-local labels for shared
|
|
; targets so ca65 scope rules do not change the branch structure.
|
|
;==============================================================================
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D462
|
|
; Increment coordinate component X=0.
|
|
;------------------------------------------------------------------------------
|
|
|
|
MovementDirectionD462:
|
|
ldx #$00
|
|
stx $00
|
|
|
|
lda #$03
|
|
sta $01
|
|
|
|
bne MovementIncrement
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D46C
|
|
; Increment coordinate component X=2.
|
|
;------------------------------------------------------------------------------
|
|
|
|
MovementDirectionD46C:
|
|
ldx #$02
|
|
stx $00
|
|
stx $01
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D472: Shared increment path.
|
|
;------------------------------------------------------------------------------
|
|
|
|
MovementIncrement:
|
|
lda $1A,x
|
|
clc
|
|
adc #$01
|
|
sta $1A,x
|
|
|
|
and #$04
|
|
bne MovementSharedTail
|
|
|
|
ldx $01
|
|
|
|
lda $022B,x
|
|
and #$F0
|
|
beq MovementSharedTail
|
|
|
|
ldx $00
|
|
|
|
lda $1A,x
|
|
and #$FC
|
|
sta $1A,x
|
|
|
|
bne MovementSharedTail
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D490
|
|
; Decrement coordinate component X=0.
|
|
;------------------------------------------------------------------------------
|
|
|
|
MovementDirectionD490:
|
|
ldx #$00
|
|
stx $00
|
|
|
|
lda #$01
|
|
sta $01
|
|
|
|
bne MovementDecrement
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D49A
|
|
; Decrement coordinate component X=2.
|
|
;------------------------------------------------------------------------------
|
|
|
|
MovementDirectionD49A:
|
|
ldx #$02
|
|
stx $00
|
|
|
|
lda #$00
|
|
sta $01
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D4A2: Shared decrement path.
|
|
;------------------------------------------------------------------------------
|
|
|
|
MovementDecrement:
|
|
lda $1A,x
|
|
sec
|
|
sbc #$01
|
|
sta $1A,x
|
|
|
|
and #$04
|
|
beq MovementSharedTail
|
|
|
|
ldx $01
|
|
|
|
lda $022B,x
|
|
and #$F0
|
|
beq MovementSharedTail
|
|
|
|
ldx $00
|
|
|
|
lda $1A,x
|
|
clc
|
|
adc #$04
|
|
and #$FC
|
|
sta $1A,x
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D4C1: Shared movement/wrap tail.
|
|
;------------------------------------------------------------------------------
|
|
|
|
MovementSharedTail:
|
|
lda $1A
|
|
|
|
cmp #$18
|
|
bcc MovementCheckLeftWrap
|
|
|
|
cmp #$A9
|
|
bcs MovementCheckLeftWrap
|
|
|
|
lda $38
|
|
and #$DF
|
|
bcc MovementStoreWrapState
|
|
|
|
MovementCheckLeftWrap:
|
|
lda #$20
|
|
ora $38
|
|
|
|
MovementStoreWrapState:
|
|
sta $38
|
|
|
|
lda $1A
|
|
cmp #$0B
|
|
bcs MovementCheckRightWrap
|
|
|
|
lda #$BF
|
|
sta $1A
|
|
bne MovementCheckAlignment
|
|
|
|
MovementCheckRightWrap:
|
|
cmp #$C0
|
|
bcc MovementCheckAlignment
|
|
|
|
lda #$0B
|
|
sta $1A
|
|
|
|
|
|
MovementCheckAlignment:
|
|
lda $1A
|
|
ora $1C
|
|
and #$07
|
|
bne MovementReturnToArithmetic
|
|
|
|
lda $50
|
|
cmp $51
|
|
beq MovementReturnToArithmetic
|
|
|
|
sta $51
|
|
|
|
inc $CC
|
|
inc $CC
|
|
|
|
|
|
MovementReturnToArithmetic:
|
|
jmp MovementApplyResult
|
|
|
|
;==============================================================================
|
|
; $D502-$D505: Controller Direction Mapping
|
|
;==============================================================================
|
|
|
|
InputDirectionTable:
|
|
.byte $03,$01,$02,$00
|
|
|
|
;==============================================================================
|
|
; $D506-$D51E: Scripted Direction/Input Update
|
|
;
|
|
; Local:
|
|
; Uses $E3 as a countdown and $E4 as an offset into the table beginning at
|
|
; $D51F.
|
|
;
|
|
; Each time $E3 reaches zero:
|
|
; - Advances $E4 by two.
|
|
; - Loads a new duration from $D51F+$E4 into $E3.
|
|
;
|
|
; It then takes the following table byte, masks it to two bits, and
|
|
; tail-jumps into UpdatePlayerMovement at $D3A6 with that value in A.
|
|
;
|
|
; Global:
|
|
; Entered from UpdatePlayerMovement when $48 is nonzero. This provides a
|
|
; scripted/autonomous direction source in place of normal controller input.
|
|
;
|
|
; Notes:
|
|
; $E4 indexes two-byte table records:
|
|
;
|
|
; byte 0 = duration/count
|
|
; byte 1 = direction/control value
|
|
;
|
|
; The second byte is masked with #$03 before entering movement processing.
|
|
;==============================================================================
|
|
|
|
UpdateScriptedDirection:
|
|
ldy $E4
|
|
|
|
dec $E3
|
|
bne @UseCurrentEntry
|
|
|
|
inc $E4
|
|
inc $E4
|
|
|
|
ldy $E4
|
|
|
|
lda ScriptedDirectionTable,y
|
|
sta $E3
|
|
|
|
@UseCurrentEntry:
|
|
lda ScriptedDirectionTable+1,y
|
|
and #$03
|
|
|
|
jmp $D3A6
|
|
|
|
;==============================================================================
|
|
; $D51F-...: Scripted Direction Table
|
|
;
|
|
; Local:
|
|
; Two-byte records used by UpdateScriptedDirection:
|
|
;
|
|
; byte 0 = duration
|
|
; byte 1 = direction/control number
|
|
;
|
|
; Global:
|
|
; Drives autonomous/scripted movement when $48 selects this path instead of
|
|
; normal player controller processing.
|
|
;==============================================================================
|
|
ScriptedDirectionTable:
|
|
.byte $00,$01
|
|
.byte $D0,$00
|
|
.byte $28,$01
|
|
.byte $28,$02
|
|
.byte $90,$03
|
|
.byte $38,$00
|
|
.byte $20,$03
|
|
.byte $18,$01
|
|
.byte $60,$02
|
|
.byte $30,$01
|
|
.byte $10,$02
|
|
.byte $48,$01
|
|
.byte $18,$02
|
|
.byte $40,$01
|
|
.byte $20,$02
|
|
.byte $18,$00
|
|
.byte $20,$03
|
|
.byte $40,$02
|
|
.byte $38,$01
|
|
.byte $18,$02
|
|
.byte $E0,$03
|
|
.byte $30,$00
|
|
.byte $28,$01
|
|
.byte $28,$02
|
|
.byte $20,$02
|
|
.byte $80,$03
|
|
.byte $40,$00
|
|
.byte $40,$01
|
|
|
|
;==============================================================================
|
|
; $D557-$D586: Update Four Gameplay Entities
|
|
;
|
|
; Local:
|
|
; Iterates four gameplay entries using X offsets:
|
|
;
|
|
; $00, $02, $04, $06
|
|
;
|
|
; Initializes several temporary values before the loop:
|
|
;
|
|
; $00 = $2F
|
|
; $01 = $02
|
|
; $02 = $1E
|
|
; $03 = $00
|
|
; $04 = $01
|
|
;
|
|
; For each entry, calls the dispatcher at $D587. After each call:
|
|
;
|
|
; $00 += 4
|
|
; $02 += 4
|
|
; $04 <<= 1
|
|
; X += 2
|
|
;
|
|
; Processing ends after X reaches $08.
|
|
;
|
|
; Global:
|
|
; Called every active gameplay frame from GameModeState04. Coordinates
|
|
; per-entry updates for four gameplay entities/state slots.
|
|
;
|
|
; Notes:
|
|
; $00 and $02 appear to advance through parallel four-byte-strided RAM
|
|
; structures.
|
|
;
|
|
; $04 becomes a per-entry bitmask:
|
|
;
|
|
; $01,$02,$04,$08
|
|
;
|
|
; The exact roles of the temporary values will become clearer as the
|
|
; dispatcher at $D587 and its handlers are decoded.
|
|
;==============================================================================
|
|
|
|
UpdateGameplayEntities:
|
|
ldx #$00
|
|
|
|
lda #$2F
|
|
sta $00
|
|
|
|
lda #$02
|
|
sta $01
|
|
|
|
lda #$1E
|
|
sta $02
|
|
|
|
lda #$00
|
|
sta $03
|
|
|
|
lda #$01
|
|
sta $04
|
|
|
|
@UpdateNextEntity:
|
|
jsr $D587
|
|
|
|
lda $00
|
|
clc
|
|
adc #$04
|
|
sta $00
|
|
|
|
lda $02
|
|
clc
|
|
adc #$04
|
|
sta $02
|
|
|
|
asl $04
|
|
|
|
inx
|
|
inx
|
|
|
|
cpx #$08
|
|
bne @UpdateNextEntity
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $D587-$D595: Gameplay Entity State Dispatcher
|
|
;
|
|
; Local:
|
|
; Reads the state value for the current entity from $B8,X and uses that
|
|
; value directly as a byte offset into EntityStateTable.
|
|
;
|
|
; The selected 16-bit handler address is copied to $10/$11 and execution
|
|
; transfers to it with an indirect JMP.
|
|
;
|
|
; Global:
|
|
; Called by UpdateGameplayEntities once for each of four gameplay entity
|
|
; slots. This provides the per-entity state machine used by those entries.
|
|
;
|
|
; Notes:
|
|
; X identifies the current entry using even offsets:
|
|
;
|
|
; $00,$02,$04,$06
|
|
;
|
|
; $B8,X is a byte offset into the pointer table, so valid state values are
|
|
; even:
|
|
;
|
|
; $00,$02,$04,$06,$08
|
|
;==============================================================================
|
|
|
|
DispatchGameplayEntityState:
|
|
ldy $B8,x
|
|
|
|
lda EntityStateTable,y
|
|
sta $10
|
|
|
|
lda EntityStateTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
;==============================================================================
|
|
; $D596-$D59F: Gameplay Entity State Table
|
|
;
|
|
; Local:
|
|
; Five 16-bit handlers indexed directly by the even state value stored in
|
|
; $B8,X.
|
|
;
|
|
; Global:
|
|
; Defines the per-entity state machine used by
|
|
; DispatchGameplayEntityState.
|
|
;
|
|
; Notes:
|
|
; States $04 and $06 deliberately share the same handler at $D5A1.
|
|
; State $08 targets $D5A0, one byte before that shared handler, suggesting
|
|
; another intentional overlapping entry point.
|
|
;==============================================================================
|
|
|
|
EntityStateTable:
|
|
.word $D8D5 ; state $00
|
|
.word $D885 ; state $02
|
|
.word $D5A1 ; state $04
|
|
.word $D5A1 ; state $06
|
|
.word EntityState08 ; state $08
|
|
|
|
;==============================================================================
|
|
; $D5A0: Entity State $08 Handler
|
|
;
|
|
; Local:
|
|
; Returns immediately.
|
|
;
|
|
; Global:
|
|
; The entity-state table uses this as the handler for state $08, effectively
|
|
; disabling further processing for that entity state.
|
|
;==============================================================================
|
|
|
|
EntityState08:
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $D5A1-$D5B4: Entity State $04/$06 Secondary Dispatcher
|
|
;
|
|
; Local:
|
|
; Called for entity states $04 and $06 from EntityStateTable.
|
|
;
|
|
; First invokes the common entity helper at $D821. It then reads the
|
|
; secondary state value at $B9,X, doubles it, and uses the result as a byte
|
|
; offset into a four-entry pointer table at $D5B5.
|
|
;
|
|
; The selected address is stored in $10/$11 and execution transfers through
|
|
; an indirect JMP.
|
|
;
|
|
; Global:
|
|
; Provides a second-level state machine for gameplay entities whose primary
|
|
; state at $B8,X is $04 or $06.
|
|
;
|
|
; Notes:
|
|
; $B9,X behaves as an ordinal secondary state here. Unlike several earlier
|
|
; state tables, the value is explicitly multiplied by two before indexing
|
|
; the pointer table.
|
|
;==============================================================================
|
|
|
|
DispatchEntitySecondaryState:
|
|
jsr $D821
|
|
|
|
lda $B9,x
|
|
asl
|
|
tay
|
|
|
|
lda EntitySecondaryStateTable,y
|
|
sta $10
|
|
|
|
lda EntitySecondaryStateTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
;==============================================================================
|
|
; $D5B5-$D5BC: Entity Secondary-State Dispatch Table
|
|
;
|
|
; Local:
|
|
; Four handler addresses selected using ($B9,X * 2).
|
|
;
|
|
; Global:
|
|
; Defines the second-level state machine used by primary entity states
|
|
; $04 and $06.
|
|
;==============================================================================
|
|
|
|
EntitySecondaryStateTable:
|
|
.word EntitySecondaryState0 ; secondary state 0
|
|
.word EntitySecondaryState1 ; secondary state 1
|
|
.word EntitySecondaryState2 ; secondary state 2
|
|
.word EntitySecondaryState3 ; secondary state 3
|
|
|
|
;==============================================================================
|
|
; $D5BD-$D5D2: Secondary-State Coordinate Adjustment
|
|
;
|
|
; Local:
|
|
; Secondary state 2 enters at $D5BD and selects Y=$03.
|
|
; Secondary state 3 enters at $D5C1 and selects Y=$01.
|
|
;
|
|
; Both then read through the indirect pointer at $02/$03, add the
|
|
; entity-specific values at $C2,X/$C3,X, write the low-byte result back
|
|
; through the pointer, and store the high-byte result in $CC.
|
|
;
|
|
; Control then tail-jumps to $D5EB.
|
|
;
|
|
; Global:
|
|
; Shared movement/update arithmetic for two secondary entity states.
|
|
;
|
|
; Notes:
|
|
; $02/$03 were initialized by UpdateGameplayEntities and advance by four
|
|
; bytes per entity, so they identify the current entity's four-byte state
|
|
; structure.
|
|
;==============================================================================
|
|
|
|
EntitySecondaryState2:
|
|
ldy #$03
|
|
bne EntitySecondaryAdjust
|
|
|
|
EntitySecondaryState3:
|
|
ldy #$01
|
|
|
|
EntitySecondaryAdjust:
|
|
lda ($02),y
|
|
clc
|
|
adc $C2,x
|
|
sta ($02),y
|
|
|
|
lda #$00
|
|
adc $C3,x
|
|
sta $CC
|
|
|
|
jmp $D5EB
|
|
|
|
;==============================================================================
|
|
; $D5D3-$D5EE: Entity Secondary States $00/$01 Movement Arithmetic
|
|
;
|
|
; Local:
|
|
; Secondary state 0 enters at $D5D3 and selects Y=$03.
|
|
; Secondary state 1 enters at $D5D7 and selects Y=$01.
|
|
;
|
|
; Both subtract the entity-specific movement value at $C2,X from the
|
|
; structure addressed by $02/$03. Borrow is converted into a high-byte
|
|
; adjustment using $C3,X and stored in $CC.
|
|
;
|
|
; Afterward, $CC is decremented. A negative result returns immediately;
|
|
; otherwise execution continues into another secondary dispatcher at $D5EF.
|
|
;
|
|
; Global:
|
|
; Complements the addition paths at $D5BD/$D5C1. Together, the four
|
|
; secondary states provide signed movement along two coordinate components.
|
|
;
|
|
; Notes:
|
|
; The shared labels are non-local because multiple handler entry points
|
|
; converge into them.
|
|
;==============================================================================
|
|
|
|
EntitySecondaryState0:
|
|
ldy #$03
|
|
bne EntitySecondarySubtract
|
|
|
|
|
|
EntitySecondaryState1:
|
|
ldy #$01
|
|
|
|
|
|
EntitySecondarySubtract:
|
|
lda ($02),y
|
|
sec
|
|
sbc $C2,x
|
|
sta ($02),y
|
|
|
|
lda #$00
|
|
bcs EntitySecondarySubtractNoBorrow
|
|
|
|
lda #$01
|
|
|
|
|
|
EntitySecondarySubtractNoBorrow:
|
|
clc
|
|
adc $C3,x
|
|
sta $CC
|
|
|
|
|
|
;==============================================================================
|
|
; $D5EB-$D600: Apply Entity Movement and Dispatch Direction Substate
|
|
;
|
|
; Local:
|
|
; Shared continuation reached by both the addition and subtraction
|
|
; secondary-state handlers.
|
|
;
|
|
; Decrements $CC. If it becomes negative, returns. Otherwise reads the
|
|
; current entity secondary state from $B9,X, doubles it, and selects a
|
|
; handler from the table at $D601.
|
|
;
|
|
; Global:
|
|
; Final arithmetic stage for entity movement before dispatching into the
|
|
; direction/substate-specific update handlers.
|
|
;==============================================================================
|
|
|
|
EntitySecondaryApplyResult:
|
|
dec $CC
|
|
bpl EntityDirectionDispatch
|
|
|
|
rts
|
|
|
|
|
|
EntityDirectionDispatch:
|
|
lda $B9,x
|
|
asl
|
|
tay
|
|
|
|
lda EntityDirectionStateTable,y
|
|
sta $10
|
|
|
|
lda EntityDirectionStateTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
;==============================================================================
|
|
; $D601-$D608: Entity Direction-State Dispatch Table
|
|
;
|
|
; Local:
|
|
; Four handlers selected from the entity's secondary state at $B9,X.
|
|
;
|
|
; Notes:
|
|
; The pointer order deliberately differs from the physical order of the
|
|
; handlers in ROM.
|
|
;==============================================================================
|
|
|
|
EntityDirectionStateTable:
|
|
.word $D609
|
|
.word $D61D
|
|
.word $D60F
|
|
.word $D617
|
|
|
|
;==============================================================================
|
|
; $D609-$D622: Entity Direction-State Handlers
|
|
;
|
|
; Local:
|
|
; Four handlers selected by EntityDirectionStateTable.
|
|
;
|
|
; Each handler configures:
|
|
;
|
|
; $05 = +1 or -1
|
|
; Y = $00 or $02
|
|
;
|
|
; before entering the shared coordinate-update code at $D623.
|
|
;
|
|
; Global:
|
|
; Provides the four direction-specific movement modes for the per-entity
|
|
; state machine.
|
|
;
|
|
; Notes:
|
|
; The four states form two coordinate axes and two signed directions:
|
|
;
|
|
; $D609 -> $05=$FF, Y=$02
|
|
; $D60F -> $05=$01, Y=$02
|
|
; $D617 -> $05=$01, Y=$00
|
|
; $D61D -> $05=$FF, Y=$00
|
|
;
|
|
; Concrete direction names remain deferred until the coordinate axes are
|
|
; mapped to screen X/Y.
|
|
;==============================================================================
|
|
|
|
EntityDirectionD609:
|
|
lda #$FF
|
|
sta $05
|
|
bne EntityDirectionAxis2
|
|
|
|
|
|
EntityDirectionD60F:
|
|
lda #$01
|
|
sta $05
|
|
|
|
|
|
EntityDirectionAxis2:
|
|
ldy #$02
|
|
bne EntityDirectionMove
|
|
|
|
|
|
EntityDirectionD617:
|
|
lda #$01
|
|
sta $05
|
|
bne EntityDirectionAxis0
|
|
|
|
|
|
EntityDirectionD61D:
|
|
lda #$FF
|
|
sta $05
|
|
|
|
|
|
EntityDirectionAxis0:
|
|
ldy #$00
|
|
|
|
;==============================================================================
|
|
; $D623-$D69A: Shared Entity Direction Movement
|
|
;
|
|
; Local:
|
|
; Applies the signed step in $05 to either byte $00 or $02 of the entity
|
|
; structure referenced by $02/$03.
|
|
;
|
|
; Performs coordinate wrapping/bounds handling, updates a per-entity flag
|
|
; stored in $39+, checks tile/grid alignment, and when the entity reaches a
|
|
; specific location ($60,$70) changes the entity primary state to $02.
|
|
;
|
|
; Global:
|
|
; Shared movement implementation for the four handlers above.
|
|
;
|
|
; Notes:
|
|
; This section eventually rejoins the earlier movement arithmetic at $D5EB
|
|
; when the entity is not aligned to the grid.
|
|
;==============================================================================
|
|
|
|
EntityDirectionMove:
|
|
lda ($02),y
|
|
clc
|
|
adc $05
|
|
sta ($02),y
|
|
|
|
ldy #$00
|
|
|
|
lda ($02),y
|
|
cmp #$0A
|
|
bne @D637
|
|
|
|
lda #$BF
|
|
sta ($02),y
|
|
bne @D64B
|
|
|
|
|
|
@D637:
|
|
cmp #$C0
|
|
bne @D641
|
|
|
|
lda #$0B
|
|
sta ($02),y
|
|
bne @D64B
|
|
|
|
|
|
@D641:
|
|
cmp #$18
|
|
bcc @D64B
|
|
|
|
cmp #$A9
|
|
bcc @D64F
|
|
|
|
|
|
@D64B:
|
|
lda #$20
|
|
bne @D651
|
|
|
|
|
|
@D64F:
|
|
lda #$00
|
|
|
|
|
|
@D651:
|
|
sta $05
|
|
|
|
txa
|
|
lsr
|
|
tay
|
|
|
|
lda $39,y
|
|
and #$DF
|
|
ora $05
|
|
sta $39,y
|
|
|
|
ldy #$00
|
|
lda ($02),y
|
|
|
|
ldy #$02
|
|
ora ($02),y
|
|
and #$07
|
|
beq @D66E
|
|
|
|
jmp EntitySecondaryApplyResult
|
|
|
|
@D66E:
|
|
ldy #$00
|
|
|
|
lda ($02),y
|
|
cmp #$60
|
|
bne $D69B
|
|
|
|
ldy #$02
|
|
|
|
lda ($02),y
|
|
cmp #$70
|
|
bne $D69B
|
|
|
|
lda #$02
|
|
sta $B8,x
|
|
|
|
lda #$00
|
|
clc
|
|
sbc $04
|
|
and $88
|
|
sta $88
|
|
|
|
txa
|
|
lsr
|
|
tay
|
|
sta $05
|
|
|
|
lda $39,y
|
|
and #$FC
|
|
ora $05
|
|
sta $39,y
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $D69B-$D6C6: Entity Movement Continuation / Target Selection
|
|
;
|
|
; Local:
|
|
; Continues entity processing after direction movement.
|
|
;
|
|
; Primary entity state $06 selects the fixed value $6F60 in $CD/$CE.
|
|
; Otherwise entity bitmasks in $04 are tested against $88 and $87.
|
|
;
|
|
; ($04 & $88) != 0 transfers to $D70A.
|
|
; ($04 & $87) != 0 transfers to $D6CF.
|
|
;
|
|
; If neither mask matches, the current entity index X selects a 16-bit value
|
|
; from EntityTargetTable and processing continues at $D778.
|
|
;
|
|
; Global:
|
|
; Chooses the next entity target/path-processing mode based on entity state
|
|
; and per-entity bitmasks.
|
|
;
|
|
; Notes:
|
|
; Cross-region branch targets remain raw until the destination blocks are
|
|
; decoded.
|
|
;==============================================================================
|
|
|
|
EntityMovementContinuation:
|
|
lda $B8,x
|
|
cmp #$06
|
|
bne @CheckEntityMasks
|
|
|
|
lda #$60
|
|
sta $CD
|
|
|
|
lda #$6F
|
|
sta $CE
|
|
|
|
jmp $D778
|
|
|
|
|
|
@CheckEntityMasks:
|
|
lda $04
|
|
and $88
|
|
bne $D70A
|
|
|
|
lda $04
|
|
and $87
|
|
bne $D6CF
|
|
|
|
txa
|
|
tay
|
|
|
|
lda EntityTargetTable,y
|
|
sta $CD
|
|
|
|
lda EntityTargetTable+1,y
|
|
sta $CE
|
|
|
|
jmp $D778
|
|
|
|
;==============================================================================
|
|
; $D6C7-$D6CE: Entity Target Table
|
|
;
|
|
; Local:
|
|
; Four 16-bit values indexed directly by the even entity offset X.
|
|
;
|
|
; Global:
|
|
; Supplies the $CD/$CE working target used by EntityMovementContinuation.
|
|
;
|
|
; Notes:
|
|
; Values are retained numerically until the consumer at $D778 is decoded.
|
|
;==============================================================================
|
|
|
|
EntityTargetTable:
|
|
.word $08A8
|
|
.word $0818
|
|
.word $D0A8
|
|
.word $D018
|
|
|
|
;==============================================================================
|
|
; $D6CF-$D6DD: Entity Target-Selection Dispatcher
|
|
;
|
|
; Local:
|
|
; Uses the current even entity index X directly as a byte offset into the
|
|
; four-entry pointer table at $D6DE.
|
|
;
|
|
; The selected handler address is stored in $10/$11 and execution transfers
|
|
; through an indirect JMP.
|
|
;
|
|
; Global:
|
|
; Entered from EntityMovementContinuation when the current entity's bit in
|
|
; $87 is set. Selects entity-specific target/path behavior.
|
|
;
|
|
; Notes:
|
|
; X is already constrained by the calling code to the even entity offsets:
|
|
;
|
|
; $00,$02,$04,$06
|
|
;
|
|
; Therefore no multiply-by-two is required here.
|
|
;==============================================================================
|
|
|
|
DispatchEntityTargetBehavior:
|
|
txa
|
|
tay
|
|
|
|
lda EntityTargetBehaviorTable,y
|
|
sta $10
|
|
|
|
lda EntityTargetBehaviorTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
;==============================================================================
|
|
; $D6DE-$D6E5: Entity Target-Behavior Dispatch Table
|
|
;
|
|
; Local:
|
|
; Four 16-bit handlers indexed directly by the even entity index X.
|
|
;
|
|
; Global:
|
|
; Selects different target/path calculations for each of the four gameplay
|
|
; entities.
|
|
;
|
|
; Notes:
|
|
; The fourth entry deliberately points backward to $D6E6, immediately after
|
|
; this table.
|
|
;==============================================================================
|
|
|
|
EntityTargetBehaviorTable:
|
|
.word EntityTargetBehaviorD73B ; X = $00
|
|
.word EntityTargetBehaviorD745 ; X = $02
|
|
.word EntityTargetBehaviorD764 ; X = $04
|
|
.word EntityTargetBehaviorD6E6 ; X = $06
|
|
|
|
;==============================================================================
|
|
; $D6E6-$D73A: Entity Target Behavior - Proximity/Direction Selection
|
|
;
|
|
; Local:
|
|
; Computes absolute differences between $1A/$2A and $1C/$2C.
|
|
; If either difference is at least $20, transfers to EntityTargetBehaviorD73B.
|
|
;
|
|
; Otherwise attempts up to five candidate directions. Each candidate is
|
|
; checked against the data addressed by $00/$01 and against the current
|
|
; entity direction/state at $B9,X.
|
|
;
|
|
; The selected value is stored into $B9,X before returning to the common
|
|
; entity movement result handler at $D5EB.
|
|
;
|
|
; Global:
|
|
; Fourth entry in EntityTargetBehaviorTable, selected for entity X=$06.
|
|
;
|
|
; Notes:
|
|
; Cross-block target $D73B remains raw until that handler is decoded.
|
|
;==============================================================================
|
|
|
|
EntityTargetBehaviorD6E6:
|
|
lda $1A
|
|
sec
|
|
sbc $2A
|
|
bcs @D6F4
|
|
|
|
sta $05
|
|
|
|
lda #$00
|
|
sec
|
|
sbc $05
|
|
|
|
@D6F4:
|
|
cmp #$20
|
|
bcs $D73B
|
|
|
|
lda $1C
|
|
sec
|
|
sbc $2C
|
|
bcs @D703
|
|
|
|
sta $05
|
|
|
|
lda #$00
|
|
sec
|
|
sbc $05
|
|
|
|
@D703:
|
|
cmp #$20
|
|
bcs $D73B
|
|
|
|
lda $4B
|
|
sta $05
|
|
|
|
lda #$05
|
|
sta $06
|
|
|
|
|
|
@D712:
|
|
dec $06
|
|
bne @D71A
|
|
|
|
lda #$02
|
|
bne @D736
|
|
|
|
|
|
@D71A:
|
|
inc $05
|
|
|
|
lda $05
|
|
and #$03
|
|
tay
|
|
|
|
lda ($00),y
|
|
and #$F8
|
|
bne @D712
|
|
|
|
lda $05
|
|
clc
|
|
adc #$02
|
|
and #$03
|
|
cmp $B9,x
|
|
beq @D712
|
|
|
|
lda $05
|
|
and #$03
|
|
|
|
|
|
@D736:
|
|
sta $B9,x
|
|
|
|
jmp EntitySecondaryApplyResult
|
|
|
|
;==============================================================================
|
|
; $D73B-$D777: Entity Target Calculation Handlers
|
|
;
|
|
; Local:
|
|
; Three handlers selected by EntityTargetBehaviorTable.
|
|
;
|
|
; $D73B:
|
|
; Uses the current $1A/$1C coordinate pair directly as the target.
|
|
;
|
|
; $D745:
|
|
; Uses $51 to select a signed coordinate offset from the table at $D75C,
|
|
; then adds that offset to $1A/$1C.
|
|
;
|
|
; $D764:
|
|
; Reflects/extrapolates the current coordinate pair relative to
|
|
; $1E/$20.
|
|
;
|
|
; All three produce the target coordinate in $CD/$CE and converge on the
|
|
; still-undecoded common processing at $D778.
|
|
;
|
|
; Global:
|
|
; Three of the four target strategies selected by
|
|
; EntityTargetBehaviorTable.
|
|
;
|
|
; Notes:
|
|
; Cross-block destination $D778 remains raw until the common handler is
|
|
; decoded separately.
|
|
;==============================================================================
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D73B: direct target
|
|
;------------------------------------------------------------------------------
|
|
|
|
EntityTargetBehaviorD73B:
|
|
lda $1A
|
|
sta $CD
|
|
|
|
lda $1C
|
|
sta $CE
|
|
|
|
bne $D778
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D745: direction-offset target
|
|
;------------------------------------------------------------------------------
|
|
|
|
EntityTargetBehaviorD745:
|
|
lda $51
|
|
asl
|
|
tay
|
|
|
|
lda EntityDirectionTargetOffsets,y
|
|
clc
|
|
adc $1A
|
|
sta $CD
|
|
|
|
lda EntityDirectionTargetOffsets+1,y
|
|
clc
|
|
adc $1C
|
|
sta $CE
|
|
|
|
jmp $D778
|
|
|
|
;==============================================================================
|
|
; $D75C-$D763: Direction Target Offset Table
|
|
;
|
|
; Local:
|
|
; Four signed coordinate offset pairs selected by ($51 * 2).
|
|
;
|
|
; As signed 8-bit values:
|
|
;
|
|
; 0 -> ( 0, -24 )
|
|
; 1 -> (-24, 0 )
|
|
; 2 -> ( 0, +24 )
|
|
; 3 -> (+24, 0 )
|
|
;
|
|
; Global:
|
|
; Used by EntityTargetBehaviorD745 to project a target position in the
|
|
; entity's current direction.
|
|
;==============================================================================
|
|
|
|
EntityDirectionTargetOffsets:
|
|
.byte $00,$E8
|
|
.byte $E8,$00
|
|
.byte $00,$18
|
|
.byte $18,$00
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D764: relative/reflected target
|
|
;
|
|
; Computes:
|
|
;
|
|
; $CD = $1A + ($1A - $1E)
|
|
; $CE = $1C + ($1C - $20)
|
|
;
|
|
; which algebraically corresponds to:
|
|
;
|
|
; $CD = 2*$1A - $1E
|
|
; $CE = 2*$1C - $20
|
|
;
|
|
; using 8-bit arithmetic.
|
|
;------------------------------------------------------------------------------
|
|
|
|
EntityTargetBehaviorD764:
|
|
lda $1A
|
|
sec
|
|
sbc $1E
|
|
|
|
clc
|
|
adc $1A
|
|
sta $CD
|
|
|
|
lda $1C
|
|
sec
|
|
sbc $20
|
|
|
|
clc
|
|
adc $1C
|
|
sta $CE
|
|
|
|
;==============================================================================
|
|
; $D778-$D79F: Common Entity Target Processing
|
|
;
|
|
; Local:
|
|
; Shared continuation used after an entity target coordinate has been
|
|
; calculated in $CD/$CE.
|
|
;
|
|
; Uses the entity primary state at $B8,X, minus $04, as a byte offset into
|
|
; a packed pointer table beginning at $D881. The selected pointer is stored
|
|
; in $0A/$0B and passed to BuildLegalDirectionList.
|
|
;
|
|
; The results returned in $0C/$0D determine the entity's next secondary
|
|
; state at $B9,X:
|
|
;
|
|
; $0C == $FF
|
|
; -> force state $02
|
|
;
|
|
; $0C != $FF and $0D == $FF
|
|
; -> store $0C into $B9,X and return
|
|
;
|
|
; $0C != $FF and $0D != $FF
|
|
; -> continue at $D7A0 for additional selection logic
|
|
;
|
|
; Global:
|
|
; Common target-evaluation stage reached by the entity target strategies
|
|
; at $D73B, $D745 and $D764, as well as fixed-target paths from earlier
|
|
; entity processing.
|
|
;
|
|
; Notes:
|
|
; $D881 remains undecoded and is therefore referenced by address.
|
|
;
|
|
; The branch to $D7A0 is intentionally kept raw because $D7A0 belongs to
|
|
; the next block and is an explicit continuation rather than an RTS.
|
|
;==============================================================================
|
|
|
|
EntityTargetCommon:
|
|
lda $B8,x
|
|
sec
|
|
sbc #$04
|
|
tay
|
|
|
|
lda $D881,y
|
|
sta $0A
|
|
|
|
lda $D882,y
|
|
sta $0B
|
|
|
|
jsr BuildLegalDirectionList
|
|
|
|
lda $0C
|
|
cmp #$FF
|
|
bne @D795
|
|
|
|
lda #$02
|
|
bne @D79D
|
|
|
|
|
|
@D795:
|
|
lda $0D
|
|
cmp #$FF
|
|
bne $D7A0
|
|
|
|
lda $0C
|
|
|
|
|
|
@D79D:
|
|
sta $B9,x
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $D7A0-$D820: Select Entity Direction Toward Target
|
|
;
|
|
; Local:
|
|
; Entered from EntityTargetCommon when both $0C and $0D returned by
|
|
; BuildLegalDirectionList are valid.
|
|
;
|
|
; Computes absolute coordinate distances between target $CD/$CE and the
|
|
; current entity coordinates addressed through $02/$03.
|
|
;
|
|
; $05 accumulates direction-order information according to:
|
|
; - sign of the horizontal/vertical difference
|
|
; - which axis has the larger absolute distance
|
|
;
|
|
; The result is used to index a direction-priority table at $D871.
|
|
; Candidate directions are compared against the four values at $0C-$0F.
|
|
; When a candidate matches, execution branches back to the common direction
|
|
; store at $D79D.
|
|
;
|
|
; If the preferred candidates fail, the routine tests directions adjacent
|
|
; to the current secondary state $B9,X before eventually returning.
|
|
;
|
|
; Global:
|
|
; Alternate continuation of EntityTargetCommon. Selects the next movement
|
|
; direction for an entity based on its current position and target.
|
|
;
|
|
; Notes:
|
|
; $05 is a temporary direction-priority index.
|
|
; $06/$07 hold absolute coordinate differences.
|
|
; $08 is temporary storage during absolute-value calculations.
|
|
;
|
|
; $D871 is not decoded yet and remains a raw table reference.
|
|
;==============================================================================
|
|
|
|
SelectEntityDirectionTowardTarget:
|
|
ldy #$00
|
|
sty $05
|
|
|
|
lda $CD
|
|
sec
|
|
sbc ($02),y
|
|
bcs @D7B9
|
|
|
|
sta $08
|
|
|
|
lda #$00
|
|
sec
|
|
sbc $08
|
|
|
|
inc $05
|
|
inc $05
|
|
inc $05
|
|
inc $05
|
|
|
|
@D7B9:
|
|
sta $06
|
|
|
|
lda $CE
|
|
|
|
ldy #$02
|
|
|
|
sec
|
|
sbc ($02),y
|
|
bcs @D7D2
|
|
|
|
sta $08
|
|
|
|
lda #$00
|
|
sec
|
|
sbc $08
|
|
|
|
inc $05
|
|
inc $05
|
|
|
|
@D7D2:
|
|
sta $07
|
|
|
|
lda $06
|
|
cmp $07
|
|
bcs @D7DB
|
|
|
|
inc $05
|
|
|
|
@D7DB:
|
|
lda $05
|
|
asl
|
|
sta $05
|
|
|
|
lda #$02
|
|
sta $06
|
|
|
|
|
|
@D7E3:
|
|
ldy $05
|
|
|
|
lda $D871,y
|
|
|
|
ldy #$00
|
|
|
|
@D7EA:
|
|
cmp $000C,y
|
|
beq $D79D
|
|
|
|
iny
|
|
cpy #$04
|
|
bne @D7EA
|
|
|
|
inc $05
|
|
|
|
dec $06
|
|
bne @D7E3
|
|
|
|
lda $B9,x
|
|
sec
|
|
sbc #$01
|
|
and #$03
|
|
|
|
ldy #$00
|
|
|
|
@D802:
|
|
cmp $000C,y
|
|
beq $D79D
|
|
|
|
iny
|
|
cpy #$04
|
|
bne @D802
|
|
|
|
lda $B9,x
|
|
clc
|
|
adc #$01
|
|
and #$03
|
|
|
|
ldy #$00
|
|
|
|
@D814:
|
|
cmp $000C,y
|
|
beq $D79D
|
|
|
|
iny
|
|
cpy #$04
|
|
bne @D814
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $D821-$D870: Select Entity Movement Parameters
|
|
;
|
|
; Local:
|
|
; Chooses the two-byte movement/step value stored at:
|
|
;
|
|
; $C2,X
|
|
; $C3,X
|
|
;
|
|
; for the current gameplay entity.
|
|
;
|
|
; Selection depends on:
|
|
;
|
|
; - primary entity state $B8,X
|
|
; - current entity coordinates through ($02)
|
|
; - entity bitmask $04 against $88
|
|
; - whether X is zero or identifies another entity
|
|
;
|
|
; Parameter pairs are copied from several global values:
|
|
;
|
|
; $B3/$B4
|
|
; $CA/$CB
|
|
; $AF/$B0
|
|
; $B1/$B2
|
|
;
|
|
; Primary state $06 instead installs the fixed pair:
|
|
;
|
|
; $00,$02
|
|
;
|
|
; Global:
|
|
; Called before the $B9,X secondary-state dispatcher at $D5A1. This chooses
|
|
; the movement increment used by the entity movement arithmetic.
|
|
;
|
|
; Notes:
|
|
; The coordinate pointer $02/$03 identifies the current entity's structure.
|
|
; X is the even entity slot index.
|
|
;==============================================================================
|
|
|
|
SelectEntityMovementSpeed:
|
|
lda $B8,x
|
|
cmp #$06
|
|
beq @D864
|
|
|
|
ldy #$02
|
|
|
|
lda ($02),y
|
|
cmp #$70
|
|
bne @D843
|
|
|
|
ldy #$00
|
|
|
|
lda ($02),y
|
|
cmp #$90
|
|
bcs @D83D
|
|
|
|
cmp #$30
|
|
bcs @D843
|
|
|
|
@D83D:
|
|
lda $B3
|
|
sta $C2,x
|
|
|
|
lda $B4
|
|
sta $C3,x
|
|
|
|
rts
|
|
|
|
|
|
@D843:
|
|
lda $04
|
|
and $88
|
|
bne @D85A
|
|
|
|
txa
|
|
bne @D854
|
|
|
|
lda $CA
|
|
sta $C2
|
|
|
|
lda $CB
|
|
sta $C3
|
|
|
|
rts
|
|
|
|
|
|
@D854:
|
|
lda $AF
|
|
sta $C2,x
|
|
|
|
lda $B0
|
|
sta $C3,x
|
|
|
|
rts
|
|
|
|
|
|
@D85A:
|
|
lda $B1
|
|
sta $C2,x
|
|
|
|
lda $B2
|
|
sta $C3,x
|
|
|
|
rts
|
|
|
|
|
|
@D864:
|
|
lda #$00
|
|
sta $C2,x
|
|
|
|
lda #$02
|
|
sta $C3,x
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $D871-$D880: Entity Direction Priority Table
|
|
;
|
|
; Local:
|
|
; Sixteen direction values used by SelectEntityDirectionTowardTarget.
|
|
;
|
|
; $05 is derived from:
|
|
; - the sign of each target-coordinate difference,
|
|
; - which axis has the greater absolute distance.
|
|
;
|
|
; $05 is doubled before indexing this table, and the routine may examine
|
|
; the following entry as its second preferred candidate.
|
|
;
|
|
; Global:
|
|
; Defines the preferred entity movement directions for the different
|
|
; relative target-position quadrants/axis priorities.
|
|
;
|
|
; Notes:
|
|
; Values are internal direction numbers 0-3. Concrete direction names remain
|
|
; deferred until the internal direction numbering is fully mapped.
|
|
;
|
|
; The natural layout is eight pairs of preferred directions.
|
|
;==============================================================================
|
|
|
|
EntityDirectionPriorityTable:
|
|
.byte $03,$02
|
|
.byte $02,$03
|
|
.byte $03,$00
|
|
.byte $00,$03
|
|
.byte $01,$02
|
|
.byte $02,$01
|
|
.byte $01,$00
|
|
.byte $00,$01
|
|
|
|
;==============================================================================
|
|
; $D881-$D884: Entity Path/Map Pointer Table
|
|
;
|
|
; Local:
|
|
; Two 16-bit values selected according to entity primary state:
|
|
;
|
|
; state $04 -> $0000
|
|
; state $06 -> $082C
|
|
;
|
|
; The selected value is placed in $0A/$0B and passed to the helper at
|
|
; BuildLegalDirectionList.
|
|
;
|
|
; Global:
|
|
; Supplies state-dependent path/map parameters used by EntityTargetCommon.
|
|
;
|
|
; Notes:
|
|
; Keep the entries as literal 16-bit values until BuildLegalDirectionList
|
|
; is decoded and the semantic meaning of $0A/$0B is established.
|
|
;==============================================================================
|
|
|
|
EntityPathParameterTable:
|
|
.word $0000
|
|
.word $082C
|
|
|
|
;==============================================================================
|
|
; $D885-$D8D4: Entity Primary State $02 Handler
|
|
;==============================================================================
|
|
|
|
UpdateEntityState02:
|
|
lda #$00
|
|
tay
|
|
sta $05
|
|
|
|
lda #$80
|
|
sta $06
|
|
|
|
lda ($02),y
|
|
cmp #$60
|
|
beq UpdateEntityState02SecondaryPhase
|
|
|
|
bcc @D89C
|
|
|
|
dec $05
|
|
|
|
lda #$01
|
|
bne @D89E
|
|
|
|
@D89C:
|
|
lda #$03
|
|
|
|
@D89E:
|
|
sta $B9,x
|
|
|
|
ldy #$01
|
|
|
|
lda ($02),y
|
|
clc
|
|
adc $06
|
|
sta ($02),y
|
|
|
|
ldy #$00
|
|
|
|
lda ($02),y
|
|
adc $05
|
|
sta ($02),y
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $D8B2-$D8D4: Entity State $02 Secondary Movement Phase
|
|
;==============================================================================
|
|
|
|
UpdateEntityState02SecondaryPhase:
|
|
lda #$00
|
|
sta $B9,x
|
|
|
|
ldy #$03
|
|
|
|
lda ($02),y
|
|
sec
|
|
sbc #$80
|
|
sta ($02),y
|
|
|
|
ldy #$02
|
|
|
|
lda ($02),y
|
|
sbc #$00
|
|
sta ($02),y
|
|
|
|
cmp #$58
|
|
beq @D8CC
|
|
|
|
rts
|
|
|
|
@D8CC:
|
|
lda #$01
|
|
sta $B9,x
|
|
|
|
lda #$04
|
|
sta $B8,x
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $D8D5-$D913: Entity Primary State $00 Handler
|
|
;
|
|
; Local:
|
|
; Initializes working movement values:
|
|
;
|
|
; $05 = $00
|
|
; $06 = $80
|
|
;
|
|
; Then uses the entity secondary state at $B9,X as a byte offset into a
|
|
; two-entry table at $D8EC.
|
|
;
|
|
; The selected subhandler adjusts bytes 3/2 of the current entity structure
|
|
; through $02/$03. When the resulting high byte crosses defined thresholds,
|
|
; $B9,X advances to secondary state $02 or resets to $00.
|
|
;
|
|
; Global:
|
|
; Handler selected by EntityStateTable for primary entity state $00.
|
|
;
|
|
; Notes:
|
|
; Unlike the $D5A1 secondary dispatcher, $B9,X is already treated as a byte
|
|
; offset here. Valid values are $00 and $02.
|
|
;==============================================================================
|
|
|
|
EntityState00:
|
|
lda #$00
|
|
sta $05
|
|
|
|
lda #$80
|
|
sta $06
|
|
|
|
ldy $B9,x
|
|
|
|
lda EntityState00SubstateTable,y
|
|
sta $10
|
|
|
|
lda EntityState00SubstateTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
|
|
;==============================================================================
|
|
; $D8EC-$D8EF: Entity State $00 Secondary Table
|
|
;==============================================================================
|
|
|
|
EntityState00SubstateTable:
|
|
.word UpdateEntityState00MovingNegative
|
|
.word UpdateEntityState00MovingPositive
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D8F0: secondary state $00
|
|
;------------------------------------------------------------------------------
|
|
|
|
UpdateEntityState00MovingNegative:
|
|
dec $05
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D8F2: secondary state $02
|
|
;------------------------------------------------------------------------------
|
|
|
|
UpdateEntityState00MovingPositive:
|
|
ldy #$03
|
|
|
|
lda ($02),y
|
|
clc
|
|
adc $06
|
|
sta ($02),y
|
|
|
|
ldy #$02
|
|
|
|
lda ($02),y
|
|
adc $05
|
|
sta ($02),y
|
|
|
|
cmp #$69
|
|
bcs @D90B
|
|
|
|
lda #$02
|
|
bne @D911
|
|
|
|
|
|
@D90B:
|
|
cmp #$70
|
|
bcc @D913
|
|
|
|
lda #$00
|
|
|
|
@D911:
|
|
sta $B9,x
|
|
|
|
@D913:
|
|
rts
|
|
;==============================================================================
|
|
; $D914-$D943: Update Four Gameplay Entity States
|
|
;
|
|
; Local:
|
|
; Iterates the four gameplay entity slots using even X offsets:
|
|
;
|
|
; $00,$02,$04,$06
|
|
;
|
|
; Initializes the same per-entity working values used by the other entity
|
|
; update coordinator:
|
|
;
|
|
; $00 = $2F
|
|
; $01 = $02
|
|
; $02 = $1E
|
|
; $03 = $00
|
|
; $04 = $01
|
|
;
|
|
; Calls the entity dispatcher at $D944 for each slot.
|
|
;
|
|
; After each call:
|
|
;
|
|
; $00 += 4
|
|
; $02 += 4
|
|
; $04 <<= 1
|
|
; X += 2
|
|
;
|
|
; Global:
|
|
; Called from GameModeState06 during its per-frame update sequence.
|
|
; Processes a second entity-state machine for all four gameplay entities.
|
|
;
|
|
; Notes:
|
|
; The layout closely parallels UpdateGameplayEntities at $D557, but uses
|
|
; a different dispatcher and therefore a different behavior set.
|
|
;==============================================================================
|
|
|
|
UpdateEntityMovementStates:
|
|
ldx #$00
|
|
|
|
lda #$2F
|
|
sta $00
|
|
|
|
lda #$02
|
|
sta $01
|
|
|
|
lda #$1E
|
|
sta $02
|
|
|
|
lda #$00
|
|
sta $03
|
|
|
|
lda #$01
|
|
sta $04
|
|
|
|
@D92A:
|
|
jsr $D944
|
|
|
|
lda $00
|
|
clc
|
|
adc #$04
|
|
sta $00
|
|
|
|
lda $02
|
|
clc
|
|
adc #$04
|
|
sta $02
|
|
|
|
asl $04
|
|
|
|
inx
|
|
inx
|
|
|
|
cpx #$08
|
|
bne @D92A
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $D944-$D952: Gameplay Entity Transition-State Dispatcher
|
|
;
|
|
; Local:
|
|
; Reads the current entity primary state from $B8,X and uses it directly as
|
|
; a byte offset into the packed pointer table at $D953.
|
|
;
|
|
; The selected 16-bit address is stored in $10/$11 and execution transfers
|
|
; to it through an indirect JMP.
|
|
;
|
|
; Global:
|
|
; Called by UpdateEntityMovementStates once for each of the four
|
|
; gameplay entity slots.
|
|
;
|
|
; Notes:
|
|
; X identifies the entity using even offsets:
|
|
;
|
|
; $00,$02,$04,$06
|
|
;
|
|
; $B8,X is itself an even byte offset into the pointer table:
|
|
;
|
|
; $00,$02,$04,$06,$08
|
|
;==============================================================================
|
|
|
|
DispatchEntityMovementState:
|
|
ldy $B8,x
|
|
|
|
lda EntityMovementStateHandlerTable,y
|
|
sta $10
|
|
|
|
lda EntityMovementStateHandlerTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
|
|
;==============================================================================
|
|
; $D953-$D95C: Gameplay Entity Transition-State Table
|
|
;
|
|
; Local:
|
|
; Five 16-bit handlers indexed directly by the entity primary state stored
|
|
; in $B8,X.
|
|
;
|
|
; Global:
|
|
; Defines the per-entity behavior used by
|
|
; DispatchEntityMovementState.
|
|
;
|
|
; Notes:
|
|
; States $00, $02, $04 and $08 all use the same handler at $D95D.
|
|
;
|
|
; State $06 reuses DispatchEntitySecondaryState at $D5A1.
|
|
;==============================================================================
|
|
|
|
EntityMovementStateHandlerTable:
|
|
.word EntityMovementStateNoOp ; state $00
|
|
.word EntityMovementStateNoOp ; state $02
|
|
.word EntityMovementStateNoOp ; state $04
|
|
.word DispatchEntitySecondaryState ; state $06
|
|
.word EntityMovementStateNoOp ; state $08
|
|
|
|
;==============================================================================
|
|
; $D95D: No-Op Entity Transition Handler
|
|
;
|
|
; Local:
|
|
; Returns immediately.
|
|
;
|
|
; Global:
|
|
; Used by EntityMovementStateHandlerTable for primary entity states
|
|
; $00, $02, $04 and $08.
|
|
;==============================================================================
|
|
EntityMovementStateNoOp:
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $D95E-$D979: Check Entity Transition State
|
|
;
|
|
; Local:
|
|
; Scans the four primary entity-state entries at:
|
|
;
|
|
; $B8,$BA,$BC,$BE
|
|
;
|
|
; If any entity is in primary state $06, stores the current A value
|
|
; ($06 from the CMP) into $0608 and returns.
|
|
;
|
|
; If no entity is in state $06, tests $88. When $88 is nonzero, stores that
|
|
; value into $0609 before returning.
|
|
;
|
|
; Global:
|
|
; Called during normal gameplay processing. Exports entity/state conditions
|
|
; to RAM $0608/$0609 for use by other gameplay systems.
|
|
;
|
|
; Notes:
|
|
; $00 is initialized but not subsequently used inside this routine in the
|
|
; decoded path. Preserve the write because another overlapping entry or
|
|
; external expectation may depend on it.
|
|
;==============================================================================
|
|
|
|
UpdateEntityStatusFlags:
|
|
ldx #$00
|
|
stx $00
|
|
|
|
@D962:
|
|
lda $B8,x
|
|
cmp #$06
|
|
bne @D96C
|
|
|
|
sta $0608
|
|
rts
|
|
|
|
@D96C:
|
|
inx
|
|
inx
|
|
|
|
cpx #$08
|
|
bne @D962
|
|
|
|
lda $88
|
|
beq UpdatePlayerVerticalRegionFlag
|
|
|
|
sta $0609
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $D97A-$D98D: Update Gameplay Range Flag
|
|
;==============================================================================
|
|
UpdatePlayerVerticalRegionFlag:
|
|
ldy #$00
|
|
|
|
lda $6A
|
|
cmp #$88
|
|
bcs @D988
|
|
|
|
iny
|
|
|
|
cmp #$42
|
|
bcs @D988
|
|
|
|
iny
|
|
|
|
@D988:
|
|
lda #$01
|
|
sta $060A,y
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $D98E-$D9C5: Update Direction-Dependent Gameplay Value
|
|
;
|
|
; Local:
|
|
; Builds a base value from the current direction $51, then selects an
|
|
; additional offset based on coordinate alignment, tile state, and $B7.
|
|
;
|
|
; The resulting value is stored in $32.
|
|
;
|
|
; Notes:
|
|
; Address-derived labels preserve the original compact control flow.
|
|
;==============================================================================
|
|
|
|
UpdatePlayerDirectionAnimation:
|
|
lda $51
|
|
asl
|
|
clc
|
|
adc #$02
|
|
sta $00
|
|
|
|
lda $1A
|
|
ora $1C
|
|
and #$07
|
|
bne @D9AE
|
|
|
|
ldy $51
|
|
|
|
lda $022B,y
|
|
and #$F0
|
|
beq @D9AE
|
|
|
|
lda $B7
|
|
and #$03
|
|
jmp @D9B2
|
|
|
|
|
|
@D9AE:
|
|
inc $B7
|
|
|
|
lda $B7
|
|
|
|
@D9B2:
|
|
and #$07
|
|
cmp #$06
|
|
bcc @D9BC
|
|
|
|
lda #$01
|
|
bne @D9C3
|
|
|
|
|
|
@D9BC:
|
|
tay
|
|
|
|
lda PlayerDirectionAnimationOffsets,y
|
|
clc
|
|
adc $00
|
|
|
|
|
|
@D9C3:
|
|
sta $32
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $D9C6-$D9CB: Direction-Value Offset Table
|
|
;
|
|
; Local:
|
|
; Six values indexed by $B7 & $07 when that result is less than six.
|
|
;
|
|
; Global:
|
|
; Provides the small offset added to the direction-derived base before the
|
|
; result is stored in $32.
|
|
;==============================================================================
|
|
|
|
PlayerDirectionAnimationOffsets:
|
|
.byte $00,$00,$00,$01,$01,$00
|
|
|
|
;==============================================================================
|
|
; $D9CC-$D9EA: Update Four Entity Display/State Values
|
|
;
|
|
; Local:
|
|
; Initializes:
|
|
;
|
|
; X = $00
|
|
; $00 = $00 or $01 depending on frame-counter bit 3
|
|
; $01 = $01
|
|
;
|
|
; Then iterates the four entity slots:
|
|
;
|
|
; X = $00,$02,$04,$06
|
|
;
|
|
; For each entity:
|
|
; - Calls the dispatcher at $D9EB.
|
|
; - Shifts $01 left once, producing per-entity masks:
|
|
;
|
|
; $01,$02,$04,$08
|
|
;
|
|
; - Advances X by two.
|
|
;
|
|
; Global:
|
|
; Called from several game-mode states and during normal gameplay. Provides
|
|
; per-frame updates for all four gameplay entities, with an alternating
|
|
; phase selected from frame-counter bit 3.
|
|
;
|
|
; Notes:
|
|
; $4B is the NMI-driven frame counter.
|
|
; $00 is a two-phase animation/control value.
|
|
; $01 is the current entity bitmask.
|
|
;==============================================================================
|
|
|
|
UpdateEntitySpriteStates:
|
|
lda #$00
|
|
tax
|
|
sta $00
|
|
|
|
lda $4B
|
|
and #$08
|
|
beq @D9DC
|
|
|
|
lda #$01
|
|
sta $00
|
|
|
|
|
|
@D9DC:
|
|
lda #$01
|
|
sta $01
|
|
|
|
|
|
@D9E0:
|
|
jsr $D9EB
|
|
|
|
asl $01
|
|
|
|
inx
|
|
inx
|
|
|
|
cpx #$08
|
|
bne @D9E0
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $D9EB-$D9F9: Per-Entity Display/State Dispatcher
|
|
;==============================================================================
|
|
|
|
DispatchEntitySpriteState:
|
|
ldy $B8,x
|
|
|
|
lda EntitySpriteStateHandlerTable,y
|
|
sta $10
|
|
|
|
lda EntitySpriteStateHandlerTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
|
|
;==============================================================================
|
|
; $D9FA-$DA03: Entity Display/State Table
|
|
;==============================================================================
|
|
EntitySpriteStateHandlerTable:
|
|
.word UpdateNormalEntitySprite ; state $00
|
|
.word UpdateNormalEntitySprite ; state $02
|
|
.word UpdateNormalEntitySprite ; state $04
|
|
.word UpdateSpecialEntitySprite ; state $06
|
|
.word $D9EA ; state $08 -> shared RTS
|
|
|
|
;==============================================================================
|
|
; $DA04-$DA3F: Entity Display/State Value Handlers
|
|
;
|
|
; Local:
|
|
; Three entry points used by EntitySpriteStateHandlerTable:
|
|
;
|
|
; $DA21 primary states $00/$02/$04
|
|
; $DA2D primary state $06
|
|
;
|
|
; $DA04 is shared calculation code entered by those handlers.
|
|
;
|
|
; Each path computes a value from the entity secondary state $B9,X, combines
|
|
; it with a base value, and stores the final result into one of $33-$36
|
|
; according to the current entity index X.
|
|
;
|
|
; Global:
|
|
; Produces per-entity display/state values during UpdateEntitySpriteStates.
|
|
;
|
|
; Notes:
|
|
; X is an even entity index ($00,$02,$04,$06). TXA/LSR converts this into
|
|
; the ordinal entity index 0-3 for the final store at $33,Y.
|
|
;==============================================================================
|
|
|
|
;==============================================================================
|
|
; $DA04-$DA3F: Entity Display/State Value Handlers
|
|
;
|
|
; Local:
|
|
; Shared calculations used by the per-entity display/state dispatcher.
|
|
;
|
|
; Global:
|
|
; UpdateNormalEntitySprite handles primary states $00/$02/$04.
|
|
; UpdateSpecialEntitySprite handles primary state $06.
|
|
;
|
|
; Notes:
|
|
; Non-local labels are intentional because multiple handler entry points
|
|
; branch backward into shared code.
|
|
;==============================================================================
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DA04
|
|
;------------------------------------------------------------------------------
|
|
|
|
CalculateEntitySpriteValue:
|
|
lda $B9,x
|
|
sta $03
|
|
|
|
lda #$0A
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DA0A
|
|
;------------------------------------------------------------------------------
|
|
|
|
CalculateEntitySpriteValueLoop:
|
|
dec $03
|
|
bmi AddEntitySpriteBase
|
|
|
|
clc
|
|
adc #$02
|
|
bne CalculateEntitySpriteValueLoop
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DA13
|
|
;------------------------------------------------------------------------------
|
|
|
|
AddEntitySpriteBase:
|
|
clc
|
|
adc $00
|
|
sta $02
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DA18
|
|
;------------------------------------------------------------------------------
|
|
|
|
StoreEntitySpriteValue:
|
|
txa
|
|
lsr
|
|
tay
|
|
|
|
lda $02
|
|
sta $0033,y
|
|
|
|
rts
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DA21
|
|
; Primary entity states $00/$02/$04.
|
|
;------------------------------------------------------------------------------
|
|
|
|
UpdateNormalEntitySprite:
|
|
lda $01
|
|
and $88
|
|
beq CalculateEntitySpriteValue
|
|
|
|
lda #$1E
|
|
sta $02
|
|
|
|
bne AddEntitySpriteBase
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DA2D
|
|
; Primary entity state $06.
|
|
;------------------------------------------------------------------------------
|
|
|
|
UpdateSpecialEntitySprite:
|
|
lda $B9,x
|
|
sta $03
|
|
|
|
lda #$20
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DA33
|
|
;------------------------------------------------------------------------------
|
|
|
|
UpdateSpecialEntitySpriteLoop:
|
|
dec $03
|
|
bmi UpdateSpecialEntitySpriteDone
|
|
|
|
clc
|
|
adc #$01
|
|
bne UpdateSpecialEntitySpriteLoop
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DA3C
|
|
;------------------------------------------------------------------------------
|
|
|
|
UpdateSpecialEntitySpriteDone:
|
|
sta $02
|
|
|
|
bmi StoreEntitySpriteValue
|
|
|
|
;==============================================================================
|
|
; $DA40-$DAF0: Gameplay Entity Collision / Slot Exchange
|
|
;
|
|
; Local:
|
|
; Copies $24 bytes from zero-page $1A-$3D to RAM $0274-$0297.
|
|
;
|
|
; Then initializes an indirect pointer to $0284 and scans entity structures
|
|
; while testing them against the primary coordinate pair at $0274/$0276.
|
|
;
|
|
; For each enabled entity, computes absolute coordinate differences. If both
|
|
; axes are within $19 and their combined distance is below $10, exchanges
|
|
; coordinate and associated state fields between the primary slot and the
|
|
; selected entity slot.
|
|
;
|
|
; If no qualifying overlap is found, advances the structure pointer backward
|
|
; by four bytes, shifts the per-entity mask, and continues.
|
|
;
|
|
; Global:
|
|
; Called in several game-mode states and during normal gameplay. Maintains
|
|
; the mirrored gameplay/object state in $0274+ and handles close-overlap
|
|
; exchanges between entity slots.
|
|
;
|
|
; Notes:
|
|
; $00/$01 form a temporary pointer, initially $0284.
|
|
; $02 counts entity slots.
|
|
; $03 is a bitmask, initially $08.
|
|
; $04-$06 are temporary coordinate/state values during a swap.
|
|
;
|
|
; $DAF1 is a separate routine and is not included in this block.
|
|
;==============================================================================
|
|
|
|
CheckEntityCollisions:
|
|
ldx #$23
|
|
|
|
@CopyWorkingState:
|
|
lda $1A,x
|
|
sta $0274,x
|
|
|
|
dex
|
|
bpl @CopyWorkingState
|
|
|
|
lda #$84
|
|
sta $00
|
|
|
|
lda #$02
|
|
sta $01
|
|
|
|
lda #$08
|
|
sta $03
|
|
|
|
lda #$03
|
|
sta $02
|
|
|
|
|
|
@CheckNextEntity:
|
|
lda $03
|
|
and $88
|
|
bne @AdvanceEntity
|
|
|
|
ldy #$00
|
|
|
|
lda $0274
|
|
cmp ($00),y
|
|
bcs @FirstAxisReverse
|
|
|
|
lda ($00),y
|
|
sec
|
|
sbc $0274
|
|
bcs @CheckFirstAxis
|
|
|
|
@FirstAxisReverse:
|
|
sbc ($00),y
|
|
|
|
@CheckFirstAxis:
|
|
cmp #$19
|
|
bcs @AdvanceEntity
|
|
|
|
sta $04
|
|
|
|
ldy #$02
|
|
|
|
lda $0276
|
|
cmp ($00),y
|
|
bcs @SecondAxisReverse
|
|
|
|
lda ($00),y
|
|
sec
|
|
sbc $0276
|
|
bcs @CheckSecondAxis
|
|
|
|
@SecondAxisReverse:
|
|
sbc ($00),y
|
|
|
|
@CheckSecondAxis:
|
|
cmp #$19
|
|
bcs @AdvanceEntity
|
|
|
|
adc $04
|
|
cmp #$10
|
|
bcs @AdvanceEntity
|
|
|
|
; Save the primary slot coordinates/state.
|
|
lda $0274
|
|
sta $03
|
|
|
|
lda $0276
|
|
sta $04
|
|
|
|
lda $028C
|
|
sta $05
|
|
|
|
lda $0292
|
|
sta $06
|
|
|
|
; Copy selected entity coordinates into the primary slot.
|
|
ldy #$00
|
|
lda ($00),y
|
|
sta $0274
|
|
|
|
lda $03
|
|
sta ($00),y
|
|
|
|
ldy #$02
|
|
lda ($00),y
|
|
sta $0276
|
|
|
|
lda $04
|
|
sta ($00),y
|
|
|
|
; Exchange the parallel status values.
|
|
ldx $02
|
|
|
|
lda $028D,x
|
|
sta $028C
|
|
|
|
lda $05
|
|
sta $028D,x
|
|
|
|
lda $0293,x
|
|
sta $0292
|
|
|
|
lda $06
|
|
sta $0293,x
|
|
|
|
jmp $DAEB
|
|
|
|
|
|
@AdvanceEntity:
|
|
lda $00
|
|
sec
|
|
sbc #$04
|
|
sta $00
|
|
|
|
lsr $03
|
|
|
|
dec $02
|
|
bmi @NoCollision
|
|
|
|
jmp @CheckNextEntity
|
|
|
|
|
|
@NoCollision:
|
|
jsr $E1DA
|
|
|
|
jmp $DAF1
|
|
|
|
;==============================================================================
|
|
; $DAF1-$DBEE: Rebuild Gameplay Entity Render Data
|
|
;
|
|
; Local:
|
|
; Builds four-byte render/object records in page $07 from mirrored gameplay
|
|
; state beginning at $0274.
|
|
;
|
|
; Working variables:
|
|
;
|
|
; $00/$01 = source pointer, initially $0274
|
|
; $02/$03 = destination pointer, initially $0700
|
|
; $04 = source-group index
|
|
; $05 = record/lookup index
|
|
; $06 = temporary lookup index
|
|
;
|
|
; X advances through even entity offsets $00,$02,$04,$06.
|
|
;
|
|
; Encoded state values at $028C+ determine which lookup-table path is used
|
|
; to construct bytes 1 and 2 of each four-byte output record.
|
|
;
|
|
; Global:
|
|
; Called by several gameplay paths to rebuild the page-$07 representation
|
|
; used by the rendering/object pipeline.
|
|
;
|
|
; Notes:
|
|
; Several ROM tables referenced here remain undecoded:
|
|
;
|
|
; $DBEE
|
|
; $DCEE
|
|
; $DD22
|
|
; EntitySpriteAttributeTable0
|
|
; EntitySpriteCoordinateOffsets
|
|
; $DE57
|
|
;
|
|
; $DBEE is particularly interesting because it is also the RTS terminating
|
|
; this routine. The ROM intentionally uses that address as both executable
|
|
; code and the base of a later indexed lookup.
|
|
;==============================================================================
|
|
BuildEntitySpriteBuffer:
|
|
lda #$74
|
|
sta $00
|
|
|
|
lda #$02
|
|
sta $01
|
|
|
|
lda #$00
|
|
sta $02
|
|
|
|
lda #$07
|
|
sta $03
|
|
|
|
lda #$00
|
|
sta $04
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DB05
|
|
; Start/restart one source group.
|
|
;------------------------------------------------------------------------------
|
|
|
|
BuildSpriteBufferNextGroup:
|
|
lda #$00
|
|
sta $05
|
|
|
|
tax
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DB0A
|
|
; Build one four-byte render record.
|
|
;------------------------------------------------------------------------------
|
|
|
|
BuildSpriteBufferNextSprite:
|
|
ldy #$02
|
|
|
|
lda ($00),y
|
|
bne AdjustSpriteY
|
|
|
|
lda #$FF
|
|
bne StoreSpriteY
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DB14
|
|
;------------------------------------------------------------------------------
|
|
|
|
AdjustSpriteY:
|
|
clc
|
|
adc EntitySpriteCoordinateOffsets,x
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DB18
|
|
;------------------------------------------------------------------------------
|
|
|
|
StoreSpriteY:
|
|
ldy #$00
|
|
sta ($02),y
|
|
|
|
ldy $04
|
|
|
|
lda $028C,y
|
|
asl
|
|
rol
|
|
rol
|
|
and #$03
|
|
|
|
beq BuildSpriteClass0
|
|
|
|
cmp #$02
|
|
beq BuildSpriteClass2
|
|
|
|
bcc BuildSpriteClass1
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DB2E
|
|
; Status-class path.
|
|
;------------------------------------------------------------------------------
|
|
|
|
lda $028C,y
|
|
asl
|
|
asl
|
|
clc
|
|
adc $05
|
|
tay
|
|
|
|
sta $06
|
|
|
|
lda $DD22,y
|
|
|
|
ldy #$01
|
|
sta ($02),y
|
|
|
|
ldy $04
|
|
lda $0292,y
|
|
|
|
ldy $06
|
|
ora EntitySpriteCoordinateOffsets,y
|
|
|
|
ldy #$02
|
|
sta ($02),y
|
|
|
|
jmp BuildSpriteX
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DB51
|
|
;------------------------------------------------------------------------------
|
|
|
|
BuildSpriteClass0:
|
|
lda $028C,y
|
|
asl
|
|
asl
|
|
clc
|
|
adc $05
|
|
tay
|
|
|
|
sta $06
|
|
|
|
lda $DBEE,y
|
|
|
|
ldy #$01
|
|
sta ($02),y
|
|
|
|
ldy $04
|
|
lda $0292,y
|
|
|
|
ldy $06
|
|
ora $DD22,y
|
|
|
|
ldy #$02
|
|
sta ($02),y
|
|
|
|
jmp BuildSpriteX
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DB74
|
|
;------------------------------------------------------------------------------
|
|
|
|
BuildSpriteClass1:
|
|
lda $028C,y
|
|
asl
|
|
asl
|
|
clc
|
|
adc $05
|
|
tay
|
|
|
|
sta $06
|
|
|
|
lda $DCEE,y
|
|
|
|
ldy #$01
|
|
sta ($02),y
|
|
|
|
ldy $04
|
|
lda $0292,y
|
|
|
|
ldy $06
|
|
ora $DE22,y
|
|
|
|
ldy #$02
|
|
sta ($02),y
|
|
|
|
jmp BuildSpriteX
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DB97
|
|
;------------------------------------------------------------------------------
|
|
|
|
BuildSpriteClass2:
|
|
lda $028C,y
|
|
asl
|
|
asl
|
|
clc
|
|
adc $05
|
|
tay
|
|
|
|
sta $06
|
|
|
|
lda $DD22,y
|
|
|
|
ldy #$01
|
|
sta ($02),y
|
|
|
|
ldy $04
|
|
lda $0292,y
|
|
|
|
ldy $06
|
|
ora EntitySpriteCoordinateOffsets,y
|
|
|
|
ldy #$02
|
|
sta ($02),y
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DBB7
|
|
; Construct byte 3 of the render record.
|
|
;------------------------------------------------------------------------------
|
|
|
|
BuildSpriteX:
|
|
ldy #$00
|
|
|
|
lda ($00),y
|
|
bne AdjustSpriteX
|
|
|
|
lda #$FF
|
|
bne StoreSpriteX
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DBC0
|
|
;------------------------------------------------------------------------------
|
|
|
|
AdjustSpriteX:
|
|
clc
|
|
adc EntitySpriteCoordinateOffsets+1,x
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DBC4
|
|
;------------------------------------------------------------------------------
|
|
|
|
StoreSpriteX:
|
|
ldy #$03
|
|
sta ($02),y
|
|
|
|
; Advance destination by one 4-byte record.
|
|
lda $02
|
|
clc
|
|
adc #$04
|
|
sta $02
|
|
|
|
inc $05
|
|
|
|
inx
|
|
inx
|
|
|
|
cpx #$08
|
|
beq BuildSpriteBufferNextSource
|
|
|
|
jmp BuildSpriteBufferNextSprite
|
|
|
|
|
|
BuildSpriteBufferNextSource:
|
|
lda $00
|
|
clc
|
|
adc #$04
|
|
sta $00
|
|
|
|
inc $04
|
|
|
|
lda $04
|
|
cmp #$06
|
|
beq BuildSpriteBufferDone
|
|
|
|
jmp BuildSpriteBufferNextGroup
|
|
|
|
BuildSpriteBufferDone:
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $DBEE-$DC3F: Gameplay Entity Render Lookup Data
|
|
;
|
|
; Local:
|
|
; Lookup data used by BuildEntitySpriteBuffer.
|
|
;
|
|
; The routine constructs an index from:
|
|
;
|
|
; ($028C,Y * 4) + $05
|
|
;
|
|
; and uses that value to index this region for render-facing object data.
|
|
;
|
|
; Global:
|
|
; Supplies tile/state values used when rebuilding the four-byte page-$07
|
|
; entity records.
|
|
;
|
|
; Notes:
|
|
; The region contains strongly patterned groups of repeated values, but the
|
|
; complete set of consumers has not yet been decoded. Keep this as one
|
|
; contiguous table during the first pass rather than assigning speculative
|
|
; semantic subdivisions.
|
|
;==============================================================================
|
|
|
|
EntitySpriteTileTable0:
|
|
|
|
; $DBEE-$DBFD
|
|
.byte $4C,$4C,$4C,$4C
|
|
.byte $00,$00,$00,$00
|
|
.byte $04,$04,$03,$03
|
|
.byte $08,$08,$07,$07
|
|
|
|
; $DBFE-$DC0D
|
|
.byte $02,$01,$02,$01
|
|
.byte $06,$05,$06,$05
|
|
.byte $03,$03,$04,$04
|
|
.byte $07,$07,$08,$08
|
|
|
|
; $DC0E-$DC1D
|
|
.byte $01,$02,$01,$02
|
|
.byte $05,$06,$05,$06
|
|
.byte $18,$18,$19,$19
|
|
.byte $18,$18,$1A,$1A
|
|
|
|
; $DC1E-$DC2D
|
|
.byte $1B,$1C,$1D,$1F
|
|
.byte $1B,$1C,$1E,$20
|
|
.byte $21,$21,$22,$22
|
|
.byte $21,$21,$23,$23
|
|
|
|
; $DC2E-$DC3D
|
|
.byte $1C,$1B,$1F,$1D
|
|
.byte $1C,$1B,$20,$1E
|
|
.byte $00,$00,$00,$00
|
|
.byte $09,$09,$0A,$0A
|
|
|
|
; $DC3E-$DC3F
|
|
.byte $0B,$0B
|
|
|
|
;==============================================================================
|
|
; $DC40-$DCED: Gameplay Entity Render Lookup Data, Continued
|
|
;
|
|
; Local:
|
|
; Additional render/tile lookup values associated with the table beginning
|
|
; at $DBEE.
|
|
;
|
|
; The data is strongly grouped into repeated pairs and four-byte patterns,
|
|
; consistent with direction/animation variants used by the four-byte entity
|
|
; render records.
|
|
;
|
|
; Global:
|
|
; Part of the graphics-facing lookup data used when gameplay state is
|
|
; converted into page-$07 render records.
|
|
;
|
|
; Notes:
|
|
; Keep these bytes as a contiguous data block for now. $DCEE is separately
|
|
; referenced by BuildEntitySpriteBuffer and therefore marks the next
|
|
; known lookup-table boundary.
|
|
;==============================================================================
|
|
EntityRenderLookupDC40:
|
|
; $DC40-$DC4F
|
|
.byte $0C,$0C,$4C,$4C
|
|
.byte $0D,$0D,$4C,$4C
|
|
.byte $0E,$0E,$4C,$4C
|
|
.byte $0F,$0F,$4C,$4C
|
|
|
|
; $DC50-$DC5F
|
|
.byte $10,$10,$4C,$4C
|
|
.byte $11,$11,$4C,$4C
|
|
.byte $12,$12,$4C,$4C
|
|
.byte $13,$13,$14,$15
|
|
|
|
; $DC60-$DC6F
|
|
.byte $16,$17,$4C,$4C
|
|
.byte $4C,$4C,$24,$24
|
|
.byte $25,$25,$24,$24
|
|
.byte $26,$26,$27,$27
|
|
|
|
; $DC70-$DC7F
|
|
.byte $4C,$4C,$28,$29
|
|
.byte $2A,$2B,$2C,$2C
|
|
.byte $2D,$2D,$29,$28
|
|
.byte $2B,$2A,$90,$91
|
|
|
|
; $DC80-$DC8F
|
|
.byte $92,$93,$94,$95
|
|
.byte $96,$97,$98,$99
|
|
.byte $9A,$9B,$9C,$9D
|
|
.byte $9E,$9F,$A0,$A1
|
|
|
|
; $DC90-$DC9F
|
|
.byte $A2,$A3,$A4,$A5
|
|
.byte $A6,$A7,$A8,$A9
|
|
.byte $AA,$AB,$AC,$AD
|
|
.byte $AE,$AF,$2E,$2F
|
|
|
|
; $DCA0-$DCAF
|
|
.byte $30,$31,$32,$2F
|
|
.byte $33,$31,$34,$2F
|
|
.byte $35,$31,$36,$2F
|
|
.byte $37,$31,$38,$2F
|
|
|
|
; $DCB0-$DCBF
|
|
.byte $39,$31,$3A,$2F
|
|
.byte $3B,$31,$3C,$2F
|
|
.byte $3D,$31,$3E,$3F
|
|
.byte $40,$41,$42,$3F
|
|
|
|
; $DCC0-$DCCF
|
|
.byte $43,$41,$44,$45
|
|
.byte $46,$47,$48,$45
|
|
.byte $49,$47,$4A,$45
|
|
.byte $4B,$47,$4D,$4E
|
|
|
|
; $DCD0-$DCDF
|
|
.byte $4F,$50,$4E,$4D
|
|
.byte $50,$4F,$4F,$50
|
|
.byte $4D,$4E,$50,$4F
|
|
.byte $4E,$4D,$4D,$4E
|
|
|
|
; $DCE0-$DCED
|
|
.byte $4F,$51,$4E,$52
|
|
.byte $53,$54,$4F,$51
|
|
.byte $4D,$4E,$53,$54
|
|
.byte $4E,$52
|
|
|
|
;==============================================================================
|
|
; $DCEE-$DD21: Gameplay Entity Render Lookup Table
|
|
;
|
|
; Local:
|
|
; Lookup values used by BuildEntitySpriteBuffer in the status-class
|
|
; path beginning at $DB74.
|
|
;
|
|
; The index is constructed from:
|
|
;
|
|
; ($028C,Y * 4) + $05
|
|
;
|
|
; and the selected byte is written as byte 1 of the generated page-$07
|
|
; render record.
|
|
;
|
|
; Global:
|
|
; Supplies graphics/tile values for one class of gameplay entity render
|
|
; states.
|
|
;
|
|
; Notes:
|
|
; The repeated $4C values and four-byte groupings strongly suggest
|
|
; animation/direction variants. Keep the table as raw values during this
|
|
; first pass.
|
|
;
|
|
; $DD22 is separately referenced by the render-data builder and therefore
|
|
; marks the next lookup-table boundary.
|
|
;==============================================================================
|
|
|
|
EntitySpriteTileTable2:
|
|
|
|
; $DCEE-$DCFD
|
|
.byte $55,$4C,$56,$4C
|
|
.byte $56,$4C,$55,$4C
|
|
.byte $4C,$57,$4C,$58
|
|
.byte $4C,$59,$4C,$5A
|
|
|
|
; $DCFE-$DD0D
|
|
.byte $4C,$5B,$4C,$5C
|
|
.byte $4C,$4C,$4C,$5D
|
|
.byte $18,$18,$19,$5E
|
|
.byte $60,$61,$19,$5E
|
|
|
|
; $DD0E-$DD1D
|
|
.byte $1B,$1C,$1D,$62
|
|
.byte $1B,$1C,$1E,$63
|
|
.byte $64,$65,$66,$67
|
|
.byte $64,$65,$68,$69
|
|
|
|
; $DD1E-$DD21
|
|
.byte $6A,$6B,$4C,$4C
|
|
|
|
|
|
|
|
;==============================================================================
|
|
; $DD22-$DE21: Gameplay Entity Render Attribute Lookup
|
|
;
|
|
; Local:
|
|
; 256-byte lookup table used by BuildEntitySpriteBuffer.
|
|
;
|
|
; Entries are predominantly:
|
|
;
|
|
; $00
|
|
; $40
|
|
; $80
|
|
; $C0
|
|
;
|
|
; These values occupy bits 6-7 and are ORed with the corresponding value
|
|
; from $0292+ before being written as byte 2 of a page-$07 four-byte render
|
|
; record.
|
|
;
|
|
; Global:
|
|
; Supplies upper-bit render attributes for gameplay entities across their
|
|
; various states, animation phases and directional variants.
|
|
;
|
|
; Notes:
|
|
; The table is exactly $100 bytes long:
|
|
;
|
|
; $DD22-$DE21
|
|
;
|
|
; $DE22 is independently referenced by another render-data path and therefore
|
|
; marks the next table boundary.
|
|
;==============================================================================
|
|
|
|
EntitySpriteAttributeTable0:
|
|
|
|
; $DD22-$DD31
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$40,$80,$C0
|
|
.byte $80,$C0,$80,$C0
|
|
.byte $80,$C0,$80,$C0
|
|
|
|
; $DD32-$DD41
|
|
.byte $00,$00,$80,$80
|
|
.byte $00,$00,$80,$80
|
|
.byte $00,$40,$00,$40
|
|
.byte $00,$40,$00,$40
|
|
|
|
; $DD42-$DD51
|
|
.byte $40,$40,$C0,$C0
|
|
.byte $40,$40,$C0,$C0
|
|
.byte $00,$40,$00,$40
|
|
.byte $00,$40,$00,$40
|
|
|
|
; $DD52-$DD61
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$40,$00,$40
|
|
.byte $00,$40,$00,$40
|
|
|
|
; $DD62-$DD71
|
|
.byte $40,$40,$40,$40
|
|
.byte $40,$40,$40,$40
|
|
.byte $00,$40,$80,$C0
|
|
.byte $00,$40,$00,$40
|
|
|
|
; $DD72-$DD81
|
|
.byte $00,$40,$00,$40
|
|
.byte $00,$00,$00,$40
|
|
.byte $00,$00,$00,$40
|
|
.byte $00,$00,$00,$40
|
|
|
|
; $DD82-$DD91
|
|
.byte $00,$00,$00,$40
|
|
.byte $00,$00,$00,$40
|
|
.byte $00,$00,$00,$40
|
|
.byte $00,$00,$00,$40
|
|
|
|
; $DD92-$DDA1
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$40,$00,$40
|
|
.byte $00,$40,$00,$40
|
|
|
|
; $DDA2-$DDB1
|
|
.byte $00,$40,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$40,$00,$40
|
|
.byte $40,$40,$40,$40
|
|
|
|
; $DDB2-$DDC1
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
|
|
; $DDC2-$DDD1
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
|
|
; $DDD2-$DDE1
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
|
|
; $DDE2-$DDF1
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
|
|
; $DDF2-$DE01
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
|
|
; $DE02-$DE11
|
|
.byte $00,$00,$00,$00
|
|
.byte $40,$40,$00,$40
|
|
.byte $80,$00,$80,$80
|
|
.byte $00,$C0,$C0,$C0
|
|
|
|
; $DE12-$DE21
|
|
.byte $00,$00,$00,$00
|
|
.byte $40,$00,$00,$00
|
|
.byte $80,$80,$80,$80
|
|
.byte $80,$80,$C0,$80
|
|
|
|
;==============================================================================
|
|
; $DE22-$DE55: Secondary Gameplay Entity Render Attribute Lookup
|
|
;
|
|
; Local:
|
|
; Lookup data used by BuildEntitySpriteBuffer in the path beginning
|
|
; at $DB74.
|
|
;
|
|
; Values from this table are ORed with the corresponding state value from
|
|
; $0292+ and written as byte 2 of a four-byte page-$07 render record.
|
|
;
|
|
; Global:
|
|
; Supplies upper-bit render attributes for one class of gameplay entity
|
|
; render states.
|
|
;
|
|
; Notes:
|
|
; As with the larger table at $DD22, the significant nonzero values occupy
|
|
; the upper bits, primarily $40 and $80.
|
|
;
|
|
; EntitySpriteCoordinateOffsets is separately referenced as another
|
|
; lookup-table base and therefore marks the next known boundary.
|
|
;==============================================================================
|
|
|
|
EntitySpriteAttributeTable1:
|
|
|
|
; $DE22-$DE31
|
|
.byte $00,$00,$00,$00
|
|
.byte $80,$00,$80,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
|
|
; $DE32-$DE41
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$40,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
|
|
; $DE42-$DE51
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
|
|
; $DE52-$DE55
|
|
.byte $00,$00,$00,$00
|
|
|
|
;==============================================================================
|
|
; $DE56-$DE5D: Entity Render Coordinate Adjustment Table
|
|
;
|
|
; Local:
|
|
; Eight coordinate-adjustment bytes used by
|
|
; BuildEntitySpriteBuffer.
|
|
;
|
|
; X takes even values $00,$02,$04,$06, and the routine reads:
|
|
;
|
|
; EntitySpriteCoordinateOffsets,X
|
|
; EntitySpriteCoordinateOffsets+1,X
|
|
;
|
|
; giving four byte pairs.
|
|
;
|
|
; Global:
|
|
; Adjusts source coordinates when building page-$07 four-byte render
|
|
; records.
|
|
;==============================================================================
|
|
|
|
EntitySpriteCoordinateOffsets:
|
|
.byte $03,$F4
|
|
.byte $03,$FC
|
|
.byte $0B,$F4
|
|
.byte $0B,$FC
|
|
|
|
;==============================================================================
|
|
; $DE5E-$DE7D: Periodic Four-Entry State Update
|
|
;
|
|
; Local:
|
|
; Once every 16 frames, updates the four entries at $6C-$6F:
|
|
;
|
|
; $07 -> remains $07
|
|
; $01 -> becomes $02
|
|
; anything else -> becomes $01
|
|
;==============================================================================
|
|
|
|
UpdatePeriodicFourEntryState:
|
|
lda $4B
|
|
and #$0F
|
|
beq @DE65
|
|
|
|
rts
|
|
|
|
|
|
@DE65:
|
|
tax
|
|
|
|
|
|
@DE66:
|
|
lda $6C,x
|
|
cmp #$07
|
|
beq @DE76
|
|
|
|
cmp #$01
|
|
bne @DE74
|
|
|
|
lda #$02
|
|
bne @DE76
|
|
|
|
|
|
@DE74:
|
|
lda #$01
|
|
|
|
|
|
@DE76:
|
|
sta $6C,x
|
|
|
|
inx
|
|
cpx #$04
|
|
bne @DE66
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $DE7E-$DF6B: Gameplay PPU / Display Update Processor
|
|
;
|
|
; Local:
|
|
; Processes several gameplay display-update buffers and writes their data
|
|
; directly to the PPU.
|
|
;
|
|
; Handles:
|
|
; - Six-byte update block at $023F using destination $026B/$026C.
|
|
; - Six-byte update block at $0245 using destination $0272/$0273.
|
|
; - Three-byte periodic update at $026F-$0271.
|
|
; - Four state values at $6C-$6F written to PPU addresses in the table
|
|
; beginning at GameplayStatusPpuAddressTable.
|
|
; - Generic PPU command stream beginning at $024B.
|
|
;
|
|
; Global:
|
|
; Central gameplay display-update routine.
|
|
;
|
|
; Notes:
|
|
; UpdateAnimatedGameplayPpuFields at $DF15 is a shared entry point reached from
|
|
; several earlier control-flow paths and is therefore a global label rather
|
|
; than a ca65 cheap-local label.
|
|
;==============================================================================
|
|
|
|
FlushGameplayPpuUpdates:
|
|
lda $48
|
|
beq @DE85
|
|
|
|
jmp UpdateAnimatedGameplayPpuFields
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DE85
|
|
; Process the update block beginning at $023F.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@DE85:
|
|
lda $023F
|
|
cmp #$FF
|
|
beq @DEB5
|
|
|
|
lda PPUSTATUS
|
|
|
|
lda $026B
|
|
sta PPUADDR
|
|
|
|
lda $026C
|
|
sta PPUADDR
|
|
|
|
ldy #$00
|
|
|
|
|
|
@DE9B:
|
|
lda $023F,y
|
|
sta PPUDATA
|
|
|
|
iny
|
|
cpy #$06
|
|
bne @DE9B
|
|
|
|
lda #$30
|
|
sta PPUDATA
|
|
|
|
lda #$FF
|
|
sta $023F
|
|
|
|
bne @DEE2
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DEB5
|
|
; Process the update block beginning at $0245.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@DEB5:
|
|
lda $0245
|
|
cmp #$FF
|
|
beq @DEE2
|
|
|
|
lda PPUSTATUS
|
|
|
|
lda $0272
|
|
sta PPUADDR
|
|
|
|
lda $0273
|
|
sta PPUADDR
|
|
|
|
ldy #$00
|
|
|
|
|
|
@DECB:
|
|
lda $0245,y
|
|
sta PPUDATA
|
|
|
|
iny
|
|
cpy #$06
|
|
bne @DECB
|
|
|
|
lda #$30
|
|
sta PPUDATA
|
|
|
|
lda #$FF
|
|
sta $0245
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DEE2
|
|
; Periodic three-byte display update.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@DEE2:
|
|
lda $4B
|
|
and #$07
|
|
bne UpdateAnimatedGameplayPpuFields
|
|
|
|
lda PPUSTATUS
|
|
|
|
lda $026D
|
|
sta PPUADDR
|
|
|
|
lda $026E
|
|
sta PPUADDR
|
|
|
|
ldx #$00
|
|
|
|
lda $4B
|
|
and #$18
|
|
beq @DF05
|
|
|
|
|
|
@DEFB:
|
|
lda $026F,x
|
|
sta PPUDATA
|
|
|
|
inx
|
|
cpx #$03
|
|
bne @DEFB
|
|
|
|
beq UpdateAnimatedGameplayPpuFields
|
|
|
|
|
|
@DF05:
|
|
lda #$20
|
|
|
|
|
|
@DF07:
|
|
sta PPUDATA
|
|
|
|
inx
|
|
cpx #$03
|
|
bne @DF07
|
|
|
|
|
|
;==============================================================================
|
|
; $DF15: Shared frame-dependent display update entry
|
|
;==============================================================================
|
|
UpdateAnimatedGameplayPpuFields:
|
|
lda $4B
|
|
and #$01
|
|
beq @DF42
|
|
|
|
ldy #$00
|
|
ldx #$00
|
|
|
|
lda $46
|
|
and $47
|
|
beq @DF27
|
|
|
|
ldy #$08
|
|
|
|
|
|
@DF27:
|
|
lda PPUSTATUS
|
|
|
|
lda GameplayStatusPpuAddressTable,y
|
|
sta PPUADDR
|
|
|
|
lda GameplayStatusPpuAddressTable+1,y
|
|
sta PPUADDR
|
|
|
|
lda $6C,x
|
|
sta PPUDATA
|
|
|
|
iny
|
|
iny
|
|
|
|
inx
|
|
cpx #$04
|
|
bne @DF27
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DF42
|
|
; Process the $024B command stream.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@DF42:
|
|
lda PPUSTATUS
|
|
|
|
ldy #$FF
|
|
|
|
|
|
@DF46:
|
|
iny
|
|
|
|
lda $024B,y
|
|
cmp #$FF
|
|
beq @DF66
|
|
|
|
sta PPUADDR
|
|
|
|
iny
|
|
|
|
lda $024B,y
|
|
sta PPUADDR
|
|
|
|
|
|
@DF55:
|
|
iny
|
|
|
|
lda $024B,y
|
|
beq @DF46
|
|
|
|
cmp #$FF
|
|
beq @DF66
|
|
|
|
sta PPUDATA
|
|
|
|
bne @DF55
|
|
|
|
|
|
@DF66:
|
|
sta $024B
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $DF6C-$DF7B: Gameplay PPU Address Table
|
|
;
|
|
; Local:
|
|
; Eight PPU addresses stored in high-byte/low-byte order.
|
|
;
|
|
; When ($46 & $47) == 0, the first four addresses are used.
|
|
; Otherwise the second four addresses are used.
|
|
;
|
|
; Values from $6C-$6F are written to the selected addresses.
|
|
;
|
|
; Notes:
|
|
; These must remain .byte pairs. Using .word would reverse each address
|
|
; because ca65 emits words little-endian.
|
|
;==============================================================================
|
|
|
|
GameplayStatusPpuAddressTable:
|
|
.byte $20,$B4
|
|
.byte $20,$A2
|
|
.byte $22,$D4
|
|
.byte $22,$C2
|
|
|
|
.byte $28,$B4
|
|
.byte $28,$A2
|
|
.byte $2A,$D4
|
|
.byte $2A,$C2
|
|
|
|
;==============================================================================
|
|
; $DF7C-$E042: Gameplay Tile / State Update
|
|
;
|
|
; Local:
|
|
; Processes selected values of $022A, updates $6C-$6F, emits a command into
|
|
; the $024B display-command buffer, updates $6A and related gameplay state,
|
|
; and may transfer control to $E0E6.
|
|
;
|
|
; Global:
|
|
; Called during the normal gameplay frame-update chain.
|
|
;
|
|
; Notes:
|
|
; $E043 and $E044 are lookup-table bases used near the end of this routine.
|
|
; Those bytes are data and begin immediately after the final JMP at $E040.
|
|
;==============================================================================
|
|
|
|
UpdateGameplayTileState:
|
|
ldx #$00
|
|
|
|
lda $022A
|
|
cmp #$09
|
|
beq $DFBB
|
|
|
|
inx
|
|
inx
|
|
|
|
cmp #$03
|
|
beq $DFBB
|
|
|
|
cmp #$01
|
|
beq @DF94
|
|
|
|
cmp #$02
|
|
beq @DF94
|
|
|
|
rts
|
|
|
|
|
|
@DF94:
|
|
jsr $E063
|
|
|
|
lda $1A
|
|
sta $02
|
|
|
|
lda $1C
|
|
sta $03
|
|
|
|
jsr $E263
|
|
|
|
ldx #$00
|
|
|
|
lda $03
|
|
and #$07
|
|
beq @DFAD
|
|
|
|
inx
|
|
inx
|
|
|
|
|
|
@DFAD:
|
|
lda $02
|
|
and #$0F
|
|
cmp #$04
|
|
beq @DFB6
|
|
|
|
inx
|
|
|
|
@DFB6:
|
|
lda #$07
|
|
sta $6C,x
|
|
|
|
@DFBB:
|
|
ldx #$04
|
|
lda #$00
|
|
sta $D5
|
|
sta $D6
|
|
|
|
lda $1A
|
|
sta $02
|
|
|
|
lda $1C
|
|
sta $03
|
|
|
|
jsr $E263
|
|
|
|
ldy #$FF
|
|
|
|
@DFCE:
|
|
iny
|
|
|
|
lda $024B,y
|
|
cmp #$FF
|
|
bne @DFCE
|
|
|
|
tya
|
|
beq @DFDC
|
|
|
|
lda #$00
|
|
sta $024B,y
|
|
|
|
iny
|
|
|
|
|
|
@DFDC:
|
|
lda $03
|
|
sta $024B,y
|
|
|
|
iny
|
|
|
|
lda $02
|
|
sta $024B,y
|
|
|
|
iny
|
|
|
|
lda $E043,x
|
|
sta $024B,y
|
|
|
|
iny
|
|
|
|
lda #$FF
|
|
sta $024B,y
|
|
|
|
lda #$07
|
|
sta $022A
|
|
|
|
lda $E044,x
|
|
sta $DC
|
|
|
|
dec $6A
|
|
bne @E012
|
|
|
|
lda #$0C
|
|
sta $3F
|
|
|
|
lda #$00
|
|
sta $87
|
|
|
|
lda #$48
|
|
sta $4C
|
|
|
|
|
|
@E012:
|
|
lda $6A
|
|
|
|
cmp #$37
|
|
beq @E01C
|
|
|
|
cmp #$86
|
|
bne $E036
|
|
|
|
@E01C:
|
|
lda #$0A
|
|
sta $D7
|
|
|
|
lda #$3C
|
|
sta $D8
|
|
|
|
ldy $93
|
|
|
|
lda GameplayStateValueLookup,y
|
|
sta $37
|
|
|
|
lda #$03
|
|
sta $3D
|
|
|
|
lda #$60
|
|
sta $2E
|
|
|
|
lda #$80
|
|
sta $30
|
|
|
|
lda $6A
|
|
and #$01
|
|
tay
|
|
|
|
lda #$01
|
|
sta $0604,y
|
|
|
|
jmp $E0E6
|
|
|
|
;==============================================================================
|
|
; $E043-$E048: Gameplay Tile-State Lookup
|
|
;
|
|
; Local:
|
|
; Used by UpdateGameplayTileState through overlapping indexed reads at
|
|
; $E043,X and $E044,X.
|
|
;==============================================================================
|
|
|
|
TileEventDisplayLookup:
|
|
.byte $08,$01,$07,$01,$07,$05
|
|
|
|
;==============================================================================
|
|
; $E049-$E05A: Activate First Available State Slot
|
|
;
|
|
; Local:
|
|
; Scans the three even-indexed entries:
|
|
;
|
|
; $BA,$BC,$BE
|
|
;
|
|
; for the first zero value. If one is found, changes it to $02 and returns.
|
|
; If all three are already active/nonzero, returns without modification.
|
|
;==============================================================================
|
|
|
|
ActivateNextStateSlotE049:
|
|
ldx #$00
|
|
|
|
@E04B:
|
|
lda $BA,x
|
|
bne @E054
|
|
|
|
lda #$02
|
|
sta $BA,x
|
|
|
|
rts
|
|
|
|
|
|
@E054:
|
|
inx
|
|
inx
|
|
|
|
cpx #$06
|
|
bne @E04B
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $E05B-$E062: Gameplay State Value Lookup
|
|
;
|
|
; Local:
|
|
; Eight sequential values indexed by $93 and copied into $37 during
|
|
; gameplay-state transitions.
|
|
;==============================================================================
|
|
|
|
GameplayStateValueLookup:
|
|
.byte $24,$25,$26,$27,$28,$29,$2A,$2B
|
|
|
|
;==============================================================================
|
|
; $E063-$E0E5: Initialize / Adjust Entity Direction State
|
|
;
|
|
; Local:
|
|
; Initializes several gameplay variables and scans all four entity slots.
|
|
;
|
|
; Initialization:
|
|
;
|
|
; if $8C == 0:
|
|
; $8A = $1E
|
|
;
|
|
; $89 = $00
|
|
; $88 = $0F
|
|
; $D9 = $00
|
|
;
|
|
; The low two bits of $39-$3C are normalized to $01, preserving the upper
|
|
; six bits.
|
|
;
|
|
; Palette/update values are installed at:
|
|
;
|
|
; $02AE = $11
|
|
; $02A9 = $0F
|
|
;
|
|
; Then the four entity structures are examined. For eligible entities in
|
|
; primary state $04, a candidate secondary direction is calculated from
|
|
; $B9,X and accepted when coordinate alignment and path-map checks permit it.
|
|
;
|
|
; Global:
|
|
; Called from UpdateGameplayTileState before that routine derives its
|
|
; direction/tile update.
|
|
;
|
|
; Notes:
|
|
; $00/$01 and $02/$03 are parallel indirect pointers.
|
|
; X advances through entity offsets $00,$02,$04,$06.
|
|
; $04 temporarily holds a candidate direction value.
|
|
;==============================================================================
|
|
InitializeEntityDirectionState:
|
|
lda $8C
|
|
bne @E06D
|
|
|
|
lda #$1E
|
|
sta $8A
|
|
|
|
lda #$00
|
|
|
|
|
|
@E06D:
|
|
sta $89
|
|
|
|
lda #$0F
|
|
sta $88
|
|
|
|
ldx #$03
|
|
|
|
@E075:
|
|
lda $39,x
|
|
and #$FC
|
|
ora #$01
|
|
sta $39,x
|
|
|
|
dex
|
|
bpl @E075
|
|
|
|
lda #$11
|
|
sta $02AE
|
|
|
|
lda #$0F
|
|
sta $02A9
|
|
|
|
lda #$00
|
|
sta $D9
|
|
|
|
ldx #$00
|
|
|
|
lda #$2F
|
|
sta $00
|
|
|
|
lda #$02
|
|
sta $01
|
|
|
|
lda #$1E
|
|
sta $02
|
|
|
|
lda #$00
|
|
sta $03
|
|
|
|
@E09E:
|
|
lda #$0F
|
|
cmp $88
|
|
beq @E0AA
|
|
|
|
lda $D2
|
|
bne @E0D1
|
|
|
|
@E0AA:
|
|
lda $B8,x
|
|
cmp #$04
|
|
bne @E0D1
|
|
|
|
lda $B9,x
|
|
clc
|
|
adc #$02
|
|
and #$03
|
|
sta $04
|
|
|
|
ldy #$00
|
|
|
|
lda ($02),y
|
|
|
|
ldy #$02
|
|
|
|
ora ($02),y
|
|
and #$07
|
|
bne @E0CD
|
|
|
|
ldy $04
|
|
|
|
lda ($00),y
|
|
and #$F8
|
|
bne @E0D1
|
|
|
|
|
|
@E0CD:
|
|
lda $04
|
|
sta $B9,x
|
|
|
|
|
|
@E0D1:
|
|
lda $00
|
|
clc
|
|
adc #$04
|
|
sta $00
|
|
|
|
lda $02
|
|
clc
|
|
adc #$04
|
|
sta $02
|
|
|
|
inx
|
|
inx
|
|
|
|
cpx #$08
|
|
bne @E0AA
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $E0E6-$E1BF: Score / State Display Update
|
|
;
|
|
; Updates the six decimal-like values at $70-$75 using increments at $DC-$E1,
|
|
; converts the result into display characters at $023F, handles progression
|
|
; state associated with $6B/$73/$67, appends display commands to $024B, then
|
|
; compares and updates the saved values at $61-$66.
|
|
;==============================================================================
|
|
|
|
UpdateScoreDisplay:
|
|
lda $48
|
|
beq @E0EB
|
|
|
|
rts
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E0EB
|
|
; Add $DC-$E1 into the six values at $70-$75 using decimal carry handling.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E0EB:
|
|
ldy #$00
|
|
|
|
lda #$06
|
|
sta $00
|
|
|
|
clc
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E0F2
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E0F2:
|
|
lda $70,y
|
|
adc $DC,y
|
|
sta $70,y
|
|
|
|
cmp #$0A
|
|
bcc @E105
|
|
|
|
sbc #$0A
|
|
sta $70,y
|
|
|
|
sec
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E105
|
|
; Clear the consumed increment and continue through all six entries.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E105:
|
|
lda #$00
|
|
sta $DC,y
|
|
|
|
iny
|
|
|
|
dec $00
|
|
bne @E0F2
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E10F
|
|
; Convert the six numeric values into display/tile values.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ldx #$00
|
|
|
|
dey
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E112
|
|
; Suppress leading zero-style values by replacing $30 with $20.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E112:
|
|
lda $70,y
|
|
jsr $E1CE
|
|
|
|
cmp #$30
|
|
bne @E12B
|
|
|
|
lda #$20
|
|
sta $023F,x
|
|
|
|
inx
|
|
|
|
dey
|
|
bne @E112
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E125
|
|
; Convert remaining digits without leading-space suppression.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E125:
|
|
lda $70,y
|
|
jsr $E1CE
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E12B
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E12B:
|
|
sta $023F,x
|
|
|
|
inx
|
|
|
|
dey
|
|
bpl @E125
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E132
|
|
; Progression check.
|
|
;------------------------------------------------------------------------------
|
|
|
|
lda $6B
|
|
bne @E196
|
|
|
|
lda #$01
|
|
cmp $73
|
|
bne @E196
|
|
|
|
lda #$01
|
|
sta $6B
|
|
sta $0602
|
|
|
|
inc $67
|
|
|
|
lda $67
|
|
sec
|
|
sbc #$02
|
|
asl
|
|
sta $00
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Locate the $FF terminator of the $024B display-command stream.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ldy #$FF
|
|
|
|
|
|
@E14D:
|
|
iny
|
|
|
|
lda $024B,y
|
|
cmp #$FF
|
|
bne @E14D
|
|
|
|
tya
|
|
beq @E15D
|
|
|
|
lda #$00
|
|
sta $024B,y
|
|
|
|
iny
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E15D
|
|
; Select a display offset according to $46 & $47.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E15D:
|
|
lda $46
|
|
and $47
|
|
beq @E165
|
|
|
|
lda #$08
|
|
|
|
|
|
@E165:
|
|
sta $01
|
|
|
|
ldx #$00
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E169
|
|
; Append two five-byte command templates from $E1C0.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E169:
|
|
lda ScorePpuCommandTemplates,x
|
|
clc
|
|
adc $01
|
|
sta $024B,y
|
|
|
|
iny
|
|
inx
|
|
|
|
lda ScorePpuCommandTemplates,x
|
|
clc
|
|
adc $00
|
|
sta $024B,y
|
|
|
|
lda #$03
|
|
sta $02
|
|
|
|
|
|
@E182:
|
|
iny
|
|
inx
|
|
|
|
lda ScorePpuCommandTemplates,x
|
|
sta $024B,y
|
|
|
|
dec $02
|
|
bne @E182
|
|
|
|
iny
|
|
inx
|
|
|
|
cpx #$0A
|
|
bne @E169
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E196
|
|
; Compare saved values $61-$66 with current values $70-$75.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E196:
|
|
ldy #$05
|
|
|
|
|
|
@E198:
|
|
lda $61,y
|
|
cmp $70,y
|
|
beq @E1A3
|
|
|
|
bcc @E1A7
|
|
|
|
rts
|
|
|
|
|
|
@E1A3:
|
|
dey
|
|
bpl @E198
|
|
|
|
rts
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E1A7
|
|
; Copy display buffer $023F-$0244 to $0245-$024A.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E1A7:
|
|
ldx #$00
|
|
|
|
|
|
@E1A9:
|
|
lda $023F,x
|
|
sta $0245,x
|
|
|
|
inx
|
|
cpx #$06
|
|
bne @E1A9
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Copy current values $70-$75 into saved values $61-$66.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ldx #$00
|
|
|
|
|
|
@E1B4:
|
|
lda $70,x
|
|
sta $61,x
|
|
|
|
inx
|
|
cpx #$06
|
|
bne @E1B4
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $E1C0-$E1C9: Score Display Command Table
|
|
;==============================================================================
|
|
|
|
ScorePpuCommandTemplates:
|
|
.byte $23,$17,$3C,$3D,$00
|
|
.byte $23,$37,$3E,$3F,$FF
|
|
|
|
;==============================================================================
|
|
; $E1CA-$E1D9: Convert High Nibble to Display Character
|
|
;
|
|
; Input:
|
|
; A = packed numeric value
|
|
;
|
|
; Output:
|
|
; A = display character code
|
|
;
|
|
; Behavior:
|
|
; Uses the original high nibble:
|
|
;
|
|
; $0-$9 -> $30-$39
|
|
; $A-$F -> $40-$45
|
|
;
|
|
; Global:
|
|
; Called by UpdateScoreDisplay while building the display buffer at
|
|
; $023F.
|
|
;==============================================================================
|
|
|
|
ConvertNibbleToDigitTile:
|
|
lsr
|
|
lsr
|
|
lsr
|
|
lsr
|
|
|
|
and #$0F
|
|
|
|
cmp #$0A
|
|
bcs @HexDigit
|
|
|
|
adc #$30
|
|
rts
|
|
|
|
@HexDigit:
|
|
adc #$36
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $E1DA-$E262: Rebuild Gameplay Coordinate/Map Buffer
|
|
;
|
|
; Local:
|
|
; Converts the primary coordinate pair $1A/$1C through the helper at $E263
|
|
; and stores the result at $0200/$0201.
|
|
;
|
|
; Then iterates through gameplay coordinate structures beginning at $1A,
|
|
; advancing X by four each iteration.
|
|
;
|
|
; For each iteration:
|
|
; - Converts the current $1A+X/$1C+X pair through $E263.
|
|
; - Initializes working 16-bit values in $12-$15.
|
|
; - Calls helpers at $E2D4 and $E2C6.
|
|
; - Emits two groups of four bytes into the buffer at $0202+.
|
|
;
|
|
; The output loop terminates when Y reaches $28.
|
|
;
|
|
; Global:
|
|
; Called after gameplay collision/entity-state changes to rebuild a
|
|
; 40-byte coordinate/map-facing buffer in page $02.
|
|
;
|
|
; Notes:
|
|
; $E263 is the next known helper and is already called elsewhere.
|
|
;==============================================================================
|
|
|
|
BuildNearbyTileAddressBuffer:
|
|
lda $1A
|
|
sta $02
|
|
|
|
lda $1C
|
|
sta $03
|
|
|
|
jsr $E263
|
|
|
|
lda $03
|
|
sta $0200
|
|
|
|
lda $02
|
|
sta $0201
|
|
|
|
ldx #$00
|
|
ldy #$00
|
|
|
|
|
|
@E1F2:
|
|
lda $1A,x
|
|
sta $02
|
|
|
|
lda $1C,x
|
|
sta $03
|
|
|
|
jsr $E263
|
|
|
|
lda #$20
|
|
sta $14
|
|
|
|
lda #$00
|
|
sta $15
|
|
|
|
lda $02
|
|
sta $12
|
|
|
|
lda $03
|
|
sta $13
|
|
|
|
jsr $E2D4
|
|
|
|
lda $13
|
|
sta $0202,y
|
|
|
|
lda $12
|
|
iny
|
|
sta $0202,y
|
|
|
|
lda $03
|
|
iny
|
|
sta $0202,y
|
|
|
|
lda $02
|
|
sec
|
|
sbc #$01
|
|
iny
|
|
sta $0202,y
|
|
|
|
lda #$20
|
|
sta $14
|
|
|
|
lda #$00
|
|
sta $15
|
|
|
|
lda $02
|
|
sta $12
|
|
|
|
lda $03
|
|
sta $13
|
|
|
|
jsr $E2C6
|
|
|
|
lda $13
|
|
iny
|
|
sta $0202,y
|
|
|
|
lda $12
|
|
iny
|
|
sta $0202,y
|
|
|
|
lda $03
|
|
iny
|
|
sta $0202,y
|
|
|
|
lda $02
|
|
clc
|
|
adc #$01
|
|
iny
|
|
sta $0202,y
|
|
|
|
inx
|
|
inx
|
|
inx
|
|
inx
|
|
|
|
iny
|
|
|
|
cpy #$28
|
|
bne @E1F2
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $E263-$E2A1: Convert Gameplay Coordinates to Map/PPU Address
|
|
;
|
|
; Input:
|
|
; $02 = first gameplay coordinate
|
|
; $03 = second gameplay coordinate
|
|
;
|
|
; Output:
|
|
; $02/$03 = converted 16-bit map/PPU-style address
|
|
;
|
|
; Local:
|
|
; Derives a nametable-style address from the coordinate pair.
|
|
;
|
|
; The second coordinate is adjusted by -4, aligned to an 8-unit boundary,
|
|
; then multiplied/shifted while carries are accumulated in $05.
|
|
;
|
|
; The first coordinate is adjusted by -4 and divided by eight before being
|
|
; added to the low address byte.
|
|
;
|
|
; The resulting address receives a base of $20xx.
|
|
;
|
|
; When ($46 & $47) is nonzero, $08 is added to the high/result byte at $03,
|
|
; selecting the corresponding alternate nametable region.
|
|
;
|
|
; Global:
|
|
; Called from several gameplay routines whenever object coordinates need to
|
|
; be converted into map/PPU addresses.
|
|
;
|
|
; Notes:
|
|
; $04/$05 are temporary low/high address components.
|
|
;==============================================================================
|
|
|
|
ConvertPixelToNametableAddress:
|
|
lda #$00
|
|
sta $05
|
|
|
|
lda $03
|
|
sec
|
|
sbc #$04
|
|
and #$F8
|
|
|
|
asl
|
|
rol $05
|
|
|
|
asl
|
|
rol $05
|
|
|
|
clc
|
|
adc #$40
|
|
sta $04
|
|
|
|
lda #$00
|
|
adc $05
|
|
sta $05
|
|
|
|
lda $02
|
|
sec
|
|
sbc #$04
|
|
|
|
lsr
|
|
lsr
|
|
lsr
|
|
|
|
clc
|
|
adc $04
|
|
sta $02
|
|
|
|
lda $05
|
|
clc
|
|
adc #$20
|
|
sta $03
|
|
|
|
lda $46
|
|
and $47
|
|
bne @E299
|
|
|
|
rts
|
|
|
|
@E299:
|
|
lda $03
|
|
clc
|
|
adc #$08
|
|
sta $03
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $E2A2-$E2C5: Read PPU Values for Coordinate Address Buffer
|
|
;
|
|
; Reads 21 PPU addresses stored at $0200-$0229 and stores the corresponding
|
|
; PPU data bytes at $022A-$023E.
|
|
;
|
|
; PPUSTATUS is read once before processing the address list.
|
|
;==============================================================================
|
|
|
|
ReadNearbyNametableTiles:
|
|
ldx #$00
|
|
ldy #$00
|
|
|
|
lda PPUSTATUS
|
|
|
|
|
|
@E2A9:
|
|
lda $0200,x
|
|
sta PPUADDR
|
|
|
|
inx
|
|
|
|
lda $0200,x
|
|
sta PPUADDR
|
|
|
|
; Buffered PPU read.
|
|
lda PPUDATA
|
|
|
|
; Actual requested value.
|
|
lda PPUDATA
|
|
sta $022A,y
|
|
|
|
inx
|
|
iny
|
|
|
|
cpx #$2A
|
|
bne @E2A9
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $E2C6-$E2D3: Add 16-Bit Working Values
|
|
;
|
|
; Input:
|
|
; $12/$13 = low/high first operand
|
|
; $14/$15 = low/high second operand
|
|
;
|
|
; Output:
|
|
; $12/$13 = 16-bit sum
|
|
;==============================================================================
|
|
|
|
Add16BitWorkingValue:
|
|
clc
|
|
|
|
lda $12
|
|
adc $14
|
|
sta $12
|
|
|
|
lda $13
|
|
adc $15
|
|
sta $13
|
|
|
|
rts
|
|
;==============================================================================
|
|
; $E2D4-$E2E1: Subtract 16-Bit Working Values
|
|
;
|
|
; Input:
|
|
; $12/$13 = low/high first operand
|
|
; $14/$15 = low/high second operand
|
|
;
|
|
; Output:
|
|
; $12/$13 = first operand - second operand
|
|
;==============================================================================
|
|
Subtract16BitWorkingValue:
|
|
sec
|
|
|
|
lda $12
|
|
sbc $14
|
|
sta $12
|
|
|
|
lda $13
|
|
sbc $15
|
|
sta $13
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $E2E2-$E381: Draw Gameplay Nametable
|
|
;
|
|
; Local:
|
|
; Expands compressed gameplay map data directly into VRAM.
|
|
;
|
|
; The primary destination begins at:
|
|
;
|
|
; $2040 when ($47 & $46) == 0
|
|
; $2840 when ($47 & $46) != 0
|
|
;
|
|
; The compressed source pointer is loaded from $FFF6/$FFF7.
|
|
;
|
|
; After the primary map is written, a small decoration pattern from
|
|
; MazeNametableDecorationTiles is written to additional PPU locations.
|
|
;
|
|
; Global:
|
|
; Called from GameModeState00 while initializing gameplay.
|
|
;
|
|
; Notes:
|
|
; $00/$01 = compressed source pointer during the first phase
|
|
; $02/$03 = PPU destination during the first phase
|
|
; $04 = number of PPU bytes remaining in current row
|
|
; $05 = repeat count extracted from the source byte
|
|
; X = row counter
|
|
; Y = compressed source index
|
|
;==============================================================================
|
|
|
|
DrawMazeNametable:
|
|
lda #$20
|
|
sta $02
|
|
|
|
lda #$40
|
|
sta $03
|
|
|
|
lda $47
|
|
and $46
|
|
beq @E2F4
|
|
|
|
lda #$28
|
|
sta $02
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E2F4
|
|
; Load compressed-map source pointer.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E2F4:
|
|
lda MazeDataPointerBytes+1
|
|
sta $01
|
|
|
|
lda MazeDataPointerBytes
|
|
sta $00
|
|
|
|
ldx #$1B
|
|
ldy #$00
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E302
|
|
; Set PPU destination for the next row.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E302:
|
|
lda PPUSTATUS
|
|
|
|
lda $02
|
|
sta PPUADDR
|
|
|
|
lda $03
|
|
sta PPUADDR
|
|
|
|
lda #$16
|
|
sta $04
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E313
|
|
; Start decoding the next compressed source byte.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E313:
|
|
lda #$00
|
|
sta $05
|
|
|
|
lda ($00),y
|
|
|
|
asl
|
|
rol $05
|
|
|
|
asl
|
|
rol $05
|
|
|
|
lda ($00),y
|
|
and #$3F
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E321
|
|
; Repeat the decoded value according to the repeat count in $05.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E321:
|
|
sta PPUDATA
|
|
|
|
dec $04
|
|
dec $05
|
|
bpl @E321
|
|
|
|
iny
|
|
bne @E32F
|
|
|
|
inc $01
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E32F
|
|
; Continue until the current row contains $16 output bytes.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E32F:
|
|
lda $04
|
|
bne @E313
|
|
|
|
lda $03
|
|
clc
|
|
adc #$20
|
|
sta $03
|
|
|
|
lda $02
|
|
adc #$00
|
|
sta $02
|
|
|
|
dex
|
|
bne @E302
|
|
|
|
|
|
;==============================================================================
|
|
; $E345-$E381: Draw additional nametable decoration strips.
|
|
;==============================================================================
|
|
|
|
ldy #$02
|
|
|
|
lda #$21
|
|
sta $00
|
|
|
|
lda #$D6
|
|
sta $01
|
|
|
|
lda $47
|
|
and $46
|
|
beq @E359
|
|
|
|
lda #$29
|
|
sta $00
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E359
|
|
; Start one decoration strip.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E359:
|
|
ldx #$07
|
|
|
|
lda PPUSTATUS
|
|
|
|
lda $00
|
|
sta PPUADDR
|
|
|
|
lda $01
|
|
sta PPUADDR
|
|
|
|
lda MazeNametableDecorationTiles,y
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E36B
|
|
; Write the selected table value eight times.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E36B:
|
|
sta PPUDATA
|
|
|
|
dex
|
|
bpl @E36B
|
|
|
|
lda $01
|
|
clc
|
|
adc #$20
|
|
sta $01
|
|
|
|
lda #$00
|
|
adc $00
|
|
sta $00
|
|
|
|
dey
|
|
bpl @E359
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $E382-$E385: Gameplay Nametable Decoration Table
|
|
;==============================================================================
|
|
|
|
MazeNametableDecorationTiles:
|
|
.byte $2D,$04,$2D
|
|
;==============================================================================
|
|
; $E385-$E3FE: Initialize Gameplay Nametable Regions
|
|
;
|
|
; Fills gameplay nametable regions with tile $2D, then clears the corresponding
|
|
; attribute-table regions.
|
|
;
|
|
; Address-based global labels are used for shared entry points to avoid ca65
|
|
; cheap-local scope issues and collisions with previously defined symbols.
|
|
;==============================================================================
|
|
|
|
ClearGameplayNametables:
|
|
lda PPUSTATUS
|
|
|
|
lda #$20
|
|
sta PPUADDR
|
|
|
|
lda #$00
|
|
sta PPUADDR
|
|
|
|
lda #$01
|
|
sta $02
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E396
|
|
; Shared entry used for another nametable pass.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ClearGameplayNametablesSecondPass:
|
|
lda #$01
|
|
sta $03
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E39A
|
|
; Initialize fill counters.
|
|
;------------------------------------------------------------------------------
|
|
|
|
InitializeNametableFillCounters:
|
|
lda #$03
|
|
sta $00
|
|
|
|
lda #$C0
|
|
sta $01
|
|
|
|
lda #$2D
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E3A4
|
|
; Shared fill loop.
|
|
;------------------------------------------------------------------------------
|
|
|
|
FillNametableByte:
|
|
sta PPUDATA
|
|
|
|
dec $01
|
|
bne FillNametableByte
|
|
|
|
dec $00
|
|
bpl FillNametableByte
|
|
|
|
dec $03
|
|
bne AdvanceNametableFillPass
|
|
|
|
lda #$40
|
|
sta $01
|
|
|
|
lda #$00
|
|
beq FillNametableByte
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E3BB
|
|
; Advance to alternate nametable / next phase.
|
|
;------------------------------------------------------------------------------
|
|
|
|
AdvanceNametableFillPass:
|
|
dec $02
|
|
bne ClearGameplayAttributeTables
|
|
|
|
lda PPUSTATUS
|
|
|
|
lda #$28
|
|
sta PPUADDR
|
|
|
|
lda #$00
|
|
sta PPUADDR
|
|
|
|
jmp ClearGameplayNametablesSecondPass
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E3CF
|
|
; Begin clearing attribute-table regions.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ClearGameplayAttributeTables:
|
|
lda #$01
|
|
sta $00
|
|
|
|
lda PPUSTATUS
|
|
|
|
lda #$23
|
|
sta PPUADDR
|
|
|
|
lda #$C0
|
|
sta PPUADDR
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E3E0
|
|
; Shared attribute-clear setup.
|
|
;------------------------------------------------------------------------------
|
|
|
|
BeginAttributeTableClear:
|
|
lda #$00
|
|
tay
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E3E3
|
|
; Write $20 zero bytes to PPUDATA.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ClearAttributeTableLoop:
|
|
sta PPUDATA
|
|
|
|
iny
|
|
cpy #$20
|
|
bne ClearAttributeTableLoop
|
|
|
|
dec $00
|
|
bne ClearSecondAttributeTable
|
|
|
|
rts
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E3F0
|
|
; Set destination to the second attribute table, $2BC0.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ClearSecondAttributeTable:
|
|
lda PPUSTATUS
|
|
|
|
lda #$2B
|
|
sta PPUADDR
|
|
|
|
lda #$C0
|
|
sta PPUADDR
|
|
|
|
bne BeginAttributeTableClear
|
|
|
|
;==============================================================================
|
|
; $E3FF-$E473: Draw Gameplay Numeric / Status Fields
|
|
;
|
|
; Local:
|
|
; Configures a PPU destination and repeatedly draws numeric fields through
|
|
; the helper at DrawSixDigitScore.
|
|
;
|
|
; Initial destination/configuration:
|
|
;
|
|
; $00/$01 = PPU destination
|
|
; $04 = destination stride
|
|
; X = index into a pointer table at ScoreFieldSourcePointerTable
|
|
;
|
|
; The destination and table index vary depending on $47 & $46.
|
|
;
|
|
; Three fields are drawn per pass. The routine may perform another pass
|
|
; according to $47 and the current field counter.
|
|
;
|
|
; Global:
|
|
; Called by GameModeState00 as part of gameplay initialization.
|
|
;
|
|
; Notes:
|
|
; DrawSixDigitScore renders one numeric field using the source pointer
|
|
; loaded from the table at ScoreFieldSourcePointerTable.
|
|
;==============================================================================
|
|
|
|
DrawGameplayScoreFields:
|
|
lda #$20
|
|
sta $00
|
|
|
|
lda #$B6
|
|
sta $01
|
|
|
|
lda #$80
|
|
sta $04
|
|
|
|
ldx #$00
|
|
|
|
lda $47
|
|
and $46
|
|
beq @E429
|
|
|
|
lda #$28
|
|
sta $00
|
|
|
|
bne @E429
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Alternate setup path.
|
|
;------------------------------------------------------------------------------
|
|
|
|
lda #$20
|
|
sta $00
|
|
|
|
lda #$83
|
|
sta $01
|
|
|
|
lda #$09
|
|
sta $04
|
|
|
|
lda #$01
|
|
sta $47
|
|
|
|
ldx #$0C
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E429
|
|
; Adjust lookup-table index for alternate player/mode state.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E429:
|
|
lda $47
|
|
and $46
|
|
beq @E436
|
|
|
|
txa
|
|
clc
|
|
adc #$06
|
|
tax
|
|
|
|
|
|
@E436:
|
|
lda #$03
|
|
sta $05
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E43A: render one status field.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E43A:
|
|
lda PPUSTATUS
|
|
|
|
lda $00
|
|
sta PPUADDR
|
|
|
|
lda $01
|
|
sta PPUADDR
|
|
|
|
lda ScoreFieldSourcePointerTable,x
|
|
sta $02
|
|
|
|
lda ScoreFieldSourcePointerTable+1,x
|
|
sta $03
|
|
|
|
jsr DrawSixDigitScore
|
|
|
|
inx
|
|
inx
|
|
|
|
lda $01
|
|
clc
|
|
adc $04
|
|
sta $01
|
|
|
|
lda #$00
|
|
adc $00
|
|
sta $00
|
|
|
|
dec $05
|
|
|
|
lda $05
|
|
cmp #$01
|
|
bne @E46D
|
|
|
|
lda $47
|
|
beq @E473
|
|
|
|
|
|
@E46D:
|
|
lda $05
|
|
bne @E43A
|
|
|
|
|
|
@E473:
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $E474-$E49E: Draw Six-Digit Numeric Field
|
|
;
|
|
; Input:
|
|
; $02/$03 = pointer to packed numeric values
|
|
;
|
|
; Local:
|
|
; Processes six source values from index 5 down to 0.
|
|
;
|
|
; Leading values whose low nibble is zero are rendered as spaces ($20).
|
|
; Once a nonzero low nibble is encountered, remaining values are converted
|
|
; through the shared conversion entry at $E1CE and written to PPUDATA.
|
|
;
|
|
; The final value at Y=0 is always converted, after which a trailing $30
|
|
; character is written.
|
|
;
|
|
; Notes:
|
|
; The conversion calls MUST target $E1CE, not $E1CA. $E1CE is the shared
|
|
; entry that begins with AND #$0F, while $E1CA additionally shifts A right
|
|
; four times.
|
|
;==============================================================================
|
|
DrawSixDigitScore:
|
|
ldy #$05
|
|
|
|
|
|
SkipLeadingZeroDigits:
|
|
lda ($02),y
|
|
and #$0F
|
|
bne ConvertCurrentScoreDigit
|
|
|
|
lda #$20
|
|
sta PPUDATA
|
|
|
|
dey
|
|
bne SkipLeadingZeroDigits
|
|
|
|
beq DrawFinalScoreDigit
|
|
|
|
|
|
LoadNextScoreDigit:
|
|
lda ($02),y
|
|
|
|
|
|
ConvertCurrentScoreDigit:
|
|
jsr $E1CE
|
|
|
|
sta PPUDATA
|
|
|
|
dey
|
|
bne LoadNextScoreDigit
|
|
|
|
|
|
DrawFinalScoreDigit:
|
|
lda ($02),y
|
|
|
|
jsr $E1CE
|
|
|
|
sta PPUDATA
|
|
|
|
lda #$30
|
|
sta PPUDATA
|
|
|
|
rts
|
|
;==============================================================================
|
|
; $E49F-$E4B0: Gameplay Status Field Source Pointer Table
|
|
;
|
|
; Local:
|
|
; Nine little-endian zero-page/RAM pointers used by the gameplay status-field
|
|
; drawing routine beginning at $E3FF.
|
|
;
|
|
; X indexes this table in steps of two. Each selected address is loaded into
|
|
; $02/$03 and passed to DrawSixDigitScore.
|
|
;
|
|
; Global:
|
|
; Selects the numeric/state arrays rendered into the different gameplay
|
|
; status display fields.
|
|
;==============================================================================
|
|
|
|
ScoreFieldSourcePointerTable:
|
|
.word $0061
|
|
.word $0070
|
|
.word $0080
|
|
|
|
.word $0061
|
|
.word $0080
|
|
.word $0070
|
|
|
|
.word $0070
|
|
.word $0061
|
|
.word $0080
|
|
|
|
;==============================================================================
|
|
; $E4B1-$E501: Build Entity Direction Candidate List
|
|
;
|
|
; Input:
|
|
; $00/$01 = pointer to direction/path data
|
|
; $0A/$0B = comparison values prepared by the caller
|
|
; X = current entity slot index
|
|
;
|
|
; Output:
|
|
; $0C-$0F = candidate direction values, with invalid entries marked $FF
|
|
;
|
|
; Local:
|
|
; First clears all four candidate entries to $FF.
|
|
;
|
|
; Then examines four values through ($00),Y. A candidate is accepted when
|
|
; either:
|
|
;
|
|
; value == $0A
|
|
;
|
|
; or:
|
|
;
|
|
; (value & $F8) != 0
|
|
; and value == $0B
|
|
;
|
|
; Accepted entries store their Y index into $0C-$0F.
|
|
;
|
|
; The entity's reverse/current-excluded direction is then calculated from
|
|
; $B9,X and explicitly removed from the candidate list.
|
|
;
|
|
; Finally performs up to three passes compacting $FF holes by shifting the
|
|
; following entry left.
|
|
;
|
|
; Global:
|
|
; Called by EntityTargetCommon at $D778 before entity direction selection.
|
|
;
|
|
; Notes:
|
|
; $0C-$0F therefore form a filtered list of legal direction indices.
|
|
;==============================================================================
|
|
|
|
BuildLegalDirectionList:
|
|
ldy #$FF
|
|
|
|
sty $0C
|
|
sty $0D
|
|
sty $0E
|
|
sty $0F
|
|
|
|
iny
|
|
|
|
|
|
ScanDirectionCandidate:
|
|
lda ($00),y
|
|
cmp $0A
|
|
beq AcceptDirectionCandidate
|
|
|
|
and #$F8
|
|
beq AcceptDirectionCandidate
|
|
|
|
cmp $0B
|
|
bne NextDirectionCandidate
|
|
|
|
|
|
AcceptDirectionCandidate:
|
|
tya
|
|
sta $000C,y
|
|
|
|
|
|
NextDirectionCandidate:
|
|
iny
|
|
cpy #$04
|
|
bne ScanDirectionCandidate
|
|
|
|
lda $B9,x
|
|
clc
|
|
adc #$02
|
|
and #$03
|
|
tay
|
|
|
|
lda #$FF
|
|
sta $000C,y
|
|
|
|
lda #$03
|
|
sta $0B
|
|
|
|
|
|
CompactDirectionListPass:
|
|
ldy #$00
|
|
|
|
|
|
CompactDirectionListEntry:
|
|
lda $000C,y
|
|
cmp #$FF
|
|
bne NextDirectionListEntry
|
|
|
|
lda $000D,y
|
|
sta $000C,y
|
|
|
|
lda #$FF
|
|
sta $000D,y
|
|
|
|
|
|
NextDirectionListEntry:
|
|
iny
|
|
cpy #$03
|
|
bne CompactDirectionListEntry
|
|
|
|
dec $0B
|
|
bne CompactDirectionListPass
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $E502-$E53B: Draw Gameplay Initialization Data
|
|
;
|
|
; Local:
|
|
; Reads compact PPU command data beginning at $E53C and writes the payloads
|
|
; directly to PPUDATA.
|
|
;
|
|
; X selects between two passes/variants.
|
|
; Y indexes the command stream.
|
|
; $00 holds the number of bytes remaining in the current payload.
|
|
;
|
|
; Global:
|
|
; Called from GameModeState00 during gameplay initialization.
|
|
;==============================================================================
|
|
|
|
DrawGameplayHudLabels:
|
|
ldx #$01
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E504
|
|
; Reset command-stream index for a pass.
|
|
;------------------------------------------------------------------------------
|
|
|
|
InitData_E504:
|
|
ldy #$00
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E506
|
|
; Start one command record.
|
|
;------------------------------------------------------------------------------
|
|
|
|
InitData_E506:
|
|
lda $E53C,y
|
|
|
|
cpx #$00
|
|
bne InitData_E50F
|
|
|
|
adc #$07
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E50F
|
|
; Write PPU destination address.
|
|
;------------------------------------------------------------------------------
|
|
|
|
InitData_E50F:
|
|
sta PPUADDR
|
|
|
|
iny
|
|
|
|
lda $E53C,y
|
|
sta PPUADDR
|
|
|
|
iny
|
|
|
|
lda $E53C,y
|
|
sta $00
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E51F
|
|
; Write record payload.
|
|
;------------------------------------------------------------------------------
|
|
|
|
InitData_E51F:
|
|
iny
|
|
|
|
lda $E53C,y
|
|
sta PPUDATA
|
|
|
|
dec $00
|
|
bne InitData_E51F
|
|
|
|
iny
|
|
|
|
cpy #$11
|
|
bne InitData_E534
|
|
|
|
lda $47
|
|
bne InitData_E534
|
|
|
|
rts
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E534
|
|
; Continue through the first/second stream section.
|
|
;------------------------------------------------------------------------------
|
|
|
|
InitData_E534:
|
|
cpy #$17
|
|
bne InitData_E506
|
|
|
|
dex
|
|
beq InitData_E504
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $E53C-$E552: Gameplay Initialization PPU Command Data
|
|
;
|
|
; Record format:
|
|
; byte 0 = PPU address high
|
|
; byte 1 = PPU address low
|
|
; byte 2 = payload length
|
|
; remaining bytes = payload written to PPUDATA
|
|
;==============================================================================
|
|
|
|
GameplayHudInitializationData:
|
|
|
|
; $E53C: PPU $2076, 8-byte payload
|
|
.byte $20,$76,$08
|
|
.byte $B4,$B5,$B6,$B7,$B8,$B9,$BA,$BB
|
|
|
|
; $E547: PPU $20F7, 3-byte payload
|
|
.byte $20,$F7,$03
|
|
.byte $B0,$B3,$B2
|
|
|
|
; $E54D: PPU $2177, 3-byte payload
|
|
.byte $21,$77,$03
|
|
.byte $B1,$B3,$B2
|
|
|
|
;==============================================================================
|
|
; $E553-$E5C0: Draw Progression / Status Markers
|
|
;
|
|
; Local:
|
|
; Returns immediately when $67 is zero.
|
|
;
|
|
; Otherwise computes:
|
|
;
|
|
; count = min($67 + 1, $07)
|
|
;
|
|
; and stores that in $02.
|
|
;
|
|
; Initializes:
|
|
;
|
|
; $03 = $04
|
|
; $00/$01 = $2317
|
|
;
|
|
; If ($46 & $47) != 0, the high destination byte is adjusted by $08.
|
|
;
|
|
; The routine then performs nested loops, calling the helper at $E59A with
|
|
; Y=$3C. The helper writes a 2x2-style pattern at the current PPU position.
|
|
;
|
|
; Global:
|
|
; Called during gameplay initialization to draw a progression/status display.
|
|
;
|
|
; Notes:
|
|
; $E59A is a valid internal helper entry point within this routine.
|
|
;==============================================================================
|
|
|
|
DrawLevelProgressMarkers:
|
|
lda $67
|
|
bne Progression_E558
|
|
|
|
rts
|
|
|
|
|
|
Progression_E558:
|
|
clc
|
|
adc #$01
|
|
|
|
cmp #$07
|
|
bcc Progression_E55F
|
|
|
|
lda #$07
|
|
|
|
|
|
Progression_E55F:
|
|
sta $02
|
|
|
|
lda #$04
|
|
sta $03
|
|
|
|
lda #$23
|
|
sta $00
|
|
|
|
lda #$17
|
|
sta $01
|
|
|
|
lda $46
|
|
and $47
|
|
beq Progression_E57C
|
|
|
|
lda $00
|
|
clc
|
|
adc #$08
|
|
sta $00
|
|
|
|
|
|
Progression_E57C:
|
|
dec $02
|
|
bne Progression_E581
|
|
|
|
rts
|
|
|
|
|
|
Progression_E581:
|
|
dec $03
|
|
bne Progression_E58A
|
|
|
|
lda $01
|
|
clc
|
|
adc #$3A
|
|
sta $01
|
|
|
|
|
|
Progression_E58A:
|
|
ldy #$3C
|
|
|
|
jsr Draw2x2Marker
|
|
|
|
lda $01
|
|
clc
|
|
adc #$02
|
|
sta $01
|
|
|
|
bne Progression_E57C
|
|
|
|
;==============================================================================
|
|
; $E59A-$E5C0: Draw 2x2 Progression Marker
|
|
;
|
|
; Input:
|
|
; $00/$01 = first PPU destination
|
|
; Y = first tile value
|
|
;
|
|
; Effect:
|
|
; Writes Y and Y+1 horizontally, then Y+2 and Y+3 one row ($20 bytes)
|
|
; below the initial destination.
|
|
;==============================================================================
|
|
|
|
Draw2x2Marker:
|
|
lda $00
|
|
sta PPUADDR
|
|
|
|
lda $01
|
|
sta PPUADDR
|
|
|
|
sty PPUDATA
|
|
|
|
iny
|
|
sty PPUDATA
|
|
|
|
lda $00
|
|
sta PPUADDR
|
|
|
|
lda $01
|
|
clc
|
|
adc #$20
|
|
sta PPUADDR
|
|
|
|
iny
|
|
sty PPUDATA
|
|
|
|
iny
|
|
sty PPUDATA
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $-$E699: Initialize Gameplay State / Markers
|
|
;
|
|
; Local:
|
|
; Builds several gameplay marker/display values using the current value at
|
|
; $68 and a collection of lookup tables beginning at LevelProgressMarkerIndexTable
|
|
;
|
|
; The routine:
|
|
; - Initializes working values at $0A-$0F.
|
|
; - Derives an index/count from $68.
|
|
; - Selects PPU coordinates according to $46/$47.
|
|
; - Draws repeated 2x2 marker blocks using Draw2x2Marker.
|
|
; - Combines several lookup-table values into $0A+ working state.
|
|
; - Writes the resulting values directly into PPU attribute/display areas.
|
|
; - Selects final values for $02B6 and $02A9.
|
|
;
|
|
; Global:
|
|
; Called from GameModeState00 during initial gameplay setup.
|
|
;
|
|
; Notes:
|
|
; Address-oriented labels are used for the larger loops to preserve the
|
|
; original compact branch structure.
|
|
;==============================================================================
|
|
|
|
InitializeLevelProgressDisplay:
|
|
lda #$00
|
|
sta $03
|
|
sta $0E
|
|
sta $0F
|
|
|
|
lda #$15
|
|
sta $0A
|
|
|
|
lda #$11
|
|
sta $0D
|
|
|
|
lda #$05
|
|
sta $0B
|
|
sta $0C
|
|
|
|
lda $68
|
|
sta $02
|
|
|
|
sec
|
|
sbc #$07
|
|
bcc UseFirstLevelProgressIndex
|
|
|
|
cmp #$0C
|
|
bcc ClampLevelProgressIndex
|
|
|
|
lda #$0C
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E5E9
|
|
;------------------------------------------------------------------------------
|
|
|
|
ClampLevelProgressIndex:
|
|
tax
|
|
|
|
lda #$07
|
|
sta $02
|
|
|
|
bne InitializeLevelProgressPosition
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E5F0
|
|
;------------------------------------------------------------------------------
|
|
|
|
UseFirstLevelProgressIndex:
|
|
ldx #$00
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E5F2
|
|
; Initial PPU destination.
|
|
;------------------------------------------------------------------------------
|
|
|
|
InitializeLevelProgressPosition:
|
|
lda #$22
|
|
sta $00
|
|
|
|
lda #$56
|
|
sta $01
|
|
|
|
lda $46
|
|
and $47
|
|
beq InitializeLevelProgressRowCounter
|
|
|
|
lda $00
|
|
clc
|
|
adc #$08
|
|
sta $00
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E605
|
|
;------------------------------------------------------------------------------
|
|
|
|
InitializeLevelProgressRowCounter:
|
|
lda #$05
|
|
sta $04
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E609
|
|
; Main marker loop.
|
|
;------------------------------------------------------------------------------
|
|
|
|
DrawNextLevelProgressMarker:
|
|
dec $04
|
|
bne SelectLevelProgressMarker
|
|
|
|
lda $01
|
|
clc
|
|
adc #$38
|
|
sta $01
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E612
|
|
; Select marker information.
|
|
;------------------------------------------------------------------------------
|
|
|
|
SelectLevelProgressMarker:
|
|
lda LevelProgressMarkerIndexTable,x
|
|
sta $05
|
|
|
|
asl
|
|
asl
|
|
adc #$60
|
|
tay
|
|
|
|
jsr Draw2x2Marker
|
|
|
|
ldy $03
|
|
|
|
lda LevelProgressAttributeIndexTable,y
|
|
sta $06
|
|
|
|
lda LevelProgressAttributeIndexTable+1,y
|
|
sta $07
|
|
|
|
ldy $05
|
|
|
|
lda LevelProgressAttributeBits,y
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E633
|
|
; Shift selected marker bits.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ShiftLevelProgressAttributeBits:
|
|
dec $07
|
|
bmi StoreLevelProgressAttributeBits
|
|
|
|
asl
|
|
asl
|
|
bcc ShiftLevelProgressAttributeBits
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E63B
|
|
; Combine marker bits into working values.
|
|
;------------------------------------------------------------------------------
|
|
|
|
StoreLevelProgressAttributeBits:
|
|
ldy $06
|
|
|
|
ora $0A,y
|
|
sta $0A,y
|
|
|
|
lda $01
|
|
clc
|
|
adc #$02
|
|
sta $01
|
|
|
|
inc $03
|
|
inc $03
|
|
|
|
inx
|
|
|
|
dec $02
|
|
bpl DrawNextLevelProgressMarker
|
|
|
|
|
|
;==============================================================================
|
|
; Write generated marker-state values into PPU memory.
|
|
;==============================================================================
|
|
|
|
ldx #$23
|
|
|
|
lda $47
|
|
and $46
|
|
beq SetLevelProgressAttributeAddress
|
|
|
|
ldx #$2B
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E65D
|
|
; Set first PPU destination.
|
|
;------------------------------------------------------------------------------
|
|
|
|
SetLevelProgressAttributeAddress:
|
|
stx PPUADDR
|
|
stx $00
|
|
|
|
lda #$E5
|
|
sta PPUADDR
|
|
|
|
ldx #$00
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E667
|
|
; Reset count for one three-byte PPU group.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ResetAttributeWriteCount:
|
|
lda #$03
|
|
sta $01
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E66B
|
|
; Write three values from $0A+.
|
|
;------------------------------------------------------------------------------
|
|
|
|
WriteLevelProgressAttribute:
|
|
lda $0A,x
|
|
sta PPUDATA
|
|
|
|
inx
|
|
|
|
dec $01
|
|
bne WriteLevelProgressAttribute
|
|
|
|
inc $02
|
|
bne SelectLevelProgressPalette
|
|
|
|
lda $00
|
|
sta PPUADDR
|
|
|
|
lda #$ED
|
|
sta PPUADDR
|
|
|
|
bne ResetAttributeWriteCount
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E685
|
|
; Select final marker/display value.
|
|
;------------------------------------------------------------------------------
|
|
|
|
SelectLevelProgressPalette:
|
|
lda $68
|
|
|
|
cmp #$10
|
|
bcc StoreLevelProgressPalette
|
|
|
|
lda #$0F
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E68D
|
|
;------------------------------------------------------------------------------
|
|
|
|
StoreLevelProgressPalette:
|
|
tay
|
|
|
|
lda LevelProgressPaletteTable,y
|
|
sta $02B6
|
|
|
|
lda #$0F
|
|
sta $02A9
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $E69A-$E6AD: Gameplay Marker Level Index Table
|
|
;==============================================================================
|
|
|
|
LevelProgressMarkerIndexTable:
|
|
.byte $00,$01,$02,$02
|
|
.byte $03,$03,$04,$04
|
|
.byte $05,$05,$06,$06
|
|
.byte $07,$07,$07,$07
|
|
.byte $07,$07,$07,$07
|
|
|
|
;==============================================================================
|
|
; $E6AE-$E6BD: Gameplay Marker Working-Value Table
|
|
;
|
|
; Used as byte pairs through $03.
|
|
;==============================================================================
|
|
|
|
LevelProgressAttributeIndexTable:
|
|
.byte $00,$03
|
|
.byte $01,$02
|
|
.byte $01,$03
|
|
.byte $02,$02
|
|
.byte $03,$01
|
|
.byte $04,$00
|
|
.byte $04,$01
|
|
.byte $05,$00
|
|
|
|
;==============================================================================
|
|
; $E6BE-$E6C5: Gameplay Marker Bit/Pattern Table
|
|
;==============================================================================
|
|
|
|
LevelProgressAttributeBits:
|
|
.byte $02,$02,$02,$02
|
|
.byte $03,$03,$03,$03
|
|
|
|
;==============================================================================
|
|
; $E6C6-$E6D5: Gameplay Marker Final Value Table
|
|
;
|
|
; Indexed by min($68,$0F). Selected value is stored at $02B6.
|
|
;==============================================================================
|
|
|
|
LevelProgressPaletteTable:
|
|
.byte $16,$16,$26,$26
|
|
.byte $06,$06,$19,$19
|
|
.byte $17,$17,$17,$17
|
|
.byte $12,$12,$12,$12
|
|
|
|
|
|
;==============================================================================
|
|
; $E6D6-$E737: Initialize Gameplay Transition State
|
|
;==============================================================================
|
|
|
|
InitializeGameplayTransitionState:
|
|
lda #$08
|
|
sta $43
|
|
sta PPUCTRL
|
|
|
|
|
|
TransitionInit_E6DD:
|
|
lda PPUSTATUS
|
|
bpl TransitionInit_E6DD
|
|
|
|
lda #$01
|
|
sta $060D
|
|
sta $060E
|
|
|
|
lda #$00
|
|
sta PPUMASK
|
|
|
|
jsr ClearPlayfieldNametable
|
|
|
|
lda #$01
|
|
sta $028D
|
|
|
|
lda #$01
|
|
sta $0293
|
|
|
|
lda #$F7
|
|
sta $0278
|
|
|
|
lda #$7C
|
|
sta $027A
|
|
|
|
lda #$FF
|
|
sta $1E
|
|
|
|
lda #$00
|
|
sta $1F
|
|
|
|
lda #$00
|
|
sta $88
|
|
|
|
ldy #$00
|
|
|
|
|
|
TransitionInit_CopyPalette:
|
|
lda GameplayTransitionPalette,y
|
|
sta $02A9,y
|
|
|
|
iny
|
|
cpy #$10
|
|
bne TransitionInit_CopyPalette
|
|
|
|
lda #$20
|
|
sta $026F
|
|
sta $0270
|
|
sta $0271
|
|
|
|
lda #$10
|
|
sta $3F
|
|
|
|
lda #$88
|
|
sta PPUCTRL
|
|
sta $43
|
|
|
|
jmp $CAA7
|
|
|
|
|
|
;==============================================================================
|
|
; $E738-$E7AE: Initialize Gameplay PPU Region
|
|
;
|
|
; Selects $2000/$2800 according to $47 & $46, performs a patterned fill,
|
|
; clears $40 PPU bytes, and conditionally writes tile $5E at $2230/$2A30.
|
|
;
|
|
; Several branches deliberately re-enter the counter setup at $E751.
|
|
;==============================================================================
|
|
|
|
ClearPlayfieldNametable:
|
|
ldx #$20
|
|
|
|
lda $47
|
|
and $46
|
|
beq SetPlayfieldPpuAddress
|
|
|
|
ldx #$28
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E742
|
|
; Initialize selected nametable address.
|
|
;------------------------------------------------------------------------------
|
|
|
|
SetPlayfieldPpuAddress:
|
|
lda PPUSTATUS
|
|
|
|
stx PPUADDR
|
|
|
|
lda #$00
|
|
sta PPUADDR
|
|
|
|
lda #$1C
|
|
sta $00
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E751
|
|
; Shared counter-setup entry.
|
|
;
|
|
; The outer $00 loop deliberately jumps back here rather than rebuilding $00.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ResetPlayfieldFillCounters:
|
|
lda #$02
|
|
sta $01
|
|
|
|
lda #$1C
|
|
sta $02
|
|
|
|
lda #$02
|
|
sta $03
|
|
|
|
lda #$2D
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E75F
|
|
; Shared PPUDATA write point.
|
|
;------------------------------------------------------------------------------
|
|
|
|
WritePlayfieldFillByte:
|
|
sta PPUDATA
|
|
|
|
ldx $01
|
|
beq AdvancePlayfieldInnerRun
|
|
|
|
dec $01
|
|
bne WritePlayfieldFillByte
|
|
|
|
lda #$20
|
|
bne WritePlayfieldFillByte
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E76E
|
|
; Process the second run counter.
|
|
;------------------------------------------------------------------------------
|
|
|
|
AdvancePlayfieldInnerRun:
|
|
ldx $02
|
|
beq AdvancePlayfieldOuterRun
|
|
|
|
dec $02
|
|
bne WritePlayfieldFillByte
|
|
|
|
lda #$2D
|
|
bne WritePlayfieldFillByte
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E77A
|
|
; Process outer fill counters.
|
|
;------------------------------------------------------------------------------
|
|
|
|
AdvancePlayfieldOuterRun:
|
|
dec $03
|
|
bne WritePlayfieldFillByte
|
|
|
|
dec $00
|
|
bne ResetPlayfieldFillCounters
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E782
|
|
; Clear $40 PPU bytes.
|
|
;------------------------------------------------------------------------------
|
|
|
|
lda #$00
|
|
tax
|
|
|
|
|
|
ClearPlayfieldTail:
|
|
sta PPUDATA
|
|
|
|
inx
|
|
cpx #$40
|
|
bne ClearPlayfieldTail
|
|
|
|
lda $87
|
|
cmp #$02
|
|
beq DrawPlayfieldSpecialTile
|
|
|
|
rts
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E794
|
|
; Optional special tile at PPU $2230 or $2A30.
|
|
;------------------------------------------------------------------------------
|
|
|
|
DrawPlayfieldSpecialTile:
|
|
ldx #$22
|
|
|
|
lda $47
|
|
and $46
|
|
beq SetSpecialTilePpuAddress
|
|
|
|
ldx #$2A
|
|
|
|
|
|
SetSpecialTilePpuAddress:
|
|
lda PPUSTATUS
|
|
|
|
stx PPUADDR
|
|
|
|
lda #$30
|
|
sta PPUADDR
|
|
|
|
lda #$5E
|
|
sta PPUDATA
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $E7AF-$E7BE: Gameplay Transition Palette
|
|
;==============================================================================
|
|
|
|
GameplayTransitionPalette:
|
|
.byte $0F,$36,$20,$06
|
|
.byte $0F,$27,$20,$06
|
|
.byte $0F,$11,$20,$33
|
|
.byte $0F,$36,$20,$11
|
|
|
|
;==============================================================================
|
|
; $E7BF-$E7CD: Gameplay Transition Update Coordinator
|
|
;
|
|
; Runs several already-known gameplay/render helpers, then dispatches through
|
|
; the state machine at $E7CE before returning to the main game-mode dispatcher.
|
|
;==============================================================================
|
|
|
|
UpdateIntermissionTransition:
|
|
jsr $EA19
|
|
jsr $EA94
|
|
jsr BuildEntitySpriteBuffer
|
|
jsr DispatchIntermissionState
|
|
|
|
jmp $CAA7
|
|
|
|
|
|
;==============================================================================
|
|
; $E7CE-$E7DC: Transition state dispatcher
|
|
;
|
|
; $87 is an even state value used directly as a byte offset into the table.
|
|
;==============================================================================
|
|
|
|
DispatchIntermissionState:
|
|
ldy $87
|
|
|
|
lda IntermissionStateHandlerTable,y
|
|
sta $10
|
|
|
|
lda IntermissionStateHandlerTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
|
|
;==============================================================================
|
|
; $E7DD-$E7E2: Transition state pointer table
|
|
;==============================================================================
|
|
|
|
IntermissionStateHandlerTable:
|
|
.word DispatchIntermissionPhase
|
|
.word DispatchIntermissionState2Phase
|
|
.word DispatchIntermissionState4Phase
|
|
|
|
|
|
;==============================================================================
|
|
; $E7E3-$E7F1: Secondary transition-state dispatcher
|
|
;
|
|
; $88 is used directly as a byte offset into another pointer table.
|
|
;==============================================================================
|
|
|
|
DispatchIntermissionPhase:
|
|
ldy $88
|
|
|
|
lda IntermissionPhaseHandlerTable,y
|
|
sta $10
|
|
|
|
lda IntermissionPhaseHandlerTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
|
|
;==============================================================================
|
|
; $E7F2-$E7F9: Transition substate pointer table
|
|
;==============================================================================
|
|
|
|
IntermissionPhaseHandlerTable:
|
|
.word UpdateIntermissionPhase0
|
|
.word UpdateIntermissionPhase1
|
|
.word UpdateIntermissionPhase2
|
|
.word UpdateIntermissionPhase3
|
|
|
|
|
|
;==============================================================================
|
|
; $E7FA-$E822: Transition substate 0
|
|
;
|
|
; Waits until $0278 reaches at least $D0, then advances $88 by two and
|
|
; initializes several mirrored object/state values.
|
|
;==============================================================================
|
|
|
|
UpdateIntermissionPhase0:
|
|
lda $0278
|
|
cmp #$D0
|
|
bcc TransitionSubstate_E802
|
|
|
|
rts
|
|
|
|
|
|
TransitionSubstate_E802:
|
|
inc $88
|
|
inc $88
|
|
|
|
lda #$0C
|
|
sta $028C
|
|
|
|
lda #$20
|
|
sta $0292
|
|
|
|
lda #$F7
|
|
sta $0274
|
|
|
|
lda #$7C
|
|
sta $0276
|
|
|
|
lda #$FE
|
|
sta $1A
|
|
|
|
lda #$E0
|
|
sta $1B
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $E823-$E84D: Transition substate 1
|
|
;
|
|
; Waits for $0274 to become zero, then advances $88 and initializes a
|
|
; different object/state configuration.
|
|
;==============================================================================
|
|
|
|
UpdateIntermissionPhase1:
|
|
lda $0274
|
|
beq TransitionSubstate_E829
|
|
|
|
rts
|
|
|
|
|
|
TransitionSubstate_E829:
|
|
inc $88
|
|
inc $88
|
|
|
|
lda #$40
|
|
sta $4C
|
|
|
|
lda #$1E
|
|
sta $028C
|
|
|
|
lda #$22
|
|
sta $0292
|
|
|
|
lda #$09
|
|
sta $0274
|
|
|
|
lda #$7C
|
|
sta $0276
|
|
|
|
lda #$01
|
|
sta $1A
|
|
|
|
lda #$00
|
|
sta $1B
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $E84E-$E8B9: Transition substate 2
|
|
;
|
|
; Waits until $0274 reaches at least $80, then advances $88 and initializes
|
|
; four related coordinate/state structures and their mirrored render values.
|
|
;==============================================================================
|
|
|
|
UpdateIntermissionPhase2:
|
|
lda #$01
|
|
sta $060D
|
|
sta $060E
|
|
|
|
lda $0274
|
|
cmp #$80
|
|
bcs TransitionSubstate_E85D
|
|
|
|
rts
|
|
|
|
|
|
TransitionSubstate_E85D:
|
|
inc $88
|
|
inc $88
|
|
|
|
lda #$01
|
|
sta $1E
|
|
sta $22
|
|
sta $26
|
|
sta $2A
|
|
|
|
lda #$C0
|
|
sta $1F
|
|
sta $23
|
|
sta $27
|
|
sta $2B
|
|
|
|
clc
|
|
|
|
lda #$38
|
|
sta $028D
|
|
|
|
adc #$01
|
|
sta $028E
|
|
|
|
adc #$01
|
|
sta $028F
|
|
|
|
adc #$01
|
|
sta $0290
|
|
|
|
lda #$21
|
|
sta $0293
|
|
sta $0294
|
|
sta $0295
|
|
sta $0296
|
|
|
|
lda #$09
|
|
sta $0278
|
|
sta $0280
|
|
|
|
lda #$19
|
|
sta $027C
|
|
sta $0284
|
|
|
|
lda #$6C
|
|
sta $027A
|
|
sta $027E
|
|
|
|
lda #$7C
|
|
sta $0282
|
|
sta $0286
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $E8BA-$E8C6: Transition substate 3
|
|
;
|
|
; Waits for $0278 to become zero, then primes delay $4C and transfers to the
|
|
; routine at $EA14.
|
|
;==============================================================================
|
|
|
|
UpdateIntermissionPhase3:
|
|
lda $0278
|
|
beq TransitionSubstate_E8C0
|
|
|
|
rts
|
|
|
|
|
|
TransitionSubstate_E8C0:
|
|
lda #$40
|
|
sta $4C
|
|
|
|
jmp $EA14
|
|
|
|
|
|
;==============================================================================
|
|
; $E8C7-$E8D5: Transition State $02 Substate Dispatcher
|
|
;
|
|
; Local:
|
|
; Uses $88 as an even byte offset into IntermissionState2PhaseTable.
|
|
;==============================================================================
|
|
|
|
DispatchIntermissionState2Phase:
|
|
ldy $88
|
|
|
|
lda IntermissionState2PhaseTable,y
|
|
sta $10
|
|
|
|
lda IntermissionState2PhaseTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
|
|
;==============================================================================
|
|
; $E8D6-$E8DB: Transition phase table
|
|
;==============================================================================
|
|
|
|
IntermissionState2PhaseTable:
|
|
.word UpdateIntermissionState2Phase0
|
|
.word UpdateIntermissionState2Phase1
|
|
.word UpdateIntermissionState2Phase2
|
|
|
|
|
|
;==============================================================================
|
|
; $E8DC-$E904: Transition phase 0
|
|
;
|
|
; Waits until $0278 reaches $A0, then advances the $88 state and initializes
|
|
; the primary mirrored object/state values.
|
|
;==============================================================================
|
|
|
|
UpdateIntermissionState2Phase0:
|
|
lda $0278
|
|
cmp #$A0
|
|
bcc TransitionPhase_E8E4
|
|
|
|
rts
|
|
|
|
|
|
TransitionPhase_E8E4:
|
|
inc $88
|
|
inc $88
|
|
|
|
lda #$0C
|
|
sta $028C
|
|
|
|
lda #$20
|
|
sta $0292
|
|
|
|
lda #$F7
|
|
sta $0274
|
|
|
|
lda #$7C
|
|
sta $0276
|
|
|
|
lda #$FF
|
|
sta $1A
|
|
|
|
lda #$00
|
|
sta $1B
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $E905-$E93E: Transition phase 1
|
|
;
|
|
; Watches $0274. At $80 it installs one object configuration. At $78 it
|
|
; clears the position pair and advances to the next phase.
|
|
;==============================================================================
|
|
|
|
UpdateIntermissionState2Phase1:
|
|
lda $0274
|
|
|
|
cmp #$80
|
|
bne TransitionPhase_E92D
|
|
|
|
lda #$FF
|
|
sta $1A
|
|
|
|
lda #$C0
|
|
sta $1B
|
|
|
|
lda #$42
|
|
sta $028E
|
|
|
|
lda #$00
|
|
sta $0294
|
|
|
|
lda #$80
|
|
sta $027C
|
|
|
|
lda #$7C
|
|
sta $027E
|
|
|
|
lda #$00
|
|
sta $22
|
|
sta $23
|
|
|
|
rts
|
|
|
|
|
|
TransitionPhase_E92D:
|
|
cmp #$78
|
|
beq TransitionPhase_E933
|
|
|
|
rts
|
|
|
|
|
|
TransitionPhase_E933:
|
|
lda #$00
|
|
sta $1A
|
|
sta $1B
|
|
|
|
inc $88
|
|
inc $88
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $E93F-$E96D: Transition phase 2
|
|
;
|
|
; Uses bit $40 of $028C and timer/state value $89 to alternate the object
|
|
; state between values $46 and $47. Eventually transfers to $EA14.
|
|
;==============================================================================
|
|
|
|
UpdateIntermissionState2Phase2:
|
|
lda $028C
|
|
and #$40
|
|
bne TransitionPhase_E953
|
|
|
|
lda #$46
|
|
sta $028C
|
|
|
|
lda #$45
|
|
sta $028E
|
|
|
|
lda #$40
|
|
sta $89
|
|
|
|
rts
|
|
|
|
|
|
TransitionPhase_E953:
|
|
dec $89
|
|
beq TransitionPhase_E958
|
|
|
|
rts
|
|
|
|
|
|
TransitionPhase_E958:
|
|
lda $028C
|
|
cmp #$47
|
|
bne TransitionPhase_E963
|
|
|
|
jmp $EA14
|
|
|
|
|
|
TransitionPhase_E963:
|
|
lda #$47
|
|
sta $028C
|
|
|
|
lda #$40
|
|
sta $89
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $E96E-$E97C: Transition State $04 Dispatcher
|
|
;
|
|
; $88 is an even byte offset into the four-entry phase table.
|
|
;==============================================================================
|
|
DispatchIntermissionState4Phase:
|
|
ldy $88
|
|
|
|
lda IntermissionState4PhaseTable,y
|
|
sta $10
|
|
|
|
lda IntermissionState4PhaseTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
;==============================================================================
|
|
; $E97D-$E984: Transition State $04 Phase Table
|
|
;==============================================================================
|
|
IntermissionState4PhaseTable:
|
|
.word UpdateIntermissionState4Phase0
|
|
.word UpdateIntermissionState4Phase1
|
|
.word UpdateIntermissionState4Phase2
|
|
.word UpdateIntermissionState4Phase3
|
|
|
|
;==============================================================================
|
|
; $E985-$E9AD: Phase 0
|
|
;
|
|
; Waits until $0278 reaches $D8, advances $88, then installs the initial
|
|
; mirrored object/state configuration.
|
|
;==============================================================================
|
|
|
|
UpdateIntermissionState4Phase0:
|
|
lda $0278
|
|
cmp #$D8
|
|
bcc TransitionPhase_E98D
|
|
|
|
rts
|
|
|
|
TransitionPhase_E98D:
|
|
inc $88
|
|
inc $88
|
|
|
|
lda #$4C
|
|
sta $028C
|
|
|
|
lda #$20
|
|
sta $0292
|
|
|
|
lda #$F7
|
|
sta $0274
|
|
|
|
lda #$7C
|
|
sta $0276
|
|
|
|
lda #$FF
|
|
sta $1A
|
|
|
|
lda #$00
|
|
sta $1B
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $E9AE-$E9D8: Phase 1
|
|
;
|
|
; Waits for $0274 to reach zero, advances $88 and installs the next object
|
|
; configuration.
|
|
;==============================================================================
|
|
|
|
UpdateIntermissionState4Phase1:
|
|
lda $0274
|
|
beq TransitionPhase_E9B4
|
|
|
|
rts
|
|
|
|
TransitionPhase_E9B4:
|
|
inc $88
|
|
inc $88
|
|
|
|
lda #$28
|
|
sta $4C
|
|
|
|
lda #$4A
|
|
sta $028C
|
|
|
|
lda #$23
|
|
sta $0292
|
|
|
|
lda #$09
|
|
sta $0274
|
|
|
|
lda #$7C
|
|
sta $0276
|
|
|
|
lda #$01
|
|
sta $1A
|
|
|
|
lda #$00
|
|
sta $1B
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $E9D9-$EA09: Phase 2
|
|
;
|
|
; Enables transition flags, waits until $0274 reaches $19, then advances $88
|
|
; and sets the next mirrored-state values.
|
|
;==============================================================================
|
|
UpdateIntermissionState4Phase2:
|
|
lda #$01
|
|
sta $060D
|
|
sta $060E
|
|
|
|
lda $0274
|
|
cmp #$19
|
|
bcs TransitionPhase_E9E8
|
|
|
|
rts
|
|
|
|
TransitionPhase_E9E8:
|
|
inc $88
|
|
inc $88
|
|
|
|
lda #$4C
|
|
sta $028D
|
|
|
|
lda #$21
|
|
sta $0293
|
|
|
|
lda #$11
|
|
sta $0278
|
|
|
|
lda #$84
|
|
sta $027A
|
|
|
|
lda #$01
|
|
sta $1E
|
|
|
|
lda #$00
|
|
sta $1F
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $EA0A-$EA18: Phase 3
|
|
;
|
|
; Waits for $0278 to reach zero, then primes the next game-mode/state
|
|
; transition.
|
|
;==============================================================================
|
|
UpdateIntermissionState4Phase3:
|
|
lda $0278
|
|
beq TransitionPhase_EA10
|
|
|
|
rts
|
|
|
|
TransitionPhase_EA10:
|
|
lda #$40
|
|
sta $4C
|
|
|
|
lda #$00
|
|
sta $3F
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $EA19-$EA93: Update Mirrored Gameplay Object Positions
|
|
;
|
|
; Local:
|
|
; Walks five four-byte structures in parallel:
|
|
;
|
|
; $00/$01 -> source gameplay structures beginning at $001A
|
|
; $02/$03 -> mirrored structures beginning at $0274
|
|
;
|
|
; Movement increments from the source structures are added into mirrored
|
|
; coordinates. Attribute bit $20 in $0292+ is adjusted according to the
|
|
; resulting coordinate, and coordinate reset/wrap handling is performed.
|
|
;
|
|
; Global:
|
|
; Called from gameplay transition processing before render data is rebuilt.
|
|
;
|
|
; Notes:
|
|
; Several branches deliberately re-enter shared code, so global address-style
|
|
; labels are used throughout.
|
|
;==============================================================================
|
|
UpdateTransitionObjectPositions:
|
|
lda #$1A
|
|
sta $00
|
|
|
|
lda #$00
|
|
sta $01
|
|
|
|
lda #$74
|
|
sta $02
|
|
|
|
lda #$02
|
|
sta $03
|
|
|
|
ldx #$00
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EA2B
|
|
; Process one structure.
|
|
;------------------------------------------------------------------------------
|
|
UpdateNextTransitionObject:
|
|
ldy #$00
|
|
|
|
lda ($02),y
|
|
beq AdvanceTransitionObjectPointers
|
|
|
|
iny
|
|
|
|
lda ($00),y
|
|
clc
|
|
adc ($02),y
|
|
sta ($02),y
|
|
|
|
dey
|
|
|
|
lda ($00),y
|
|
adc ($02),y
|
|
sta ($02),y
|
|
|
|
cmp #$C0
|
|
bcc UpdateTransitionObjectAttribute
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EA44
|
|
; Set attribute bit $20.
|
|
;------------------------------------------------------------------------------
|
|
SetTransitionObjectAttributeBit:
|
|
lda #$20
|
|
ora $0292,x
|
|
sta $0292,x
|
|
|
|
bne CheckTransitionObjectWrap
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EA4E
|
|
; Clear/set attribute according to coordinate range.
|
|
;
|
|
; If value < $40, branch backward to $EA44 and set bit $20.
|
|
; Otherwise clear bit $20 with mask $DF.
|
|
;------------------------------------------------------------------------------
|
|
|
|
UpdateTransitionObjectAttribute:
|
|
cmp #$40
|
|
bcc SetTransitionObjectAttributeBit
|
|
|
|
lda #$DF
|
|
and $0292,x
|
|
sta $0292,x
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EA5A
|
|
; Coordinate wrap/reset test.
|
|
;------------------------------------------------------------------------------
|
|
|
|
CheckTransitionObjectWrap:
|
|
ldy #$00
|
|
|
|
lda ($02),y
|
|
cmp #$FC
|
|
bcc CheckTransitionObjectLowBoundary
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EA62
|
|
; Reset coordinate/movement state.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ResetTransitionObjectPosition:
|
|
lda #$00
|
|
sta ($02),y
|
|
sta ($00),y
|
|
|
|
iny
|
|
sta ($00),y
|
|
|
|
iny
|
|
sta ($02),y
|
|
|
|
bne AdvanceTransitionObjectPointers
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EA70
|
|
; Values below $04 also take the reset path.
|
|
;------------------------------------------------------------------------------
|
|
|
|
CheckTransitionObjectLowBoundary:
|
|
cmp #$04
|
|
bcc ResetTransitionObjectPosition
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EA74
|
|
; Advance both source and mirrored pointers.
|
|
;------------------------------------------------------------------------------
|
|
|
|
AdvanceTransitionObjectPointers:
|
|
lda $00
|
|
clc
|
|
adc #$04
|
|
sta $00
|
|
|
|
lda $01
|
|
adc #$00
|
|
sta $01
|
|
|
|
lda $02
|
|
clc
|
|
adc #$04
|
|
sta $02
|
|
|
|
lda $03
|
|
adc #$00
|
|
sta $03
|
|
|
|
inx
|
|
|
|
cpx #$05
|
|
bne UpdateNextTransitionObject
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $EA94-$EAA2: Gameplay Animation State Dispatcher
|
|
;
|
|
; $87 is an even state value used directly as an offset into the pointer table
|
|
; at $EAA3.
|
|
;==============================================================================
|
|
|
|
DispatchTransitionAnimation:
|
|
ldy $87
|
|
|
|
lda TransitionAnimationHandlerTable,y
|
|
sta $10
|
|
|
|
lda TransitionAnimationHandlerTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
;==============================================================================
|
|
; $EAA3-$EAA8: Gameplay Animation State Table
|
|
;==============================================================================
|
|
|
|
TransitionAnimationHandlerTable:
|
|
.word DispatchTransitionAnimationPhase
|
|
.word DispatchTransitionAnimationState2
|
|
.word DispatchTransitionAnimationState4
|
|
|
|
;==============================================================================
|
|
; $EAA9-$EAB7: Animation Substate Dispatcher
|
|
;
|
|
; $88 is an even state value used directly as an offset into this table.
|
|
;==============================================================================
|
|
|
|
DispatchTransitionAnimationPhase:
|
|
ldy $88
|
|
|
|
lda TransitionAnimationPhaseTable,y
|
|
sta $10
|
|
|
|
lda TransitionAnimationPhaseTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
|
|
;==============================================================================
|
|
; $EAB8-$EABF: Animation Substate Table
|
|
;==============================================================================
|
|
|
|
TransitionAnimationPhaseTable:
|
|
.word UpdateTransitionAnimationFrame
|
|
.word UpdateTransitionAnimationType1
|
|
.word UpdateTransitionAnimationType2
|
|
.word UpdateTransitionAnimationPattern
|
|
|
|
|
|
;==============================================================================
|
|
; $EAC0-$EACD: Animation Substate 0
|
|
;
|
|
; Advances $B7 modulo eight and uses it to select a value for $028D.
|
|
;==============================================================================
|
|
|
|
UpdateTransitionAnimationFrame:
|
|
inc $B7
|
|
|
|
lda $B7
|
|
and #$07
|
|
tay
|
|
|
|
lda TransitionAnimationFrameTable,y
|
|
sta $028D
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $EACE-$EAD5: Animation frame table
|
|
;==============================================================================
|
|
|
|
TransitionAnimationFrameTable:
|
|
.byte $04,$04,$04,$05
|
|
.byte $05,$04,$01,$01
|
|
|
|
|
|
;==============================================================================
|
|
; $EAD6-$EAEC: Animation Substate 1
|
|
;
|
|
; Runs only when ($4B & 7) == 0. Alternates $028C between $0C and $0D
|
|
; according to frame-counter bit 3, then falls back into the common animation
|
|
; update path beginning at $EAC0.
|
|
;==============================================================================
|
|
|
|
UpdateTransitionAnimationType1:
|
|
lda $4B
|
|
and #$07
|
|
bne UpdateTransitionAnimationFrame
|
|
|
|
lda $4B
|
|
and #$08
|
|
bne AnimationSubstate_EAE7
|
|
|
|
lda #$0C
|
|
bne AnimationSubstate_EAE9
|
|
|
|
|
|
AnimationSubstate_EAE7:
|
|
lda #$0D
|
|
|
|
|
|
AnimationSubstate_EAE9:
|
|
sta $028C
|
|
|
|
bne UpdateTransitionAnimationFrame
|
|
|
|
|
|
;==============================================================================
|
|
; $EAED-$EB03: Animation Substate 2
|
|
;
|
|
; Updates only once every eight frames and alternates $028C between $1E/$1F
|
|
; according to frame-counter bit 3.
|
|
;==============================================================================
|
|
|
|
UpdateTransitionAnimationType2:
|
|
lda $4B
|
|
and #$07
|
|
beq AnimationSubstate_EAF5
|
|
|
|
rts
|
|
|
|
|
|
AnimationSubstate_EAF5:
|
|
lda $4B
|
|
and #$08
|
|
bne AnimationSubstate_EB00
|
|
|
|
lda #$1E
|
|
bne AnimationSubstate_EB02
|
|
|
|
|
|
AnimationSubstate_EB00:
|
|
lda #$1F
|
|
|
|
|
|
AnimationSubstate_EB02:
|
|
sta $028C
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $EB04-$EB28: Animation Substate 3
|
|
;
|
|
; Advances $B7 modulo eight, maps the result through a small index table, and
|
|
; uses the selected entry to load four consecutive animation values into
|
|
; $028D-$0290.
|
|
;
|
|
; The final BNE intentionally branches backward into the common update path.
|
|
;==============================================================================
|
|
|
|
UpdateTransitionAnimationPattern:
|
|
inc $B7
|
|
|
|
lda $B7
|
|
and #$07
|
|
tay
|
|
|
|
lda TransitionAnimationPatternIndex,y
|
|
tay
|
|
|
|
lda TransitionAnimationPatternTiles,y
|
|
sta $028D
|
|
|
|
lda TransitionAnimationPatternTiles+1,y
|
|
sta $028E
|
|
|
|
lda TransitionAnimationPatternTiles+2,y
|
|
sta $028F
|
|
|
|
lda TransitionAnimationPatternTiles+3,y
|
|
sta $0290
|
|
|
|
bne UpdateTransitionAnimationType2
|
|
|
|
|
|
;==============================================================================
|
|
; $EB29-$EB30: Animation pattern index table
|
|
;==============================================================================
|
|
|
|
TransitionAnimationPatternIndex:
|
|
.byte $00,$00,$00,$04
|
|
.byte $04,$00,$08,$08
|
|
|
|
|
|
;==============================================================================
|
|
; $EB31-$EB3C: Animation pattern data
|
|
;
|
|
; Indexed using offsets 0, 4 and 8. The final logical group continues beyond
|
|
; this initial range, so preserve the next code/data boundary carefully.
|
|
;==============================================================================
|
|
TransitionAnimationPatternTiles:
|
|
.byte $3C,$3D,$3E,$3F
|
|
.byte $3C,$40,$3E,$41
|
|
.byte $38,$39,$3A,$3B
|
|
|
|
;==============================================================================
|
|
; $EB3D-$EB4B: Gameplay Animation State $02 Dispatcher
|
|
;==============================================================================
|
|
|
|
DispatchTransitionAnimationState2:
|
|
ldy $88
|
|
|
|
lda TransitionAnimationState2Table,y
|
|
sta $10
|
|
|
|
lda TransitionAnimationState2Table+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
|
|
;==============================================================================
|
|
; $EB4C-$EB51: Gameplay Animation State $02 Pointer Table
|
|
;==============================================================================
|
|
|
|
TransitionAnimationState2Table:
|
|
.word UpdateTransitionAnimationFrame
|
|
.word UpdateTransitionAnimationState2
|
|
.word UpdateTransitionAnimationFrame
|
|
|
|
|
|
;==============================================================================
|
|
; $EB52-$EB6C: Animation State $02 Handler
|
|
;==============================================================================
|
|
|
|
UpdateTransitionAnimationState2:
|
|
jsr UpdateTransitionAnimationType1
|
|
|
|
lda $0274
|
|
cmp #$7D
|
|
bne AnimationState2_EB62
|
|
|
|
lda #$43
|
|
sta $028E
|
|
|
|
rts
|
|
|
|
|
|
AnimationState2_EB62:
|
|
cmp #$7B
|
|
beq AnimationState2_EB68
|
|
|
|
rts
|
|
|
|
|
|
AnimationState2_EB68:
|
|
lda #$44
|
|
sta $028E
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $EB6D-$EB7B: Gameplay Animation State $04 Dispatcher
|
|
;==============================================================================
|
|
DispatchTransitionAnimationState4:
|
|
ldy $88
|
|
|
|
lda TransitionAnimationState4Table,y
|
|
sta $10
|
|
|
|
lda TransitionAnimationState4Table+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
;==============================================================================
|
|
; $EB7C-$EB83: Gameplay Animation State $04 Pointer Table
|
|
;==============================================================================
|
|
|
|
TransitionAnimationState4Table:
|
|
.word UpdateTransitionAnimationFrame
|
|
.word UpdateTransitionAnimationState4Type1
|
|
.word UpdateTransitionAnimationState4Type2
|
|
.word UpdateTransitionAnimationState4Type2
|
|
|
|
;==============================================================================
|
|
; $EB84-$EB9E: Animation State $04 Handler 1
|
|
;
|
|
; Alternates $028C between $48/$49 every eight frames, while non-update
|
|
; frames tail-jump into the common $EAC0 animation updater.
|
|
;==============================================================================
|
|
UpdateTransitionAnimationState4Type1:
|
|
lda $4B
|
|
and #$07
|
|
beq AnimationState4_EB8E
|
|
|
|
jmp UpdateTransitionAnimationFrame
|
|
|
|
AnimationState4_EB8E:
|
|
lda $4B
|
|
and #$08
|
|
bne AnimationState4_EB97
|
|
|
|
lda #$48
|
|
bne AnimationState4_EB99
|
|
|
|
AnimationState4_EB97:
|
|
lda #$49
|
|
|
|
AnimationState4_EB99:
|
|
sta $028C
|
|
|
|
jmp UpdateTransitionAnimationFrame
|
|
|
|
;==============================================================================
|
|
; $EB9F-$EBB5: Animation State $04 Handler 2/3
|
|
;
|
|
; Alternates $028C between $4A and $4B every eight frames.
|
|
;==============================================================================
|
|
|
|
UpdateTransitionAnimationState4Type2:
|
|
lda $4B
|
|
and #$07
|
|
beq AnimationState4_EBA6
|
|
|
|
rts
|
|
|
|
AnimationState4_EBA6:
|
|
lda $4B
|
|
and #$08
|
|
bne AnimationState4_EBB0
|
|
|
|
lda #$4A
|
|
bne AnimationState4_EBB2
|
|
|
|
AnimationState4_EBB0:
|
|
lda #$4B
|
|
|
|
AnimationState4_EBB2:
|
|
sta $028C
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $EBB6-$EC3F: Gameplay Lookup Data
|
|
;
|
|
; Raw lookup data preserved byte-for-byte.
|
|
; Semantic subdivision is deferred until the consuming routines are decoded.
|
|
;==============================================================================
|
|
|
|
MazeGameplayData_EBB6:
|
|
|
|
; $EBB6-$EBC5
|
|
.byte $00,$07,$00,$00,$00,$04,$01,$06
|
|
.byte $01,$01,$01,$04,$01,$04,$02,$02
|
|
|
|
; $EBC6-$EBD5
|
|
.byte $02,$03,$02,$03,$02,$02,$02,$03
|
|
.byte $02,$02,$02,$02,$03,$03,$03,$05
|
|
|
|
; $EBD6-$EBE5
|
|
.byte $03,$02,$03,$03,$03,$02,$03,$02
|
|
.byte $04,$03,$03,$02,$03,$02,$04,$03
|
|
|
|
; $EBE6-$EBF5
|
|
.byte $03,$01,$04,$02,$05,$03,$03,$05
|
|
.byte $04,$02,$05,$03,$03,$02,$04,$02
|
|
|
|
; $EBF6-$EC05
|
|
.byte $06,$03,$03,$01,$05,$02,$06,$03
|
|
.byte $03,$01,$05,$02,$07,$03,$03,$03
|
|
|
|
; $EC06-$EC15
|
|
.byte $05,$02,$07,$03,$03,$01,$06,$02
|
|
.byte $07,$03,$03,$01,$06,$02,$07,$03
|
|
|
|
; $EC16-$EC25
|
|
.byte $03,$00,$06,$02,$07,$03,$03,$01
|
|
.byte $06,$02,$07,$03,$03,$00,$06,$02
|
|
|
|
; $EC26-$EC35
|
|
.byte $07,$03,$03,$00,$06,$02,$07,$03
|
|
.byte $03,$00,$06,$02,$07,$03,$04,$00
|
|
|
|
; $EC36-$EC3F
|
|
.byte $06,$02,$07,$03,$04,$00,$06,$02
|
|
.byte $07,$03
|
|
|
|
|
|
;==============================================================================
|
|
; $EC40-$ECAB: Gameplay Parameter Lookup Data
|
|
;
|
|
; Raw lookup data preserved byte-for-byte.
|
|
;
|
|
; The byte pattern strongly resembles little-endian 16-bit quantities, but
|
|
; semantic grouping is intentionally deferred until the consuming routines
|
|
; have been identified.
|
|
;==============================================================================
|
|
MazeGameplayData_EC40:
|
|
; $EC40-$EC4F
|
|
.byte $D0,$00,$C0,$00,$A0,$00,$B0,$00
|
|
.byte $A0,$00,$80,$00,$A0,$00,$B0,$00
|
|
|
|
; $EC50-$EC5F
|
|
.byte $90,$00,$50,$00,$50,$00,$D0,$00
|
|
.byte $C0,$00,$A0,$00,$B0,$00,$A0,$00
|
|
|
|
; $EC60-$EC6F
|
|
.byte $80,$00,$B0,$00,$C0,$00,$A0,$00
|
|
.byte $50,$00,$50,$00,$F0,$00,$E0,$00
|
|
|
|
; $EC70-$EC7F
|
|
.byte $C0,$00,$E0,$00,$D0,$00,$B0,$00
|
|
.byte $E0,$00,$F0,$00,$D0,$00,$70,$00
|
|
|
|
; $EC80-$EC8F
|
|
.byte $70,$00,$00,$01,$F0,$00,$D0,$00
|
|
.byte $00,$01,$F0,$00,$D0,$00,$00,$01
|
|
|
|
; $EC90-$EC9F
|
|
.byte $10,$01,$F0,$00,$80,$00,$80,$00
|
|
.byte $00,$01,$F0,$00,$D0,$00,$00,$01
|
|
|
|
; $ECA0-$ECAB
|
|
.byte $F0,$00,$D0,$00,$20,$01,$30,$01
|
|
.byte $10,$01,$80,$00
|
|
|
|
|
|
|
|
;==============================================================================
|
|
; $ECAC-$ECFF: Gameplay Lookup / Parameter Data
|
|
;
|
|
; Raw data preserved byte-for-byte. Semantic subdivision is intentionally
|
|
; deferred until the consuming routines are decoded.
|
|
;==============================================================================
|
|
|
|
MazeGameplayData_ECAC:
|
|
|
|
; $ECAC-$ECBB
|
|
.byte $80,$00,$07,$14,$07,$14,$05,$14
|
|
.byte $05,$FF,$07,$14,$07,$14,$05,$FF
|
|
|
|
; $ECBC-$ECCB
|
|
.byte $00,$00,$05,$14,$05,$14,$05,$FF
|
|
.byte $00,$00,$05,$14,$05,$14,$05,$FF
|
|
|
|
; $ECCC-$ECDB
|
|
.byte $00,$00,$14,$0A,$1E,$0F,$28,$14
|
|
.byte $32,$19,$3C,$1E,$50,$28,$64,$32
|
|
|
|
; $ECDC-$ECEB
|
|
.byte $02,$1E,$5A,$00,$03,$32,$00,$00
|
|
.byte $04,$00,$00,$00,$01,$07,$11,$20
|
|
|
|
; $ECEC-$ECFB
|
|
.byte $2D,$1F,$D0,$D0,$10,$13,$D0,$D0
|
|
.byte $10,$1D,$2D,$11,$C3,$C3,$03,$11
|
|
|
|
; $ECFC-$ECFF
|
|
.byte $C3,$C3,$03,$11
|
|
|
|
;==============================================================================
|
|
; $ED00-$EDFF: Gameplay Lookup / Pattern Data
|
|
;
|
|
; Raw data preserved byte-for-byte. This region contains highly structured
|
|
; repeated values and bit-pattern-like fields, but semantic subdivisions are
|
|
; deferred until the routines that consume this region are identified.
|
|
;==============================================================================
|
|
|
|
MazeLayoutData_ED00:
|
|
|
|
; $ED00-$ED0F
|
|
.byte $2D,$11,$03,$1F,$10,$1D,$03,$1F
|
|
.byte $10,$1D,$03,$11,$03,$1F,$10,$1D
|
|
|
|
; $ED10-$ED1F
|
|
.byte $03,$1F,$10,$1D,$03,$11,$2D,$11
|
|
.byte $01,$11,$20,$11,$03,$11,$20,$11
|
|
|
|
; $ED20-$ED2F
|
|
.byte $03,$11,$03,$11,$20,$11,$03,$11
|
|
.byte $20,$11,$01,$11,$2D,$11,$03,$1E
|
|
|
|
; $ED30-$ED3F
|
|
.byte $10,$1C,$03,$1E,$10,$1C,$03,$1A
|
|
.byte $03,$1E,$10,$1C,$03,$1E,$10,$1C
|
|
|
|
; $ED40-$ED4F
|
|
.byte $03,$11,$2D,$11,$C3,$C3,$C3,$C3
|
|
.byte $83,$11,$2D,$11,$03,$1F,$10,$1D
|
|
|
|
; $ED50-$ED5F
|
|
.byte $03,$1B,$03,$1F,$10,$10,$10,$1D
|
|
.byte $03,$1B,$03,$1F,$10,$1D,$03,$11
|
|
|
|
; $ED60-$ED6F
|
|
.byte $2D,$11,$03,$1E,$10,$1C,$03,$11
|
|
.byte $03,$1E,$10,$13,$10,$1C,$03,$11
|
|
|
|
; $ED70-$ED7F
|
|
.byte $03,$1E,$10,$1C,$03,$11,$2D,$11
|
|
.byte $C3,$03,$11,$83,$11,$83,$11,$C3
|
|
|
|
; $ED80-$ED8F
|
|
.byte $03,$11,$2D,$1E,$90,$1D,$03,$15
|
|
.byte $10,$18,$08,$1A,$08,$19,$10,$14
|
|
|
|
; $ED90-$ED9F
|
|
.byte $03,$1F,$90,$1C,$2D,$E0,$11,$03
|
|
.byte $11,$C0,$80,$11,$03,$11,$E0,$2D
|
|
|
|
; $EDA0-$EDAF
|
|
.byte $E0,$11,$03,$11,$00,$1F,$17,$2C
|
|
.byte $16,$1D,$00,$11,$03,$11,$E0,$2D
|
|
|
|
; $EDB0-$EDBF
|
|
.byte $22,$90,$1C,$03,$1A,$00,$11,$80
|
|
.byte $11,$00,$1A,$03,$1E,$90,$21,$04
|
|
|
|
; $EDC0-$EDCF
|
|
.byte $06,$C0,$03,$40,$11,$80,$11,$40
|
|
.byte $03,$C0,$05,$2D,$22,$90,$1D,$03
|
|
|
|
; $EDD0-$EDDF
|
|
.byte $1B,$00,$1E,$90,$1C,$00,$1B,$03
|
|
.byte $1F,$90,$21,$2D,$E0,$11,$03,$11
|
|
|
|
; $EDE0-$EDEF
|
|
.byte $C0,$80,$11,$03,$11,$E0,$2D,$E0
|
|
.byte $11,$03,$11,$00,$1F,$90,$1D,$00
|
|
|
|
; $EDF0-$EDFF
|
|
.byte $11,$03,$11,$E0,$2D,$1F,$90,$1C
|
|
.byte $03,$1A,$00,$1E,$10,$13,$10,$1C
|
|
|
|
;==============================================================================
|
|
; $EE00-$EE8B: Gameplay Lookup / Pattern Data
|
|
;
|
|
; Raw data preserved byte-for-byte.
|
|
;==============================================================================
|
|
|
|
MazeLayoutData_EE00:
|
|
|
|
; $EE00-$EE0F
|
|
.byte $00,$1A,$03,$1E,$90,$1D,$2D,$11
|
|
.byte $C3,$C3,$03,$11,$C3,$C3,$03,$11
|
|
|
|
; $EE10-$EE1F
|
|
.byte $2D,$11,$03,$19,$10,$1D,$03,$19
|
|
.byte $10,$18,$09,$1A,$09,$19,$10,$18
|
|
|
|
; $EE20-$EE2F
|
|
.byte $03,$1F,$10,$18,$03,$11,$2D,$11
|
|
.byte $01,$43,$11,$C3,$03,$00,$C3,$03
|
|
|
|
; $EE30-$EE3F
|
|
.byte $11,$43,$01,$11,$2D,$15,$10,$1D
|
|
.byte $03,$11,$03,$1B,$03,$1F,$90,$1D
|
|
|
|
; $EE40-$EE4F
|
|
.byte $03,$1B,$03,$11,$03,$1F,$10,$14
|
|
.byte $2D,$15,$10,$1C,$03,$1A,$03,$11
|
|
|
|
; $EE50-$EE5F
|
|
.byte $03,$1E,$10,$13,$10,$1C,$03,$11
|
|
.byte $03,$1A,$03,$1E,$10,$14,$2D,$11
|
|
|
|
; $EE60-$EE6F
|
|
.byte $C3,$03,$11,$83,$11,$83,$11,$C3
|
|
.byte $03,$11,$2D,$11,$03,$19,$90,$12
|
|
|
|
; $EE70-$EE7F
|
|
.byte $10,$18,$03,$1A,$03,$19,$10,$12
|
|
.byte $90,$18,$03,$11,$2D,$11,$C3,$C3
|
|
|
|
; $EE80-$EE8B
|
|
.byte $C3,$C3,$83,$11,$2D,$1E,$D0,$D0
|
|
.byte $D0,$D0,$90,$1C
|
|
|
|
|
|
;==============================================================================
|
|
; $EE8C-$EECF: Initialize Runtime Work Buffers
|
|
;
|
|
; Initializes zero-page runtime pointers and hardware state, clears $0600-$060F,
|
|
; then clears sixteen locations at eight-byte intervals beginning at $0620.
|
|
;==============================================================================
|
|
|
|
InitializeAudioEngine:
|
|
lda #$00
|
|
sta audioRequestPtr
|
|
|
|
lda #$06
|
|
sta audioRequestPtr+1
|
|
|
|
lda #$20
|
|
sta audioChannelTablePtr
|
|
|
|
lda #$06
|
|
sta audioChannelTablePtr+1
|
|
|
|
lda $F100
|
|
sta audioSequenceTablePtr
|
|
|
|
lda $F101
|
|
sta audioSequenceTablePtr+1
|
|
|
|
lda #$40
|
|
sta audioWorkValue
|
|
|
|
lda #$1F
|
|
sta APUSTATUS
|
|
|
|
lda #$C0
|
|
sta APUFRAMECNT
|
|
|
|
ldy #$00
|
|
|
|
lda #$00
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EEB8
|
|
; Clear sixteen contiguous bytes through ($F0).
|
|
;------------------------------------------------------------------------------
|
|
|
|
RuntimeInit_Clear0600:
|
|
sta (audioRequestPtr),y
|
|
|
|
iny
|
|
cpy #$10
|
|
bne RuntimeInit_Clear0600
|
|
|
|
ldy #$00
|
|
ldx #$10
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EEC3
|
|
; Clear sixteen entries at an eight-byte stride.
|
|
;
|
|
; LDA #$00 is intentionally executed on every iteration.
|
|
;------------------------------------------------------------------------------
|
|
RuntimeInit_Clear0620Stride:
|
|
lda #$00
|
|
sta (audioChannelTablePtr),y
|
|
|
|
tya
|
|
clc
|
|
adc #$08
|
|
tay
|
|
|
|
dex
|
|
bne RuntimeInit_Clear0620Stride
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $EED0-$EF2C: Initialize and Scan Runtime Command Slots
|
|
;
|
|
; Clears runtime work values, then scans sixteen 8-byte entries addressed
|
|
; through $F2/$F3. Occupied entries update flags through $FE/$FF, while newly
|
|
; activated entries copy four bytes through the pointer selected in $F6.
|
|
;
|
|
; Execution falls through at $EF2D into the next processing phase.
|
|
;==============================================================================
|
|
|
|
InitializeAudioChannels:
|
|
lda #$00
|
|
sta audioChannelFlags
|
|
sta $F9
|
|
sta $FA
|
|
sta $FB
|
|
sta audioChannelOffset
|
|
sta $FF
|
|
|
|
lda #$F8
|
|
sta audioIndirectPtr
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EEE2
|
|
; Examine one eight-byte slot.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ScanAudioChannelSlot:
|
|
ldy $FD
|
|
|
|
lda (audioChannelTablePtr),y
|
|
beq AdvanceAudioChannelSlot
|
|
|
|
cmp #$05
|
|
bcc ActivateAudioChannelSlot
|
|
|
|
sec
|
|
sbc #$05
|
|
tay
|
|
|
|
lda #$01
|
|
sta ($FE),y
|
|
|
|
jmp AdvanceAudioChannelSlot
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EEF5
|
|
; Process slot values $01-$04.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ActivateAudioChannelSlot:
|
|
sec
|
|
sbc #$01
|
|
tay
|
|
|
|
lda ($FE),y
|
|
bne AdvanceAudioChannelSlot
|
|
|
|
lda #$01
|
|
sta ($FE),y
|
|
|
|
tya
|
|
tax
|
|
|
|
adc #$04
|
|
|
|
ldy $FD
|
|
sta ($F2),y
|
|
|
|
txa
|
|
asl
|
|
asl
|
|
sta $F6
|
|
|
|
ldx #$00
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EF12
|
|
; Set initial four-byte copy count.
|
|
;------------------------------------------------------------------------------
|
|
|
|
BeginAudioChannelParameterCopy:
|
|
lda #$04
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EF14
|
|
; Push the current copy count.
|
|
;
|
|
; The loop at $EF20 deliberately returns here, so PHA is repeated on every
|
|
; iteration.
|
|
;------------------------------------------------------------------------------
|
|
|
|
CopyAudioChannelParameter:
|
|
pha
|
|
|
|
iny
|
|
|
|
lda ($F2),y
|
|
sta ($F6,x)
|
|
|
|
inc $F6
|
|
|
|
pla
|
|
|
|
sec
|
|
sbc #$01
|
|
bne CopyAudioChannelParameter
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EF22
|
|
; Advance to the next eight-byte slot.
|
|
;------------------------------------------------------------------------------
|
|
|
|
AdvanceAudioChannelSlot:
|
|
lda $FD
|
|
clc
|
|
adc #$08
|
|
sta $FD
|
|
|
|
cmp #$80
|
|
bcc ScanAudioChannelSlot
|
|
|
|
; Fall through to $EF2D.
|
|
|
|
|
|
;==============================================================================
|
|
; $EF2D-$F006: Process Runtime Command Entries
|
|
;
|
|
; Continuation of the runtime command-slot scan.
|
|
;
|
|
; $FC indexes source commands through ($F0).
|
|
; $FD indexes eight-byte runtime records through ($F2).
|
|
;
|
|
; Empty runtime records are initialized from tables through $F4/$F5 and
|
|
; command bytes fetched through the helper at $F0C3. Active records update
|
|
; countdowns and command parameters before both indices advance.
|
|
;==============================================================================
|
|
|
|
UpdateAudioChannels:
|
|
ldy #$00
|
|
sty $FC
|
|
sty $FD
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EF33
|
|
; Process one source entry.
|
|
;------------------------------------------------------------------------------
|
|
|
|
UpdateNextAudioSequence:
|
|
ldy $FC
|
|
|
|
lda ($F0),y
|
|
bne CheckAudioChannelActive
|
|
|
|
jmp AdvanceAudioSequence
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EF3B
|
|
; Check the corresponding runtime record.
|
|
;------------------------------------------------------------------------------
|
|
|
|
CheckAudioChannelActive:
|
|
ldy $FD
|
|
|
|
lda ($F2),y
|
|
bne TickAudioChannelDelay
|
|
|
|
lda $FC
|
|
asl
|
|
tay
|
|
|
|
lda ($F4),y
|
|
pha
|
|
|
|
lda $FD
|
|
adc #$05
|
|
tay
|
|
|
|
pla
|
|
sta ($F2),y
|
|
|
|
lda $FC
|
|
asl
|
|
adc #$01
|
|
tay
|
|
|
|
lda ($F4),y
|
|
pha
|
|
|
|
lda $FD
|
|
adc #$06
|
|
tay
|
|
|
|
pla
|
|
sta ($F2),y
|
|
|
|
jsr $F0C3
|
|
|
|
ldy $FD
|
|
sta ($F2),y
|
|
|
|
jsr $F0C3
|
|
tax
|
|
|
|
lda $FD
|
|
clc
|
|
adc #$01
|
|
tay
|
|
|
|
txa
|
|
sta ($F2),y
|
|
|
|
jsr $F0C3
|
|
tax
|
|
|
|
lda $FD
|
|
clc
|
|
adc #$02
|
|
tay
|
|
|
|
txa
|
|
sta ($F2),y
|
|
|
|
jsr $F0C3
|
|
tax
|
|
|
|
lda $FD
|
|
clc
|
|
adc #$04
|
|
tay
|
|
|
|
txa
|
|
sta ($F2),y
|
|
|
|
jmp DecodeAudioCommand
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EF94
|
|
; Decrement the active record countdown at offset 7.
|
|
;------------------------------------------------------------------------------
|
|
|
|
TickAudioChannelDelay:
|
|
lda $FD
|
|
clc
|
|
adc #$07
|
|
tay
|
|
|
|
lda ($F2),y
|
|
sec
|
|
sbc #$01
|
|
sta ($F2),y
|
|
|
|
bne AdvanceAudioSequence
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EFA2
|
|
; Fetch and decode the next runtime command byte.
|
|
;------------------------------------------------------------------------------
|
|
|
|
DecodeAudioCommand:
|
|
jsr $F0C3
|
|
|
|
cmp #$F0
|
|
bcs $F00D
|
|
|
|
cmp #$C0
|
|
bcs LoadAudioCommandDelay
|
|
|
|
pha
|
|
|
|
and #$F0
|
|
lsr
|
|
lsr
|
|
lsr
|
|
tax
|
|
|
|
lda AudioFrequencyLookupTable,x
|
|
sta $FE
|
|
|
|
lda AudioFrequencyLookupTable+1,x
|
|
sta $FF
|
|
|
|
pla
|
|
|
|
and #$0F
|
|
beq ApplyAudioFrequencyMask
|
|
|
|
tax
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EFC4
|
|
; Shift the selected mask by the command low nibble.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ShiftAudioFrequencyMask:
|
|
lsr $FE
|
|
ror $FF
|
|
|
|
dex
|
|
bne ShiftAudioFrequencyMask
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EFCB
|
|
; Merge the generated mask into the runtime record.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ApplyAudioFrequencyMask:
|
|
lda $FD
|
|
clc
|
|
adc #$04
|
|
tay
|
|
|
|
lda ($F2),y
|
|
and #$F8
|
|
ora $FE
|
|
sta ($F2),y
|
|
|
|
lda $FF
|
|
dey
|
|
sta ($F2),y
|
|
|
|
ldy $FD
|
|
|
|
lda ($F2),y
|
|
cmp #$05
|
|
bcc LoadAudioCommandDelay
|
|
|
|
sec
|
|
sbc #$04
|
|
sta ($F2),y
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EFEB
|
|
; Load the new runtime countdown.
|
|
;------------------------------------------------------------------------------
|
|
|
|
LoadAudioCommandDelay:
|
|
jsr $F0C3
|
|
pha
|
|
|
|
lda $FD
|
|
clc
|
|
adc #$07
|
|
tay
|
|
|
|
pla
|
|
sta ($F2),y
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EFF8
|
|
; Advance to the next runtime/source entry.
|
|
;------------------------------------------------------------------------------
|
|
|
|
AdvanceAudioSequence:
|
|
lda $FD
|
|
clc
|
|
adc #$08
|
|
sta $FD
|
|
|
|
lda $FC
|
|
adc #$01
|
|
sta $FC
|
|
|
|
cmp #$10
|
|
|
|
; Fall through at $F007 to the next control-flow block.
|
|
|
|
;==============================================================================
|
|
; $F007-$F00C: Runtime command-loop termination / continuation
|
|
;
|
|
; Entry is the fall-through from the CMP #$10 at $F005.
|
|
;==============================================================================
|
|
|
|
FinishAudioSequenceScan:
|
|
bcs AudioSequenceUpdateDone
|
|
|
|
jmp UpdateNextAudioSequence
|
|
|
|
|
|
AudioSequenceUpdateDone:
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $F00D-$F01D: Runtime Command Dispatcher
|
|
;
|
|
; Input:
|
|
; A = command byte >= $F0
|
|
;
|
|
; Uses the low nibble to select a handler through the pointer table at $F01E.
|
|
;==============================================================================
|
|
|
|
DispatchAudioCommand:
|
|
and #$0F
|
|
asl
|
|
tax
|
|
|
|
lda AudioCommandHandlerTable,x
|
|
sta $FE
|
|
|
|
lda AudioCommandHandlerTable+1,x
|
|
sta $FF
|
|
|
|
jmp ($00FE)
|
|
|
|
|
|
;==============================================================================
|
|
; $F01E-$F03D: Runtime Command Handler Table
|
|
;
|
|
; Sixteen 16-bit handlers. Unsupported command values use the no-op handler
|
|
; at $F03E.
|
|
;==============================================================================
|
|
|
|
AudioCommandHandlerTable:
|
|
.word StopAudioSequence ; $F0
|
|
.word AudioCommandF1 ; $F1
|
|
.word AudioCommandF2 ; $F2
|
|
.word AudioCommandF3 ; $F3
|
|
.word AudioCommandF4 ; $F4
|
|
.word AudioCommandF5 ; $F5
|
|
.word AudioCommandF6 ; $F6
|
|
.word StopAudioSequence ; $F7
|
|
.word StopAudioSequence ; $F8
|
|
.word StopAudioSequence ; $F9
|
|
.word StopAudioSequence ; $FA
|
|
.word StopAudioSequence ; $FB
|
|
.word StopAudioSequence ; $FC
|
|
.word StopAudioSequence ; $FD
|
|
.word StopAudioSequence ; $FE
|
|
.word StopAudioSequence ; $FF
|
|
|
|
|
|
;==============================================================================
|
|
; $F03E-$F04A: Runtime command no-op/terminate handler
|
|
;
|
|
; Clears the current source entry and current runtime record, then advances
|
|
; through the common continuation at $EFF8.
|
|
;==============================================================================
|
|
|
|
StopAudioSequence:
|
|
ldy $FC
|
|
|
|
lda #$00
|
|
sta ($F0),y
|
|
|
|
ldy $FD
|
|
sta ($F2),y
|
|
|
|
jmp AdvanceAudioSequence
|
|
|
|
|
|
;==============================================================================
|
|
; $F04B-$F062: Runtime command $F1
|
|
;
|
|
; Fetches one command byte and merges its bits into runtime-record byte 0/1.
|
|
;==============================================================================
|
|
|
|
AudioCommandF1:
|
|
jsr FetchAudioSequenceByte
|
|
pha
|
|
|
|
lda $FD
|
|
clc
|
|
adc #$01
|
|
tay
|
|
|
|
lda ($F2),y
|
|
and #$3F
|
|
sta ($F2),y
|
|
|
|
pla
|
|
ora ($F2),y
|
|
sta ($F2),y
|
|
|
|
jmp DecodeAudioCommand
|
|
|
|
;==============================================================================
|
|
; $F063-$F07A: Runtime command $F2
|
|
;==============================================================================
|
|
|
|
AudioCommandF2:
|
|
jsr FetchAudioSequenceByte
|
|
pha
|
|
|
|
lda $FD
|
|
clc
|
|
adc #$01
|
|
tay
|
|
|
|
lda ($F2),y
|
|
and #$CF
|
|
sta ($F2),y
|
|
|
|
pla
|
|
ora ($F2),y
|
|
sta ($F2),y
|
|
|
|
jmp DecodeAudioCommand
|
|
|
|
;==============================================================================
|
|
; $F07B-$F092: Runtime command $F3
|
|
;==============================================================================
|
|
|
|
AudioCommandF3:
|
|
jsr FetchAudioSequenceByte
|
|
pha
|
|
|
|
lda $FD
|
|
clc
|
|
adc #$01
|
|
tay
|
|
|
|
lda ($F2),y
|
|
and #$F0
|
|
sta ($F2),y
|
|
|
|
pla
|
|
ora ($F2),y
|
|
sta ($F2),y
|
|
|
|
jmp DecodeAudioCommand
|
|
|
|
;==============================================================================
|
|
; $F093-$F0A2: Runtime command $F4
|
|
;==============================================================================
|
|
|
|
AudioCommandF4:
|
|
jsr FetchAudioSequenceByte
|
|
pha
|
|
|
|
lda $FD
|
|
clc
|
|
adc #$02
|
|
tay
|
|
|
|
pla
|
|
sta ($F2),y
|
|
|
|
jmp DecodeAudioCommand
|
|
|
|
;==============================================================================
|
|
; $F0A3-$F0B2: Runtime command $F5
|
|
;==============================================================================
|
|
|
|
AudioCommandF5:
|
|
jsr FetchAudioSequenceByte
|
|
pha
|
|
|
|
lda $FD
|
|
clc
|
|
adc #$04
|
|
tay
|
|
|
|
pla
|
|
sta ($F2),y
|
|
|
|
jmp DecodeAudioCommand
|
|
|
|
;==============================================================================
|
|
; $F0B3-$F0C2: Runtime command $F6
|
|
;==============================================================================
|
|
|
|
AudioCommandF6:
|
|
jsr FetchAudioSequenceByte
|
|
pha
|
|
|
|
lda $FD
|
|
clc
|
|
adc #$01
|
|
tay
|
|
|
|
pla
|
|
sta ($F2),y
|
|
|
|
jmp DecodeAudioCommand
|
|
|
|
;==============================================================================
|
|
; $F0C3-$F0E7: Fetch Runtime Command Byte
|
|
;
|
|
; Uses the 16-bit source pointer stored in runtime-record bytes +5/+6.
|
|
;
|
|
; Output:
|
|
; A = byte read from the command stream
|
|
;
|
|
; Side effect:
|
|
; Advances the source pointer by one and writes it back into bytes +5/+6.
|
|
;==============================================================================
|
|
|
|
FetchAudioSequenceByte:
|
|
lda $FD
|
|
clc
|
|
adc #$05
|
|
tay
|
|
|
|
lda ($F2),y
|
|
sta $FE
|
|
|
|
iny
|
|
|
|
lda ($F2),y
|
|
sta $FF
|
|
|
|
ldx #$00
|
|
|
|
lda ($FE,x)
|
|
pha
|
|
|
|
lda $FE
|
|
|
|
dey
|
|
clc
|
|
adc #$01
|
|
sta ($F2),y
|
|
|
|
lda $FF
|
|
adc #$00
|
|
|
|
iny
|
|
sta ($F2),y
|
|
|
|
pla
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $F0E8-$F14F: Runtime / Audio Lookup Data
|
|
;
|
|
; Raw data preserved byte-for-byte.
|
|
;
|
|
; The first portion is referenced by UpdateAudioChannels through
|
|
; $F0E8,X / $F0E9,X as paired mask values. Later portions appear to contain
|
|
; additional pointers and command/parameter data.
|
|
;
|
|
; Semantic subdivision is deferred until all consumers are decoded.
|
|
;==============================================================================
|
|
AudioFrequencyLookupTable:
|
|
; $F0E8-$F0F7
|
|
.byte $03,$F9,$03,$C0,$03,$8A,$03,$57
|
|
.byte $03,$27,$02,$FA,$02,$CF,$02,$A7
|
|
|
|
; $F0F8-$F107
|
|
.byte $02,$81,$02,$5D,$02,$3B,$02,$1B
|
|
.byte $02,$F1,$CB,$F3,$14,$F4,$22,$F1
|
|
|
|
; $F108-$F117
|
|
.byte $3C,$F3,$3F,$F4,$50,$F4,$37,$F1
|
|
.byte $E4,$F1,$1D,$F3,$CF,$F1,$62,$F1
|
|
|
|
; $F118-$F127
|
|
.byte $8D,$F1,$B0,$F1,$07,$F2,$7A,$F2
|
|
.byte $61,$F4,$01,$03,$7F,$08,$A2,$0C
|
|
|
|
; $F128-$F137
|
|
.byte $A2,$0C,$A2,$0C,$A2,$0C,$A2,$0C
|
|
.byte $A2,$0C,$A2,$0C,$A2,$0C,$F0,$03
|
|
|
|
; $F138-$F147
|
|
.byte $04,$7F,$08,$33,$01,$23,$01,$03
|
|
.byte $01,$A2,$01,$92,$01,$72,$01,$52
|
|
|
|
; $F148-$F14F
|
|
.byte $01,$32,$01,$22,$01,$02,$01,$A1
|
|
|
|
|
|
|
|
;==============================================================================
|
|
; $F150-$F24F: Runtime / Audio Command Data
|
|
;
|
|
; Raw data preserved byte-for-byte.
|
|
;
|
|
; The region contains strongly patterned pairs and command-like values used
|
|
; by the late-PRG runtime/audio interpreter. Semantic subdivision is deferred
|
|
; until its individual consumers are mapped.
|
|
;==============================================================================
|
|
AudioSequenceData_F150:
|
|
; $F150-$F15F
|
|
.byte $01,$91,$01,$C0,$08,$91,$01,$A1
|
|
.byte $01,$02,$01,$22,$01,$32,$01,$52
|
|
|
|
; $F160-$F16F
|
|
.byte $01,$F0,$01,$96,$7F,$28,$82,$01
|
|
.byte $92,$01,$A2,$01,$B2,$01,$03,$01
|
|
|
|
; $F170-$F17F
|
|
.byte $13,$01,$23,$01,$33,$01,$43,$01
|
|
.byte $53,$01,$33,$01,$23,$01,$13,$01
|
|
|
|
; $F180-$F18F
|
|
.byte $03,$01,$B2,$01,$A2,$01,$92,$01
|
|
.byte $82,$01,$72,$01,$F0,$01,$96,$7F
|
|
|
|
; $F190-$F19F
|
|
.byte $28,$A2,$01,$B2,$01,$03,$01,$13
|
|
.byte $01,$23,$01,$33,$01,$43,$01,$53
|
|
|
|
; $F1A0-$F1AF
|
|
.byte $01,$33,$01,$23,$01,$13,$01,$03
|
|
.byte $01,$B2,$01,$A2,$01,$92,$01,$F0
|
|
|
|
; $F1B0-$F1BF
|
|
.byte $01,$96,$7F,$28,$B2,$01,$03,$01
|
|
.byte $13,$01,$23,$01,$33,$01,$43,$01
|
|
|
|
; $F1C0-$F1CF
|
|
.byte $53,$01,$33,$01,$23,$01,$13,$01
|
|
.byte $03,$01,$B2,$01,$A2,$01,$F0,$02
|
|
|
|
; $F1D0-$F1DF
|
|
.byte $9C,$7F,$28,$31,$01,$71,$01,$A1
|
|
.byte $01,$12,$01,$32,$01,$72,$01,$A2
|
|
|
|
; $F1E0-$F1EF
|
|
.byte $01,$13,$01,$F0,$02,$00,$7F,$10
|
|
.byte $20,$03,$50,$03,$80,$02,$A0,$02
|
|
|
|
; $F1F0-$F1FF
|
|
.byte $21,$02,$51,$02,$81,$01,$A1,$01
|
|
.byte $02,$01,$22,$01,$32,$01,$52,$01
|
|
|
|
; $F200-$F20F
|
|
.byte $F5,$18,$73,$01,$C0,$08,$F0,$01
|
|
.byte $03,$7F,$08,$72,$02,$82,$08,$72
|
|
|
|
; $F210-$F21F
|
|
.byte $02,$82,$08,$72,$02,$82,$08,$42
|
|
.byte $02,$52,$04,$32,$04,$82,$06,$82
|
|
|
|
; $F220-$F22F
|
|
.byte $08,$B2,$02,$03,$10,$C0,$08,$72
|
|
.byte $02,$82,$08,$72,$02,$82,$08,$72
|
|
|
|
; $F230-$F23F
|
|
.byte $02,$82,$08,$42,$02,$52,$04,$32
|
|
.byte $04,$82,$06,$82,$08,$42,$02,$52
|
|
|
|
; $F240-$F24F
|
|
.byte $10,$C0,$08,$72,$02,$82,$08,$72
|
|
.byte $02,$82,$08,$72,$02,$82,$08,$42
|
|
|
|
;==============================================================================
|
|
; $F250-$F34F: Runtime / Audio Command Data
|
|
;
|
|
; Raw data preserved byte-for-byte.
|
|
; Semantic subdivision is deferred until the individual stream consumers are
|
|
; fully mapped.
|
|
;==============================================================================
|
|
|
|
AudioSequenceData_F250:
|
|
|
|
; $F250-$F25F
|
|
.byte $02,$52,$04,$32,$04,$82,$06,$82
|
|
.byte $08,$A2,$02,$B2,$08,$03,$02,$13
|
|
|
|
; $F260-$F26F
|
|
.byte $0A,$13,$02,$23,$0C,$03,$02,$13
|
|
.byte $08,$A2,$02,$B2,$08,$82,$0A,$A2
|
|
|
|
; $F270-$F27F
|
|
.byte $02,$B2,$0A,$72,$02,$82,$10,$C0
|
|
.byte $08,$F0,$02,$81,$7F,$40,$80,$08
|
|
|
|
; $F280-$F28F
|
|
.byte $C0,$06,$80,$04,$C0,$02,$80,$08
|
|
.byte $C0,$06,$80,$04,$C0,$02,$80,$08
|
|
|
|
; $F290-$F29F
|
|
.byte $C0,$06,$80,$04,$C0,$02,$01,$04
|
|
.byte $C0,$01,$11,$04,$C0,$01,$21,$04
|
|
|
|
; $F2A0-$F2AF
|
|
.byte $C0,$01,$31,$04,$C0,$01,$80,$08
|
|
.byte $C0,$06,$80,$04,$C0,$02,$80,$08
|
|
|
|
; $F2B0-$F2BF
|
|
.byte $C0,$06,$80,$04,$C0,$02,$80,$08
|
|
.byte $C0,$06,$80,$04,$C0,$02,$01,$04
|
|
|
|
; $F2C0-$F2CF
|
|
.byte $C0,$01,$11,$04,$C0,$01,$21,$04
|
|
.byte $C0,$01,$31,$04,$C0,$01,$80,$08
|
|
|
|
; $F2D0-$F2DF
|
|
.byte $C0,$06,$80,$04,$C0,$02,$80,$08
|
|
.byte $C0,$06,$80,$04,$C0,$02,$80,$08
|
|
|
|
; $F2E0-$F2EF
|
|
.byte $C0,$06,$80,$04,$C0,$02,$01,$04
|
|
.byte $C0,$01,$11,$04,$C0,$01,$21,$04
|
|
|
|
; $F2F0-$F2FF
|
|
.byte $C0,$01,$31,$04,$C0,$01,$81,$0A
|
|
.byte $31,$04,$C0,$01,$21,$04,$C0,$01
|
|
|
|
; $F300-$F30F
|
|
.byte $11,$04,$C0,$01,$B0,$04,$C0,$01
|
|
.byte $80,$04,$C0,$01,$70,$04,$C0,$01
|
|
|
|
; $F310-$F31F
|
|
.byte $60,$08,$C0,$02,$70,$08,$C0,$02
|
|
.byte $80,$0C,$C0,$06,$F0,$02,$98,$7F
|
|
|
|
; $F320-$F32F
|
|
.byte $28,$33,$01,$23,$01,$13,$01,$03
|
|
.byte $01,$A2,$01,$82,$01,$72,$01,$52
|
|
|
|
; $F330-$F33F
|
|
.byte $01,$32,$01,$12,$01,$A1,$01,$71
|
|
.byte $01,$31,$01,$F0,$01,$42,$7F,$38
|
|
|
|
; $F340-$F34F
|
|
.byte $23,$02,$33,$02,$43,$02,$53,$02
|
|
.byte $43,$02,$33,$02,$23,$02,$13,$02
|
|
|
|
;==============================================================================
|
|
; $F350-$F44F: Runtime / Audio Command Data
|
|
;
|
|
; Raw command/parameter stream preserved byte-for-byte.
|
|
; Semantic subdivision is deferred until all stream consumers are mapped.
|
|
;==============================================================================
|
|
|
|
AudioSequenceData_F350:
|
|
|
|
; $F350-$F35F
|
|
.byte $23,$02,$33,$02,$43,$02,$33,$02
|
|
.byte $23,$02,$13,$02,$03,$02,$13,$02
|
|
|
|
; $F360-$F36F
|
|
.byte $23,$02,$33,$02,$23,$02,$13,$02
|
|
.byte $03,$02,$B2,$02,$03,$02,$13,$02
|
|
|
|
; $F370-$F37F
|
|
.byte $23,$02,$13,$02,$03,$02,$B2,$02
|
|
.byte $A2,$02,$B2,$02,$03,$02,$23,$02
|
|
|
|
; $F380-$F38F
|
|
.byte $03,$02,$B2,$02,$A2,$02,$92,$02
|
|
.byte $A2,$02,$B2,$02,$03,$02,$B2,$02
|
|
|
|
; $F390-$F39F
|
|
.byte $A2,$02,$92,$02,$82,$02,$92,$02
|
|
.byte $A2,$02,$03,$02,$A2,$02,$92,$02
|
|
|
|
; $F3A0-$F3AF
|
|
.byte $82,$02,$F2,$00,$F3,$00,$F5,$18
|
|
.byte $31,$01,$71,$01,$B1,$01,$32,$01
|
|
|
|
; $F3B0-$F3BF
|
|
.byte $72,$01,$B2,$01,$33,$01,$73,$01
|
|
.byte $C0,$02,$31,$01,$71,$01,$B1,$01
|
|
|
|
; $F3C0-$F3CF
|
|
.byte $32,$01,$72,$01,$B2,$01,$33,$01
|
|
.byte $73,$01,$F0,$01,$81,$7F,$40,$31
|
|
|
|
; $F3D0-$F3DF
|
|
.byte $08,$32,$08,$A1,$08,$71,$08,$32
|
|
.byte $07,$A1,$07,$71,$0C,$C0,$06,$41
|
|
|
|
; $F3E0-$F3EF
|
|
.byte $08,$42,$08,$B1,$08,$81,$08,$42
|
|
.byte $07,$B1,$07,$81,$0C,$C0,$06,$31
|
|
|
|
; $F3F0-$F3FF
|
|
.byte $08,$32,$08,$A1,$08,$71,$08,$32
|
|
.byte $07,$A1,$07,$71,$0C,$C0,$06,$61
|
|
|
|
; $F400-$F40F
|
|
.byte $05,$71,$05,$81,$05,$81,$05,$91
|
|
.byte $05,$A1,$05,$A1,$05,$B1,$05,$02
|
|
|
|
; $F410-$F41F
|
|
.byte $05,$32,$0C,$F0,$02,$82,$7F,$40
|
|
.byte $30,$18,$A0,$08,$30,$0E,$A0,$0C
|
|
|
|
; $F420-$F42F
|
|
.byte $C0,$06,$40,$18,$B0,$08,$40,$0E
|
|
.byte $B0,$0C,$C0,$06,$30,$18,$A0,$08
|
|
|
|
; $F430-$F43F
|
|
.byte $30,$0E,$A0,$0C,$C0,$06,$A0,$0F
|
|
.byte $01,$0F,$21,$0F,$31,$0C,$F0,$01
|
|
|
|
; $F440-$F44F
|
|
.byte $9F,$7F,$28,$01,$01,$41,$01,$71
|
|
.byte $01,$A1,$01,$02,$01,$F5,$18,$F0
|
|
|
|
|
|
;==============================================================================
|
|
; $F450-$F49A: Runtime / Audio Command Data
|
|
;
|
|
; Raw command data preserved byte-for-byte.
|
|
;==============================================================================
|
|
|
|
AudioSequenceData_F450:
|
|
|
|
; $F450-$F45F
|
|
.byte $01,$9F,$7F,$28,$02,$01,$A1,$01
|
|
.byte $71,$01,$41,$01,$F5,$18,$01,$01
|
|
|
|
; $F460-$F46F
|
|
.byte $F0,$01,$9F,$7F,$28,$52,$01,$92
|
|
.byte $01,$03,$01,$33,$01,$F5,$18,$53
|
|
|
|
; $F470-$F47F
|
|
.byte $03,$F5,$28,$53,$01,$33,$01,$03
|
|
.byte $01,$92,$01,$F5,$18,$52,$03,$92
|
|
|
|
; $F480-$F48F
|
|
.byte $01,$13,$01,$43,$01,$73,$01,$F5
|
|
.byte $18,$93,$0A,$F5,$28,$93,$01,$73
|
|
|
|
; $F490-$F49A
|
|
.byte $01,$43,$01,$13,$01,$F5,$18,$92
|
|
.byte $03,$F0,$FF
|
|
|
|
;==============================================================================
|
|
; $F49B-$F64F: PRG Padding
|
|
;==============================================================================
|
|
.res $0B5B, $FF
|
|
|
|
|
|
;==============================================================================
|
|
; $FFF6-$FFF9: Final ROM Data
|
|
;
|
|
; Notes:
|
|
; $FFF6/$FFF7 are read directly by DrawMazeNametable:
|
|
;
|
|
; lda $FFF7
|
|
; sta $01
|
|
; lda $FFF6
|
|
; sta $00
|
|
;
|
|
; Therefore the first two bytes form the little-endian value $ECEC.
|
|
;
|
|
; $FFF8/$FFF9 form the little-endian value $C10E.
|
|
;==============================================================================
|
|
|
|
MazeDataPointerBytes:
|
|
.byte $EC,$EC
|
|
.byte $0E,$C1
|
|
|
|
;==============================================================================
|
|
; $FFFA-$FFFF: Interrupt Vectors
|
|
;==============================================================================
|
|
.org $FFFA
|
|
CpuInterruptVectors:
|
|
.word NmiHandler ; NMI
|
|
.word Reset ; Reset
|
|
.word IrqHandler ; IRQ/BRK
|