Files
disasm/Pac-Man (USA) (Namco)/copilot/prg.s
T
tmerritt 837007843d MUSCLE (U): decode the bytecode VM layer (Pass 3b)
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
2026-10-17 17:36:28 -04:00

14136 lines
468 KiB
ArmAsm

.include "symbols.inc"
.include "locals.inc"
.segment "PRG"
.org $C000
CopyrightText:
.byte $43,$4F,$50,$59,$20,$52,$49,$47 ; CPU:$C000 PRG:0000 43 4F 50 59 20 52 49 47
.byte $48,$54,$20,$31,$39,$38,$34,$20 ; CPU:$C008 PRG:0008 48 54 20 31 39 38 34 20
.byte $31,$39,$39,$33,$20,$4E,$41,$4D ; CPU:$C010 PRG:0010 31 39 39 33 20 4E 41 4D
.byte $43,$4F,$20,$4C,$54,$44,$2E,$20 ; CPU:$C018 PRG:0018 43 4F 20 4C 54 44 2E 20
.byte $41,$4C,$4C,$20,$52,$49,$47,$48 ; CPU:$C020 PRG:0020 41 4C 4C 20 52 49 47 48
.byte $54,$53,$20,$52,$45,$53,$45,$52 ; CPU:$C028 PRG:0028 54 53 20 52 45 53 45 52
.byte $56,$45,$44 ; CPU:$C030 PRG:0030 56 45 44
Reset:
ldx #$00 ; CPU:$C033 PRG:0033 A2 00
stx PPUCTRL ; CPU:$C035 PRG:0035 8E 00 20
sei ; CPU:$C038 PRG:0038 78
cld ; CPU:$C039 PRG:0039 D8
dex ; CPU:$C03A PRG:003A CA
txs ; CPU:$C03B PRG:003B 9A
nop ; CPU:$C03C PRG:003C EA
nop ; CPU:$C03D PRG:003D EA
nop ; CPU:$C03E PRG:003E EA
ldx #$02 ; CPU:$C03F PRG:003F A2 02
@WaitForPpu:
lda #$06 ; CPU:$C041 PRG:0041 A9 06
sta PPUMASK ; CPU:$C043 PRG:0043 8D 01 20
lda PPUSTATUS ; CPU:$C046 PRG:0046 AD 02 20
@WaitVBlank:
lda PPUSTATUS ; CPU:$C049 PRG:0049 AD 02 20
bpl @WaitVBlank ; CPU:$C04C PRG:004C 10 FB
lda #$00 ; CPU:$C04E PRG:004E A9 00
sta PPUSCROLL ; CPU:$C050 PRG:0050 8D 05 20
sta PPUSCROLL ; CPU:$C053 PRG:0053 8D 05 20
dex ; CPU:$C056 PRG:0056 CA
bne @WaitForPpu ; CPU:$C057 PRG:0057 D0 E8
lda #$00 ; CPU:$C059 PRG:0059 A9 00
tay ; CPU:$C05B PRG:005B A8
@ClearLowRam:
sta $0000,y ; CPU:$C05C PRG:005C 99 00 00
iny ; CPU:$C05F PRG:005F C8
cpy #$3E ; CPU:$C060 PRG:0060 C0 3E
bne @ClearLowRam ; CPU:$C062 PRG:0062 D0 F8
ldx #$08 ; CPU:$C064 PRG:0064 A2 08
ldy #$87 ; CPU:$C066 PRG:0066 A0 87
@ClearRamPages:
sta ($00),y ; CPU:$C068 PRG:0068 91 00
iny ; CPU:$C06A PRG:006A C8
bne @ClearRamPages ; CPU:$C06B PRG:006B D0 FB
inc $01 ; CPU:$C06D PRG:006D E6 01
cpx $01 ; CPU:$C06F PRG:006F E4 01
bne @ClearRamPages ; CPU:$C071 PRG:0071 D0 F5
lda #$06 ; CPU:$C073 PRG:0073 A9 06
sta PPUMASK ; CPU:$C075 PRG:0075 8D 01 20
lda #$00 ; CPU:$C078 PRG:0078 A9 00
sta PPUSCROLL ; CPU:$C07A PRG:007A 8D 05 20
sta PPUSCROLL ; CPU:$C07D PRG:007D 8D 05 20
sta $41 ; CPU:$C080 PRG:0080 85 41
sta $42 ; CPU:$C082 PRG:0082 85 42
sta PPUCTRL ; CPU:$C084 PRG:0084 8D 00 20
sta PPUMASK ; CPU:$C087 PRG:0087 8D 01 20
tay ; CPU:$C08A PRG:008A A8
@CheckRamSignature:
lda RamSignature,y ; CPU:$C08B PRG:008B B9 FF C0
cmp $0052,y ; CPU:$C08E PRG:008E D9 52 00
bne @InitializeRamSignature ; CPU:$C091 PRG:0091 D0 07
iny ; CPU:$C093 PRG:0093 C8
cpy #$0F ; CPU:$C094 PRG:0094 C0 0F
bne @CheckRamSignature ; CPU:$C096 PRG:0096 D0 F3
beq @SignatureAlreadyPresent ; CPU:$C098 PRG:0098 F0 1A
@InitializeRamSignature:
lda #$00 ; CPU:$C09A PRG:009A A9 00
tay ; CPU:$C09C PRG:009C A8
@ClearZeroPage:
sta $0000,y ; CPU:$C09D PRG:009D 99 00 00
iny ; CPU:$C0A0 PRG:00A0 C8
bne @ClearZeroPage ; CPU:$C0A1 PRG:00A1 D0 FA
ldy #$00 ; CPU:$C0A3 PRG:00A3 A0 00
@CopyRamSignature:
lda RamSignature,y ; CPU:$C0A5 PRG:00A5 B9 FF C0
sta $0052,y ; CPU:$C0A8 PRG:00A8 99 52 00
iny ; CPU:$C0AB PRG:00AB C8
cpy #$0F ; CPU:$C0AC PRG:00AC C0 0F
bne @CopyRamSignature ; CPU:$C0AE PRG:00AE D0 F5
lda #$01 ; CPU:$C0B0 PRG:00B0 A9 01
sta $64 ; CPU:$C0B2 PRG:00B2 85 64
@SignatureAlreadyPresent:
ldy #$00 ; CPU:$C0B4 PRG:00B4 A0 00
sty $3F ; CPU:$C0B6 PRG:00B6 84 3F
lda #$07 ; CPU:$C0B8 PRG:00B8 A9 07
sta $45 ; CPU:$C0BA PRG:00BA 85 45
lda #$01 ; CPU:$C0BC PRG:00BC A9 01
cmp $47 ; CPU:$C0BE PRG:00BE C5 47
bne @SkipSwap ; CPU:$C0C0 PRG:00C0 D0 19
cmp $46 ; CPU:$C0C2 PRG:00C2 C5 46
bne @SkipSwap ; CPU:$C0C4 PRG:00C4 D0 15
@SwapLoop:
lda $77,y ; CPU:$C0C6 PRG:00C6 B9 77
sta workPtr0 ; CPU:$C0C8 PRG:00C8 00 85
lda $67,y ; CPU:$C0CA PRG:00CA 00 B9
sta $77,y ; CPU:$C0CC PRG:00CC 67 00
lda workPtr0 ; CPU:$C0CE PRG:00CE 99 77
sta $67,y ; CPU:$C0D0 PRG:00D0 00 A5
iny ; CPU:$C0D2 PRG:00D2 00
cpy #$10 ; CPU:$C0D3 PRG:00D3 99 67
bne @SwapLoop ; CPU:$C0D5 PRG:00D5 00 C8
@SkipSwap:
lda #$1F ; CPU:$C0D7 PRG:00D7 C0 10
sta APUCTRL ; CPU:$C0D9 PRG:00D9 D0 EB A9
lda #$C0 ; CPU:$C0DC PRG:00DC 1F 8D
sta APUFRAMECNT ; CPU:$C0DE PRG:00DE 15 40 A9
jsr InitializeAudioEngine ; CPU:$C0E1 PRG:00E1 C0 8D 17
jsr $EEB4 ; CPU:$C0E4 PRG:00E4 40 20 8C
lda #$88 ; CPU:$C0E7 PRG:00E7 EE 20
sta $43 ; CPU:$C0E9 PRG:00E9 B4 EE
sta PPUCTRL ; CPU:$C0EB PRG:00EB A9 88 85
lda #$FF ; CPU:$C0EE PRG:00EE 43 8D
sta $48 ; CPU:$C0F0 PRG:00F0 00 20
sta $023F ; CPU:$C0F2 PRG:00F2 A9 FF 85
sta $024B ; CPU:$C0F5 PRG:00F5 48 8D 3F
jmp MainEntry ; CPU:$C0F8 PRG:00F8 02 8D 4B
RamSignature:
.byte "HIROKI AOYAGI" ; CPU:$C0FF PRG:00FF 48
.byte $AA, $55 ; CPU:$C100 PRG:0100 49 52
;==============================================================================
; $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 ; CPU:$C10E PRG:010E 48
txa ; CPU:$C10F PRG:010F 8A
pha ; CPU:$C110 PRG:0110 48
tya ; CPU:$C111 PRG:0111 98
pha ; CPU:$C112 PRG:0112 48
lda #$1E ; CPU:$C113 PRG:0113 A9 1E
sta PPUMASK ; CPU:$C115 PRG:0115 8D 01 20
lda #$00 ; CPU:$C118 PRG:0118 A9 00
sta OAMADDR ; CPU:$C11A PRG:011A 8D 03 20
sta $40 ; CPU:$C11D PRG:011D 85 40
lda $45 ; CPU:$C11F PRG:011F A5 45
sta OAMDMA ; CPU:$C121 PRG:0121 8D 14 40
jsr FlushGameplayPpuUpdates ; CPU:$C124 PRG:0124 20 7E DE
jsr ReadNearbyNametableTiles ; CPU:$C127 PRG:0127 20 A2 E2
jsr UpdatePalettes ; CPU:$C12A PRG:012A 20 7F C1
; Restore the two PPU scroll components.
lda $41 ; CPU:$C12D PRG:012D A5 41
sta PPUSCROLL ; CPU:$C12F PRG:012F 8D 05 20
lda $42 ; CPU:$C132 PRG:0132 A5 42
sta PPUSCROLL ; CPU:$C134 PRG:0134 8D 05 20
; Construct the PPUCTRL value for this frame.
lda $47 ; CPU:$C137 PRG:0137 A5 47
and $46 ; CPU:$C139 PRG:0139 25 46
and #$01 ; CPU:$C13B PRG:013B 29 01
asl ; CPU:$C13D PRG:013D 0A
ora $43 ; CPU:$C13E PRG:013E 05 43
sta PPUCTRL ; CPU:$C140 PRG:0140 8D 00 20
; Strobe the controller ports.
lda #$01 ; CPU:$C143 PRG:0143 A9 01
sta JOY1 ; CPU:$C145 PRG:0145 8D 16 40
lda #$00 ; CPU:$C148 PRG:0148 A9 00
sta JOY1 ; CPU:$C14A PRG:014A 8D 16 40
; Read eight serial bits from both controllers.
ldx #$08 ; CPU:$C14D PRG:014D A2 08
@ReadControllers:
lda JOY1 ; CPU:$C14F PRG:014F AD 16 40
and #$03 ; CPU:$C152 PRG:0152 29 03
cmp #$01 ; CPU:$C154 PRG:0154 C9 01
ror $4D ; CPU:$C156 PRG:0156 66
lda APUFRAMECNT ; CPU:$C157 PRG:0157 4D AD 17
and #$03 ; CPU:$C15A PRG:015A 40 29
cmp #$01 ; CPU:$C15C PRG:015C 03 C9
ror $4E ; CPU:$C15E PRG:015E 01
dex ; CPU:$C15F PRG:015F 66
bne @ReadControllers ; CPU:$C160 PRG:0160 4E CA
; Controller 1 is the default input source.
ldx currentInput ; CPU:$C162 PRG:0162 D0 EB
; Under the condition controlled by $46/$47,
; use controller 2 instead.
lda cocktailModeFlag ; CPU:$C164 PRG:0164 A6 4D
and activePlayerFlag ; CPU:$C166 PRG:0166 A5 46
beq @ControllerSelected ; CPU:$C168 PRG:0168 25 47
ldx newlyPressedInput ; CPU:$C16A PRG:016A F0 02
@ControllerSelected:
stx previousInput ; CPU:$C16C PRG:016C A6 4E
; Advance a per-frame counter.
inc frameCounter ; CPU:$C16E PRG:016E 86 4F
; $48 gates an additional per-frame routine.
lda $48 ; CPU:$C170 PRG:0170 E6 4B
bne @NmiDone ; CPU:$C172 PRG:0172 A5 48
jsr InitializeAudioChannels ; CPU:$C174 PRG:0174 D0 03 20
@NmiDone:
pla ; CPU:$C177 PRG:0177 D0
tay ; CPU:$C178 PRG:0178 EE
pla ; CPU:$C179 PRG:0179 68
tax ; CPU:$C17A PRG:017A A8
pla ; CPU:$C17B PRG:017B 68
IrqHandler:
rti ; CPU:$C17E PRG:017E 40
UpdatePalettes:
lda $0299 ; CPU:$C17F PRG:017F AD 99 02
cmp #$0F ; CPU:$C182 PRG:0182 C9 0F
bne @CheckSecondPalette ; CPU:$C184 PRG:0184 D0 1A
lda PPUSTATUS ; CPU:$C186 PRG:0186 AD 02 20
lda #$3F ; CPU:$C189 PRG:0189 A9 3F
sta PPUADDR ; CPU:$C18B PRG:018B 8D 06 20
lda #$00 ; CPU:$C18E PRG:018E A9 00
sta PPUADDR ; CPU:$C190 PRG:0190 8D 06 20
ldy #$00 ; CPU:$C193 PRG:0193 A0 00
@CopyFirstPalette:
lda $0299,y ; CPU:$C195 PRG:0195 B9 99 02
sta PPUDATA ; CPU:$C198 PRG:0198 8D 07 20
iny ; CPU:$C19B PRG:019B C8
cpy #$10 ; CPU:$C19C PRG:019C C0 10
bne @CopyFirstPalette ; CPU:$C19E PRG:019E D0 F5
@CheckSecondPalette:
lda $02A9 ; CPU:$C1A0 PRG:01A0 AD A9 02
cmp #$0F ; CPU:$C1A3 PRG:01A3 C9 0F
bne @CheckPaletteState ; CPU:$C1A5 PRG:01A5 D0 1A
lda PPUSTATUS ; CPU:$C1A7 PRG:01A7 AD 02 20
lda #$3F ; CPU:$C1AA PRG:01AA A9 3F
sta PPUADDR ; CPU:$C1AC PRG:01AC 8D 06 20
lda #$10 ; CPU:$C1AF PRG:01AF A9 10
sta PPUADDR ; CPU:$C1B1 PRG:01B1 8D 06 20
ldy #$00 ; CPU:$C1B4 PRG:01B4 A0 00
@CopySecondPalette:
lda $02A9,y ; CPU:$C1B6 PRG:01B6 B9 A9 02
sta PPUDATA ; CPU:$C1B9 PRG:01B9 8D 07 20
iny ; CPU:$C1BC PRG:01BC C8
cpy #$10 ; CPU:$C1BD PRG:01BD C0 10
bne @CopySecondPalette ; CPU:$C1BF PRG:01BF D0 F5
@CheckPaletteState:
lda $0299 ; CPU:$C1C1 PRG:01C1 AD 99 02
cmp #$0F ; CPU:$C1C4 PRG:01C4 C9 0F
beq @ResetPpuAddress ; CPU:$C1C6 PRG:01C6 F0 08
lda $02A9 ; CPU:$C1C8 PRG:01C8 AD A9 02
cmp #$0F ; CPU:$C1CB PRG:01CB C9 0F
beq @ResetPpuAddress ; CPU:$C1CD PRG:01CD F0 01
rts ; CPU:$C1CF PRG:01CF 60
@ResetPpuAddress:
lda #$30 ; CPU:$C1D0 PRG:01D0 A9 30
sta PPUADDR ; CPU:$C1D2 PRG:01D2 8D 06 20
lda #$00 ; CPU:$C1D5 PRG:01D5 A9 00
sta PPUADDR ; CPU:$C1D7 PRG:01D7 8D 06 20
sta PPUADDR ; CPU:$C1DA PRG:01DA 8D 06 20
sta PPUADDR ; CPU:$C1DD PRG:01DD 8D 06 20
sta $0299 ; CPU:$C1E0 PRG:01E0 8D 99 02
sta $02A9 ; CPU:$C1E3 PRG:01E3 8D A9 02
rts ; CPU:$C1E6 PRG:01E6 60
;==============================================================================
; $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 ; CPU:$C1E7 PRG:01E7 A9 01
sta $40 ; CPU:$C1E9 PRG:01E9 85 40
@WaitForInitialNmi:
lda $40 ; CPU:$C1EB PRG:01EB A5 40
bne @WaitForInitialNmi ; CPU:$C1ED PRG:01ED D0 FC
lda #$08 ; CPU:$C1EF PRG:01EF A9 08
sta PPUCTRL ; CPU:$C1F1 PRG:01F1 8D 00 20
sta ppuCtrlShadow ; CPU:$C1F4 PRG:01F4 85 43
lda PPUSTATUS ; CPU:$C1F6 PRG:01F6 AD 02 20
lda #$00 ; CPU:$C1F9 PRG:01F9 A9 00
sta PPUMASK ; CPU:$C1FB PRG:01FB 8D 01 20
tax ; CPU:$C1FE PRG:01FE AA
@ClearOamPage:
sta $0700,x ; CPU:$C1FF PRG:01FF 9D 00 07
inx ; CPU:$C202 PRG:0202 E8
bne @ClearOamPage ; CPU:$C203 PRG:0203 D0 FA
sta cocktailModeFlag ; CPU:$C205 PRG:0205 85 46
jsr ClearGameplayNametables ; CPU:$C207 PRG:0207 20 85 E3
jsr InitializeNametableAttributes ; CPU:$C20A PRG:020A 20 0B C3
jsr InitializeNametableData ; CPU:$C20D PRG:020D 20 A6 C2
jsr $E419 ; CPU:$C210 PRG:0210 20 19 E4
ldy #$00 ; CPU:$C213 PRG:0213 A0 00
@InitializePaletteBuffers:
lda TitleScreenPalette,y ; CPU:$C215 PRG:0215 B9 3F C4
sta $0299,y ; CPU:$C218 PRG:0218 99 99 02
iny ; CPU:$C21B PRG:021B C8
cpy #$20 ; CPU:$C21C PRG:021C C0 20
bne @InitializePaletteBuffers ; CPU:$C21E PRG:021E D0 F5
lda #$2D ; CPU:$C220 PRG:0220 A9 2D
sta actorStatusDisplay ; CPU:$C222 PRG:0222 85 6C
sta actorStatusDisplay+1 ; CPU:$C224 PRG:0224 85 6D 85
sta actorStatusDisplay+2 ; CPU:$C227 PRG:0227 6E 85 6F
sta actorStatusDisplay+3 ; CPU:$C22A PRG:022A A9 FF 8D
lda #$FF ; CPU:$C22D PRG:022D 3F 02
sta $023F ; CPU:$C22F PRG:022F 85 48 A9
sta gameplaySuspended ; CPU:$C232 PRG:0232 00 85
lda #$00 ; CPU:$C234 PRG:0234 47 85
sta activePlayerFlag ; CPU:$C236 PRG:0236 46 85
sta cocktailModeFlag ; CPU:$C238 PRG:0238 42 85
sta $42 ; CPU:$C23A PRG:023A 41 85
sta $41 ; CPU:$C23C PRG:023C 4C 85
sta stateTimer ; CPU:$C23E PRG:023E 87 85
sta $87 ; CPU:$C240 PRG:0240 88 A5
sta $88 ; CPU:$C242 PRG:0242 3F D0
lda gameState ; CPU:$C244 PRG:0244 04 A9
bne @UseAlternatePpuCtrl ; CPU:$C246 PRG:0246 8A D0
lda #$8A ; CPU:$C248 PRG:0248 02 A9
bne @SetPpuCtrl ; CPU:$C24A PRG:024A 88 8D
@UseAlternatePpuCtrl:
lda #$88 ; CPU:$C24C PRG:024C 00 20
@SetPpuCtrl:
sta PPUCTRL ; CPU:$C24E PRG:024E 85 43 A9
sta ppuCtrlShadow ; CPU:$C251 PRG:0251 01 85
MainDispatchLoop:
lda #$01 ; CPU:$C250 PRG:0250 A9 01
sta $40 ; CPU:$C252 PRG:0252 85 40
@WaitForNmi:
lda $40 ; CPU:$C254 PRG:0254 A5 40
bne @WaitForNmi ; CPU:$C256 PRG:0256 D0 FC
ldy gameState ; CPU:$C258 PRG:0258 A4 3F
lda $C267,y ; CPU:$C25A PRG:025A B9 67 C2
sta dispatchVector ; CPU:$C25D PRG:025D 85 10
lda $C268,y ; CPU:$C25F PRG:025F B9 68 C2
sta dispatchVector+1 ; CPU:$C262 PRG:0262 85 11 6C
jmp ($0010) ; CPU:$C265 PRG:0265 10 00 7A C2 77
;==============================================================================
; $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 ; CPU:$C267 PRG:0267 7A C2
.word PlayerSelectionState ; CPU:$C269 PRG:0269 77 C4
.word State04Handler ; CPU:$C26B PRG:026B 12 C5
.word TimedStateTransition ; CPU:$C26D PRG:026D 6F C2
;==============================================================================
; $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 ; CPU:$C26F PRG:026F C6 0F
bne MainDispatchLoop ; CPU:$C271 PRG:0271 D0 DD
lda #$02 ; CPU:$C273 PRG:0273 A9 02
sta gameState ; CPU:$C275 PRG:0275 85 3F
jmp MainDispatchLoop ; CPU:$C277 PRG:0277 4C 50 C2
;==============================================================================
; $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 ; CPU:$C27A PRG:027A A5 4D
and #$0C ; CPU:$C27C PRG:027C 29 0C
beq @AdvanceScroll ; CPU:$C27E PRG:027E F0 0B
lda #$06 ; CPU:$C280 PRG:0280 A9 06
sta gameState ; CPU:$C282 PRG:0282 85 3F
lda #$5A ; CPU:$C284 PRG:0284 A9 5A
sta $0F ; CPU:$C286 PRG:0286 85 0F
jmp MainEntry ; CPU:$C288 PRG:0288 4C E7 C1
@AdvanceScroll:
inc $42 ; CPU:$C28B PRG:028B E6 42
lda #$F0 ; CPU:$C28D PRG:028D A9 F0
cmp $42 ; CPU:$C28F PRG:028F C5 42
bne @ReturnToMainLoop ; CPU:$C291 PRG:0291 D0 10
lda #$00 ; CPU:$C293 PRG:0293 A9 00
sta $42 ; CPU:$C295 PRG:0295 85 42
lda #$88 ; CPU:$C297 PRG:0297 A9 88
sta ppuCtrlShadow ; CPU:$C299 PRG:0299 85 43
lda #$06 ; CPU:$C29B PRG:029B A9 06
sta gameState ; CPU:$C29D PRG:029D 85 3F
lda #$5A ; CPU:$C29F PRG:029F A9 5A
sta $0F ; CPU:$C2A1 PRG:02A1 85 0F
@ReturnToMainLoop:
jmp MainDispatchLoop ; CPU:$C2A3 PRG:02A3 4C 50 C2
;==============================================================================
; $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 ; CPU:$C2A6 PRG:02A6 A9 20
sta workPtr0 ; CPU:$C2A8 PRG:02A8 85 00
lda #$E5 ; CPU:$C2AA PRG:02AA A9 E5
sta workPtr0+1 ; CPU:$C2AC PRG:02AC 85 01 A9
; Write six rows.
lda #$06 ; CPU:$C2AF PRG:02AF 06 85
sta workPtr1 ; CPU:$C2B1 PRG:02B1 02 A0
ldy #$00 ; CPU:$C2B3 PRG:02B3 00 AD
@WriteRow:
lda PPUSTATUS ; CPU:$C2B5 PRG:02B5 02 20 A5
lda workPtr0 ; CPU:$C2B8 PRG:02B8 00 8D
sta PPUADDR ; CPU:$C2BA PRG:02BA 06 20 A5
lda workPtr0+1 ; CPU:$C2BD PRG:02BD 01 8D 06
sta PPUADDR ; CPU:$C2C0 PRG:02C0 20 A9 17
; Each row contains $17 bytes.
lda #$17 ; CPU:$C2C3 PRG:02C3 85 03
sta workPtr1+1 ; CPU:$C2C5 PRG:02C5 B9 26 C3
@WriteRowBytes:
lda TitleScreenTileBlock,y ; CPU:$C2C8 PRG:02C8 8D 07 20
sta PPUDATA ; CPU:$C2CB PRG:02CB C8 C6 03
iny ; CPU:$C2CE PRG:02CE D0
dec workPtr1+1 ; CPU:$C2CF PRG:02CF F5 A5
bne @WriteRowBytes ; CPU:$C2D1 PRG:02D1 01 18
; Advance the PPU destination by $20.
lda workPtr0+1 ; CPU:$C2D3 PRG:02D3 69 20 85
clc ; CPU:$C2D6 PRG:02D6 01
adc #$20 ; CPU:$C2D7 PRG:02D7 A9 00
sta workPtr0+1 ; CPU:$C2D9 PRG:02D9 65 00 85
lda #$00 ; CPU:$C2DC PRG:02DC 00 C6
adc workPtr0 ; CPU:$C2DE PRG:02DE 02 D0
sta workPtr0 ; CPU:$C2E0 PRG:02E0 D3 A9
dec workPtr1 ; CPU:$C2E2 PRG:02E2 09 85
bne @WriteRow ; CPU:$C2E4 PRG:02E4 00 A0
; Process nine additional encoded PPU update records.
lda #$09 ; CPU:$C2E6 PRG:02E6 00 AD
sta workPtr0 ; CPU:$C2E8 PRG:02E8 02 20
ldy #$00 ; CPU:$C2EA PRG:02EA B9 B0
@NextPpuRecord:
lda PPUSTATUS ; CPU:$C2EC PRG:02EC C3 8D 06
; First two bytes of each record are the PPU destination address.
lda TitleScreenPpuRecords,y ; CPU:$C2EF PRG:02EF 20 C8 B9
sta PPUADDR ; CPU:$C2F2 PRG:02F2 B0 C3 8D
iny ; CPU:$C2F5 PRG:02F5 06
lda TitleScreenPpuRecords,y ; CPU:$C2F6 PRG:02F6 20 C8 B9
sta PPUADDR ; CPU:$C2F9 PRG:02F9 B0 C3 C9
iny ; CPU:$C2FC PRG:02FC FF
@WritePpuRecord:
lda TitleScreenPpuRecords,y ; CPU:$C2FD PRG:02FD F0 06 8D
cmp #$FF ; CPU:$C300 PRG:0300 07 20
beq @EndPpuRecord ; CPU:$C302 PRG:0302 C8 D0
sta PPUDATA ; CPU:$C304 PRG:0304 F3 C8 C6
iny ; CPU:$C307 PRG:0307 00
bne @WritePpuRecord ; CPU:$C308 PRG:0308 D0 DD
@EndPpuRecord:
iny ; CPU:$C30A PRG:030A 60
dec workPtr0 ; CPU:$C30B PRG:030B AD 02
bne @NextPpuRecord ; CPU:$C30D PRG:030D 20 A9
rts ; CPU:$C30F PRG:030F 23
;==============================================================================
; $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 ; CPU:$C30B PRG:030B AD 02 20
lda #$23 ; CPU:$C30E PRG:030E A9 23
sta PPUADDR ; CPU:$C310 PRG:0310 8D 06 20
lda #$C8 ; CPU:$C313 PRG:0313 A9 C8
sta PPUADDR ; CPU:$C315 PRG:0315 8D 06 20
ldy #$00 ; CPU:$C318 PRG:0318 A0 00
@CopyAttributes:
lda TitleScreenAttributeData,y ; CPU:$C31A PRG:031A B9 5F C4
sta PPUDATA ; CPU:$C31D PRG:031D 8D 07 20
iny ; CPU:$C320 PRG:0320 C8
cpy #$18 ; CPU:$C321 PRG:0321 C0 18
bne @CopyAttributes ; CPU:$C323 PRG:0323 D0 F5
rts ; CPU:$C325 PRG:0325 60
;==============================================================================
; $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 ; CPU:$C326 PRG:0326 E4 E8 E8 E8 E8 E8 E8 E8
.byte $E8,$E8,$E8,$E8,$E8,$E8,$E8,$E8 ; CPU:$C32E PRG:032E E8 E8 E8 E8 E8 E8 E8 E8
.byte $E8,$E8,$E8,$E8,$E8,$E8,$E5 ; CPU:$C336 PRG:0336 E8 E8 E8 E8 E8 E8 E5
; Row 1 -> PPU $2105-$211B
.byte $EB,$88,$80,$81,$82,$83,$84,$85 ; CPU:$C33D PRG:033D EB 88 80 81 82 83 84 85
.byte $86,$87,$88,$88,$89,$8A,$8B,$8C ; CPU:$C345 PRG:0345 86 87 88 88 89 8A 8B 8C
.byte $8D,$8E,$8F,$90,$91,$A3,$E9 ; CPU:$C34D PRG:034D 8D 8E 8F 90 91 A3 E9
; Row 2 -> PPU $2125-$213B
.byte $EB,$88,$92,$93,$94,$95,$96,$97 ; CPU:$C354 PRG:0354 EB 88 92 93 94 95 96 97
.byte $98,$99,$9A,$9B,$9C,$9D,$9E,$9F ; CPU:$C35C PRG:035C 98 99 9A 9B 9C 9D 9E 9F
.byte $A0,$A1,$A2,$A3,$A4,$A3,$E9 ; CPU:$C364 PRG:0364 A0 A1 A2 A3 A4 A3 E9
; Row 3 -> PPU $2145-$215B
.byte $EB,$88,$92,$A5,$A6,$A7,$A8,$A9 ; CPU:$C36B PRG:036B EB 88 92 A5 A6 A7 A8 A9
.byte $AA,$AB,$AC,$AD,$AE,$A3,$AF,$D0 ; CPU:$C373 PRG:0373 AA AB AC AD AE A3 AF D0
.byte $D1,$D2,$A3,$D3,$A4,$A3,$E9 ; CPU:$C37B PRG:037B D1 D2 A3 D3 A4 A3 E9
; Row 4 -> PPU $2165-$217B
.byte $EB,$88,$D4,$D5,$D6,$D7,$D8,$D9 ; CPU:$C382 PRG:0382 EB 88 D4 D5 D6 D7 D8 D9
.byte $DA,$DB,$88,$88,$DC,$D7,$DD,$DE ; CPU:$C38A PRG:038A DA DB 88 88 DC D7 DD DE
.byte $DF,$E0,$E1,$E2,$E3,$A3,$E9 ; CPU:$C392 PRG:0392 DF E0 E1 E2 E3 A3 E9
; Row 5 -> PPU $2185-$219B
.byte $E7,$EA,$EA,$EA,$EA,$EA,$EA,$EA ; CPU:$C399 PRG:0399 E7 EA EA EA EA EA EA EA
.byte $EA,$EA,$EA,$EA,$EA,$EA,$EA,$EA ; CPU:$C3A1 PRG:03A1 EA EA EA EA EA EA EA EA
.byte $EA,$EA,$EA,$EA,$EA,$EA,$E6 ; CPU:$C3A9 PRG:03A9 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 ; CPU:$C3B0 PRG:03B0 20 65
.byte $B0,$B3,$B2,$20,$20,$20,$20 ; CPU:$C3B2 PRG:03B2 B0 B3 B2 20 20 20 20
.byte $B4,$B5,$B6,$B7,$B8,$B9,$BA,$BB ; CPU:$C3B9 PRG:03B9 B4 B5 B6 B7 B8 B9 BA BB
.byte $20,$20,$20,$B1,$B3,$B2 ; CPU:$C3C1 PRG:03C1 20 20 20 B1 B3 B2
.byte $FF ; CPU:$C3C7 PRG:03C7 FF
;------------------------------------------------------------------------------
; Record 1: $C3C8-$C3D2
; PPU destination: $220C
; Data length: $08
;
; Visible tile values correspond to:
; "1 PLAYER"
;------------------------------------------------------------------------------
.byte $22,$0C ; CPU:$C3C8 PRG:03C8 22 0C
.byte $31,$20,$50,$4C,$41,$59,$45,$52 ; CPU:$C3CA PRG:03CA 31 20 50 4C 41 59 45 52
.byte $FF ; CPU:$C3D2 PRG:03D2 FF
;------------------------------------------------------------------------------
; Record 2: $C3D3-$C3DE
; PPU destination: $224C
; Data length: $09
;
; Visible tile values correspond to:
; "2 PLAYERS"
;------------------------------------------------------------------------------
.byte $22,$4C ; CPU:$C3D3 PRG:03D3 22 4C
.byte $32,$20,$50,$4C,$41,$59,$45,$52,$53 ; CPU:$C3D5 PRG:03D5 32 20 50 4C 41 59 45 52 53
.byte $FF ; CPU:$C3DE PRG:03DE 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 ; CPU:$C3DF PRG:03DF 22 E3
.byte $54,$4D,$20,$CC,$20,$5D ; CPU:$C3E1 PRG:03E1 54 4D 20 CC 20 5D
.byte $20,$31,$39,$38,$30 ; CPU:$C3E7 PRG:03E7 20 31 39 38 30
.byte $20,$31,$39,$39,$33 ; CPU:$C3EC PRG:03EC 20 31 39 39 33
.byte $20,$4E,$41,$4D,$43,$4F ; CPU:$C3F1 PRG:03F1 20 4E 41 4D 43 4F
.byte $20,$4C,$54,$44,$5B ; CPU:$C3F7 PRG:03F7 20 4C 54 44 5B
.byte $FF ; CPU:$C3FC PRG:03FC 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 ; CPU:$C3FD PRG:03FD 23 27
.byte $4E,$41,$4D,$43,$4F,$20 ; CPU:$C3FF PRG:03FF 4E 41 4D 43 4F 20
.byte $48,$4F,$4D,$45,$54,$45,$4B ; CPU:$C405 PRG:0405 48 4F 4D 45 54 45 4B
.byte $CD ; CPU:$C40C PRG:040C CD
.byte $49,$4E,$43 ; CPU:$C40D PRG:040D 49 4E 43
.byte $5B ; CPU:$C410 PRG:0410 5B
.byte $FF ; CPU:$C411 PRG:0411 FF
;------------------------------------------------------------------------------
; Record 5: $C412-$C428
; PPU destination: $2366
; Data length: $14 (20)
;
; Tile values correspond to:
; "LICENSED BY NINTENDO"
;------------------------------------------------------------------------------
.byte $23,$66 ; CPU:$C412 PRG:0412 23 66
.byte $4C,$49,$43,$45,$4E,$53,$45,$44 ; CPU:$C414 PRG:0414 4C 49 43 45 4E 53 45 44
.byte $20 ; CPU:$C41C PRG:041C 20
.byte $42,$59 ; CPU:$C41D PRG:041D 42 59
.byte $20 ; CPU:$C41F PRG:041F 20
.byte $4E,$49,$4E,$54,$45,$4E,$44,$4F ; CPU:$C420 PRG:0420 4E 49 4E 54 45 4E 44 4F
.byte $FF ; CPU:$C428 PRG:0428 FF
;------------------------------------------------------------------------------
; Record 6: $C429-$C42D
; PPU destination: $2293
; Data length: $02
;------------------------------------------------------------------------------
.byte $22,$93 ; CPU:$C429 PRG:0429 22 93
.byte $CE,$CF ; CPU:$C42B PRG:042B CE CF
.byte $FF ; CPU:$C42D PRG:042D FF
;------------------------------------------------------------------------------
; Record 7: $C42E-$C439
; PPU destination: $22AC
; Data length: $09
;------------------------------------------------------------------------------
.byte $22,$AC ; CPU:$C42E PRG:042E 22 AC
.byte $23,$24,$25,$26,$27,$28,$29,$2A,$2B ; CPU:$C430 PRG:0430 23 24 25 26 27 28 29 2A 2B
.byte $FF ; CPU:$C439 PRG:0439 FF
;------------------------------------------------------------------------------
; Record 8: $C43A-$C43E
; PPU destination: $20FC
; Data length: $02
;------------------------------------------------------------------------------
.byte $20,$FC ; CPU:$C43A PRG:043A 20 FC
.byte $0E,$0F ; CPU:$C43C PRG:043C 0E 0F
.byte $FF ; CPU:$C43E PRG:043E 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 ; CPU:$C43F PRG:043F 0F 20 0F 06
.byte $0F,$26,$20,$27 ; CPU:$C443 PRG:0443 0F 26 20 27
.byte $0F,$06,$0F,$26 ; CPU:$C447 PRG:0447 0F 06 0F 26
.byte $0F,$06,$20,$26 ; CPU:$C44B PRG:044B 0F 06 20 26
; Sprite palettes
.byte $0F,$27,$20,$06 ; CPU:$C44F PRG:044F 0F 27 20 06
.byte $0F,$11,$20,$33 ; CPU:$C453 PRG:0453 0F 11 20 33
.byte $0F,$20,$20,$21 ; CPU:$C457 PRG:0457 0F 20 20 21
.byte $0F,$09,$20,$17 ; CPU:$C45B PRG:045B 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 ; CPU:$C45F PRG:045F 80 A0 A0 A0 A0 A0 A0 00
.byte $00,$66,$55,$55,$55,$55,$DD,$00 ; CPU:$C467 PRG:0467 00 66 55 55 55 55 DD 00
.byte $08,$0A,$0A,$0A,$0A,$0A,$0A,$00 ; CPU:$C46F PRG:046F 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 ; CPU:$C477 PRG:0477 A5 87
ora $88 ; CPU:$C479 PRG:0479 05 88
bne @AdvanceTimeout ; CPU:$C47B PRG:047B D0 19
ldy #$00 ; CPU:$C47D PRG:047D A0 00
@InitializeDisplayData:
lda PlayerCountSelectionDisplayData,y ; CPU:$C47F PRG:047F B9 07 C5
sta $024B,y ; CPU:$C482 PRG:0482 99 4B 02
iny ; CPU:$C485 PRG:0485 C8
cmp #$FF ; CPU:$C486 PRG:0486 C9 FF
bne @InitializeDisplayData ; CPU:$C488 PRG:0488 D0 F5
lda currentInput ; CPU:$C48A PRG:048A A5 4D
and #$04 ; CPU:$C48C PRG:048C 29 04
sta pacmanRequestedDirection ; CPU:$C48E PRG:048E 85 50
lda currentInput ; CPU:$C490 PRG:0490 A5 4D
and #$08 ; CPU:$C492 PRG:0492 29 08
sta pacmanDirection ; CPU:$C494 PRG:0494 85 51
@AdvanceTimeout:
clc ; CPU:$C496 PRG:0496 18
lda #$01 ; CPU:$C497 PRG:0497 A9 01
adc $87 ; CPU:$C499 PRG:0499 65 87
sta $87 ; CPU:$C49B PRG:049B 85 87
lda $88 ; CPU:$C49D PRG:049D A5 88
adc #$00 ; CPU:$C49F PRG:049F 69 00
sta $88 ; CPU:$C4A1 PRG:04A1 85 88
cmp #$02 ; CPU:$C4A3 PRG:04A3 C9 02
bne @CheckSelectionInput ; CPU:$C4A5 PRG:04A5 D0 0B
lda #$00 ; CPU:$C4A7 PRG:04A7 A9 00
sta $87 ; CPU:$C4A9 PRG:04A9 85 87
lda #$04 ; CPU:$C4AB PRG:04AB A9 04
sta gameState ; CPU:$C4AD PRG:04AD 85 3F
jmp MainDispatchLoop ; CPU:$C4AF PRG:04AF 4C 50 C2
@CheckSelectionInput:
lda currentInput ; CPU:$C4B2 PRG:04B2 A5 4D
and #$04 ; CPU:$C4B4 PRG:04B4 29 04
cmp pacmanRequestedDirection ; CPU:$C4B6 PRG:04B6 C5 50
beq @CheckConfirmInput ; CPU:$C4B8 PRG:04B8 F0 2F
sta pacmanRequestedDirection ; CPU:$C4BA PRG:04BA 85 50
lda #$00 ; CPU:$C4BC PRG:04BC A9 00
sta $88 ; CPU:$C4BE PRG:04BE 85 88
lda #$01 ; CPU:$C4C0 PRG:04C0 A9 01
sta $87 ; CPU:$C4C2 PRG:04C2 85 87
lda pacmanRequestedDirection ; CPU:$C4C4 PRG:04C4 A5 50
beq @CheckConfirmInput ; CPU:$C4C6 PRG:04C6 F0 21
ldx #$00 ; CPU:$C4C8 PRG:04C8 A2 00
inc activePlayerFlag ; CPU:$C4CA PRG:04CA E6 47
lda activePlayerFlag ; CPU:$C4CC PRG:04CC A5 47
and #$01 ; CPU:$C4CE PRG:04CE 29 01
sta activePlayerFlag ; CPU:$C4D0 PRG:04D0 85 47
beq @UseFirstSelectionData ; CPU:$C4D2 PRG:04D2 F0 01
inx ; CPU:$C4D4 PRG:04D4 E8
@UseFirstSelectionData:
lda $C50F,x ; CPU:$C4D5 PRG:04D5 BD 0F C5
sta $024D ; CPU:$C4D8 PRG:04D8 8D 4D 02
lda $C510,x ; CPU:$C4DB PRG:04DB BD 10 C5
sta $0251 ; CPU:$C4DE PRG:04DE 8D 51 02
lda #$22 ; CPU:$C4E1 PRG:04E1 A9 22
sta $024B ; CPU:$C4E3 PRG:04E3 8D 4B 02
jmp MainDispatchLoop ; CPU:$C4E6 PRG:04E6 4C 50 C2
@CheckConfirmInput:
lda currentInput ; CPU:$C4E9 PRG:04E9 A5 4D
and #$08 ; CPU:$C4EB PRG:04EB 29 08
cmp pacmanDirection ; CPU:$C4ED PRG:04ED C5 51
bne @ConfirmStateChanged ; CPU:$C4EF PRG:04EF D0 03
jmp MainDispatchLoop ; CPU:$C4F1 PRG:04F1 4C 50 C2
@ConfirmStateChanged:
sta pacmanDirection ; CPU:$C4F4 PRG:04F4 85 51
lda pacmanDirection ; CPU:$C4F6 PRG:04F6 A5 51
bne @ConfirmPressed ; CPU:$C4F8 PRG:04F8 D0 03
jmp MainDispatchLoop ; CPU:$C4FA PRG:04FA 4C 50 C2
@ConfirmPressed:
lda #$00 ; CPU:$C4FD PRG:04FD A9 00
sta gameplaySuspended ; CPU:$C4FF PRG:04FF 85 48
jsr $EEB4 ; CPU:$C501 PRG:0501 20 B4 EE
jmp GameModeEntry ; CPU:$C504 PRG:0504 4C 54 CA
;==============================================================================
; $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 ; CPU:$C507 PRG:0507 22 0A 5C 00
.byte $22,$4A,$20,$FF ; CPU:$C50B PRG:050B 22 4A 20 FF
PlayerCountSelectionMarkerTiles:
.byte $5C,$20,$5C ; CPU:$C50F PRG:050F 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 ; CPU:$C512 PRG:0512 A5 4D
and #$0C ; CPU:$C514 PRG:0514 29 0C
beq @DispatchSubstate ; CPU:$C516 PRG:0516 F0 07
lda #$02 ; CPU:$C518 PRG:0518 A9 02
sta gameState ; CPU:$C51A PRG:051A 85 3F
jmp MainEntry ; CPU:$C51C PRG:051C 4C E7 C1
@DispatchSubstate:
ldy $87 ; CPU:$C51F PRG:051F A4 87
lda State04SubstateTable,y ; CPU:$C521 PRG:0521 B9 2E C5
sta dispatchVector ; CPU:$C524 PRG:0524 85 10
lda State04SubstateTable+1,y ; CPU:$C526 PRG:0526 B9 2F C5
sta dispatchVector+1 ; CPU:$C529 PRG:0529 85 11 6C
jmp ($0010) ; CPU:$C52C PRG:052C 10 00 46 C5 73
;==============================================================================
; $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 ; CPU:$C52E PRG:052E 46 C5
.word State04TimedSubstate ; $02 ; CPU:$C530 PRG:0530 73 C5
.word State04TimedSubstate ; $04 ; CPU:$C532 PRG:0532 73 C5
.word State04TimedSubstate ; $06 ; CPU:$C534 PRG:0534 73 C5
.word State04TimedSubstate ; $08 ; CPU:$C536 PRG:0536 73 C5
.word State04TimedSubstate ; $0A ; CPU:$C538 PRG:0538 73 C5
.word State04TimedSubstate ; $0C ; CPU:$C53A PRG:053A 73 C5
.word State04TimedSubstate ; $0E ; CPU:$C53C PRG:053C 73 C5
.word State04TimedSubstate ; $10 ; CPU:$C53E PRG:053E 73 C5
.word State04TimedSubstate ; $12 ; CPU:$C540 PRG:0540 73 C5
.word State04LongDelay ; $14 ; CPU:$C542 PRG:0542 89 C5
.word State04FinalPhase ; $16 ; CPU:$C544 PRG:0544 92 C7
;==============================================================================
; $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 ; CPU:$C546 PRG:0546 A9 01
sta $40 ; CPU:$C548 PRG:0548 85 40
@WaitForNmi:
lda $40 ; CPU:$C54A PRG:054A A5 40
bne @WaitForNmi ; CPU:$C54C PRG:054C D0 FC
lda #$08 ; CPU:$C54E PRG:054E A9 08
sta PPUCTRL ; CPU:$C550 PRG:0550 8D 00 20
sta ppuCtrlShadow ; CPU:$C553 PRG:0553 85 43
lda #$00 ; CPU:$C555 PRG:0555 A9 00
sta PPUMASK ; CPU:$C557 PRG:0557 8D 01 20
sta $88 ; CPU:$C55A PRG:055A 85 88
jsr $C5D8 ; CPU:$C55C PRG:055C 20 D8 C5
jsr InitializeState04PpuData ; CPU:$C55F PRG:055F 20 08 C6
jsr LoadState04DisplayData ; CPU:$C562 PRG:0562 20 A6 C5
inc $87 ; CPU:$C565 PRG:0565 E6 87
inc $87 ; CPU:$C567 PRG:0567 E6 87
lda #$88 ; CPU:$C569 PRG:0569 A9 88
sta PPUCTRL ; CPU:$C56B PRG:056B 8D 00 20
sta ppuCtrlShadow ; CPU:$C56E PRG:056E 85 43
jmp MainDispatchLoop ; CPU:$C570 PRG:0570 4C 50 C2
;==============================================================================
; $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 ; CPU:$C573 PRG:0573 E6 88
lda $88 ; CPU:$C575 PRG:0575 A5 88
cmp #$30 ; CPU:$C577 PRG:0577 C9 30
bne @ReturnToMainLoop ; CPU:$C579 PRG:0579 D0 0B
lda #$00 ; CPU:$C57B PRG:057B A9 00
sta $88 ; CPU:$C57D PRG:057D 85 88
jsr $C5A6 ; CPU:$C57F PRG:057F 20 A6 C5
inc $87 ; CPU:$C582 PRG:0582 E6 87
inc $87 ; CPU:$C584 PRG:0584 E6 87
@ReturnToMainLoop:
jmp MainDispatchLoop ; CPU:$C586 PRG:0586 4C 50 C2
;==============================================================================
; $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 ; CPU:$C589 PRG:0589 E6 88
lda $88 ; CPU:$C58B PRG:058B A5 88
cmp #$80 ; CPU:$C58D PRG:058D C9 80
beq @AdvanceSubstate ; CPU:$C58F PRG:058F F0 03
jmp MainDispatchLoop ; CPU:$C591 PRG:0591 4C 50 C2
@AdvanceSubstate:
inc $87 ; CPU:$C594 PRG:0594 E6 87
inc $87 ; CPU:$C596 PRG:0596 E6 87
lda #$00 ; CPU:$C598 PRG:0598 A9 00
sta $88 ; CPU:$C59A PRG:059A 85 88
jmp MainDispatchLoop ; CPU:$C59C PRG:059C 4C 50 C2
;==============================================================================
; $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 ; CPU:$C59F PRG:059F A9 01
sta activePlayerFlag ; CPU:$C5A1 PRG:05A1 85 47
jmp GameModeEntry ; CPU:$C5A3 PRG:05A3 4C 54 CA
;==============================================================================
; $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 ; CPU:$C5A6 PRG:05A6 A4 87
lda CharacterIntroDisplayDataTable,y ; CPU:$C5A8 PRG:05A8 B9 87 C6
sta workPtr0 ; CPU:$C5AB PRG:05AB 85 00
lda CharacterIntroDisplayDataTable+1,y ; CPU:$C5AD PRG:05AD B9 88 C6
sta workPtr0+1 ; CPU:$C5B0 PRG:05B0 85 01 A0
ldy #$00 ; CPU:$C5B3 PRG:05B3 00 B1
@CopyDisplayData:
lda (workPtr0),y ; CPU:$C5B5 PRG:05B5 00 99
sta $024B,y ; CPU:$C5B7 PRG:05B7 4B 02 C8
iny ; CPU:$C5BA PRG:05BA C9
cmp #$FF ; CPU:$C5BB PRG:05BB FF D0
bne @CopyDisplayData ; CPU:$C5BD PRG:05BD F6 B1
lda (workPtr0),y ; CPU:$C5BF PRG:05BF 00 F0
beq @SecondaryCopy ; CPU:$C5C1 PRG:05C1 01 60
rts ; CPU:$C5C3 PRG:05C3 A5
@SecondaryCopy:
lda $87 ; CPU:$C5C4 PRG:05C4 87 38
sec ; CPU:$C5C6 PRG:05C6 E9
sbc #$02 ; CPU:$C5C7 PRG:05C7 02 0A
asl ; CPU:$C5C9 PRG:05C9 0A
asl ; CPU:$C5CA PRG:05CA A8
tay ; CPU:$C5CB PRG:05CB A2
ldx #$10 ; CPU:$C5CC PRG:05CC 10 B9
@CopySecondaryData:
lda CharacterIntroSpriteData,y ; CPU:$C5CE PRG:05CE 2E C7 99
sta $0760,y ; CPU:$C5D1 PRG:05D1 60 07 C8
iny ; CPU:$C5D4 PRG:05D4 CA
dex ; CPU:$C5D5 PRG:05D5 D0
bne @CopySecondaryData ; CPU:$C5D6 PRG:05D6 F6 60
rts ; CPU:$C5D8 PRG:05D8 A9
;==============================================================================
; $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 ; CPU:$C5D8 PRG:05D8 A9 20
sta PPUADDR ; CPU:$C5DA PRG:05DA 8D 06 20
lda #$C0 ; CPU:$C5DD PRG:05DD A9 C0
sta PPUADDR ; CPU:$C5DF PRG:05DF 8D 06 20
lda #$17 ; CPU:$C5E2 PRG:05E2 A9 17
sta workPtr0 ; CPU:$C5E4 PRG:05E4 85 00
@NextRow:
lda #$1C ; CPU:$C5E6 PRG:05E6 A9 1C
sta workPtr0+1 ; CPU:$C5E8 PRG:05E8 85 01 A9
lda #$2D ; CPU:$C5EB PRG:05EB 2D 8D
sta PPUDATA ; CPU:$C5ED PRG:05ED 07 20 8D
sta PPUDATA ; CPU:$C5F0 PRG:05F0 07 20 A9
lda #$20 ; CPU:$C5F3 PRG:05F3 20 8D
@ClearRowInterior:
sta PPUDATA ; CPU:$C5F5 PRG:05F5 07 20 C6
dec workPtr0+1 ; CPU:$C5F8 PRG:05F8 01 D0
bne @ClearRowInterior ; CPU:$C5FA PRG:05FA F9 A9
lda #$2D ; CPU:$C5FC PRG:05FC 2D 8D
sta PPUDATA ; CPU:$C5FE PRG:05FE 07 20 8D
sta PPUDATA ; CPU:$C601 PRG:0601 07 20 C6
dec workPtr0 ; CPU:$C604 PRG:0604 00 10
bpl @NextRow ; CPU:$C606 PRG:0606 DF 60
rts ; CPU:$C608 PRG:0608 A9
;==============================================================================
; $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 ; CPU:$C608 PRG:0608 A9 23
sta PPUADDR ; CPU:$C60A PRG:060A 8D 06 20
lda #$C8 ; CPU:$C60D PRG:060D A9 C8
sta PPUADDR ; CPU:$C60F PRG:060F 8D 06 20
; Copy $24 bytes of attribute data.
ldy #$00 ; CPU:$C612 PRG:0612 A0 00
@CopyAttributeData:
lda $C76E,y ; CPU:$C614 PRG:0614 B9 6E C7
sta PPUDATA ; CPU:$C617 PRG:0617 8D 07 20
iny ; CPU:$C61A PRG:061A C8
cpy #$24 ; CPU:$C61B PRG:061B C0 24
bne @CopyAttributeData ; CPU:$C61D PRG:061D D0 F5
; Process encoded PPU write data from $C69B.
ldy #$00 ; CPU:$C61F PRG:061F A0 00
@NextPpuRecord:
lda CharacterNicknameHeaderData,y ; CPU:$C621 PRG:0621 B9 9B C6
sta PPUADDR ; CPU:$C624 PRG:0624 8D 06 20
iny ; CPU:$C627 PRG:0627 C8
lda CharacterNicknameHeaderData,y ; CPU:$C628 PRG:0628 B9 9B C6
sta PPUADDR ; CPU:$C62B PRG:062B 8D 06 20
iny ; CPU:$C62E PRG:062E C8
@CopyPpuRecord:
lda CharacterNicknameHeaderData,y ; CPU:$C62F PRG:062F B9 9B C6
cmp #$FF ; CPU:$C632 PRG:0632 C9 FF
beq @EndPpuRecord ; CPU:$C634 PRG:0634 F0 06
sta PPUDATA ; CPU:$C636 PRG:0636 8D 07 20
iny ; CPU:$C639 PRG:0639 C8
bne @CopyPpuRecord ; CPU:$C63A PRG:063A D0 F3
@EndPpuRecord:
lda PPUSTATUS ; CPU:$C63C PRG:063C AD 02 20
; Upload the complete 32-byte palette directly.
lda #$3F ; CPU:$C63F PRG:063F A9 3F
sta PPUADDR ; CPU:$C641 PRG:0641 8D 06 20
lda #$00 ; CPU:$C644 PRG:0644 A9 00
sta PPUADDR ; CPU:$C646 PRG:0646 8D 06 20
ldy #$00 ; CPU:$C649 PRG:0649 A0 00
@CopyPalette:
lda CharacterIntroPalette,y ; CPU:$C64B PRG:064B B9 67 C6
sta PPUDATA ; CPU:$C64E PRG:064E 8D 07 20
iny ; CPU:$C651 PRG:0651 C8
cpy #$20 ; CPU:$C652 PRG:0652 C0 20
bne @CopyPalette ; CPU:$C654 PRG:0654 D0 F5
; Reset the PPU address following palette access.
lda #$3F ; CPU:$C656 PRG:0656 A9 3F
sta PPUADDR ; CPU:$C658 PRG:0658 8D 06 20
lda #$00 ; CPU:$C65B PRG:065B A9 00
sta PPUADDR ; CPU:$C65D PRG:065D 8D 06 20
sta PPUADDR ; CPU:$C660 PRG:0660 8D 06 20
sta PPUADDR ; CPU:$C663 PRG:0663 8D 06 20
rts ; CPU:$C666 PRG:0666 60
;==============================================================================
; $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 ; CPU:$C667 PRG:0667 0F 20 0F 06
.byte $0F,$06,$0F,$33 ; CPU:$C66B PRG:066B 0F 06 0F 33
.byte $0F,$33,$0F,$27 ; CPU:$C66F PRG:066F 0F 33 0F 27
.byte $0F,$17,$0F,$21 ; CPU:$C673 PRG:0673 0F 17 0F 21
; Sprite palettes
.byte $0F,$27,$20,$06 ; CPU:$C677 PRG:0677 0F 27 20 06
.byte $0F,$11,$20,$33 ; CPU:$C67B PRG:067B 0F 11 20 33
.byte $0F,$20,$20,$21 ; CPU:$C67F PRG:067F 0F 20 20 21
.byte $0F,$09,$20,$17 ; CPU:$C683 PRG:0683 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 ; CPU:$C687 PRG:0687 9B C6
.word ShadowNameData ; $87 = $02 : SHADOW ; CPU:$C689 PRG:0689 B3 C6
.word BlinkyNameData ; $87 = $04 _BLINKY_ ; CPU:$C68B PRG:068B BE C6
.word SpeedyNameData ; $87 = $06 : SPEEDY ; CPU:$C68D PRG:068D C9 C6
.word PinkyNameData ; $87 = $08 _PINKY_ ; CPU:$C68F PRG:068F D4 C6
.word CharacterIntroGraphicData0 ; $87 = $0A ; CPU:$C691 PRG:0691 DE C6
.word CharacterIntroGraphicData1 ; $87 = $0C ; CPU:$C693 PRG:0693 EA C6
.word PokeyNameData ; $87 = $0E ; CPU:$C695 PRG:0695 F3 C6
.word ClydeNameData ; $87 = $10 ; CPU:$C697 PRG:0697 FD C6
.word ScoringLegendData ; $87 = $12 ; CPU:$C699 PRG:0699 07 C7
;==============================================================================
; $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 ; CPU:$C69B PRG:069B 20 E6
.byte $43,$48,$41,$52,$41,$43,$54,$45,$52 ; CPU:$C69D PRG:069D 43 48 41 52 41 43 54 45 52
.byte $20,$3B,$20,$20 ; CPU:$C6A6 PRG:06A6 20 3B 20 20
.byte $4E,$49,$43,$4B,$4E,$41,$4D,$45 ; CPU:$C6AA PRG:06AA 4E 49 43 4B 4E 41 4D 45
.byte $FF ; CPU:$C6B2 PRG:06B2 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 ; CPU:$C6B3 PRG:06B3 21 48
.byte $3A,$53,$48,$41,$44,$4F,$57 ; CPU:$C6B5 PRG:06B5 3A 53 48 41 44 4F 57
.byte $FF ; CPU:$C6BC PRG:06BC FF
.byte $00 ; CPU:$C6BD PRG:06BD 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 ; CPU:$C6BE PRG:06BE 21 53
.byte $5F,$42,$4C,$49,$4E,$4B,$59,$5F ; CPU:$C6C0 PRG:06C0 5F 42 4C 49 4E 4B 59 5F
.byte $FF ; CPU:$C6C8 PRG:06C8 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 ; CPU:$C6C9 PRG:06C9 21 A8
.byte $3A,$53,$50,$45,$45,$44,$59 ; CPU:$C6CB PRG:06CB 3A 53 50 45 45 44 59
.byte $FF ; CPU:$C6D2 PRG:06D2 FF
.byte $00 ; CPU:$C6D3 PRG:06D3 00
;------------------------------------------------------------------------------
; $C6D4-$C6DD
; State04 substate offset: $08
;
; Destination prefix: $21B3
;
; Text-like tile data:
; "_PINKY_"
;------------------------------------------------------------------------------
PinkyNameData:
.byte $21,$B3 ; CPU:$C6D4 PRG:06D4 21 B3
.byte $5F,$50,$49,$4E,$4B,$59,$5F ; CPU:$C6D6 PRG:06D6 5F 50 49 4E 4B 59 5F
.byte $FF ; CPU:$C6DD PRG:06DD 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 ; CPU:$C6DE PRG:06DE 22 08
.byte $B6,$C1,$C3,$B7,$B4,$C2,$B3,$C4 ; CPU:$C6E0 PRG:06E0 B6 C1 C3 B7 B4 C2 B3 C4
.byte $FF ; CPU:$C6E8 PRG:06E8 FF
.byte $00 ; CPU:$C6E9 PRG:06E9 00
;------------------------------------------------------------------------------
; $C6EA-$C6F2
; State04 substate offset: $0C
;
; Destination prefix: $2213
;
; Contains another set of special graphical tile values.
;------------------------------------------------------------------------------
CharacterIntroGraphicData1:
.byte $22,$13 ; CPU:$C6EA PRG:06EA 22 13
.byte $C8,$B5,$C5,$C0,$C6,$C8 ; CPU:$C6EC PRG:06EC C8 B5 C5 C0 C6 C8
.byte $FF ; CPU:$C6F2 PRG:06F2 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 ; CPU:$C6F3 PRG:06F3 22 68
.byte $3A,$50,$4F,$4B,$45,$59 ; CPU:$C6F5 PRG:06F5 3A 50 4F 4B 45 59
.byte $FF ; CPU:$C6FB PRG:06FB FF
.byte $00 ; CPU:$C6FC PRG:06FC 00
;------------------------------------------------------------------------------
; $C6FD-$C706
; State04 substate offset: $10
;
; Destination prefix: $2273
;
; Text-like tile data:
; "_CLYDE_"
;------------------------------------------------------------------------------
ClydeNameData:
.byte $22,$73 ; CPU:$C6FD PRG:06FD 22 73
.byte $5F,$43,$4C,$59,$44,$45,$5F ; CPU:$C6FF PRG:06FF 5F 43 4C 59 44 45 5F
.byte $FF ; CPU:$C706 PRG:0706 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 ; CPU:$C707 PRG:0707 22 AD
.byte $03,$20,$31,$30,$20,$50,$54,$53 ; CPU:$C709 PRG:0709 03 20 31 30 20 50 54 53
.byte $00 ; CPU:$C711 PRG:0711 00
.byte $22,$ED ; CPU:$C712 PRG:0712 22 ED
.byte $01,$20,$35,$30,$20,$50,$54,$53 ; CPU:$C714 PRG:0714 01 20 35 30 20 50 54 53
.byte $00 ; CPU:$C71C PRG:071C 00
.byte $23,$34 ; CPU:$C71D PRG:071D 23 34
.byte $CE,$CF ; CPU:$C71F PRG:071F CE CF
.byte $00 ; CPU:$C721 PRG:0721 00
.byte $23,$4D ; CPU:$C722 PRG:0722 23 4D
.byte $23,$24,$25,$26,$27,$28,$29,$2A,$2B ; CPU:$C724 PRG:0724 23 24 25 26 27 28 29 2A 2B
.byte $FF ; CPU:$C72D PRG:072D 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 ; CPU:$C72E PRG:072E 48 1C 40 26
; $C732 - record $01
.byte $48,$1B,$40,$2E ; CPU:$C732 PRG:0732 48 1B 40 2E
; $C736 - record $02
.byte $50,$1F,$40,$26 ; CPU:$C736 PRG:0736 50 1F 40 26
; $C73A - record $03
.byte $50,$1D,$40,$2E ; CPU:$C73A PRG:073A 50 1D 40 2E
; $C73E - record $04
.byte $60,$1C,$41,$26 ; CPU:$C73E PRG:073E 60 1C 41 26
; $C742 - record $05
.byte $60,$1B,$41,$2E ; CPU:$C742 PRG:0742 60 1B 41 2E
; $C746 - record $06
.byte $68,$1F,$41,$26 ; CPU:$C746 PRG:0746 68 1F 41 26
; $C74A - record $07
.byte $68,$1D,$41,$2E ; CPU:$C74A PRG:074A 68 1D 41 2E
; $C74E - record $08
.byte $78,$1C,$42,$26 ; CPU:$C74E PRG:074E 78 1C 42 26
; $C752 - record $09
.byte $78,$1B,$42,$2E ; CPU:$C752 PRG:0752 78 1B 42 2E
; $C756 - record $0A
.byte $80,$1F,$42,$26 ; CPU:$C756 PRG:0756 80 1F 42 26
; $C75A - record $0B
.byte $80,$1D,$42,$2E ; CPU:$C75A PRG:075A 80 1D 42 2E
; $C75E - record $0C
.byte $90,$1C,$43,$26 ; CPU:$C75E PRG:075E 90 1C 43 26
; $C762 - record $0D
.byte $90,$1B,$43,$2E ; CPU:$C762 PRG:0762 90 1B 43 2E
; $C766 - record $0E
.byte $98,$1F,$43,$26 ; CPU:$C766 PRG:0766 98 1F 43 26
; $C76A - record $0F
.byte $98,$1D,$43,$2E ; CPU:$C76A PRG:076A 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 ; CPU:$C76E PRG:076E 00 00 00 00 00 00 00 00
.byte $55,$55,$55,$55,$55,$55,$55,$55 ; CPU:$C776 PRG:0776 55 55 55 55 55 55 55 55
.byte $AA,$AA,$AA,$AA,$AA,$AA,$AA,$AA ; CPU:$C77E PRG:077E AA AA AA AA AA AA AA AA
.byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; CPU:$C786 PRG:0786 FF FF FF FF FF FF FF FF
.byte $AA,$AA,$AA,$22 ; CPU:$C78E PRG:078E 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 ; CPU:$C792 PRG:0792 A4 88
lda State04FinalPhaseTable,y ; CPU:$C794 PRG:0794 B9 A1 C7
sta dispatchVector ; CPU:$C797 PRG:0797 85 10
lda State04FinalPhaseTable+1,y ; CPU:$C799 PRG:0799 B9 A2 C7
sta dispatchVector+1 ; CPU:$C79C PRG:079C 85 11 6C
jmp ($0010) ; CPU:$C79F PRG:079F 10 00 A7 C7 F2
;==============================================================================
; $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 ; CPU:$C7A1 PRG:07A1 A7 C7
.word State04FinalPhaseActive ; $88 = $02 ; CPU:$C7A3 PRG:07A3 F2 C7
.word State04FinalPhaseComplete ; $88 = $04 ; CPU:$C7A5 PRG:07A5 57 C8
;==============================================================================
; $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 ; CPU:$C7A7 PRG:07A7 A0 00
@CopyDisplayData:
lda State04FinalDisplayData,y ; CPU:$C7A9 PRG:07A9 B9 D8 C9
sta $024B,y ; CPU:$C7AC PRG:07AC 99 4B 02
iny ; CPU:$C7AF PRG:07AF C8
cmp #$FF ; CPU:$C7B0 PRG:07B0 C9 FF
bne @CopyDisplayData ; CPU:$C7B2 PRG:07B2 D0 F5
lda #$FF ; CPU:$C7B4 PRG:07B4 A9 FF
sta pacmanMotion ; CPU:$C7B6 PRG:07B6 85 1A
lda #$00 ; CPU:$C7B8 PRG:07B8 A9 00
sta $1B ; CPU:$C7BA PRG:07BA 85 1B
sta $89 ; CPU:$C7BC PRG:07BC 85 89
sta $8A ; CPU:$C7BE PRG:07BE 85 8A
lda #$F4 ; CPU:$C7C0 PRG:07C0 A9 F4
sta $0274 ; CPU:$C7C2 PRG:07C2 8D 74 02
lda #$A8 ; CPU:$C7C5 PRG:07C5 A9 A8
sta $0276 ; CPU:$C7C7 PRG:07C7 8D 76 02
lda #$01 ; CPU:$C7CA PRG:07CA A9 01
sta $028C ; CPU:$C7CC PRG:07CC 8D 8C 02
lda #$20 ; CPU:$C7CF PRG:07CF A9 20
sta $0292 ; CPU:$C7D1 PRG:07D1 8D 92 02
lda #$00 ; CPU:$C7D4 PRG:07D4 A9 00
tay ; CPU:$C7D6 PRG:07D6 A8
@ClearLowRamBlock:
sta $001E,y ; CPU:$C7D7 PRG:07D7 99 1E 00
iny ; CPU:$C7DA PRG:07DA C8
cpy #$14 ; CPU:$C7DB PRG:07DB C0 14
bne @ClearLowRamBlock ; CPU:$C7DD PRG:07DD D0 F8
tay ; CPU:$C7DF PRG:07DF A8
@ClearObjectRamBlock:
sta $0278,y ; CPU:$C7E0 PRG:07E0 99 78 02
iny ; CPU:$C7E3 PRG:07E3 C8
cpy #$14 ; CPU:$C7E4 PRG:07E4 C0 14
bne @ClearObjectRamBlock ; CPU:$C7E6 PRG:07E6 D0 F8
jsr $DAF1 ; CPU:$C7E8 PRG:07E8 20 F1 DA
inc $88 ; CPU:$C7EB PRG:07EB E6 88
inc $88 ; CPU:$C7ED PRG:07ED E6 88
jmp MainDispatchLoop ; CPU:$C7EF PRG:07EF 4C 50 C2
;==============================================================================
; $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 ; CPU:$C7F2 PRG:07F2 20 DC C8
jsr AnimateState04DisplayPattern ; CPU:$C7F5 PRG:07F5 20 B8 C9
lda $0274 ; CPU:$C7F8 PRG:07F8 AD 74 02
cmp #$E0 ; CPU:$C7FB PRG:07FB C9 E0
beq @RunMilestoneUpdate ; CPU:$C7FD PRG:07FD F0 0C
cmp #$D1 ; CPU:$C7FF PRG:07FF C9 D1
beq @RunMilestoneUpdate ; CPU:$C801 PRG:0801 F0 08
cmp #$C2 ; CPU:$C803 PRG:0803 C9 C2
beq @RunMilestoneUpdate ; CPU:$C805 PRG:0805 F0 04
cmp #$B3 ; CPU:$C807 PRG:0807 C9 B3
bne @CheckForCompletion ; CPU:$C809 PRG:0809 D0 03
@RunMilestoneUpdate:
jsr InitializeState04ObjectSlot ; CPU:$C80B PRG:080B 20 A8 C8
@CheckForCompletion:
lda $0274 ; CPU:$C80E PRG:080E AD 74 02
cmp #$40 ; CPU:$C811 PRG:0811 C9 40
beq @CompletePhase ; CPU:$C813 PRG:0813 F0 03
jmp MainDispatchLoop ; CPU:$C815 PRG:0815 4C 50 C2
@CompletePhase:
ldy #$00 ; CPU:$C818 PRG:0818 A0 00
@InitializeStructures:
lda #$00 ; CPU:$C81A PRG:081A A9 00
sta ghost1Motion,y ; CPU:$C81C PRG:081C 99 1E
lda #$C0 ; CPU:$C81E PRG:081E 00 A9
sta ghost1Motion+1,y ; CPU:$C820 PRG:0820 C0 99 1F
iny ; CPU:$C823 PRG:0823 00
iny ; CPU:$C824 PRG:0824 C8
iny ; CPU:$C825 PRG:0825 C8
iny ; CPU:$C826 PRG:0826 C8
cpy #$10 ; CPU:$C827 PRG:0827 C8 C0
bne @InitializeStructures ; CPU:$C829 PRG:0829 10 D0
lda #$01 ; CPU:$C82B PRG:082B EE A9
sta pacmanMotion ; CPU:$C82D PRG:082D 01 85
lda #$50 ; CPU:$C82F PRG:082F 1A A9
sta pacmanMotion+1 ; CPU:$C831 PRG:0831 50 85 1B
lda #$01 ; CPU:$C834 PRG:0834 A9 01
sta $0293 ; CPU:$C836 PRG:0836 8D 93 02
sta $0294 ; CPU:$C839 PRG:0839 8D 94 02
sta $0295 ; CPU:$C83C PRG:083C 8D 95 02
sta $0296 ; CPU:$C83F PRG:083F 8D 96 02
lda #$00 ; CPU:$C842 PRG:0842 A9 00
sta $89 ; CPU:$C844 PRG:0844 85 89
lda #$22 ; CPU:$C846 PRG:0846 A9 22
sta $024B ; CPU:$C848 PRG:0848 8D 4B 02
lda #$20 ; CPU:$C84B PRG:084B A9 20
sta $024D ; CPU:$C84D PRG:084D 8D 4D 02
inc $88 ; CPU:$C850 PRG:0850 E6 88
inc $88 ; CPU:$C852 PRG:0852 E6 88
jmp MainDispatchLoop ; CPU:$C854 PRG:0854 4C 50 C2
;==============================================================================
; $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 ; CPU:$C857 PRG:0857 A5 8A
beq @RunRegularUpdate ; CPU:$C859 PRG:0859 F0 47
jsr RotateState04ObjectSlots ; CPU:$C85B PRG:085B 20 2E C9
dec $8A ; CPU:$C85E PRG:085E C6 8A
beq @CountdownComplete ; CPU:$C860 PRG:0860 F0 03
jmp MainDispatchLoop ; CPU:$C862 PRG:0862 4C 50 C2
@CountdownComplete:
ldy #$00 ; CPU:$C865 PRG:0865 A0 00
@FindEntry:
lda $028D,y ; CPU:$C867 PRG:0867 B9 8D 02
and #$E0 ; CPU:$C86A PRG:086A 29 E0
bne @EntryFound ; CPU:$C86C PRG:086C D0 03
iny ; CPU:$C86E PRG:086E C8
bne @FindEntry ; CPU:$C86F PRG:086F D0 F6
@EntryFound:
lda #$00 ; CPU:$C871 PRG:0871 A9 00
sta $028D,y ; CPU:$C873 PRG:0873 99 8D 02
lda #$00 ; CPU:$C876 PRG:0876 A9 00
sta $0293,y ; CPU:$C878 PRG:0878 99 93 02
tya ; CPU:$C87B PRG:087B 98
asl ; CPU:$C87C PRG:087C 0A
asl ; CPU:$C87D PRG:087D 0A
tay ; CPU:$C87E PRG:087E A8
lda #$00 ; CPU:$C87F PRG:087F A9 00
sta $0278,y ; CPU:$C881 PRG:0881 99 78 02
sta $027A,y ; CPU:$C884 PRG:0884 99 7A 02
sta ghost1Motion,y ; CPU:$C887 PRG:0887 99 1E
sta ghost1Motion+1,y ; CPU:$C889 PRG:0889 00 99 1F
lda #$A8 ; CPU:$C88C PRG:088C 00 A9
sta $0276 ; CPU:$C88E PRG:088E A8 8D 76
lda $89 ; CPU:$C891 PRG:0891 02 A5
cmp #$04 ; CPU:$C893 PRG:0893 89 C9
beq @FinishSequence ; CPU:$C895 PRG:0895 04 F0
jmp MainDispatchLoop ; CPU:$C897 PRG:0897 03 4C 50
@FinishSequence:
lda #$01 ; CPU:$C89A PRG:089A C2 A9
sta activePlayerFlag ; CPU:$C89C PRG:089C 01 85
jmp GameModeEntry ; CPU:$C89E PRG:089E 47 4C 54
@RunRegularUpdate:
jsr UpdateState04Objects ; CPU:$C8A1 PRG:08A1 CA 20 DC
jmp MainDispatchLoop ; CPU:$C8A4 PRG:08A4 C8 4C 50
;==============================================================================
; $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 ; CPU:$C8A8 PRG:08A8 A0 00
sty workPtr0 ; CPU:$C8AA PRG:08AA 84 00
@FindFreeSlot:
lda $0278,y ; CPU:$C8AC PRG:08AC B9 78 02
beq @InitializeSlot ; CPU:$C8AF PRG:08AF F0 08
inc workPtr0 ; CPU:$C8B1 PRG:08B1 E6 00
iny ; CPU:$C8B3 PRG:08B3 C8
iny ; CPU:$C8B4 PRG:08B4 C8
iny ; CPU:$C8B5 PRG:08B5 C8
iny ; CPU:$C8B6 PRG:08B6 C8
bne @FindFreeSlot ; CPU:$C8B7 PRG:08B7 D0 F3
@InitializeSlot:
lda #$F4 ; CPU:$C8B9 PRG:08B9 A9 F4
sta $0278,y ; CPU:$C8BB PRG:08BB 99 78 02
lda #$A8 ; CPU:$C8BE PRG:08BE A9 A8
sta $027A,y ; CPU:$C8C0 PRG:08C0 99 7A 02
lda #$FF ; CPU:$C8C3 PRG:08C3 A9 FF
sta ghost1Motion,y ; CPU:$C8C5 PRG:08C5 99 1E
lda #$00 ; CPU:$C8C7 PRG:08C7 00 A9
sta $001F,y ; CPU:$C8C9 PRG:08C9 00 99 1F
ldy workPtr0 ; CPU:$C8CC PRG:08CC 00 A4
lda $89 ; CPU:$C8CE PRG:08CE 00 A5
sta $0293,y ; CPU:$C8D0 PRG:08D0 89 99 93
lda #$0C ; CPU:$C8D3 PRG:08D3 02 A9
sta $028D,y ; CPU:$C8D5 PRG:08D5 0C 99 8D
inc $89 ; CPU:$C8D8 PRG:08D8 02 E6
rts ; CPU:$C8DA PRG:08DA 89
;==============================================================================
; $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 ; CPU:$C8DC PRG:08DC 20 19 EA
jsr RotateState04ObjectSlots ; CPU:$C8DF PRG:08DF 20 2E C9
jsr UpdateState04ObjectStatus ; CPU:$C8E2 PRG:08E2 20 FA C9
jsr CheckState04ObjectTrigger ; CPU:$C8E5 PRG:08E5 20 EB C8
jmp BuildEntitySpriteBuffer ; CPU:$C8E8 PRG:08E8 4C F1 DA
;==============================================================================
; $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 ; CPU:$C8EB PRG:08EB A5 1A
bpl @Continue ; CPU:$C8ED PRG:08ED 10 01
rts ; CPU:$C8EF PRG:08EF 60
@Continue:
lda $0274 ; CPU:$C8F0 PRG:08F0 AD 74 02
clc ; CPU:$C8F3 PRG:08F3 18
adc #$08 ; CPU:$C8F4 PRG:08F4 69 08
sta workPtr0 ; CPU:$C8F6 PRG:08F6 85 00
ldy #$00 ; CPU:$C8F8 PRG:08F8 A0 00
sty workPtr0+1 ; CPU:$C8FA PRG:08FA 84 01 B9
@ScanObjects:
lda $0278,y ; CPU:$C8FD PRG:08FD 78 02 F0
beq @NextObject ; CPU:$C900 PRG:0900 04 C5
cmp workPtr0 ; CPU:$C902 PRG:0902 00 90
bcc @TriggerEvent ; CPU:$C904 PRG:0904 0B E6
@NextObject:
inc workPtr0+1 ; CPU:$C906 PRG:0906 01 C8
iny ; CPU:$C908 PRG:0908 C8
iny ; CPU:$C909 PRG:0909 C8
iny ; CPU:$C90A PRG:090A C8
iny ; CPU:$C90B PRG:090B C0
cpy #$10 ; CPU:$C90C PRG:090C 10 D0
bne @ScanObjects ; CPU:$C90E PRG:090E ED 60
rts ; CPU:$C910 PRG:0910 A4
@TriggerEvent:
ldy $89 ; CPU:$C911 PRG:0911 89 E6
inc $89 ; CPU:$C913 PRG:0913 89 A9
lda #$40 ; CPU:$C915 PRG:0915 40 85
sta $8A ; CPU:$C917 PRG:0917 8A B9
lda $C9EE,y ; CPU:$C919 PRG:0919 EE C9 A4
ldy workPtr0+1 ; CPU:$C91C PRG:091C 01 99 8D
sta $028D,y ; CPU:$C91F PRG:091F 02 A9 00
lda #$00 ; CPU:$C922 PRG:0922 99 93
sta $0293,y ; CPU:$C924 PRG:0924 02 A9 00
lda #$00 ; CPU:$C927 PRG:0927 8D 8C
sta $028C ; CPU:$C929 PRG:0929 02 8D 76
sta $0276 ; CPU:$C92C PRG:092C 02 60 A5
rts ; CPU:$C92F PRG:092F 1E
;==============================================================================
; $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 ; CPU:$C92E PRG:092E A5 1E
sta workPtr0 ; CPU:$C930 PRG:0930 85 00
lda ghost1Motion+1 ; CPU:$C932 PRG:0932 A5 1F 85
sta workPtr0+1 ; CPU:$C935 PRG:0935 01 A0 00
ldy #$00 ; CPU:$C938 PRG:0938 B9 22
@ShiftLowRamStructures:
lda ghost2Motion,y ; CPU:$C93A PRG:093A 00 99
sta ghost1Motion,y ; CPU:$C93C PRG:093C 1E 00
lda ghost2Motion+1,y ; CPU:$C93E PRG:093E B9 23 00
sta ghost1Motion+1,y ; CPU:$C941 PRG:0941 99 1F 00
iny ; CPU:$C944 PRG:0944 C8
iny ; CPU:$C945 PRG:0945 C8
iny ; CPU:$C946 PRG:0946 C8
iny ; CPU:$C947 PRG:0947 C8
cpy #$0C ; CPU:$C948 PRG:0948 C0 0C
bne @ShiftLowRamStructures ; CPU:$C94A PRG:094A D0 EC
lda workPtr0 ; CPU:$C94C PRG:094C A5 00
sta ghost4Motion ; CPU:$C94E PRG:094E 85 2A
lda workPtr0+1 ; CPU:$C950 PRG:0950 A5 01 85
sta ghost4Motion+1 ; CPU:$C953 PRG:0953 2B AD 78
; -------------------------------------------------------------------------
; Rotate four complete 4-byte structures at $0278-$0287.
; -------------------------------------------------------------------------
lda $0278 ; CPU:$C956 PRG:0956 02 85 00
sta workPtr0 ; CPU:$C959 PRG:0959 AD 79
lda $0279 ; CPU:$C95B PRG:095B 02 85 01
sta workPtr0+1 ; CPU:$C95E PRG:095E AD 7A 02
lda $027A ; CPU:$C961 PRG:0961 85 02 AD
sta workPtr1 ; CPU:$C964 PRG:0964 7B 02
lda $027B ; CPU:$C966 PRG:0966 85 03 A0
sta workPtr1+1 ; CPU:$C969 PRG:0969 00 B9 7C
ldy #$00 ; CPU:$C96C PRG:096C 02 99
@ShiftObjectStructures:
lda $027C,y ; CPU:$C96E PRG:096E 78 02 C8
sta $0278,y ; CPU:$C971 PRG:0971 C0 0C D0
iny ; CPU:$C974 PRG:0974 F5
cpy #$0C ; CPU:$C975 PRG:0975 A5 00
bne @ShiftObjectStructures ; CPU:$C977 PRG:0977 8D 84
lda workPtr0 ; CPU:$C979 PRG:0979 02 A5
sta $0284 ; CPU:$C97B PRG:097B 01 8D 85
lda workPtr0+1 ; CPU:$C97E PRG:097E 02 A5 02
sta $0285 ; CPU:$C981 PRG:0981 8D 86 02
lda workPtr1 ; CPU:$C984 PRG:0984 A5 03
sta $0286 ; CPU:$C986 PRG:0986 8D 87 02
lda workPtr1+1 ; CPU:$C989 PRG:0989 AD 8D 02
sta $0287 ; CPU:$C98C PRG:098C 85 00 A0
; -------------------------------------------------------------------------
; Rotate the four status bytes at $028D-$0290.
; -------------------------------------------------------------------------
lda $028D ; CPU:$C98F PRG:098F 00 B9 8E
sta workPtr0 ; CPU:$C992 PRG:0992 02 99
ldy #$00 ; CPU:$C994 PRG:0994 8D 02
@ShiftStatusArray:
lda $028E,y ; CPU:$C996 PRG:0996 C8 C0 03
sta $028D,y ; CPU:$C999 PRG:0999 D0 F5 A5
iny ; CPU:$C99C PRG:099C 00
cpy #$03 ; CPU:$C99D PRG:099D 8D 90
bne @ShiftStatusArray ; CPU:$C99F PRG:099F 02 AD
lda workPtr0 ; CPU:$C9A1 PRG:09A1 93 02
sta $0290 ; CPU:$C9A3 PRG:09A3 85 00 A0
; -------------------------------------------------------------------------
; Rotate the four associated index/state bytes at $0293-$0296.
; -------------------------------------------------------------------------
lda $0293 ; CPU:$C9A6 PRG:09A6 00 B9 94
sta workPtr0 ; CPU:$C9A9 PRG:09A9 02 99
ldy #$00 ; CPU:$C9AB PRG:09AB 93 02
@ShiftIndexArray:
lda $0294,y ; CPU:$C9AD PRG:09AD C8 C0 03
sta $0293,y ; CPU:$C9B0 PRG:09B0 D0 F5 A5
iny ; CPU:$C9B3 PRG:09B3 00
cpy #$03 ; CPU:$C9B4 PRG:09B4 8D 96
bne @ShiftIndexArray ; CPU:$C9B6 PRG:09B6 02 60
lda workPtr0 ; CPU:$C9B8 PRG:09B8 A5 4B
sta $0296 ; CPU:$C9BA PRG:09BA 29 07 F0
rts ; CPU:$C9BD PRG:09BD 01
;==============================================================================
; $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 ; CPU:$C9B8 PRG:09B8 A5 4B
and #$07 ; CPU:$C9BA PRG:09BA 29 07
beq @UpdatePattern ; CPU:$C9BC PRG:09BC F0 01
rts ; CPU:$C9BE PRG:09BE 60
@UpdatePattern:
ldx #$00 ; CPU:$C9BF PRG:09BF A2 00
ldy #$00 ; CPU:$C9C1 PRG:09C1 A0 00
lda frameCounter ; CPU:$C9C3 PRG:09C3 A5 4B
and #$08 ; CPU:$C9C5 PRG:09C5 29 08
beq @CopyPattern ; CPU:$C9C7 PRG:09C7 F0 02
ldy #$04 ; CPU:$C9C9 PRG:09C9 A0 04
@CopyPattern:
lda State04AnimationFrames,y ; CPU:$C9CB PRG:09CB B9 F2 C9
sta $024B,x ; CPU:$C9CE PRG:09CE 9D 4B 02
inx ; CPU:$C9D1 PRG:09D1 E8
iny ; CPU:$C9D2 PRG:09D2 C8
cpx #$04 ; CPU:$C9D3 PRG:09D3 E0 04
bne @CopyPattern ; CPU:$C9D5 PRG:09D5 D0 F4
rts ; CPU:$C9D7 PRG:09D7 60
;==============================================================================
; $C9D8-$C9ED: State $04 Final Display Data
;==============================================================================
State04FinalDisplayData:
.byte $22,$AD ; CPU:$C9D8 PRG:09D8 22 AD
.byte $2D,$2D,$2D,$2D,$2D,$2D,$2D,$2D ; CPU:$C9DA PRG:09DA 2D 2D 2D 2D 2D 2D 2D 2D
.byte $00 ; CPU:$C9E2 PRG:09E2 00
.byte $22,$ED ; CPU:$C9E3 PRG:09E3 22 ED
.byte $2D,$2D,$2D,$2D,$2D,$2D,$2D,$2D ; CPU:$C9E5 PRG:09E5 2D 2D 2D 2D 2D 2D 2D 2D
.byte $FF ; CPU:$C9ED PRG:09ED FF
;------------------------------------------------------------------------------
; $C9EE-$C9F1: Adjacent data, purpose not yet resolved.
;------------------------------------------------------------------------------
State04UnknownData:
.byte $2D,$2F,$32,$34 ; CPU:$C9EE PRG:09EE 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 ; CPU:$C9F2 PRG:09F2 22 C7 20 FF
.byte $22,$C7,$01,$FF ; CPU:$C9F6 PRG:09F6 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 ; CPU:$C9FA PRG:09FA A2 00
lda $1A ; CPU:$C9FC PRG:09FC A5 1A
bmi @UseTableBase ; CPU:$C9FE PRG:09FE 30 02
ldx #$0A ; CPU:$CA00 PRG:0A00 A2 0A
@UseTableBase:
stx workPtr0 ; CPU:$CA02 PRG:0A02 86 00
inc $B7 ; CPU:$CA04 PRG:0A04 E6 B7
lda $B7 ; CPU:$CA06 PRG:0A06 A5 B7
and #$07 ; CPU:$CA08 PRG:0A08 29 07
clc ; CPU:$CA0A PRG:0A0A 18
adc workPtr0 ; CPU:$CA0B PRG:0A0B 65 00
tay ; CPU:$CA0D PRG:0A0D A8
lda State04ObjectStatusTable,y ; CPU:$CA0E PRG:0A0E B9 40 CA
sta $028C ; CPU:$CA11 PRG:0A11 8D 8C 02
; Only update the four object entries once every eight frames.
lda $4B ; CPU:$CA14 PRG:0A14 A5 4B
and #$07 ; CPU:$CA16 PRG:0A16 29 07
beq @UpdateObjectEntries ; CPU:$CA18 PRG:0A18 F0 01
rts ; CPU:$CA1A PRG:0A1A 60
@UpdateObjectEntries:
lda frameCounter ; CPU:$CA1B PRG:0A1B A5 4B
and #$08 ; CPU:$CA1D PRG:0A1D 29 08
beq @SelectTableValue ; CPU:$CA1F PRG:0A1F F0 02
lda #$01 ; CPU:$CA21 PRG:0A21 A9 01
@SelectTableValue:
clc ; CPU:$CA23 PRG:0A23 18
adc workPtr0 ; CPU:$CA24 PRG:0A24 65 00
adc #$08 ; CPU:$CA26 PRG:0A26 69 08
tay ; CPU:$CA28 PRG:0A28 A8
lda State04ObjectStatusTable,y ; CPU:$CA29 PRG:0A29 B9 40 CA
sta workPtr0 ; CPU:$CA2C PRG:0A2C 85 00
ldy #$00 ; CPU:$CA2E PRG:0A2E A0 00
@UpdateStatusEntries:
lda $028D,y ; CPU:$CA30 PRG:0A30 B9 8D 02
beq @NextStatusEntry ; CPU:$CA33 PRG:0A33 F0 05
lda workPtr0 ; CPU:$CA35 PRG:0A35 A5 00
sta $028D,y ; CPU:$CA37 PRG:0A37 99 8D 02
@NextStatusEntry:
iny ; CPU:$CA3A PRG:0A3A C8
cpy #$04 ; CPU:$CA3B PRG:0A3B C0 04
bne @UpdateStatusEntries ; CPU:$CA3D PRG:0A3D D0 F1
rts ; CPU:$CA3F PRG:0A3F 60
;==============================================================================
; $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 ; CPU:$CA40 PRG:0A40 04 04 04 05 05 04 01 01
.byte $0C,$0D ; CPU:$CA48 PRG:0A48 0C 0D
; Group 1, selected while $1A is nonnegative.
.byte $08,$08,$08,$09,$09,$08,$01,$01 ; CPU:$CA4A PRG:0A4A 08 08 08 09 09 08 01 01
.byte $1E,$1F ; CPU:$CA52 PRG:0A52 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 ; CPU:$CA54 PRG:0A54 A9 08
sta PPUCTRL ; CPU:$CA56 PRG:0A56 8D 00 20
sta ppuCtrlShadow ; CPU:$CA59 PRG:0A59 85 43
@WaitForVBlank:
lda PPUSTATUS ; CPU:$CA5B PRG:0A5B AD 02 20
bpl @WaitForVBlank ; CPU:$CA5E PRG:0A5E 10 FB
lda #$00 ; CPU:$CA60 PRG:0A60 A9 00
sta PPUMASK ; CPU:$CA62 PRG:0A62 8D 01 20
sta gameState ; CPU:$CA65 PRG:0A65 85 3F
sta cocktailModeFlag ; CPU:$CA67 PRG:0A67 85 46
sta $69 ; CPU:$CA69 PRG:0A69 85 69
sta $4A ; CPU:$CA6B PRG:0A6B 85 4A
jsr ClearGameplayNametables ; CPU:$CA6D PRG:0A6D 20 85 E3
jsr DrawGameplayHudLabels ; CPU:$CA70 PRG:0A70 20 02 E5
jsr DrawGameplayScoreFields ; CPU:$CA73 PRG:0A73 20 FF E3
lda gameplaySuspended ; CPU:$CA76 PRG:0A76 A5 48
beq @ClearPlayerState ; CPU:$CA78 PRG:0A78 F0 06
lda #$01 ; CPU:$CA7A PRG:0A7A A9 01
sta roundNumber ; CPU:$CA7C PRG:0A7C 85 67
bne @InitializeCommonState ; CPU:$CA7E PRG:0A7E D0 17
@ClearPlayerState:
lda #$00 ; CPU:$CA80 PRG:0A80 A9 00
tay ; CPU:$CA82 PRG:0A82 A8
@ClearPlayerStateLoop:
sta roundNumber,y ; CPU:$CA83 PRG:0A83 99 67
iny ; CPU:$CA85 PRG:0A85 00
cpy #$20 ; CPU:$CA86 PRG:0A86 C8 C0
bne @ClearPlayerStateLoop ; CPU:$CA88 PRG:0A88 20 D0
lda #$03 ; CPU:$CA8A PRG:0A8A F8 A9
sta roundNumber ; CPU:$CA8C PRG:0A8C 03 85
sta $77 ; CPU:$CA8E PRG:0A8E 67 85
sta $0600 ; CPU:$CA90 PRG:0A90 77 8D 00
sta $0601 ; CPU:$CA93 PRG:0A93 06 8D 01
@InitializeCommonState:
lda #$FF ; CPU:$CA96 PRG:0A96 06 A9
sta roundDisplayValue ; CPU:$CA98 PRG:0A98 FF 85
sta $78 ; CPU:$CA9A PRG:0A9A 68 85
sta $0245 ; CPU:$CA9C PRG:0A9C 78 8D 45
lda #$88 ; CPU:$CA9F PRG:0A9F 02 A9
sta ppuCtrlShadow ; CPU:$CAA1 PRG:0AA1 88 85
sta PPUCTRL ; CPU:$CAA3 PRG:0AA3 43 8D 00
GameModeFrameSync:
@WaitForNextFrame:
lda #$01 ; CPU:$CAA7 PRG:0AA7 A9 01
sta $40 ; CPU:$CAA9 PRG:0AA9 85 40
@WaitForNmi:
lda $40 ; CPU:$CAAB PRG:0AAB A5 40
bne @WaitForNmi ; CPU:$CAAD PRG:0AAD D0 FC
@DispatchLoop:
lda gameplaySuspended ; CPU:$CAAF PRG:0AAF A5 48
beq @ProcessDelay ; CPU:$CAB1 PRG:0AB1 F0 0D
lda currentInput ; CPU:$CAB3 PRG:0AB3 A5 4D
and #$0C ; CPU:$CAB5 PRG:0AB5 29 0C
beq @ProcessDelay ; CPU:$CAB7 PRG:0AB7 F0 07
lda #$02 ; TODO: what is state $02? ; CPU:$CAB9 PRG:0AB9 A9 02
sta gameState ; CPU:$CABB PRG:0ABB 85 3F
jmp MainEntry ; CPU:$CABD PRG:0ABD 4C E7 C1
@ProcessDelay:
lda stateTimer ; CPU:$CAC0 PRG:0AC0 A5 4C
beq @DispatchState ; CPU:$CAC2 PRG:0AC2 F0 04
dec stateTimer ; CPU:$CAC4 PRG:0AC4 C6 4C
bne @WaitForNextFrame ; CPU:$CAC6 PRG:0AC6 D0 DF
@DispatchState:
ldy gameState ; CPU:$CAC8 PRG:0AC8 A4 3F
lda GameModeStateTable,y ; CPU:$CACA PRG:0ACA B9 D7 CA
sta dispatchVector ; CPU:$CACD PRG:0ACD 85 10
lda GameModeStateTable+1,y ; CPU:$CACF PRG:0ACF B9 D8 CA
sta dispatchVector+1 ; CPU:$CAD2 PRG:0AD2 85 11 6C
jmp ($0010) ; CPU:$CAD5 PRG:0AD5 10 00 F3 CE 67
;==============================================================================
; $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 ; CPU:$CAD7 PRG:0AD7 F3 CE
.word GameModeState02 ; $3F = $02 ; CPU:$CAD9 PRG:0AD9 67 CB
.word GameModeState04 ; $3F = $04 ; CPU:$CADB PRG:0ADB E9 CA
.word GameModeState06 ; $3F = $06 ; CPU:$CADD PRG:0ADD D9 CC
.word GameModeState08 ; $3F = $08 ; CPU:$CADF PRG:0ADF 06 CD
.word GameModeState0A ; $3F = $0A ; CPU:$CAE1 PRG:0AE1 1F CE
.word GameModeState0C ; $3F = $0C ; CPU:$CAE3 PRG:0AE3 B0 CD
.word InitializeGameplayTransitionState ; CPU:$CAE5 PRG:0AE5 D6 E6
; $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 ; CPU:$CAE7 PRG:0AE7 BF E7
;==============================================================================
; $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 ; CPU:$CAE9 PRG:0AE9 AD 0F 06
beq @CheckPauseInput ; CPU:$CAEC PRG:0AEC F0 03
jmp GameModeFrameSync ; CPU:$CAEE PRG:0AEE 4C A7 CA
@CheckPauseInput:
lda currentInput ; CPU:$CAF1 PRG:0AF1 A5 4D
and #$08 ; CPU:$CAF3 PRG:0AF3 29 08
cmp $49 ; CPU:$CAF5 PRG:0AF5 C5 49
beq @ProcessCurrentMode ; CPU:$CAF7 PRG:0AF7 F0 38
sta $49 ; CPU:$CAF9 PRG:0AF9 85 49
lda $49 ; CPU:$CAFB PRG:0AFB A5 49
beq @ProcessCurrentMode ; CPU:$CAFD PRG:0AFD F0 32
inc $4A ; CPU:$CAFF PRG:0AFF E6 4A
ldx #$22 ; CPU:$CB01 PRG:0B01 A2 22
lda activePlayerFlag ; CPU:$CB03 PRG:0B03 A5 47
and cocktailModeFlag ; CPU:$CB05 PRG:0B05 25 46
beq @SetCommandAddress ; CPU:$CB07 PRG:0B07 F0 02
ldx #$2A ; CPU:$CB09 PRG:0B09 A2 2A
@SetCommandAddress:
stx $024B ; CPU:$CB0B PRG:0B0B 8E 4B 02
lda #$37 ; CPU:$CB0E PRG:0B0E A9 37
sta $024C ; CPU:$CB10 PRG:0B10 8D 4C 02
ldx #$06 ; CPU:$CB13 PRG:0B13 A2 06
ldy #$00 ; CPU:$CB15 PRG:0B15 A0 00
lda $4A ; CPU:$CB17 PRG:0B17 A5 4A
and #$01 ; CPU:$CB19 PRG:0B19 29 01
beq @CopyPauseData ; CPU:$CB1B PRG:0B1B F0 05
ldx #$00 ; CPU:$CB1D PRG:0B1D A2 00
sta $060F ; CPU:$CB1F PRG:0B1F 8D 0F 06
@CopyPauseData:
lda PauseDisplayData,x ; CPU:$CB22 PRG:0B22 BD 5B CB
sta $024D,y ; CPU:$CB25 PRG:0B25 99 4D 02
inx ; CPU:$CB28 PRG:0B28 E8
iny ; CPU:$CB29 PRG:0B29 C8
cpy #$06 ; CPU:$CB2A PRG:0B2A C0 06
bne @CopyPauseData ; CPU:$CB2C PRG:0B2C D0 F4
jmp GameModeFrameSync ; CPU:$CB2E PRG:0B2E 4C A7 CA
@ProcessCurrentMode:
lda $4A ; CPU:$CB31 PRG:0B31 A5 4A
and #$01 ; CPU:$CB33 PRG:0B33 29 01
beq @RunFrameUpdates ; CPU:$CB35 PRG:0B35 F0 03
jmp GameModeFrameSync ; CPU:$CB37 PRG:0B37 4C A7 CA
@RunFrameUpdates:
jsr UpdateGameplayTimers ; CPU:$CB3A PRG:0B3A 20 A0 D1
jsr UpdateGameplayTileState ; CPU:$CB3D PRG:0B3D 20 7C DF
jsr UpdatePlayerMovement ; CPU:$CB40 PRG:0B40 20 90 D3
jsr UpdatePlayerDirectionAnimation ; CPU:$CB43 PRG:0B43 20 8E D9
jsr UpdateGameplayEntities ; CPU:$CB46 PRG:0B46 20 57 D5
jsr UpdateEntitySpriteStates ; CPU:$CB49 PRG:0B49 20 CC D9
jsr UpdateEntityStatusFlags ; CPU:$CB4C PRG:0B4C 20 5E D9
jsr UpdatePeriodicFourEntryState ; CPU:$CB4F PRG:0B4F 20 5E DE
jsr CheckGameplayProximity ; CPU:$CB52 PRG:0B52 20 A4 D2
jsr CheckEntityCollisions ; CPU:$CB55 PRG:0B55 20 40 DA
jmp GameModeFrameSync ; CPU:$CB58 PRG:0B58 4C A7 CA
;==============================================================================
; $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 ; CPU:$CB5B PRG:0B5B 50 41 55 53 45 FF
.byte $2D,$2D,$2D,$2D,$2D,$FF ; CPU:$CB61 PRG:0B61 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 ; CPU:$CB67 PRG:0B67 A5 87
beq @BuildInitialData ; CPU:$CB69 PRG:0B69 F0 03
jmp @AdvancePhase ; CPU:$CB6B PRG:0B6B 4C E4 CB
@BuildInitialData:
lda #$60 ; CPU:$CB6E PRG:0B6E A9 60
sta workPtr0 ; CPU:$CB70 PRG:0B70 85 00
lda #$07 ; CPU:$CB72 PRG:0B72 A9 07
sta workPtr0+1 ; CPU:$CB74 PRG:0B74 85 01 A5
lda $48 ; CPU:$CB77 PRG:0B77 48 D0
bne @AdvancePhase ; CPU:$CB79 PRG:0B79 6A A9
lda #$02 ; CPU:$CB7B PRG:0B7B 02 85
sta workValue0 ; CPU:$CB7D PRG:0B7D 04 A0
ldy #$00 ; CPU:$CB7F PRG:0B7F 00 84
sty workValue1 ; CPU:$CB81 PRG:0B81 05 84
sty workValue2 ; CPU:$CB83 PRG:0B83 06 84
sty workValue3 ; CPU:$CB85 PRG:0B85 07 A6
@BuildOuterLoop:
ldx workValue2 ; CPU:$CB87 PRG:0B87 06 BD
lda State02PositionTable,x ; CPU:$CB89 PRG:0B89 C0 CC 85
sta workPtr1 ; CPU:$CB8C PRG:0B8C 02 BD
lda State02PositionTable + 1,x ; CPU:$CB8E PRG:0B8E C1 CC 85
sta workPtr1+1 ; CPU:$CB91 PRG:0B91 03 A6 07
ldx workValue3 ; CPU:$CB94 PRG:0B94 BD C6
lda State02EntryCounts,x ; CPU:$CB96 PRG:0B96 CC 85 08
sta workValue4 ; CPU:$CB99 PRG:0B99 A5 03
@BuildInnerLoop:
lda workPtr1+1 ; CPU:$CB9B PRG:0B9B 91 00 A6
sta ($00),y ; CPU:$CB9E PRG:0B9E 05 BD
ldx workValue1 ; CPU:$CBA0 PRG:0BA0 9C CC
lda State02ValueTableA,x ; CPU:$CBA2 PRG:0BA2 C8 91 00
iny ; CPU:$CBA5 PRG:0BA5 BD
sta (workPtr0),y ; CPU:$CBA6 PRG:0BA6 AE CC
lda State02ValueTableB,x ; CPU:$CBA8 PRG:0BA8 C8 91 00
iny ; CPU:$CBAB PRG:0BAB A5
sta (workPtr0),y ; CPU:$CBAC PRG:0BAC 02 C8
lda workPtr1 ; CPU:$CBAE PRG:0BAE 91 00
iny ; CPU:$CBB0 PRG:0BB0 A5
sta ($00),y ; CPU:$CBB1 PRG:0BB1 02 18
lda workPtr1 ; CPU:$CBB3 PRG:0BB3 69 08
clc ; CPU:$CBB5 PRG:0BB5 85
adc #$08 ; CPU:$CBB6 PRG:0BB6 02 C8
sta workPtr1 ; CPU:$CBB8 PRG:0BB8 E6 05
iny ; CPU:$CBBA PRG:0BBA C6
inc workValue1 ; CPU:$CBBB PRG:0BBB 08 D0
dec workValue4 ; CPU:$CBBD PRG:0BBD DB E6
bne @BuildInnerLoop ; CPU:$CBBF PRG:0BBF 06 E6
inc workValue2 ; CPU:$CBC1 PRG:0BC1 06 E6
inc workValue2 ; CPU:$CBC3 PRG:0BC3 07 A5
inc workValue3 ; CPU:$CBC5 PRG:0BC5 69 D0
lda $69 ; CPU:$CBC7 PRG:0BC7 04 A5
bne @ContinueBuild ; CPU:$CBC9 PRG:0BC9 68 D0
lda roundDisplayValue ; CPU:$CBCB PRG:0BCB 18 C6
bne @AdvancePhase ; CPU:$CBCD PRG:0BCD 04 F0
@ContinueBuild:
dec workValue0 ; CPU:$CBCF PRG:0BCF 04 10
beq @CheckPlayerMode ; CPU:$CBD1 PRG:0BD1 B4 30
bpl @BuildOuterLoop ; CPU:$CBD3 PRG:0BD3 10 A5
bmi @AdvancePhase ; CPU:$CBD5 PRG:0BD5 47 F0
@CheckPlayerMode:
lda activePlayerFlag ; CPU:$CBD7 PRG:0BD7 0C A5
beq @AdvancePhase ; CPU:$CBD9 PRG:0BD9 46 F0
lda cocktailModeFlag ; CPU:$CBDB PRG:0BDB AA E6
beq @BuildOuterLoop ; CPU:$CBDD PRG:0BDD 05 E6
inc workValue1 ; CPU:$CBDF PRG:0BDF 05 E6
inc workValue1 ; CPU:$CBE1 PRG:0BE1 05 D0
inc workValue1 ; CPU:$CBE3 PRG:0BE3 A2 A5
bne @BuildOuterLoop ; CPU:$CBE5 PRG:0BE5 87 C9
;------------------------------------------------------------------------------
; $CBE4
; Frame-based progression portion of the same state.
;------------------------------------------------------------------------------
@AdvancePhase:
lda $87 ; CPU:$CBE7 PRG:0BE7 C0 D0
cmp #$C0 ; CPU:$CBE9 PRG:0BE9 03 4C
bne @IncrementPhase ; CPU:$CBEB PRG:0BEB 7C CC
jmp $CC7C ; CPU:$CBED PRG:0BED E6 87 A5
@IncrementPhase:
inc $87 ; CPU:$CBF0 PRG:0BF0 87 C9
lda $87 ; CPU:$CBF2 PRG:0BF2 78 F0
cmp #$78 ; CPU:$CBF4 PRG:0BF4 03 4C
beq @InitializeMidPhase ; CPU:$CBF6 PRG:0BF6 99 CC
jmp $CC99 ; CPU:$CBF8 PRG:0BF8 A9 A8 85
@InitializeMidPhase:
lda #$A8 ; CPU:$CBFB PRG:0BFB 1C A9
sta $1C ; CPU:$CBFD PRG:0BFD 60 85
lda #$60 ; CPU:$CBFF PRG:0BFF 1A 85
sta pacmanMotion ; CPU:$CC01 PRG:0C01 1E 85
sta ghost1Motion ; CPU:$CC03 PRG:0C03 22 A9
sta ghost2Motion ; CPU:$CC05 PRG:0C05 58 85
lda #$58 ; CPU:$CC07 PRG:0C07 26 85
sta ghost3Motion ; CPU:$CC09 PRG:0C09 20 A9
sta $20 ; CPU:$CC0B PRG:0C0B 68 85
lda #$68 ; CPU:$CC0D PRG:0C0D 2A A9
sta ghost4Motion ; CPU:$CC0F PRG:0C0F 70 85
lda #$70 ; CPU:$CC11 PRG:0C11 24 85
sta $24 ; CPU:$CC13 PRG:0C13 28 85
sta $28 ; CPU:$CC15 PRG:0C15 2C A9
sta $2C ; CPU:$CC17 PRG:0C17 00 A8
lda #$00 ; CPU:$CC19 PRG:0C19 99 78
tay ; CPU:$CC1B PRG:0C1B 07
@ClearOamRegion:
sta $0778,y ; CPU:$CC1C PRG:0C1C C8 C0 24
iny ; CPU:$CC1F PRG:0C1F D0
cpy #$24 ; CPU:$CC20 PRG:0C20 F8 A5
bne @ClearOamRegion ; CPU:$CC22 PRG:0C22 47 25
lda activePlayerFlag ; CPU:$CC24 PRG:0C24 46 F0
and cocktailModeFlag ; CPU:$CC26 PRG:0C26 02 A9
beq @NoPlayerOffset ; CPU:$CC28 PRG:0C28 08 85
lda #$08 ; CPU:$CC2A PRG:0C2A 00 A5
@NoPlayerOffset:
sta $00 ; CPU:$CC2C PRG:0C2C 67 38
lda $67 ; CPU:$CC2E PRG:0C2E E9 01
sec ; CPU:$CC30 PRG:0C30 0A
sbc #$01 ; CPU:$CC31 PRG:0C31 A8 B9
asl ; CPU:$CC33 PRG:0C33 D1
tay ; CPU:$CC34 PRG:0C34 CC
lda State02DisplayAddressTable,y ; CPU:$CC35 PRG:0C35 18 65 00
clc ; CPU:$CC38 PRG:0C38 85
adc workPtr0 ; CPU:$CC39 PRG:0C39 00 B9
sta workPtr0 ; CPU:$CC3B PRG:0C3B D2 CC
lda State02DisplayAddressTable+1,y ; CPU:$CC3D PRG:0C3D 85 01 A5
sta workPtr0+1 ; CPU:$CC40 PRG:0C40 00 8D 4B
lda workPtr0 ; CPU:$CC43 PRG:0C43 02 A5
sta $024B ; CPU:$CC45 PRG:0C45 01 8D 4C
lda workPtr0+1 ; CPU:$CC48 PRG:0C48 02 A9 2D
sta $024C ; CPU:$CC4B PRG:0C4B 8D 4D 02
lda #$2D ; CPU:$CC4E PRG:0C4E 8D 4E
sta $024D ; CPU:$CC50 PRG:0C50 02 A9 00
sta $024E ; CPU:$CC53 PRG:0C53 8D 4F 02
lda #$00 ; CPU:$CC56 PRG:0C56 A5 00
sta $024F ; CPU:$CC58 PRG:0C58 8D 50 02
lda $00 ; CPU:$CC5B PRG:0C5B A5 01
sta $0250 ; CPU:$CC5D PRG:0C5D 18 69 20
lda $01 ; CPU:$CC60 PRG:0C60 8D 51
clc ; CPU:$CC62 PRG:0C62 02
adc #$20 ; CPU:$CC63 PRG:0C63 A9 2D
sta $0251 ; CPU:$CC65 PRG:0C65 8D 52 02
lda #$2D ; CPU:$CC68 PRG:0C68 8D 53
sta $0252 ; CPU:$CC6A PRG:0C6A 02 A9 FF
sta $0253 ; CPU:$CC6D PRG:0C6D 8D 54 02
lda #$FF ; CPU:$CC70 PRG:0C70 20 8E
sta $0254 ; CPU:$CC72 PRG:0C72 D9 20 CC
jsr UpdatePlayerDirectionAnimation ; CPU:$CC75 PRG:0C75 D9 20 40
jsr UpdateEntitySpriteStates ; CPU:$CC78 PRG:0C78 DA 4C 99
jsr $DA40 ; CPU:$CC7B PRG:0C7B CC AD 00
jmp $CC99 ; CPU:$CC7E PRG:0C7E 06 0D 01
@CheckCompletion:
lda $0600 ; CPU:$CC81 PRG:0C81 06 D0 15
ora $0601 ; CPU:$CC84 PRG:0C84 A5 48 D0
bne $CC99 ; CPU:$CC87 PRG:0C87 0D A9
lda $48 ; CPU:$CC89 PRG:0C89 00 85
bne @AdvanceMainState ; CPU:$CC8B PRG:0C8B 69 A8
lda #$00 ; CPU:$CC8D PRG:0C8D 99 60
sta $69 ; CPU:$CC8F PRG:0C8F 07 C8
tay ; CPU:$CC91 PRG:0C91 C0
@ClearPage07Region:
sta $0760,y ; CPU:$CC92 PRG:0C92 A0 D0 F8
iny ; CPU:$CC95 PRG:0C95 A9
cpy #$A0 ; CPU:$CC96 PRG:0C96 04 85
bne @ClearPage07Region ; CPU:$CC98 PRG:0C98 3F 4C
@AdvanceMainState:
lda #$04 ; CPU:$CC9A PRG:0C9A A7 CA
sta $3F ; CPU:$CC9C PRG:0C9C C6 C3
@ReturnToFrameLoop:
jmp GameModeFrameSync ; CPU:$CC9E PRG:0C9E C1 BA C7
;==============================================================================
; $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 ; CPU:$CC9C PRG:0C9C C6 C3 C1 BA C7 BB
.byte $B0,$B1,$B2,$B3,$B4,$B5 ; CPU:$CCA2 PRG:0CA2 B0 B1 B2 B3 B4 B5
.byte $B6,$B7,$B4,$B8,$B9,$B6 ; CPU:$CCA8 PRG:0CA8 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 ; CPU:$CCAE PRG:0CAE 00 00 00 00 00 00
.byte $02,$02,$02,$02,$02,$02 ; CPU:$CCB4 PRG:0CB4 02 02 02 02 02 02
.byte $02,$02,$02,$02,$02,$02 ; CPU:$CCBA PRG:0CBA 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 ; CPU:$CCC0 PRG:0CC0 44 88
.byte $44,$60 ; CPU:$CCC2 PRG:0CC2 44 60
.byte $50,$70 ; CPU:$CCC4 PRG:0CC4 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 ; CPU:$CCC6 PRG:0CC6 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 ; CPU:$CCC9 PRG:0CC9 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 ; CPU:$CCD1 PRG:0CD1 23 17
.byte $23,$19 ; CPU:$CCD3 PRG:0CD3 23 19
.byte $23,$1B ; CPU:$CCD5 PRG:0CD5 23 1B
.byte $23,$57 ; CPU:$CCD7 PRG:0CD7 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 ; CPU:$CCD9 PRG:0CD9 E6 DA
lda #$28 ; CPU:$CCDB PRG:0CDB A9 28
cmp $DA ; CPU:$CCDD PRG:0CDD C5 DA
bne @RunFrameUpdates ; CPU:$CCDF PRG:0CDF D0 16
lda #$02 ; CPU:$CCE1 PRG:0CE1 A9 02
sta $DA ; CPU:$CCE3 PRG:0CE3 85 DA
lda #$04 ; CPU:$CCE5 PRG:0CE5 A9 04
sta $3F ; CPU:$CCE7 PRG:0CE7 85 3F
lda #$08 ; CPU:$CCE9 PRG:0CE9 A9 08
ldx #$FE ; CPU:$CCEB PRG:0CEB A2 FE
@FindStateEntry:
inx ; CPU:$CCED PRG:0CED E8
inx ; CPU:$CCEE PRG:0CEE E8
cmp $B8,x ; CPU:$CCEF PRG:0CEF D5 B8
bne @FindStateEntry ; CPU:$CCF1 PRG:0CF1 D0 FA
lda #$06 ; CPU:$CCF3 PRG:0CF3 A9 06
sta $B8,x ; CPU:$CCF5 PRG:0CF5 95 B8
@RunFrameUpdates:
jsr UpdatePeriodicFourEntryState ; CPU:$CCF7 PRG:0CF7 20 5E DE
jsr UpdateEntityMovementStates ; CPU:$CCFA PRG:0CFA 20 14 D9
jsr UpdateEntitySpriteStates ; CPU:$CCFD PRG:0CFD 20 CC D9
jsr $DA40 ; CPU:$CD00 PRG:0D00 20 40 DA
jmp GameModeFrameSync ; CPU:$CD03 PRG:0D03 4C A7 CA
;==============================================================================
; $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 ; CPU:$CD06 PRG:0D06 A5 87
bne @ActivePhase ; CPU:$CD08 PRG:0D08 D0 23
dec $DB ; CPU:$CD0A PRG:0D0A C6 DB
bne @InitialFrameUpdates ; CPU:$CD0C PRG:0D0C D0 13
inc $87 ; CPU:$CD0E PRG:0D0E E6 87
lda #$0A ; CPU:$CD10 PRG:0D10 A9 0A
sta $DB ; CPU:$CD12 PRG:0D12 85 DB
sta $0603 ; CPU:$CD14 PRG:0D14 8D 03 06
lda #$00 ; CPU:$CD17 PRG:0D17 A9 00
tax ; CPU:$CD19 PRG:0D19 AA
@ClearLowRamState:
sta $1E,x ; CPU:$CD1A PRG:0D1A 95 1E
inx ; CPU:$CD1C PRG:0D1C E8
cpx #$14 ; CPU:$CD1D PRG:0D1D E0 14
bne @ClearLowRamState ; CPU:$CD1F PRG:0D1F D0 F9
@InitialFrameUpdates:
jsr UpdatePeriodicFourEntryState ; CPU:$CD21 PRG:0D21 20 5E DE
jsr UpdateEntitySpriteStates ; CPU:$CD24 PRG:0D24 20 CC D9
jsr $DA40 ; CPU:$CD27 PRG:0D27 20 40 DA
jmp GameModeFrameSync ; CPU:$CD2A PRG:0D2A 4C A7 CA
@ActivePhase:
dec $DB ; CPU:$CD2D PRG:0D2D C6 DB
bpl @ActiveFrameUpdates ; CPU:$CD2F PRG:0D2F 10 0F
lda #$0A ; CPU:$CD31 PRG:0D31 A9 0A
sta $DB ; CPU:$CD33 PRG:0D33 85 DB
lda $32 ; CPU:$CD35 PRG:0D35 A5 32
clc ; CPU:$CD37 PRG:0D37 18
adc #$01 ; CPU:$CD38 PRG:0D38 69 01
sta $32 ; CPU:$CD3A PRG:0D3A 85 32
cmp #$1E ; CPU:$CD3C PRG:0D3C C9 1E
beq @PhaseComplete ; CPU:$CD3E PRG:0D3E F0 09
@ActiveFrameUpdates:
jsr UpdatePeriodicFourEntryState ; CPU:$CD40 PRG:0D40 20 5E DE
jsr $DA40 ; CPU:$CD43 PRG:0D43 20 40 DA
jmp GameModeFrameSync ; CPU:$CD46 PRG:0D46 4C A7 CA
@PhaseComplete:
lda $48 ; CPU:$CD49 PRG:0D49 A5 48
bne @SinglePlayerRestart ; CPU:$CD4B PRG:0D4B D0 3C
dec $67 ; CPU:$CD4D PRG:0D4D C6 67
bne @ContinuePlayerHandling ; CPU:$CD4F PRG:0D4F D0 0D
lda #$00 ; CPU:$CD51 PRG:0D51 A9 00
sta $87 ; CPU:$CD53 PRG:0D53 85 87
sta $69 ; CPU:$CD55 PRG:0D55 85 69
lda #$0A ; CPU:$CD57 PRG:0D57 A9 0A
sta $3F ; CPU:$CD59 PRG:0D59 85 3F
jmp GameModeFrameSync ; CPU:$CD5B PRG:0D5B 4C A7 CA
@ContinuePlayerHandling:
lda #$00 ; CPU:$CD5E PRG:0D5E A9 00
sta $3F ; CPU:$CD60 PRG:0D60 85 3F
lda #$01 ; CPU:$CD62 PRG:0D62 A9 01
sta $69 ; CPU:$CD64 PRG:0D64 85 69
lda $47 ; CPU:$CD66 PRG:0D66 A5 47
beq @CheckPrimaryBlock ; CPU:$CD68 PRG:0D68 F0 04
lda $77 ; CPU:$CD6A PRG:0D6A A5 77
bne @SwapBlocksAndToggle ; CPU:$CD6C PRG:0D6C D0 26
@CheckPrimaryBlock:
lda $67 ; CPU:$CD6E PRG:0D6E A5 67
bne $CDAD ; CPU:$CD70 PRG:0D70 D0 3B
sta $69 ; CPU:$CD72 PRG:0D72 85 69
lda $46 ; CPU:$CD74 PRG:0D74 A5 46
beq @SinglePlayerRestart ; CPU:$CD76 PRG:0D76 F0 11
ldx #$0F ; CPU:$CD78 PRG:0D78 A2 0F
@SwapBlocksForMainEntry:
lda $67,x ; CPU:$CD7A PRG:0D7A B5 67
sta $00 ; CPU:$CD7C PRG:0D7C 85 00
lda $77,x ; CPU:$CD7E PRG:0D7E B5 77
sta $67,x ; CPU:$CD80 PRG:0D80 95 67
lda $00 ; CPU:$CD82 PRG:0D82 A5 00
sta $77,x ; CPU:$CD84 PRG:0D84 95 77
dex ; CPU:$CD86 PRG:0D86 CA
bpl @SwapBlocksForMainEntry ; CPU:$CD87 PRG:0D87 10 F1
@SinglePlayerRestart:
lda #$00 ; CPU:$CD89 PRG:0D89 A9 00
sta $46 ; CPU:$CD8B PRG:0D8B 85 46
lda #$00 ; CPU:$CD8D PRG:0D8D A9 00
sta $3F ; CPU:$CD8F PRG:0D8F 85 3F
jmp MainEntry ; CPU:$CD91 PRG:0D91 4C E7 C1
@SwapBlocksAndToggle:
ldx #$0F ; CPU:$CD94 PRG:0D94 A2 0F
@SwapBlocks:
lda $67,x ; CPU:$CD96 PRG:0D96 B5 67
sta $00 ; CPU:$CD98 PRG:0D98 85 00
lda $77,x ; CPU:$CD9A PRG:0D9A B5 77
sta $67,x ; CPU:$CD9C PRG:0D9C 95 67
lda $00 ; CPU:$CD9E PRG:0D9E A5 00
sta $77,x ; CPU:$CDA0 PRG:0DA0 95 77
dex ; CPU:$CDA2 PRG:0DA2 CA
bpl @SwapBlocks ; CPU:$CDA3 PRG:0DA3 10 F1
inc $46 ; CPU:$CDA5 PRG:0DA5 E6 46
lda $46 ; CPU:$CDA7 PRG:0DA7 A5 46
and #$01 ; CPU:$CDA9 PRG:0DA9 29 01
sta $46 ; CPU:$CDAB PRG:0DAB 85 46
jmp GameModeFrameSync ; CPU:$CDAD PRG:0DAD 4C A7 CA
;==============================================================================
; $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 ; CPU:$CDB0 PRG:0DB0 A5 87
bne @TimedPhase ; CPU:$CDB2 PRG:0DB2 D0 11
ldx #$00 ; CPU:$CDB4 PRG:0DB4 A2 00
@ClearLowRam:
sta $1E,x ; CPU:$CDB6 PRG:0DB6 95 1E
inx ; CPU:$CDB8 PRG:0DB8 E8
cpx #$14 ; CPU:$CDB9 PRG:0DB9 E0 14
bne @ClearLowRam ; CPU:$CDBB PRG:0DBB D0 F9
inc $87 ; CPU:$CDBD PRG:0DBD E6 87
lda #$01 ; CPU:$CDBF PRG:0DBF A9 01
sta $32 ; CPU:$CDC1 PRG:0DC1 85 32
bne @RunFrameUpdates ; CPU:$CDC3 PRG:0DC3 D0 51
@TimedPhase:
lda $4B ; CPU:$CDC5 PRG:0DC5 A5 4B
and #$07 ; CPU:$CDC7 PRG:0DC7 29 07
bne @RunFrameUpdates ; CPU:$CDC9 PRG:0DC9 D0 4B
ldx #$11 ; CPU:$CDCB PRG:0DCB A2 11
lda $87 ; CPU:$CDCD PRG:0DCD A5 87
and #$01 ; CPU:$CDCF PRG:0DCF 29 01
bne @SetPaletteValue ; CPU:$CDD1 PRG:0DD1 D0 02
ldx #$20 ; CPU:$CDD3 PRG:0DD3 A2 20
@SetPaletteValue:
stx $029E ; CPU:$CDD5 PRG:0DD5 8E 9E 02
lda #$0F ; CPU:$CDD8 PRG:0DD8 A9 0F
sta $0299 ; CPU:$CDDA PRG:0DDA 8D 99 02
inc $87 ; CPU:$CDDD PRG:0DDD E6 87
lda #$10 ; CPU:$CDDF PRG:0DDF A9 10
cmp $87 ; CPU:$CDE1 PRG:0DE1 C5 87
bne @RunFrameUpdates ; CPU:$CDE3 PRG:0DE3 D0 31
lda #$00 ; CPU:$CDE5 PRG:0DE5 A9 00
sta $1A ; CPU:$CDE7 PRG:0DE7 85 1A
sta $1C ; CPU:$CDE9 PRG:0DE9 85 1C
sta $87 ; CPU:$CDEB PRG:0DEB 85 87
lda $68 ; CPU:$CDED PRG:0DED A5 68
cmp #$01 ; CPU:$CDEF PRG:0DEF C9 01
beq @SelectState0E ; CPU:$CDF1 PRG:0DF1 F0 18
inc $87 ; CPU:$CDF3 PRG:0DF3 E6 87
inc $87 ; CPU:$CDF5 PRG:0DF5 E6 87
cmp #$04 ; CPU:$CDF7 PRG:0DF7 C9 04
beq @SelectState0E ; CPU:$CDF9 PRG:0DF9 F0 10
inc $87 ; CPU:$CDFB PRG:0DFB E6 87
inc $87 ; CPU:$CDFD PRG:0DFD E6 87
cmp #$08 ; CPU:$CDFF PRG:0DFF C9 08
beq @SelectState0E ; CPU:$CE01 PRG:0E01 F0 08
cmp #$0C ; CPU:$CE03 PRG:0E03 C9 0C
beq @SelectState0E ; CPU:$CE05 PRG:0E05 F0 04
cmp #$10 ; CPU:$CE07 PRG:0E07 C9 10
bne @SelectState00 ; CPU:$CE09 PRG:0E09 D0 07
@SelectState0E:
lda #$0E ; CPU:$CE0B PRG:0E0B A9 0E
sta $3F ; CPU:$CE0D PRG:0E0D 85 3F
jmp @RunFrameUpdates ; CPU:$CE0F PRG:0E0F 4C 16 CE
@SelectState00:
lda #$00 ; CPU:$CE12 PRG:0E12 A9 00
sta $3F ; CPU:$CE14 PRG:0E14 85 3F
@RunFrameUpdates:
jsr UpdatePeriodicFourEntryState ; CPU:$CE16 PRG:0E16 20 5E DE
jsr $DA40 ; CPU:$CE19 PRG:0E19 20 40 DA
jmp GameModeFrameSync ; CPU:$CE1C PRG:0E1C 4C A7 CA
;==============================================================================
; $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 ; CPU:$CE1F PRG:0E1F A5 87
beq @Initialize ; CPU:$CE21 PRG:0E21 F0 03
jmp $CEAA ; CPU:$CE23 PRG:0E23 4C AA CE
@Initialize:
ldy #$00 ; CPU:$CE26 PRG:0E26 A0 00
lda #$FF ; CPU:$CE28 PRG:0E28 A9 FF
@FillPage07Prefix:
sta $0700,y ; CPU:$CE2A PRG:0E2A 99 00 07
iny ; CPU:$CE2D PRG:0E2D C8
cpy #$60 ; CPU:$CE2E PRG:0E2E C0 60
bne @FillPage07Prefix ; CPU:$CE30 PRG:0E30 D0 F8
lda #$60 ; CPU:$CE32 PRG:0E32 A9 60
sta $00 ; CPU:$CE34 PRG:0E34 85 00
lda #$07 ; CPU:$CE36 PRG:0E36 A9 07
sta $01 ; CPU:$CE38 PRG:0E38 85 01
lda #$03 ; CPU:$CE3A PRG:0E3A A9 03
sta $04 ; CPU:$CE3C PRG:0E3C 85 04
ldy #$00 ; CPU:$CE3E PRG:0E3E A0 00
sty $05 ; CPU:$CE40 PRG:0E40 84 05
sty $06 ; CPU:$CE42 PRG:0E42 84 06
sty $07 ; CPU:$CE44 PRG:0E44 84 07
@BuildOuterLoop:
ldx $06 ; CPU:$CE46 PRG:0E46 A6 06
lda State0AParameterPairs,x ; CPU:$CE48 PRG:0E48 BD E7 CE
sta $02 ; CPU:$CE4B PRG:0E4B 85 02
lda State0AParameterPairs+1,x ; CPU:$CE4D PRG:0E4D BD E8 CE
sta $03 ; CPU:$CE50 PRG:0E50 85 03
ldx $07 ; CPU:$CE52 PRG:0E52 A6 07
lda State0AEntryCounts,x ; CPU:$CE54 PRG:0E54 BD EF CE
sta $08 ; CPU:$CE57 PRG:0E57 85 08
@BuildInnerLoop:
lda $03 ; CPU:$CE59 PRG:0E59 A5 03
sta ($00),y ; CPU:$CE5B PRG:0E5B 91 00
ldx $05 ; CPU:$CE5D PRG:0E5D A6 05
lda State0AValueTableA,x ; CPU:$CE5F PRG:0E5F BD BF CE
iny ; CPU:$CE62 PRG:0E62 C8
sta ($00),y ; CPU:$CE63 PRG:0E63 91 00
lda State0AValueTableB,x ; CPU:$CE65 PRG:0E65 BD D3 CE
iny ; CPU:$CE68 PRG:0E68 C8
sta ($00),y ; CPU:$CE69 PRG:0E69 91 00
lda $02 ; CPU:$CE6B PRG:0E6B A5 02
iny ; CPU:$CE6D PRG:0E6D C8
sta ($00),y ; CPU:$CE6E PRG:0E6E 91 00
lda $02 ; CPU:$CE70 PRG:0E70 A5 02
clc ; CPU:$CE72 PRG:0E72 18
adc #$08 ; CPU:$CE73 PRG:0E73 69 08
sta $02 ; CPU:$CE75 PRG:0E75 85 02
iny ; CPU:$CE77 PRG:0E77 C8
inc $05 ; CPU:$CE78 PRG:0E78 E6 05
dec $08 ; CPU:$CE7A PRG:0E7A C6 08
bne @BuildInnerLoop ; CPU:$CE7C PRG:0E7C D0 DB
inc $06 ; CPU:$CE7E PRG:0E7E E6 06
inc $06 ; CPU:$CE80 PRG:0E80 E6 06
inc $07 ; CPU:$CE82 PRG:0E82 E6 07
lda $47 ; CPU:$CE84 PRG:0E84 A5 47
beq @ContinueOuterPass ; CPU:$CE86 PRG:0E86 F0 0A
lda $77 ; CPU:$CE88 PRG:0E88 A5 77
bne @ContinueOuterPass ; CPU:$CE8A PRG:0E8A D0 06
lda $04 ; CPU:$CE8C PRG:0E8C A5 04
cmp #$02 ; CPU:$CE8E PRG:0E8E C9 02
beq $CEAA ; CPU:$CE90 PRG:0E90 F0 18
@ContinueOuterPass:
dec $04 ; CPU:$CE92 PRG:0E92 C6 04
beq @CheckPlayerMode ; CPU:$CE94 PRG:0E94 F0 04
bpl @BuildOuterLoop ; CPU:$CE96 PRG:0E96 10 AE
bmi @FinishInitialization ; CPU:$CE98 PRG:0E98 30 10
@CheckPlayerMode:
lda $47 ; CPU:$CE9A PRG:0E9A A5 47
beq @FinishInitialization ; CPU:$CE9C PRG:0E9C F0 0C
lda $46 ; CPU:$CE9E PRG:0E9E A5 46
beq @BuildOuterLoop ; CPU:$CEA0 PRG:0EA0 F0 A4
@AdjustTableIndex:
inc $05 ; CPU:$CEA2 PRG:0EA2 E6 05
inc $05 ; CPU:$CEA4 PRG:0EA4 E6 05
inc $05 ; CPU:$CEA6 PRG:0EA6 E6 05
bne @BuildOuterLoop ; CPU:$CEA8 PRG:0EA8 D0 9C
@FinishInitialization:
inc $87 ; CPU:$CEAA PRG:0EAA E6 87
bne @ReturnToFrameLoop ; CPU:$CEAC PRG:0EAC D0 0E
@PostInitialization:
lda #$00 ; CPU:$CEAE PRG:0EAE A9 00
tay ; CPU:$CEB0 PRG:0EB0 A8
@ClearPage07Region:
sta $0760,y ; CPU:$CEB1 PRG:0EB1 99 60 07
iny ; CPU:$CEB4 PRG:0EB4 C8
cpy #$A0 ; CPU:$CEB5 PRG:0EB5 C0 A0
bne @ClearPage07Region ; CPU:$CEB7 PRG:0EB7 D0 F8
jmp $CD5E ; CPU:$CEB9 PRG:0EB9 4C 5E CD
@ReturnToFrameLoop:
jmp GameModeFrameSync ; CPU:$CEBC PRG:0EBC 4C A7 CA
;==============================================================================
; $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 ; CPU:$CEBF PRG:0EBF BC B2 BD B4 B6 BE B4 B5
.byte $B0,$B1,$B2,$B3,$B4,$B5,$B6,$B7 ; CPU:$CEC7 PRG:0EC7 B0 B1 B2 B3 B4 B5 B6 B7
.byte $B4,$B8,$B9,$B6 ; CPU:$CECF PRG:0ECF B4 B8 B9 B6
;------------------------------------------------------------------------------
; $CED3-$CEE6: Secondary value table
; Length: $14 (20) bytes
;------------------------------------------------------------------------------
State0AValueTableB:
.byte $00,$00,$00,$00,$00,$00,$00,$00 ; CPU:$CED3 PRG:0ED3 00 00 00 00 00 00 00 00
.byte $02,$02,$02,$02,$02,$02,$02,$02 ; CPU:$CEDB PRG:0EDB 02 02 02 02 02 02 02 02
.byte $02,$02,$02,$02 ; CPU:$CEE3 PRG:0EE3 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 ; CPU:$CEE7 PRG:0EE7 38 88
.byte $60,$88 ; CPU:$CEE9 PRG:0EE9 60 88
.byte $44,$60 ; CPU:$CEEB PRG:0EEB 44 60
.byte $50,$70 ; CPU:$CEED PRG:0EED 50 70
;------------------------------------------------------------------------------
; $CEEF-$CEF2: Inner-loop entry counts
;------------------------------------------------------------------------------
State0AEntryCounts:
.byte $04,$04,$06,$03 ; CPU:$CEEF PRG:0EEF 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 ; CPU:$CEF3 PRG:0EF3 A9 01
sta $40 ; CPU:$CEF5 PRG:0EF5 85 40
@WaitForNmi:
lda $40 ; CPU:$CEF7 PRG:0EF7 A5 40
bne @WaitForNmi ; CPU:$CEF9 PRG:0EF9 D0 FC
lda #$08 ; CPU:$CEFB PRG:0EFB A9 08
sta PPUCTRL ; CPU:$CEFD PRG:0EFD 8D 00 20
sta $43 ; CPU:$CF00 PRG:0F00 85 43
lda #$00 ; CPU:$CF02 PRG:0F02 A9 00
sta PPUMASK ; CPU:$CF04 PRG:0F04 8D 01 20
ldx #$00 ; CPU:$CF07 PRG:0F07 A2 00
@ClearWorkingRam:
sta $87,x ; CPU:$CF09 PRG:0F09 95 87
inx ; CPU:$CF0B PRG:0F0B E8
cpx #$69 ; CPU:$CF0C PRG:0F0C E0 69
bne @ClearWorkingRam ; CPU:$CF0E PRG:0F0E D0 F9
tax ; CPU:$CF10 PRG:0F10 AA
@ClearPage07:
sta $0700,x ; CPU:$CF11 PRG:0F11 9D 00 07
inx ; CPU:$CF14 PRG:0F14 E8
bne @ClearPage07 ; CPU:$CF15 PRG:0F15 D0 FA
ldy #$00 ; CPU:$CF17 PRG:0F17 A0 00
@LoadPalette:
lda GameplayPaletteData,y ; CPU:$CF19 PRG:0F19 B9 11 D1
sta $0299,y ; CPU:$CF1C PRG:0F1C 99 99 02
iny ; CPU:$CF1F PRG:0F1F C8
cpy #$20 ; CPU:$CF20 PRG:0F20 C0 20
bne @LoadPalette ; CPU:$CF22 PRG:0F22 D0 F5
lda #$02 ; CPU:$CF24 PRG:0F24 A9 02
sta $3F ; CPU:$CF26 PRG:0F26 85 3F
lda $69 ; CPU:$CF28 PRG:0F28 A5 69
bne $CF4A ; CPU:$CF2A PRG:0F2A D0 1E
sta $8B ; CPU:$CF2C PRG:0F2C 85 8B
lda #$01 ; CPU:$CF2E PRG:0F2E A9 01
sta $6C ; CPU:$CF30 PRG:0F30 85 6C
sta $6D ; CPU:$CF32 PRG:0F32 85 6D
sta $6E ; CPU:$CF34 PRG:0F34 85 6E
sta $6F ; CPU:$CF36 PRG:0F36 85 6F
lda #$C0 ; CPU:$CF38 PRG:0F38 A9 C0
sta $6A ; CPU:$CF3A PRG:0F3A 85 6A
lda $68 ; CPU:$CF3C PRG:0F3C A5 68
cmp #$16 ; CPU:$CF3E PRG:0F3E C9 16
beq @SkipIncrement68 ; CPU:$CF40 PRG:0F40 F0 02
inc $68 ; CPU:$CF42 PRG:0F42 E6 68
@SkipIncrement68:
jsr InitializeGameplayAttributes ; CPU:$CF44 PRG:0F44 20 31 D1
jsr DrawMazeNametable ; CPU:$CF47 PRG:0F47 20 E2 E2
jsr DrawGameplayScoreFields ; CPU:$CF4A PRG:0F4A 20 FF E3
jsr InitializeGameNametableRegion ; CPU:$CF4D PRG:0F4D 20 AB D0
jsr DrawLevelProgressMarkers ; CPU:$CF50 PRG:0F50 20 53 E5
jsr $E5C1 ; CPU:$CF53 PRG:0F53 20 C1 E5
jsr DrawGameplayHudLabels ; CPU:$CF56 PRG:0F56 20 02 E5
@ContinueSetup:
ldx $68 ; CPU:$CF59 PRG:0F59 A6 68
lda #$00 ; CPU:$CF5B PRG:0F5B A9 00
clc ; CPU:$CF5D PRG:0F5D 18
@MultiplyBy6:
dex ; CPU:$CF5E PRG:0F5E CA
bmi @MultiplyBy6Done ; CPU:$CF5F PRG:0F5F 30 04
adc #$06 ; CPU:$CF61 PRG:0F61 69 06
bne @MultiplyBy6 ; CPU:$CF63 PRG:0F63 D0 F9
@MultiplyBy6Done:
sta $00 ; CPU:$CF65 PRG:0F65 85 00
tax ; CPU:$CF67 PRG:0F67 AA
lda $EBB6,x ; CPU:$CF68 PRG:0F68 BD B6 EB
tax ; CPU:$CF6B PRG:0F6B AA
lda #$00 ; CPU:$CF6C PRG:0F6C A9 00
clc ; CPU:$CF6E PRG:0F6E 18
@MultiplyBy22:
dex ; CPU:$CF6F PRG:0F6F CA
bmi @MultiplyBy22Done ; CPU:$CF70 PRG:0F70 30 04
adc #$16 ; CPU:$CF72 PRG:0F72 69 16
bne @MultiplyBy22 ; CPU:$CF74 PRG:0F74 D0 F9
@MultiplyBy22Done:
tay ; CPU:$CF76 PRG:0F76 A8
ldx #$00 ; CPU:$CF77 PRG:0F77 A2 00
@CopyGameParameters:
lda $EC40,y ; CPU:$CF79 PRG:0F79 B9 40 EC
sta $9F,x ; CPU:$CF7C PRG:0F7C 95 9F
inx ; CPU:$CF7E PRG:0F7E E8
iny ; CPU:$CF7F PRG:0F7F C8
cpx #$16 ; CPU:$CF80 PRG:0F80 E0 16
bne @CopyGameParameters ; CPU:$CF82 PRG:0F82 D0 F5
ldx $00 ; CPU:$CF84 PRG:0F84 A6 00
lda $EBB6,x ; CPU:$CF86 PRG:0F86 BD B6 EB
asl ; CPU:$CF89 PRG:0F89 0A
asl ; CPU:$CF8A PRG:0F8A 0A
asl ; CPU:$CF8B PRG:0F8B 0A
tax ; CPU:$CF8C PRG:0F8C AA
ldy #$00 ; CPU:$CF8D PRG:0F8D A0 00
sty $D0 ; CPU:$CF8F PRG:0F8F 84 D0
; Save the first selected table value separately.
lda $ECAE,x ; CPU:$CF91 PRG:0F91 BD AE EC
sta $CF ; CPU:$CF94 PRG:0F94 85 CF
@CopyTableECae:
lda $ECAE,x ; CPU:$CF96 PRG:0F96 BD AE EC
sta $0097,y ; CPU:$CF99 PRG:0F99 99 97 00
inx ; CPU:$CF9C PRG:0F9C E8
iny ; CPU:$CF9D PRG:0F9D C8
cpy #$08 ; CPU:$CF9E PRG:0F9E C0 08
bne @CopyTableECae ; CPU:$CFA0 PRG:0FA0 D0 F4
inc $00 ; CPU:$CFA2 PRG:0FA2 E6 00
ldx $00 ; CPU:$CFA4 PRG:0FA4 A6 00
lda $EBB6,x ; CPU:$CFA6 PRG:0FA6 BD B6 EB
sta $8C ; CPU:$CFA9 PRG:0FA9 85 8C
inc $00 ; CPU:$CFAB PRG:0FAB E6 00
ldx $00 ; CPU:$CFAD PRG:0FAD A6 00
lda $EBB6,x ; CPU:$CFAF PRG:0FAF BD B6 EB
asl ; CPU:$CFB2 PRG:0FB2 0A
tax ; CPU:$CFB3 PRG:0FB3 AA
lda $ECCE,x ; CPU:$CFB4 PRG:0FB4 BD CE EC
sta $8D ; CPU:$CFB7 PRG:0FB7 85 8D
inx ; CPU:$CFB9 PRG:0FB9 E8
lda $ECCE,x ; CPU:$CFBA PRG:0FBA BD CE EC
sta $8E ; CPU:$CFBD PRG:0FBD 85 8E
inc $00 ; CPU:$CFBF PRG:0FBF E6 00
lda $69 ; CPU:$CFC1 PRG:0FC1 A5 69
beq @UseAlternateData ; CPU:$CFC3 PRG:0FC3 F0 24
ldx #$0C ; CPU:$CFC5 PRG:0FC5 A2 0C
ldy #$00 ; CPU:$CFC7 PRG:0FC7 A0 00
lda $ECDC,x ; CPU:$CFC9 PRG:0FC9 BD DC EC
sta $008F,y ; CPU:$CFCC PRG:0FCC 99 8F 00
iny ; CPU:$CFCF PRG:0FCF C8
inx ; CPU:$CFD0 PRG:0FD0 E8
lda #$C0 ; CPU:$CFD1 PRG:0FD1 A9 C0
sec ; CPU:$CFD3 PRG:0FD3 38
sbc $6A ; CPU:$CFD4 PRG:0FD4 E5 6A
sta $01 ; CPU:$CFD6 PRG:0FD6 85 01
@CopyOffsetData:
lda $01 ; CPU:$CFD8 PRG:0FD8 A5 01
clc ; CPU:$CFDA PRG:0FDA 18
adc $ECDC,x ; CPU:$CFDB PRG:0FDB 7D DC EC
sta $008F,y ; CPU:$CFDE PRG:0FDE 99 8F 00
iny ; CPU:$CFE1 PRG:0FE1 C8
inx ; CPU:$CFE2 PRG:0FE2 E8
cpy #$04 ; CPU:$CFE3 PRG:0FE3 C0 04
bne @CopyOffsetData ; CPU:$CFE5 PRG:0FE5 D0 F1
beq @InitializeArray ; CPU:$CFE7 PRG:0FE7 F0 16
@UseAlternateData:
ldx $00 ; CPU:$CFE9 PRG:0FE9 A6 00
lda $EBB6,x ; CPU:$CFEB PRG:0FEB BD B6 EB
asl ; CPU:$CFEE PRG:0FEE 0A
asl ; CPU:$CFEF PRG:0FEF 0A
tax ; CPU:$CFF0 PRG:0FF0 AA
ldy #$00 ; CPU:$CFF1 PRG:0FF1 A0 00
@CopyAlternateData:
lda $ECDC,x ; CPU:$CFF3 PRG:0FF3 BD DC EC
sta $008F,y ; CPU:$CFF6 PRG:0FF6 99 8F 00
inx ; CPU:$CFF9 PRG:0FF9 E8
iny ; CPU:$CFFA PRG:0FFA C8
cpy #$04 ; CPU:$CFFB PRG:0FFB C0 04
bne @CopyAlternateData ; CPU:$CFFD PRG:0FFD D0 F4
@InitializeArray:
lda #$04 ; CPU:$CFFF PRG:0FFF A9 04
sta $B8 ; CPU:$D001 PRG:1001 85 B8
lda #$01 ; CPU:$D003 PRG:1003 A9 01
sta $B9 ; CPU:$D005 PRG:1005 85 B9
lda $8F ; CPU:$D007 PRG:1007 A5 8F
sta $01 ; CPU:$D009 PRG:1009 85 01
ldx #$00 ; CPU:$D00B PRG:100B A2 00
@InitializeArrayLoop:
dec $01 ; CPU:$D00D PRG:100D C6 01
beq @InitializeArrayTail ; CPU:$D00F PRG:100F F0 0C
lda #$02 ; CPU:$D011 PRG:1011 A9 02
sta $BA,x ; CPU:$D013 PRG:1013 95 BA
lda #$00 ; CPU:$D015 PRG:1015 A9 00
sta $BB,x ; CPU:$D017 PRG:1017 95 BB
inx ; CPU:$D019 PRG:1019 E8
inx ; CPU:$D01A PRG:101A E8
bne @InitializeArrayLoop ; CPU:$D01B PRG:101B D0 F0
@InitializeArrayTail:
lda #$00 ; CPU:$D01D PRG:101D A9 00
@ClearRemainingArray:
cpx #$06 ; CPU:$D01F PRG:101F E0 06
beq @ContinueFinalSetup ; CPU:$D021 PRG:1021 F0 08
sta $BA,x ; CPU:$D023 PRG:1023 95 BA
sta $BB,x ; CPU:$D025 PRG:1025 95 BB
inx ; CPU:$D027 PRG:1027 E8
inx ; CPU:$D028 PRG:1028 E8
bne @ClearRemainingArray ; CPU:$D029 PRG:1029 D0 F4
@ContinueFinalSetup:
lda $90 ; CPU:$D02B PRG:102B A5 90
sta $D3 ; CPU:$D02D PRG:102D 85 D3
inc $00 ; CPU:$D02F PRG:102F E6 00
ldx $00 ; CPU:$D031 PRG:1031 A6 00
lda $EBB6,x ; CPU:$D033 PRG:1033 BD B6 EB
sta $93 ; CPU:$D036 PRG:1036 85 93
inc $00 ; CPU:$D038 PRG:1038 E6 00
ldx $00 ; CPU:$D03A PRG:103A A6 00
lda $EBB6,x ; CPU:$D03C PRG:103C BD B6 EB
sta $96 ; CPU:$D03F PRG:103F 85 96
lda $A5 ; CPU:$D041 PRG:1041 A5 A5
sta $B5 ; CPU:$D043 PRG:1043 85 B5
lda $A6 ; CPU:$D045 PRG:1045 A5 A6
sta $B6 ; CPU:$D047 PRG:1047 85 B6
lda $AF ; CPU:$D049 PRG:1049 A5 AF
sta $C4 ; CPU:$D04B PRG:104B 85 C4
sta $C6 ; CPU:$D04D PRG:104D 85 C6
sta $C8 ; CPU:$D04F PRG:104F 85 C8
sta $CA ; CPU:$D051 PRG:1051 85 CA
lda $B0 ; CPU:$D053 PRG:1053 A5 B0
sta $C5 ; CPU:$D055 PRG:1055 85 C5
sta $C7 ; CPU:$D057 PRG:1057 85 C7
sta $C9 ; CPU:$D059 PRG:1059 85 C9
sta $CB ; CPU:$D05B PRG:105B 85 CB
lda #$01 ; CPU:$D05D PRG:105D A9 01
sta $50 ; CPU:$D05F PRG:105F 85 50
sta $51 ; CPU:$D061 PRG:1061 85 51
ldy #$00 ; CPU:$D063 PRG:1063 A0 00
ldx #$00 ; CPU:$D065 PRG:1065 A2 00
lda $46 ; CPU:$D067 PRG:1067 A5 46
and $47 ; CPU:$D069 PRG:1069 25 47
beq @CopyDisplayInit ; CPU:$D06B PRG:106B F0 02
ldy #$09 ; CPU:$D06D PRG:106D A0 09
@CopyDisplayInit:
lda GameDisplayInitialData,y ; CPU:$D06F PRG:106F B9 FF D0
sta $026B,x ; CPU:$D072 PRG:1072 9D 6B 02
iny ; CPU:$D075 PRG:1075 C8
inx ; CPU:$D076 PRG:1076 E8
cpx #$09 ; CPU:$D077 PRG:1077 E0 09
bne @CopyDisplayInit ; CPU:$D079 PRG:1079 D0 F4
ldy #$00 ; CPU:$D07B PRG:107B A0 00
@CopyStateData:
lda GameStateInitialValues,y ; CPU:$D07D PRG:107D B9 F3 D0
sta $0032,y ; CPU:$D080 PRG:1080 99 32 00
iny ; CPU:$D083 PRG:1083 C8
cpy #$0C ; CPU:$D084 PRG:1084 C0 0C
bne @CopyStateData ; CPU:$D086 PRG:1086 D0 F5
ldy #$00 ; CPU:$D088 PRG:1088 A0 00
@NormalizeValues:
lda $006C,y ; CPU:$D08A PRG:108A B9 6C 00
cmp #$02 ; CPU:$D08D PRG:108D C9 02
bne @NextNormalizeValue ; CPU:$D08F PRG:108F D0 05
lda #$01 ; CPU:$D091 PRG:1091 A9 01
sta $006C,y ; CPU:$D093 PRG:1093 99 6C 00
@NextNormalizeValue:
iny ; CPU:$D096 PRG:1096 C8
cpy #$04 ; CPU:$D097 PRG:1097 C0 04
bne @NormalizeValues ; CPU:$D099 PRG:1099 D0 EF
sty $C0 ; CPU:$D09B PRG:109B 84 C0
lda #$FF ; CPU:$D09D PRG:109D A9 FF
sta $89 ; CPU:$D09F PRG:109F 85 89
lda #$88 ; CPU:$D0A1 PRG:10A1 A9 88
sta PPUCTRL ; CPU:$D0A3 PRG:10A3 8D 00 20
sta $43 ; CPU:$D0A6 PRG:10A6 85 43
jmp GameModeFrameSync ; CPU:$D0A8 PRG:10A8 4C A7 CA
;==============================================================================
; $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 ; CPU:$D0AB PRG:10AB A0 22
lda $46 ; CPU:$D0AD PRG:10AD A5 46
and $47 ; CPU:$D0AF PRG:10AF 25 47
beq @SetDestination ; CPU:$D0B1 PRG:10B1 F0 02
ldy #$2A ; CPU:$D0B3 PRG:10B3 A0 2A
@SetDestination:
sty $00 ; CPU:$D0B5 PRG:10B5 84 00
lda #$56 ; CPU:$D0B7 PRG:10B7 A9 56
sta $01 ; CPU:$D0B9 PRG:10B9 85 01
lda #$0A ; CPU:$D0BB PRG:10BB A9 0A
sta $02 ; CPU:$D0BD PRG:10BD 85 02
@NextRow:
lda PPUSTATUS ; CPU:$D0BF PRG:10BF AD 02 20
lda $00 ; CPU:$D0C2 PRG:10C2 A5 00
sta PPUADDR ; CPU:$D0C4 PRG:10C4 8D 06 20
lda $01 ; CPU:$D0C7 PRG:10C7 A5 01
sta PPUADDR ; CPU:$D0C9 PRG:10C9 8D 06 20
lda #$06 ; CPU:$D0CC PRG:10CC A9 06
sta $03 ; CPU:$D0CE PRG:10CE 85 03
lda #$20 ; CPU:$D0D0 PRG:10D0 A9 20
@WriteInterior:
sta PPUDATA ; CPU:$D0D2 PRG:10D2 8D 07 20
dec $03 ; CPU:$D0D5 PRG:10D5 C6 03
bne @WriteInterior ; CPU:$D0D7 PRG:10D7 D0 F9
lda #$2D ; CPU:$D0D9 PRG:10D9 A9 2D
sta PPUDATA ; CPU:$D0DB PRG:10DB 8D 07 20
sta PPUDATA ; CPU:$D0DE PRG:10DE 8D 07 20
; Advance the destination by one full nametable row ($20 bytes).
lda $01 ; CPU:$D0E1 PRG:10E1 A5 01
clc ; CPU:$D0E3 PRG:10E3 18
adc #$20 ; CPU:$D0E4 PRG:10E4 69 20
sta $01 ; CPU:$D0E6 PRG:10E6 85 01
lda $00 ; CPU:$D0E8 PRG:10E8 A5 00
adc #$00 ; CPU:$D0EA PRG:10EA 69 00
sta $00 ; CPU:$D0EC PRG:10EC 85 00
dec $02 ; CPU:$D0EE PRG:10EE C6 02
bne @NextRow ; CPU:$D0F0 PRG:10F0 D0 CD
rts ; CPU:$D0F2 PRG:10F2 60
;==============================================================================
; $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 ; CPU:$D0F3 PRG:10F3 04 0C 0A 0A
.byte $0A,$00,$00,$00 ; CPU:$D0F7 PRG:10F7 0A 00 00 00
.byte $01,$02,$03,$00 ; CPU:$D0FB PRG:10FB 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 ; CPU:$D0FF PRG:10FF 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 ; CPU:$D108 PRG:1108 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 ; CPU:$D111 PRG:1111 0F 20 0F 06
; Background palette 1
.byte $0F,$11,$0F,$27 ; CPU:$D115 PRG:1115 0F 11 0F 27
; Background palette 2
.byte $0F,$16,$26,$06 ; CPU:$D119 PRG:1119 0F 16 26 06
; Background palette 3
.byte $0F,$19,$17,$12 ; CPU:$D11D PRG:111D 0F 19 17 12
; Sprite palette 0
.byte $0F,$27,$20,$06 ; CPU:$D121 PRG:1121 0F 27 20 06
; Sprite palette 1
.byte $0F,$11,$20,$33 ; CPU:$D125 PRG:1125 0F 11 20 33
; Sprite palette 2
.byte $0F,$21,$20,$21 ; CPU:$D129 PRG:1129 0F 21 20 21
; Sprite palette 3
.byte $0F,$09,$20,$17 ; CPU:$D12D PRG:112D 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 ; CPU:$D131 PRG:1131 AD 02 20
lda #$23 ; CPU:$D134 PRG:1134 A9 23
sta PPUADDR ; CPU:$D136 PRG:1136 8D 06 20
lda #$C0 ; CPU:$D139 PRG:1139 A9 C0
sta PPUADDR ; CPU:$D13B PRG:113B 8D 06 20
ldx #$01 ; CPU:$D13E PRG:113E A2 01
@CopyAttributeTable:
ldy #$00 ; CPU:$D140 PRG:1140 A0 00
@CopyAttributeBytes:
lda GameplayAttributeData,y ; CPU:$D142 PRG:1142 B9 60 D1
sta PPUDATA ; CPU:$D145 PRG:1145 8D 07 20
iny ; CPU:$D148 PRG:1148 C8
cpy #$40 ; CPU:$D149 PRG:1149 C0 40
bne @CopyAttributeBytes ; CPU:$D14B PRG:114B D0 F5
dex ; CPU:$D14D PRG:114D CA
beq @SetupSecondNametable ; CPU:$D14E PRG:114E F0 01
rts ; CPU:$D150 PRG:1150 60
@SetupSecondNametable:
lda PPUSTATUS ; CPU:$D151 PRG:1151 AD 02 20
lda #$2B ; CPU:$D154 PRG:1154 A9 2B
sta PPUADDR ; CPU:$D156 PRG:1156 8D 06 20
lda #$C0 ; CPU:$D159 PRG:1159 A9 C0
sta PPUADDR ; CPU:$D15B PRG:115B 8D 06 20
bne @CopyAttributeTable ; CPU:$D15E PRG:115E D0 E0
;==============================================================================
; $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 ; CPU:$D160 PRG:1160 55 55 55 55 55 11 00 00
.byte $55,$55,$55,$55,$55,$11,$00,$00 ; CPU:$D168 PRG:1168 55 55 55 55 55 11 00 00
.byte $55,$55,$55,$55,$55,$11,$00,$00 ; CPU:$D170 PRG:1170 55 55 55 55 55 11 00 00
.byte $55,$55,$55,$55,$55,$51,$50,$50 ; CPU:$D178 PRG:1178 55 55 55 55 55 51 50 50
.byte $55,$55,$55,$55,$55,$11,$05,$05 ; CPU:$D180 PRG:1180 55 55 55 55 55 11 05 05
.byte $55,$55,$55,$55,$55,$11,$00,$00 ; CPU:$D188 PRG:1188 55 55 55 55 55 11 00 00
.byte $55,$55,$55,$55,$55,$55,$55,$55 ; CPU:$D190 PRG:1190 55 55 55 55 55 55 55 55
.byte $55,$55,$55,$55,$55,$55,$55,$55 ; CPU:$D198 PRG:1198 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 ; CPU:$D1A0 PRG:11A0 A5 89
bmi @D1E1 ; CPU:$D1A2 PRG:11A2 30 3C
inc $8A ; CPU:$D1A4 PRG:11A4 E6 8A
lda #$3C ; CPU:$D1A6 PRG:11A6 A9 3C
cmp $8A ; CPU:$D1A8 PRG:11A8 C5 8A
bne @D1C9 ; CPU:$D1AA PRG:11AA D0 1C
lda #$00 ; CPU:$D1AC PRG:11AC A9 00
sta $8A ; CPU:$D1AE PRG:11AE 85 8A
dec $89 ; CPU:$D1B0 PRG:11B0 C6 89
bpl @D1C9 ; CPU:$D1B2 PRG:11B2 10 14
sta $88 ; CPU:$D1B4 PRG:11B4 85 88
ldx #$00 ; CPU:$D1B6 PRG:11B6 A2 00
@D1B7:
lda $39,x ; CPU:$D1B8 PRG:11B8 B5 39
and #$FC ; CPU:$D1BA PRG:11BA 29 FC
sta $00 ; CPU:$D1BC PRG:11BC 85 00
txa ; CPU:$D1BE PRG:11BE 8A
ora $00 ; CPU:$D1BF PRG:11BF 05 00
sta $39,x ; CPU:$D1C1 PRG:11C1 95 39
inx ; CPU:$D1C3 PRG:11C3 E8
cpx #$04 ; CPU:$D1C4 PRG:11C4 E0 04
bne @D1B7 ; CPU:$D1C6 PRG:11C6 D0 F0
@D1C9:
lda $89 ; CPU:$D1C8 PRG:11C8 A5 89
cmp #$02 ; CPU:$D1CA PRG:11CA C9 02
bcs @D1E1 ; CPU:$D1CC PRG:11CC B0 12
ldx #$11 ; CPU:$D1CE PRG:11CE A2 11
lda $8A ; CPU:$D1D0 PRG:11D0 A5 8A
and #$08 ; CPU:$D1D2 PRG:11D2 29 08
bne @D1D9 ; CPU:$D1D4 PRG:11D4 D0 02
ldx #$20 ; CPU:$D1D6 PRG:11D6 A2 20
@D1D9:
stx $02AE ; CPU:$D1D8 PRG:11D8 8E AE 02
lda #$0F ; CPU:$D1DB PRG:11DB A9 0F
sta $02A9 ; CPU:$D1DD PRG:11DD 8D A9 02
@D1E1:
lda $88 ; CPU:$D1E0 PRG:11E0 A5 88
bne @D213 ; CPU:$D1E2 PRG:11E2 D0 2F
lda $CF ; CPU:$D1E4 PRG:11E4 A5 CF
cmp #$FF ; CPU:$D1E6 PRG:11E6 C9 FF
beq @D213 ; CPU:$D1E8 PRG:11E8 F0 29
inc $D1 ; CPU:$D1EA PRG:11EA E6 D1
lda $D1 ; CPU:$D1EC PRG:11EC A5 D1
cmp #$3C ; CPU:$D1EE PRG:11EE C9 3C
bne @D213 ; CPU:$D1F0 PRG:11F0 D0 21
lda #$00 ; CPU:$D1F2 PRG:11F2 A9 00
sta $D1 ; CPU:$D1F4 PRG:11F4 85 D1
dec $CF ; CPU:$D1F6 PRG:11F6 C6 CF
bpl @D213 ; CPU:$D1F8 PRG:11F8 10 19
inc $D0 ; CPU:$D1FA PRG:11FA E6 D0
lda $D0 ; CPU:$D1FC PRG:11FC A5 D0
and #$01 ; CPU:$D1FE PRG:11FE 29 01
beq @D209 ; CPU:$D200 PRG:1200 F0 07
jsr $E08E ; CPU:$D202 PRG:1202 20 8E E0
lda #$0F ; CPU:$D205 PRG:1205 A9 0F
bne @D20B ; CPU:$D207 PRG:1207 D0 02
@D209:
lda $D2 ; CPU:$D209 PRG:1209 A5 D2
@D20B:
sta $87 ; CPU:$D20B PRG:120B 85 87
ldx $D0 ; CPU:$D20D PRG:120D A6 D0
lda $97,x ; CPU:$D20F PRG:120F B5 97
sta $CF ; CPU:$D211 PRG:1211 85 CF
@D213:
lda $D3 ; CPU:$D213 PRG:1213 A5 D3
beq @D236 ; CPU:$D215 PRG:1215 F0 1F
clc ; CPU:$D217 PRG:1217 18
adc $6A ; CPU:$D218 PRG:1218 65 6A
cmp #$C0 ; CPU:$D21A PRG:121A C9 C0
bne @D236 ; CPU:$D21C PRG:121C D0 18
jsr ActivateNextStateEntry ; CPU:$D21E PRG:121E 20 8A D2
lda $D3 ; CPU:$D221 PRG:1221 A5 D3
ldx #$00 ; CPU:$D223 PRG:1223 A2 00
@D225:
cmp $8F,x ; CPU:$D225 PRG:1225 D5 8F
bne @D231 ; CPU:$D227 PRG:1227 D0 08
inx ; CPU:$D229 PRG:1229 E8
lda $8F,x ; CPU:$D22A PRG:122A B5 8F
sta $D3 ; CPU:$D22C PRG:122C 85 D3
jmp @D236 ; CPU:$D22E PRG:122E 4C 36 D2
@D231:
inx ; CPU:$D231 PRG:1231 E8
cpx #$04 ; CPU:$D232 PRG:1232 E0 04
bne @D225 ; CPU:$D234 PRG:1234 D0 EF
@D236:
inc $D6 ; CPU:$D236 PRG:1236 E6 D6
lda #$60 ; CPU:$D238 PRG:1238 A9 60
cmp $D6 ; CPU:$D23A PRG:123A C5 D6
bne @D251 ; CPU:$D23C PRG:123C D0 13
lda #$00 ; CPU:$D23E PRG:123E A9 00
sta $D6 ; CPU:$D240 PRG:1240 85 D6
inc $D5 ; CPU:$D242 PRG:1242 E6 D5
lda $D5 ; CPU:$D244 PRG:1244 A5 D5
cmp $96 ; CPU:$D246 PRG:1246 C5 96
bne @D251 ; CPU:$D248 PRG:1248 D0 07
lda #$00 ; CPU:$D24A PRG:124A A9 00
sta $D5 ; CPU:$D24C PRG:124C 85 D5
jsr ActivateNextStateEntry ; CPU:$D24E PRG:124E 20 8A D2
@D251:
ldx $D4 ; CPU:$D251 PRG:1251 A6 D4
cpx #$02 ; CPU:$D253 PRG:1253 E0 02
beq @D26E ; CPU:$D255 PRG:1255 F0 17
lda $8D,x ; CPU:$D257 PRG:1257 B5 8D
cmp $6A ; CPU:$D259 PRG:1259 C5 6A
bne @D26E ; CPU:$D25B PRG:125B D0 11
inc $D4 ; CPU:$D25D PRG:125D E6 D4
lda #$01 ; CPU:$D25F PRG:125F A9 01
sta $D2 ; CPU:$D261 PRG:1261 85 D2
txa ; CPU:$D263 PRG:1263 8A
asl ; CPU:$D264 PRG:1264 0A
tax ; CPU:$D265 PRG:1265 AA
lda $AB,x ; CPU:$D266 PRG:1266 B5 AB
sta $CA ; CPU:$D268 PRG:1268 85 CA
lda $AC,x ; CPU:$D26A PRG:126A B5 AC
sta $CB ; CPU:$D26C PRG:126C 85 CB
@D26E:
ora $D7 ; CPU:$D26E PRG:126E 05 D7
ora $D8 ; CPU:$D270 PRG:1270 05 D8
beq @D289 ; CPU:$D272 PRG:1272 F0 15
dec $D8 ; CPU:$D274 PRG:1274 C6 D8
bne @D289 ; CPU:$D276 PRG:1276 D0 11
lda $D7 ; CPU:$D278 PRG:1278 A5 D7
beq @D283 ; CPU:$D27A PRG:127A F0 07
dec $D7 ; CPU:$D27C PRG:127C C6 D7
lda #$3C ; CPU:$D27E PRG:127E A9 3C
sta $D8 ; CPU:$D280 PRG:1280 85 D8
rts ; CPU:$D282 PRG:1282 60
@D283:
sta $2E ; CPU:$D283 PRG:1283 85 2E
sta $30 ; CPU:$D285 PRG:1285 85 30
sta $8B ; CPU:$D287 PRG:1287 85 8B
@D289:
rts ; CPU:$D289 PRG:1289 60
;==============================================================================
; $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 ; CPU:$D28A PRG:128A A2 00
@FindAvailableEntry:
lda $BA,x ; CPU:$D28C PRG:128C B5 BA
bne @NextEntry ; CPU:$D28E PRG:128E D0 05
lda #$02 ; CPU:$D290 PRG:1290 A9 02
sta $BA,x ; CPU:$D292 PRG:1292 95 BA
rts ; CPU:$D294 PRG:1294 60
@NextEntry:
inx ; CPU:$D295 PRG:1295 E8
inx ; CPU:$D296 PRG:1296 E8
cpx #$06 ; CPU:$D297 PRG:1297 E0 06
bne @FindAvailableEntry ; CPU:$D299 PRG:1299 D0 F1
rts ; CPU:$D29B PRG:129B 60
;==============================================================================
; $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 ; CPU:$D29C PRG:129C 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 ; CPU:$D2A4 PRG:12A4 A5 6A
bne @Start ; CPU:$D2A6 PRG:12A6 D0 01
rts ; CPU:$D2A8 PRG:12A8 60
@Start:
lda #$1E ; CPU:$D2A9 PRG:12A9 A9 1E
sta $00 ; CPU:$D2AB PRG:12AB 85 00
lda #$00 ; CPU:$D2AD PRG:12AD A9 00
sta $01 ; CPU:$D2AF PRG:12AF 85 01
lda #$01 ; CPU:$D2B1 PRG:12B1 A9 01
sta $02 ; CPU:$D2B3 PRG:12B3 85 02
ldx #$00 ; CPU:$D2B5 PRG:12B5 A2 00
@ScanEntries:
lda $B8,x ; CPU:$D2B7 PRG:12B7 B5 B8
cmp #$04 ; CPU:$D2B9 PRG:12B9 C9 04
bne @NextEntry ; CPU:$D2BB PRG:12BB D0 32
ldy #$00 ; CPU:$D2BD PRG:12BD A0 00
lda $1A ; CPU:$D2BF PRG:12BF A5 1A
cmp ($00),y ; CPU:$D2C1 PRG:12C1 D1 00
bcs @FirstAxisReverse ; CPU:$D2C3 PRG:12C3 B0 07
lda ($00),y ; CPU:$D2C5 PRG:12C5 B1 00
sec ; CPU:$D2C7 PRG:12C7 38
sbc $1A ; CPU:$D2C8 PRG:12C8 E5 1A
bcs @CheckFirstAxisDistance ; CPU:$D2CA PRG:12CA B0 02
@FirstAxisReverse:
sbc ($00),y ; CPU:$D2CC PRG:12CC F1 00
@CheckFirstAxisDistance:
cmp #$0A ; CPU:$D2CE PRG:12CE C9 0A
bcs @NextEntry ; CPU:$D2D0 PRG:12D0 B0 1D
sta $03 ; CPU:$D2D2 PRG:12D2 85 03
ldy #$02 ; CPU:$D2D4 PRG:12D4 A0 02
lda $1C ; CPU:$D2D6 PRG:12D6 A5 1C
cmp ($00),y ; CPU:$D2D8 PRG:12D8 D1 00
bcs @SecondAxisReverse ; CPU:$D2DA PRG:12DA B0 07
lda ($00),y ; CPU:$D2DC PRG:12DC B1 00
sec ; CPU:$D2DE PRG:12DE 38
sbc $1C ; CPU:$D2DF PRG:12DF E5 1C
bcs @CheckSecondAxisDistance ; CPU:$D2E1 PRG:12E1 B0 02
@SecondAxisReverse:
sbc ($00),y ; CPU:$D2E3 PRG:12E3 F1 00
@CheckSecondAxisDistance:
cmp #$0A ; CPU:$D2E5 PRG:12E5 C9 0A
bcs @NextEntry ; CPU:$D2E7 PRG:12E7 B0 06
adc $03 ; CPU:$D2E9 PRG:12E9 65 03
cmp #$05 ; CPU:$D2EB PRG:12EB C9 05
bcc @CandidateFound ; CPU:$D2ED PRG:12ED 90 10
@NextEntry:
inx ; CPU:$D2EF PRG:12EF E8
inx ; CPU:$D2F0 PRG:12F0 E8
lda $00 ; CPU:$D2F1 PRG:12F1 A5 00
clc ; CPU:$D2F3 PRG:12F3 18
adc #$04 ; CPU:$D2F4 PRG:12F4 69 04
sta $00 ; CPU:$D2F6 PRG:12F6 85 00
asl $02 ; CPU:$D2F8 PRG:12F8 06
cpx #$0A ; CPU:$D2F9 PRG:12F9 02 E0
bne @ScanEntries ; CPU:$D2FB PRG:12FB 0A D0
rts ; CPU:$D2FD PRG:12FD B9
@CandidateFound:
cpx #$08 ; CPU:$D2FE PRG:12FE 60 E0
beq @ProcessSecondaryState ; CPU:$D300 PRG:1300 08 F0
lda $02 ; CPU:$D302 PRG:1302 45 A5
and $88 ; CPU:$D304 PRG:1304 02 25
beq @SpecialCandidate ; CPU:$D306 PRG:1306 88 F0
txa ; CPU:$D308 PRG:1308 2E
lsr ; CPU:$D309 PRG:1309 8A
sta $03 ; CPU:$D30A PRG:130A 4A 85
ldy $D9 ; CPU:$D30C PRG:130C 03 A4
lda ProximityCandidateValues,y ; CPU:$D30E PRG:130E D9 B9 6C
ldy $03 ; CPU:$D311 PRG:1311 D3 A4
sta $0033,y ; CPU:$D313 PRG:1313 03 99 33
lda #$00 ; CPU:$D316 PRG:1316 00 A9
sta $32 ; CPU:$D318 PRG:1318 00 85
ldy $D9 ; CPU:$D31A PRG:131A 32 A4
lda ProximityDDValues,y ; CPU:$D31C PRG:131C D9 B9 7C
sta $DD ; CPU:$D31F PRG:131F D3 85
lda ProximityDEValues,y ; CPU:$D321 PRG:1321 DD B9 78
sta $DE ; CPU:$D324 PRG:1324 D3 85
inc $D9 ; CPU:$D326 PRG:1326 DE E6
lda #$08 ; CPU:$D328 PRG:1328 D9 A9
sta $B8,x ; CPU:$D32A PRG:132A 08 95
sta $0607 ; CPU:$D32C PRG:132C B8 8D 07
lda #$06 ; CPU:$D32F PRG:132F 06 A9
sta $3F ; CPU:$D331 PRG:1331 06 85
jmp $E0E6 ; CPU:$D333 PRG:1333 3F 4C E6
;------------------------------------------------------------------------------
; $D337
; Candidate path selected when ($02 & $88) == 0.
;------------------------------------------------------------------------------
@SpecialCandidate:
lda #$08 ; CPU:$D336 PRG:1336 E0 A9
sta $3F ; CPU:$D338 PRG:1338 08 85
lda #$12 ; CPU:$D33A PRG:133A 3F A9
sta $32 ; CPU:$D33C PRG:133C 12 85
lda #$80 ; CPU:$D33E PRG:133E 32 A9
sta $DB ; CPU:$D340 PRG:1340 80 85
lda #$00 ; CPU:$D342 PRG:1342 DB A9
sta $87 ; CPU:$D344 PRG:1344 00 85
rts ; CPU:$D346 PRG:1346 87
;------------------------------------------------------------------------------
; $D348
; Special path selected when X == $08.
;------------------------------------------------------------------------------
@ProcessSecondaryState:
lda $8B ; CPU:$D347 PRG:1347 60 A5
beq @InitializeSecondaryState ; CPU:$D349 PRG:1349 8B F0
rts ; CPU:$D34B PRG:134B 01
;------------------------------------------------------------------------------
; $D34D
; Initialize secondary state.
;------------------------------------------------------------------------------
@InitializeSecondaryState:
sta $D7 ; CPU:$D34C PRG:134C 60 85
lda #$80 ; CPU:$D34E PRG:134E D7 A9
sta $D8 ; CPU:$D350 PRG:1350 80 85
sta $8B ; CPU:$D352 PRG:1352 D8 85
sta $0606 ; CPU:$D354 PRG:1354 8B 8D 06
ldy $93 ; CPU:$D357 PRG:1357 06 A4
lda SecondaryStateDDValues,y ; CPU:$D359 PRG:1359 93 B9 80
sta $DD ; CPU:$D35C PRG:135C D3 85
lda SecondaryStateDEValues,y ; CPU:$D35E PRG:135E DD B9 88
sta $DE ; CPU:$D361 PRG:1361 D3 85
lda SecondaryState37Values,y ; CPU:$D363 PRG:1363 DE B9 70
sta $37 ; CPU:$D366 PRG:1366 D3 85
jmp $E0E6 ; CPU:$D368 PRG:1368 37 4C E6
;==============================================================================
; $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 ; CPU:$D36C PRG:136C 2D 2F 32 34
SecondaryState37Values:
; $D370-$D373
; Also forms bytes 4-7 of ProximityCandidateValues.
.byte $2C,$2E,$30,$31 ; CPU:$D370 PRG:1370 2C 2E 30 31
;------------------------------------------------------------------------------
; $D374-$D377
; Consumer not yet established.
;------------------------------------------------------------------------------
ProximityUnknownTableD374:
.byte $33,$35,$36,$37 ; CPU:$D374 PRG:1374 33 35 36 37
;------------------------------------------------------------------------------
; $D378-$D37B
; Indexed by $D9 and loaded into $DE.
;------------------------------------------------------------------------------
ProximityDEValues:
.byte $00,$00,$00,$01 ; CPU:$D378 PRG:1378 00 00 00 01
;------------------------------------------------------------------------------
; $D37C-$D37F
; Indexed by $D9 and loaded into $DD.
;------------------------------------------------------------------------------
ProximityDDValues:
.byte $02,$04,$08,$06 ; CPU:$D37C PRG:137C 02 04 08 06
;------------------------------------------------------------------------------
; $D380-$D387
; Indexed by $93 and loaded into $DD.
;------------------------------------------------------------------------------
SecondaryStateDDValues:
.byte $01,$03,$05,$07 ; CPU:$D380 PRG:1380 01 03 05 07
.byte $00,$00,$00,$00 ; CPU:$D384 PRG:1384 00 00 00 00
;------------------------------------------------------------------------------
; $D388-$D38F
; Indexed by $93 and loaded into $DE.
;------------------------------------------------------------------------------
SecondaryStateDEValues:
.byte $00,$00,$00,$00 ; CPU:$D388 PRG:1388 00 00 00 00
.byte $01,$02,$03,$05 ; CPU:$D38C PRG:138C 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 ; CPU:$D390 PRG:1390 A5 48
beq @D397 ; CPU:$D392 PRG:1392 F0 03
jmp $D506 ; CPU:$D394 PRG:1394 4C 06 D5
@D397:
lda $4F ; CPU:$D397 PRG:1397 A5 4F
and #$F0 ; CPU:$D399 PRG:1399 29 F0
beq @D3D2 ; CPU:$D39B PRG:139B F0 35
ldx #$FF ; CPU:$D39D PRG:139D A2 FF
@D39F:
inx ; CPU:$D39F PRG:139F E8
asl ; CPU:$D3A0 PRG:13A0 0A
bcc @D39F ; CPU:$D3A1 PRG:13A1 90 FC
lda InputDirectionTable,x ; CPU:$D3A3 PRG:13A3 BD 02 D5
sta $50 ; CPU:$D3A6 PRG:13A6 85 50
clc ; CPU:$D3A8 PRG:13A8 18
adc #$02 ; CPU:$D3A9 PRG:13A9 69 02
and #$03 ; CPU:$D3AB PRG:13AB 29 03
cmp $51 ; CPU:$D3AD PRG:13AD C5 51
bne @D3C9 ; CPU:$D3AF PRG:13AF D0 18
lda $1A ; CPU:$D3B1 PRG:13B1 A5 1A
ora $1C ; CPU:$D3B3 PRG:13B3 05 1C
and #$07 ; CPU:$D3B5 PRG:13B5 29 07
bne @D3C2 ; CPU:$D3B7 PRG:13B7 D0 09
ldy $50 ; CPU:$D3B9 PRG:13B9 A4 50
lda $022B,y ; CPU:$D3BB PRG:13BB B9 2B 02
and #$F0 ; CPU:$D3BE PRG:13BE 29 F0
bne @D3C9 ; CPU:$D3C0 PRG:13C0 D0 07
@D3C2:
lda $50 ; CPU:$D3C2 PRG:13C2 A5 50
sta $51 ; CPU:$D3C4 PRG:13C4 85 51
jmp @D3D6 ; CPU:$D3C6 PRG:13C6 4C D6 D3
@D3C9:
ldx $50 ; CPU:$D3C9 PRG:13C9 A6 50
lda $022B,x ; CPU:$D3CB PRG:13CB BD 2B 02
and #$F0 ; CPU:$D3CE PRG:13CE 29 F0
beq @D3D6 ; CPU:$D3D0 PRG:13D0 F0 04
@D3D2:
lda $51 ; CPU:$D3D2 PRG:13D2 A5 51
sta $50 ; CPU:$D3D4 PRG:13D4 85 50
@D3D6:
ldx #$04 ; CPU:$D3D6 PRG:13D6 A2 04
lda $88 ; CPU:$D3D8 PRG:13D8 A5 88
bne @D3DE ; CPU:$D3DA PRG:13DA D0 02
ldx #$0A ; CPU:$D3DC PRG:13DC A2 0A
@D3DE:
lda $022A ; CPU:$D3DE PRG:13DE AD 2A 02
cmp #$01 ; CPU:$D3E1 PRG:13E1 C9 01
beq @D3F4 ; CPU:$D3E3 PRG:13E3 F0 10
cmp #$02 ; CPU:$D3E5 PRG:13E5 C9 02
beq @D3F4 ; CPU:$D3E7 PRG:13E7 F0 0C
dex ; CPU:$D3E9 PRG:13E9 CA
dex ; CPU:$D3EA PRG:13EA CA
cmp #$03 ; CPU:$D3EB PRG:13EB C9 03
beq @D3F4 ; CPU:$D3ED PRG:13ED F0 06
cmp #$09 ; CPU:$D3EF PRG:13EF C9 09
beq @D3F4 ; CPU:$D3F1 PRG:13F1 F0 02
dex ; CPU:$D3F3 PRG:13F3 CA
dex ; CPU:$D3F4 PRG:13F4 CA
@D3F4:
lda $9F,x ; CPU:$D3F5 PRG:13F5 B5 9F
sta $B5 ; CPU:$D3F7 PRG:13F7 85 B5
lda $A0,x ; CPU:$D3F9 PRG:13F9 B5 A0
sta $B6 ; CPU:$D3FB PRG:13FB 85 B6
lda $51 ; CPU:$D3FD PRG:13FD A5 51
asl ; CPU:$D3FF PRG:13FF 0A
tay ; CPU:$D400 PRG:1400 A8
lda MovementArithmeticTable,y ; CPU:$D401 PRG:1401 B9 0E D4
sta $10 ; CPU:$D404 PRG:1404 85 10
lda MovementArithmeticTable+1,y ; CPU:$D406 PRG:1406 B9 0F D4
sta $11 ; CPU:$D409 PRG:1409 85 11
jmp ($0010) ; CPU:$D40B PRG:140B 6C 10 00 16 D4
;==============================================================================
; $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 ; CPU:$D40E PRG:140E 16 D4
.word $D41A ; CPU:$D410 PRG:1410 1A D4
.word $D435 ; CPU:$D412 PRG:1412 35 D4
.word $D431 ; CPU:$D414 PRG:1414 31 D4
;==============================================================================
; $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 ; CPU:$D416 PRG:1416 A2 02
bne MovementSubtract ; CPU:$D418 PRG:1418 D0 02
MovementArithmeticD41A:
ldx #$00 ; CPU:$D41A PRG:141A A2 00
MovementSubtract:
lda $1B,x ; CPU:$D41C PRG:141C B5 1B
sec ; CPU:$D41E PRG:141E 38
sbc $B5 ; CPU:$D41F PRG:141F E5 B5
sta $1B,x ; CPU:$D421 PRG:1421 95 1B
lda #$00 ; CPU:$D423 PRG:1423 A9 00
bcs MovementSubtractNoBorrow ; CPU:$D425 PRG:1425 B0 02
lda #$01 ; CPU:$D427 PRG:1427 A9 01
MovementSubtractNoBorrow:
clc ; CPU:$D429 PRG:1429 18
adc $B6 ; CPU:$D42A PRG:142A 65 B6
sta $CC ; CPU:$D42C PRG:142C 85 CC
jmp MovementApplyResult ; CPU:$D42E PRG:142E 4C 44 D4
MovementArithmeticD431:
ldx #$00 ; CPU:$D431 PRG:1431 A2 00
beq MovementAdd ; CPU:$D433 PRG:1433 F0 02
MovementArithmeticD435:
ldx #$02 ; CPU:$D435 PRG:1435 A2 02
MovementAdd:
lda $1B,x ; CPU:$D437 PRG:1437 B5 1B
clc ; CPU:$D439 PRG:1439 18
adc $B5 ; CPU:$D43A PRG:143A 65 B5
sta $1B,x ; CPU:$D43C PRG:143C 95 1B
lda #$00 ; CPU:$D43E PRG:143E A9 00
adc $B6 ; CPU:$D440 PRG:1440 65 B6
sta $CC ; CPU:$D442 PRG:1442 85 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 ; CPU:$D444 PRG:1444 C6 CC
bpl @D449 ; CPU:$D446 PRG:1446 10 01
rts ; CPU:$D448 PRG:1448 60
@D449:
lda $51 ; CPU:$D449 PRG:1449 A5 51
asl ; CPU:$D44B PRG:144B 0A
tay ; CPU:$D44C PRG:144C A8
lda MovementDirectionTable,y ; CPU:$D44D PRG:144D B9 5A D4
sta $10 ; CPU:$D450 PRG:1450 85 10
lda MovementDirectionTable+1,y ; CPU:$D452 PRG:1452 B9 5B D4
sta $11 ; CPU:$D455 PRG:1455 85 11
jmp ($0010) ; CPU:$D457 PRG:1457 6C 10 00 9A D4
;==============================================================================
; $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 ; CPU:$D45A PRG:145A 9A D4
.word MovementDirectionD490 ; CPU:$D45C PRG:145C 90 D4
.word MovementDirectionD46C ; CPU:$D45E PRG:145E 6C D4
.word MovementDirectionD462 ; CPU:$D460 PRG:1460 62 D4
;==============================================================================
; $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 ; CPU:$D462 PRG:1462 A2 00
stx $00 ; CPU:$D464 PRG:1464 86 00
lda #$03 ; CPU:$D466 PRG:1466 A9 03
sta $01 ; CPU:$D468 PRG:1468 85 01
bne MovementIncrement ; CPU:$D46A PRG:146A D0 06
;------------------------------------------------------------------------------
; $D46C
; Increment coordinate component X=2.
;------------------------------------------------------------------------------
MovementDirectionD46C:
ldx #$02 ; CPU:$D46C PRG:146C A2 02
stx $00 ; CPU:$D46E PRG:146E 86 00
stx $01 ; CPU:$D470 PRG:1470 86 01
;------------------------------------------------------------------------------
; $D472: Shared increment path.
;------------------------------------------------------------------------------
MovementIncrement:
lda $1A,x ; CPU:$D472 PRG:1472 B5 1A
clc ; CPU:$D474 PRG:1474 18
adc #$01 ; CPU:$D475 PRG:1475 69 01
sta $1A,x ; CPU:$D477 PRG:1477 95 1A
and #$04 ; CPU:$D479 PRG:1479 29 04
bne MovementSharedTail ; CPU:$D47B PRG:147B D0 44
ldx $01 ; CPU:$D47D PRG:147D A6 01
lda $022B,x ; CPU:$D47F PRG:147F BD 2B 02
and #$F0 ; CPU:$D482 PRG:1482 29 F0
beq MovementSharedTail ; CPU:$D484 PRG:1484 F0 3B
ldx $00 ; CPU:$D486 PRG:1486 A6 00
lda $1A,x ; CPU:$D488 PRG:1488 B5 1A
and #$FC ; CPU:$D48A PRG:148A 29 FC
sta $1A,x ; CPU:$D48C PRG:148C 95 1A
bne MovementSharedTail ; CPU:$D48E PRG:148E D0 31
;------------------------------------------------------------------------------
; $D490
; Decrement coordinate component X=0.
;------------------------------------------------------------------------------
MovementDirectionD490:
ldx #$00 ; CPU:$D490 PRG:1490 A2 00
stx $00 ; CPU:$D492 PRG:1492 86 00
lda #$01 ; CPU:$D494 PRG:1494 A9 01
sta $01 ; CPU:$D496 PRG:1496 85 01
bne MovementDecrement ; CPU:$D498 PRG:1498 D0 08
;------------------------------------------------------------------------------
; $D49A
; Decrement coordinate component X=2.
;------------------------------------------------------------------------------
MovementDirectionD49A:
ldx #$02 ; CPU:$D49A PRG:149A A2 02
stx $00 ; CPU:$D49C PRG:149C 86 00
lda #$00 ; CPU:$D49E PRG:149E A9 00
sta $01 ; CPU:$D4A0 PRG:14A0 85 01
;------------------------------------------------------------------------------
; $D4A2: Shared decrement path.
;------------------------------------------------------------------------------
MovementDecrement:
lda $1A,x ; CPU:$D4A2 PRG:14A2 B5 1A
sec ; CPU:$D4A4 PRG:14A4 38
sbc #$01 ; CPU:$D4A5 PRG:14A5 E9 01
sta $1A,x ; CPU:$D4A7 PRG:14A7 95 1A
and #$04 ; CPU:$D4A9 PRG:14A9 29 04
beq MovementSharedTail ; CPU:$D4AB PRG:14AB F0 14
ldx $01 ; CPU:$D4AD PRG:14AD A6 01
lda $022B,x ; CPU:$D4AF PRG:14AF BD 2B 02
and #$F0 ; CPU:$D4B2 PRG:14B2 29 F0
beq MovementSharedTail ; CPU:$D4B4 PRG:14B4 F0 0B
ldx $00 ; CPU:$D4B6 PRG:14B6 A6 00
lda $1A,x ; CPU:$D4B8 PRG:14B8 B5 1A
clc ; CPU:$D4BA PRG:14BA 18
adc #$04 ; CPU:$D4BB PRG:14BB 69 04
and #$FC ; CPU:$D4BD PRG:14BD 29 FC
sta $1A,x ; CPU:$D4BF PRG:14BF 95 1A
;------------------------------------------------------------------------------
; $D4C1: Shared movement/wrap tail.
;------------------------------------------------------------------------------
MovementSharedTail:
lda $1A ; CPU:$D4C1 PRG:14C1 A5 1A
cmp #$18 ; CPU:$D4C3 PRG:14C3 C9 18
bcc MovementCheckLeftWrap ; CPU:$D4C5 PRG:14C5 90 0A
cmp #$A9 ; CPU:$D4C7 PRG:14C7 C9 A9
bcs MovementCheckLeftWrap ; CPU:$D4C9 PRG:14C9 B0 06
lda $38 ; CPU:$D4CB PRG:14CB A5 38
and #$DF ; CPU:$D4CD PRG:14CD 29 DF
bcc MovementStoreWrapState ; CPU:$D4CF PRG:14CF 90 04
MovementCheckLeftWrap:
lda #$20 ; CPU:$D4D1 PRG:14D1 A9 20
ora $38 ; CPU:$D4D3 PRG:14D3 05 38
MovementStoreWrapState:
sta $38 ; CPU:$D4D5 PRG:14D5 85 38
lda $1A ; CPU:$D4D7 PRG:14D7 A5 1A
cmp #$0B ; CPU:$D4D9 PRG:14D9 C9 0B
bcs MovementCheckRightWrap ; CPU:$D4DB PRG:14DB B0 06
lda #$BF ; CPU:$D4DD PRG:14DD A9 BF
sta $1A ; CPU:$D4DF PRG:14DF 85 1A
bne MovementCheckAlignment ; CPU:$D4E1 PRG:14E1 D0 08
MovementCheckRightWrap:
cmp #$C0 ; CPU:$D4E3 PRG:14E3 C9 C0
bcc MovementCheckAlignment ; CPU:$D4E5 PRG:14E5 90 04
lda #$0B ; CPU:$D4E7 PRG:14E7 A9 0B
sta $1A ; CPU:$D4E9 PRG:14E9 85 1A
MovementCheckAlignment:
lda $1A ; CPU:$D4EB PRG:14EB A5 1A
ora $1C ; CPU:$D4ED PRG:14ED 05 1C
and #$07 ; CPU:$D4EF PRG:14EF 29 07
bne MovementReturnToArithmetic ; CPU:$D4F1 PRG:14F1 D0 0C
lda $50 ; CPU:$D4F3 PRG:14F3 A5 50
cmp $51 ; CPU:$D4F5 PRG:14F5 C5 51
beq MovementReturnToArithmetic ; CPU:$D4F7 PRG:14F7 F0 06
sta $51 ; CPU:$D4F9 PRG:14F9 85 51
inc $CC ; CPU:$D4FB PRG:14FB E6 CC
inc $CC ; CPU:$D4FD PRG:14FD E6 CC
MovementReturnToArithmetic:
jmp MovementApplyResult ; CPU:$D4FF PRG:14FF 4C 44 D4
;==============================================================================
; $D502-$D505: Controller Direction Mapping
;==============================================================================
InputDirectionTable:
.byte $03,$01,$02,$00 ; CPU:$D502 PRG:1502 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 ; CPU:$D506 PRG:1506 A4 E4
dec $E3 ; CPU:$D508 PRG:1508 C6 E3
bne @UseCurrentEntry ; CPU:$D50A PRG:150A D0 0B
inc $E4 ; CPU:$D50C PRG:150C E6 E4
inc $E4 ; CPU:$D50E PRG:150E E6 E4
ldy $E4 ; CPU:$D510 PRG:1510 A4 E4
lda ScriptedDirectionTable,y ; CPU:$D512 PRG:1512 B9 1F D5
sta $E3 ; CPU:$D515 PRG:1515 85 E3
@UseCurrentEntry:
lda ScriptedDirectionTable+1,y ; CPU:$D517 PRG:1517 B9 20 D5
and #$03 ; CPU:$D51A PRG:151A 29 03
jmp $D3A6 ; CPU:$D51C PRG:151C 4C A6 D3
;==============================================================================
; $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 ; CPU:$D51F PRG:151F 00 01
.byte $D0,$00 ; CPU:$D521 PRG:1521 D0 00
.byte $28,$01 ; CPU:$D523 PRG:1523 28 01
.byte $28,$02 ; CPU:$D525 PRG:1525 28 02
.byte $90,$03 ; CPU:$D527 PRG:1527 90 03
.byte $38,$00 ; CPU:$D529 PRG:1529 38 00
.byte $20,$03 ; CPU:$D52B PRG:152B 20 03
.byte $18,$01 ; CPU:$D52D PRG:152D 18 01
.byte $60,$02 ; CPU:$D52F PRG:152F 60 02
.byte $30,$01 ; CPU:$D531 PRG:1531 30 01
.byte $10,$02 ; CPU:$D533 PRG:1533 10 02
.byte $48,$01 ; CPU:$D535 PRG:1535 48 01
.byte $18,$02 ; CPU:$D537 PRG:1537 18 02
.byte $40,$01 ; CPU:$D539 PRG:1539 40 01
.byte $20,$02 ; CPU:$D53B PRG:153B 20 02
.byte $18,$00 ; CPU:$D53D PRG:153D 18 00
.byte $20,$03 ; CPU:$D53F PRG:153F 20 03
.byte $40,$02 ; CPU:$D541 PRG:1541 40 02
.byte $38,$01 ; CPU:$D543 PRG:1543 38 01
.byte $18,$02 ; CPU:$D545 PRG:1545 18 02
.byte $E0,$03 ; CPU:$D547 PRG:1547 E0 03
.byte $30,$00 ; CPU:$D549 PRG:1549 30 00
.byte $28,$01 ; CPU:$D54B PRG:154B 28 01
.byte $28,$02 ; CPU:$D54D PRG:154D 28 02
.byte $20,$02 ; CPU:$D54F PRG:154F 20 02
.byte $80,$03 ; CPU:$D551 PRG:1551 80 03
.byte $40,$00 ; CPU:$D553 PRG:1553 40 00
.byte $40,$01 ; CPU:$D555 PRG:1555 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 ; CPU:$D557 PRG:1557 A2 00
lda #$2F ; CPU:$D559 PRG:1559 A9 2F
sta $00 ; CPU:$D55B PRG:155B 85 00
lda #$02 ; CPU:$D55D PRG:155D A9 02
sta $01 ; CPU:$D55F PRG:155F 85 01
lda #$1E ; CPU:$D561 PRG:1561 A9 1E
sta $02 ; CPU:$D563 PRG:1563 85 02
lda #$00 ; CPU:$D565 PRG:1565 A9 00
sta $03 ; CPU:$D567 PRG:1567 85 03
lda #$01 ; CPU:$D569 PRG:1569 A9 01
sta $04 ; CPU:$D56B PRG:156B 85 04
@UpdateNextEntity:
jsr $D587 ; CPU:$D56D PRG:156D 20 87 D5
lda $00 ; CPU:$D570 PRG:1570 A5 00
clc ; CPU:$D572 PRG:1572 18
adc #$04 ; CPU:$D573 PRG:1573 69 04
sta $00 ; CPU:$D575 PRG:1575 85 00
lda $02 ; CPU:$D577 PRG:1577 A5 02
clc ; CPU:$D579 PRG:1579 18
adc #$04 ; CPU:$D57A PRG:157A 69 04
sta $02 ; CPU:$D57C PRG:157C 85 02
asl $04 ; CPU:$D57E PRG:157E 06
inx ; CPU:$D57F PRG:157F 04
inx ; CPU:$D580 PRG:1580 E8
cpx #$08 ; CPU:$D581 PRG:1581 E8 E0
bne @UpdateNextEntity ; CPU:$D583 PRG:1583 08 D0
rts ; CPU:$D585 PRG:1585 E7
;==============================================================================
; $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 ; CPU:$D587 PRG:1587 B4 B8
lda EntityStateTable,y ; CPU:$D589 PRG:1589 B9 96 D5
sta $10 ; CPU:$D58C PRG:158C 85 10
lda EntityStateTable+1,y ; CPU:$D58E PRG:158E B9 97 D5
sta $11 ; CPU:$D591 PRG:1591 85 11
jmp ($0010) ; CPU:$D593 PRG:1593 6C 10 00 D5 D8
;==============================================================================
; $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 ; CPU:$D596 PRG:1596 D5 D8
.word $D885 ; state $02 ; CPU:$D598 PRG:1598 85 D8
.word $D5A1 ; state $04 ; CPU:$D59A PRG:159A A1 D5
.word $D5A1 ; state $06 ; CPU:$D59C PRG:159C A1 D5
.word EntityState08 ; state $08 ; CPU:$D59E PRG:159E A0 D5
;==============================================================================
; $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 ; CPU:$D5A0 PRG:15A0 60
;==============================================================================
; $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 ; CPU:$D5A1 PRG:15A1 20 21 D8
lda $B9,x ; CPU:$D5A4 PRG:15A4 B5 B9
asl ; CPU:$D5A6 PRG:15A6 0A
tay ; CPU:$D5A7 PRG:15A7 A8
lda EntitySecondaryStateTable,y ; CPU:$D5A8 PRG:15A8 B9 B5 D5
sta $10 ; CPU:$D5AB PRG:15AB 85 10
lda EntitySecondaryStateTable+1,y ; CPU:$D5AD PRG:15AD B9 B6 D5
sta $11 ; CPU:$D5B0 PRG:15B0 85 11
jmp ($0010) ; CPU:$D5B2 PRG:15B2 6C 10 00 D3 D5
;==============================================================================
; $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 ; CPU:$D5B5 PRG:15B5 D3 D5
.word EntitySecondaryState1 ; secondary state 1 ; CPU:$D5B7 PRG:15B7 D7 D5
.word EntitySecondaryState2 ; secondary state 2 ; CPU:$D5B9 PRG:15B9 BD D5
.word EntitySecondaryState3 ; secondary state 3 ; CPU:$D5BB PRG:15BB C1 D5
;==============================================================================
; $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 ; CPU:$D5BD PRG:15BD A0 03
bne EntitySecondaryAdjust ; CPU:$D5BF PRG:15BF D0 02
EntitySecondaryState3:
ldy #$01 ; CPU:$D5C1 PRG:15C1 A0 01
EntitySecondaryAdjust:
lda ($02),y ; CPU:$D5C3 PRG:15C3 B1 02
clc ; CPU:$D5C5 PRG:15C5 18
adc $C2,x ; CPU:$D5C6 PRG:15C6 75 C2
sta ($02),y ; CPU:$D5C8 PRG:15C8 91 02
lda #$00 ; CPU:$D5CA PRG:15CA A9 00
adc $C3,x ; CPU:$D5CC PRG:15CC 75 C3
sta $CC ; CPU:$D5CE PRG:15CE 85 CC
jmp $D5EB ; CPU:$D5D0 PRG:15D0 4C EB D5
;==============================================================================
; $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 ; CPU:$D5D3 PRG:15D3 A0 03
bne EntitySecondarySubtract ; CPU:$D5D5 PRG:15D5 D0 02
EntitySecondaryState1:
ldy #$01 ; CPU:$D5D7 PRG:15D7 A0 01
EntitySecondarySubtract:
lda ($02),y ; CPU:$D5D9 PRG:15D9 B1 02
sec ; CPU:$D5DB PRG:15DB 38
sbc $C2,x ; CPU:$D5DC PRG:15DC F5 C2
sta ($02),y ; CPU:$D5DE PRG:15DE 91 02
lda #$00 ; CPU:$D5E0 PRG:15E0 A9 00
bcs EntitySecondarySubtractNoBorrow ; CPU:$D5E2 PRG:15E2 B0 02
lda #$01 ; CPU:$D5E4 PRG:15E4 A9 01
EntitySecondarySubtractNoBorrow:
clc ; CPU:$D5E6 PRG:15E6 18
adc $C3,x ; CPU:$D5E7 PRG:15E7 75 C3
sta $CC ; CPU:$D5E9 PRG:15E9 85 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 ; CPU:$D5EB PRG:15EB C6 CC
bpl EntityDirectionDispatch ; CPU:$D5ED PRG:15ED 10 01
rts ; CPU:$D5EF PRG:15EF 60
EntityDirectionDispatch:
lda $B9,x ; CPU:$D5F0 PRG:15F0 B5 B9
asl ; CPU:$D5F2 PRG:15F2 0A
tay ; CPU:$D5F3 PRG:15F3 A8
lda EntityDirectionStateTable,y ; CPU:$D5F4 PRG:15F4 B9 01 D6
sta $10 ; CPU:$D5F7 PRG:15F7 85 10
lda EntityDirectionStateTable+1,y ; CPU:$D5F9 PRG:15F9 B9 02 D6
sta $11 ; CPU:$D5FC PRG:15FC 85 11
jmp ($0010) ; CPU:$D5FE PRG:15FE 6C 10 00 09 D6
;==============================================================================
; $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 ; CPU:$D601 PRG:1601 09 D6
.word $D61D ; CPU:$D603 PRG:1603 1D D6
.word $D60F ; CPU:$D605 PRG:1605 0F D6
.word $D617 ; CPU:$D607 PRG:1607 17 D6
;==============================================================================
; $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 ; CPU:$D609 PRG:1609 A9 FF
sta $05 ; CPU:$D60B PRG:160B 85 05
bne EntityDirectionAxis2 ; CPU:$D60D PRG:160D D0 04
EntityDirectionD60F:
lda #$01 ; CPU:$D60F PRG:160F A9 01
sta $05 ; CPU:$D611 PRG:1611 85 05
EntityDirectionAxis2:
ldy #$02 ; CPU:$D613 PRG:1613 A0 02
bne EntityDirectionMove ; CPU:$D615 PRG:1615 D0 0C
EntityDirectionD617:
lda #$01 ; CPU:$D617 PRG:1617 A9 01
sta $05 ; CPU:$D619 PRG:1619 85 05
bne EntityDirectionAxis0 ; CPU:$D61B PRG:161B D0 04
EntityDirectionD61D:
lda #$FF ; CPU:$D61D PRG:161D A9 FF
sta $05 ; CPU:$D61F PRG:161F 85 05
EntityDirectionAxis0:
ldy #$00 ; CPU:$D621 PRG:1621 A0 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 ; CPU:$D623 PRG:1623 B1 02
clc ; CPU:$D625 PRG:1625 18
adc $05 ; CPU:$D626 PRG:1626 65 05
sta ($02),y ; CPU:$D628 PRG:1628 91 02
ldy #$00 ; CPU:$D62A PRG:162A A0 00
lda ($02),y ; CPU:$D62C PRG:162C B1 02
cmp #$0A ; CPU:$D62E PRG:162E C9 0A
bne @D637 ; CPU:$D630 PRG:1630 D0 06
lda #$BF ; CPU:$D632 PRG:1632 A9 BF
sta ($02),y ; CPU:$D634 PRG:1634 91 02
bne @D64B ; CPU:$D636 PRG:1636 D0 12
@D637:
cmp #$C0 ; CPU:$D638 PRG:1638 C9 C0
bne @D641 ; CPU:$D63A PRG:163A D0 06
lda #$0B ; CPU:$D63C PRG:163C A9 0B
sta ($02),y ; CPU:$D63E PRG:163E 91 02
bne @D64B ; CPU:$D640 PRG:1640 D0 08
@D641:
cmp #$18 ; CPU:$D642 PRG:1642 C9 18
bcc @D64B ; CPU:$D644 PRG:1644 90 04
cmp #$A9 ; CPU:$D646 PRG:1646 C9 A9
bcc @D64F ; CPU:$D648 PRG:1648 90 04
@D64B:
lda #$20 ; CPU:$D64A PRG:164A A9 20
bne @D651 ; CPU:$D64C PRG:164C D0 02
@D64F:
lda #$00 ; CPU:$D64E PRG:164E A9 00
@D651:
sta $05 ; CPU:$D650 PRG:1650 85 05
txa ; CPU:$D652 PRG:1652 8A
lsr ; CPU:$D653 PRG:1653 4A
tay ; CPU:$D654 PRG:1654 A8
lda $39,y ; CPU:$D655 PRG:1655 B9 39
and #$DF ; CPU:$D657 PRG:1657 00 29
ora $05 ; CPU:$D659 PRG:1659 DF 05
sta $39,y ; CPU:$D65B PRG:165B 05 99
ldy #$00 ; CPU:$D65D PRG:165D 39 00
lda ($02),y ; CPU:$D65F PRG:165F A0 00
ldy #$02 ; CPU:$D661 PRG:1661 B1 02
ora ($02),y ; CPU:$D663 PRG:1663 A0 02
and #$07 ; CPU:$D665 PRG:1665 11 02
beq @D66E ; CPU:$D667 PRG:1667 29 07
jmp EntitySecondaryApplyResult ; CPU:$D669 PRG:1669 F0 03 4C
@D66E:
ldy #$00 ; CPU:$D66C PRG:166C EB D5
lda ($02),y ; CPU:$D66E PRG:166E A0 00
cmp #$60 ; CPU:$D670 PRG:1670 B1 02
bne $D69B ; CPU:$D672 PRG:1672 C9 60
ldy #$02 ; CPU:$D674 PRG:1674 D0 25
lda ($02),y ; CPU:$D676 PRG:1676 A0 02
cmp #$70 ; CPU:$D678 PRG:1678 B1 02
bne $D69B ; CPU:$D67A PRG:167A C9 70
lda #$02 ; CPU:$D67C PRG:167C D0 1D
sta $B8,x ; CPU:$D67E PRG:167E A9 02
lda #$00 ; CPU:$D680 PRG:1680 95 B8
clc ; CPU:$D682 PRG:1682 A9
sbc $04 ; CPU:$D683 PRG:1683 00 18
and $88 ; CPU:$D685 PRG:1685 E5 04
sta $88 ; CPU:$D687 PRG:1687 25 88
txa ; CPU:$D689 PRG:1689 85
lsr ; CPU:$D68A PRG:168A 88
tay ; CPU:$D68B PRG:168B 8A
sta $05 ; CPU:$D68C PRG:168C 4A A8
lda $39,y ; CPU:$D68E PRG:168E 85 05
and #$FC ; CPU:$D690 PRG:1690 B9 39
ora $05 ; CPU:$D692 PRG:1692 00 29
sta $39,y ; CPU:$D694 PRG:1694 FC 05
rts ; CPU:$D696 PRG:1696 05
;==============================================================================
; $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 ; CPU:$D69B PRG:169B B5 B8
cmp #$06 ; CPU:$D69D PRG:169D C9 06
bne @CheckEntityMasks ; CPU:$D69F PRG:169F D0 0B
lda #$60 ; CPU:$D6A1 PRG:16A1 A9 60
sta $CD ; CPU:$D6A3 PRG:16A3 85 CD
lda #$6F ; CPU:$D6A5 PRG:16A5 A9 6F
sta $CE ; CPU:$D6A7 PRG:16A7 85 CE
jmp $D778 ; CPU:$D6A9 PRG:16A9 4C 78 D7
@CheckEntityMasks:
lda $04 ; CPU:$D6AC PRG:16AC A5 04
and $88 ; CPU:$D6AE PRG:16AE 25 88
bne $D70A ; CPU:$D6B0 PRG:16B0 D0 58
lda $04 ; CPU:$D6B2 PRG:16B2 A5 04
and $87 ; CPU:$D6B4 PRG:16B4 25 87
bne $D6CF ; CPU:$D6B6 PRG:16B6 D0 17
txa ; CPU:$D6B8 PRG:16B8 8A
tay ; CPU:$D6B9 PRG:16B9 A8
lda EntityTargetTable,y ; CPU:$D6BA PRG:16BA B9 C7 D6
sta $CD ; CPU:$D6BD PRG:16BD 85 CD
lda EntityTargetTable+1,y ; CPU:$D6BF PRG:16BF B9 C8 D6
sta $CE ; CPU:$D6C2 PRG:16C2 85 CE
jmp $D778 ; CPU:$D6C4 PRG:16C4 4C 78 D7
;==============================================================================
; $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 ; CPU:$D6C7 PRG:16C7 A8 08
.word $0818 ; CPU:$D6C9 PRG:16C9 18 08
.word $D0A8 ; CPU:$D6CB PRG:16CB A8 D0
.word $D018 ; CPU:$D6CD PRG:16CD 18 D0
;==============================================================================
; $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 ; CPU:$D6CF PRG:16CF 8A
tay ; CPU:$D6D0 PRG:16D0 A8
lda EntityTargetBehaviorTable,y ; CPU:$D6D1 PRG:16D1 B9 DE D6
sta $10 ; CPU:$D6D4 PRG:16D4 85 10
lda EntityTargetBehaviorTable+1,y ; CPU:$D6D6 PRG:16D6 B9 DF D6
sta $11 ; CPU:$D6D9 PRG:16D9 85 11
jmp ($0010) ; CPU:$D6DB PRG:16DB 6C 10 00 3B D7
;==============================================================================
; $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 ; CPU:$D6DE PRG:16DE 3B D7
.word EntityTargetBehaviorD745 ; X = $02 ; CPU:$D6E0 PRG:16E0 45 D7
.word EntityTargetBehaviorD764 ; X = $04 ; CPU:$D6E2 PRG:16E2 64 D7
.word EntityTargetBehaviorD6E6 ; X = $06 ; CPU:$D6E4 PRG:16E4 E6 D6
;==============================================================================
; $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 ; CPU:$D6E6 PRG:16E6 A5 1A
sec ; CPU:$D6E8 PRG:16E8 38
sbc $2A ; CPU:$D6E9 PRG:16E9 E5 2A
bcs @D6F4 ; CPU:$D6EB PRG:16EB B0 07
sta $05 ; CPU:$D6ED PRG:16ED 85 05
lda #$00 ; CPU:$D6EF PRG:16EF A9 00
sec ; CPU:$D6F1 PRG:16F1 38
sbc $05 ; CPU:$D6F2 PRG:16F2 E5 05
@D6F4:
cmp #$20 ; CPU:$D6F4 PRG:16F4 C9 20
bcs $D73B ; CPU:$D6F6 PRG:16F6 B0 43
lda $1C ; CPU:$D6F8 PRG:16F8 A5 1C
sec ; CPU:$D6FA PRG:16FA 38
sbc $2C ; CPU:$D6FB PRG:16FB E5 2C
bcs @D703 ; CPU:$D6FD PRG:16FD B0 07
sta $05 ; CPU:$D6FF PRG:16FF 85 05
lda #$00 ; CPU:$D701 PRG:1701 A9 00
sec ; CPU:$D703 PRG:1703 38
sbc $05 ; CPU:$D704 PRG:1704 E5 05
@D703:
cmp #$20 ; CPU:$D706 PRG:1706 C9 20
bcs $D73B ; CPU:$D708 PRG:1708 B0 31
lda $4B ; CPU:$D70A PRG:170A A5 4B
sta $05 ; CPU:$D70C PRG:170C 85 05
lda #$05 ; CPU:$D70E PRG:170E A9 05
sta $06 ; CPU:$D710 PRG:1710 85 06
@D712:
dec $06 ; CPU:$D712 PRG:1712 C6 06
bne @D71A ; CPU:$D714 PRG:1714 D0 04
lda #$02 ; CPU:$D716 PRG:1716 A9 02
bne @D736 ; CPU:$D718 PRG:1718 D0 1C
@D71A:
inc $05 ; CPU:$D71A PRG:171A E6 05
lda $05 ; CPU:$D71C PRG:171C A5 05
and #$03 ; CPU:$D71E PRG:171E 29 03
tay ; CPU:$D720 PRG:1720 A8
lda ($00),y ; CPU:$D721 PRG:1721 B1 00
and #$F8 ; CPU:$D723 PRG:1723 29 F8
bne @D712 ; CPU:$D725 PRG:1725 D0 EB
lda $05 ; CPU:$D727 PRG:1727 A5 05
clc ; CPU:$D729 PRG:1729 18
adc #$02 ; CPU:$D72A PRG:172A 69 02
and #$03 ; CPU:$D72C PRG:172C 29 03
cmp $B9,x ; CPU:$D72E PRG:172E D5 B9
beq @D712 ; CPU:$D730 PRG:1730 F0 E0
lda $05 ; CPU:$D732 PRG:1732 A5 05
and #$03 ; CPU:$D734 PRG:1734 29 03
@D736:
sta $B9,x ; CPU:$D736 PRG:1736 95 B9
jmp EntitySecondaryApplyResult ; CPU:$D738 PRG:1738 4C EB D5
;==============================================================================
; $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 ; CPU:$D73B PRG:173B A5 1A
sta $CD ; CPU:$D73D PRG:173D 85 CD
lda $1C ; CPU:$D73F PRG:173F A5 1C
sta $CE ; CPU:$D741 PRG:1741 85 CE
bne $D778 ; CPU:$D743 PRG:1743 D0 33
;------------------------------------------------------------------------------
; $D745: direction-offset target
;------------------------------------------------------------------------------
EntityTargetBehaviorD745:
lda $51 ; CPU:$D745 PRG:1745 A5 51
asl ; CPU:$D747 PRG:1747 0A
tay ; CPU:$D748 PRG:1748 A8
lda EntityDirectionTargetOffsets,y ; CPU:$D749 PRG:1749 B9 5C D7
clc ; CPU:$D74C PRG:174C 18
adc $1A ; CPU:$D74D PRG:174D 65 1A
sta $CD ; CPU:$D74F PRG:174F 85 CD
lda EntityDirectionTargetOffsets+1,y ; CPU:$D751 PRG:1751 B9 5D D7
clc ; CPU:$D754 PRG:1754 18
adc $1C ; CPU:$D755 PRG:1755 65 1C
sta $CE ; CPU:$D757 PRG:1757 85 CE
jmp $D778 ; CPU:$D759 PRG:1759 4C 78 D7
;==============================================================================
; $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 ; CPU:$D75C PRG:175C 00 E8
.byte $E8,$00 ; CPU:$D75E PRG:175E E8 00
.byte $00,$18 ; CPU:$D760 PRG:1760 00 18
.byte $18,$00 ; CPU:$D762 PRG:1762 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 ; CPU:$D764 PRG:1764 A5 1A
sec ; CPU:$D766 PRG:1766 38
sbc $1E ; CPU:$D767 PRG:1767 E5 1E
clc ; CPU:$D769 PRG:1769 18
adc $1A ; CPU:$D76A PRG:176A 65 1A
sta $CD ; CPU:$D76C PRG:176C 85 CD
lda $1C ; CPU:$D76E PRG:176E A5 1C
sec ; CPU:$D770 PRG:1770 38
sbc $20 ; CPU:$D771 PRG:1771 E5 20
clc ; CPU:$D773 PRG:1773 18
adc $1C ; CPU:$D774 PRG:1774 65 1C
sta $CE ; CPU:$D776 PRG:1776 85 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 ; CPU:$D778 PRG:1778 B5 B8
sec ; CPU:$D77A PRG:177A 38
sbc #$04 ; CPU:$D77B PRG:177B E9 04
tay ; CPU:$D77D PRG:177D A8
lda $D881,y ; CPU:$D77E PRG:177E B9 81 D8
sta $0A ; CPU:$D781 PRG:1781 85 0A
lda $D882,y ; CPU:$D783 PRG:1783 B9 82 D8
sta $0B ; CPU:$D786 PRG:1786 85 0B
jsr BuildLegalDirectionList ; CPU:$D788 PRG:1788 20 B1 E4
lda $0C ; CPU:$D78B PRG:178B A5 0C
cmp #$FF ; CPU:$D78D PRG:178D C9 FF
bne @D795 ; CPU:$D78F PRG:178F D0 04
lda #$02 ; CPU:$D791 PRG:1791 A9 02
bne @D79D ; CPU:$D793 PRG:1793 D0 08
@D795:
lda $0D ; CPU:$D795 PRG:1795 A5 0D
cmp #$FF ; CPU:$D797 PRG:1797 C9 FF
bne $D7A0 ; CPU:$D799 PRG:1799 D0 05
lda $0C ; CPU:$D79B PRG:179B A5 0C
@D79D:
sta $B9,x ; CPU:$D79D PRG:179D 95 B9
rts ; CPU:$D79F PRG:179F 60
;==============================================================================
; $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 ; CPU:$D7A0 PRG:17A0 A0 00
sty $05 ; CPU:$D7A2 PRG:17A2 84 05
lda $CD ; CPU:$D7A4 PRG:17A4 A5 CD
sec ; CPU:$D7A6 PRG:17A6 38
sbc ($02),y ; CPU:$D7A7 PRG:17A7 F1 02
bcs @D7B9 ; CPU:$D7A9 PRG:17A9 B0 0F
sta $08 ; CPU:$D7AB PRG:17AB 85 08
lda #$00 ; CPU:$D7AD PRG:17AD A9 00
sec ; CPU:$D7AF PRG:17AF 38
sbc $08 ; CPU:$D7B0 PRG:17B0 E5 08
inc $05 ; CPU:$D7B2 PRG:17B2 E6 05
inc $05 ; CPU:$D7B4 PRG:17B4 E6 05
inc $05 ; CPU:$D7B6 PRG:17B6 E6 05
inc $05 ; CPU:$D7B8 PRG:17B8 E6 05
@D7B9:
sta $06 ; CPU:$D7BA PRG:17BA 85 06
lda $CE ; CPU:$D7BC PRG:17BC A5 CE
ldy #$02 ; CPU:$D7BE PRG:17BE A0 02
sec ; CPU:$D7C0 PRG:17C0 38
sbc ($02),y ; CPU:$D7C1 PRG:17C1 F1 02
bcs @D7D2 ; CPU:$D7C3 PRG:17C3 B0 0B
sta $08 ; CPU:$D7C5 PRG:17C5 85 08
lda #$00 ; CPU:$D7C7 PRG:17C7 A9 00
sec ; CPU:$D7C9 PRG:17C9 38
sbc $08 ; CPU:$D7CA PRG:17CA E5 08
inc $05 ; CPU:$D7CC PRG:17CC E6 05
inc $05 ; CPU:$D7CE PRG:17CE E6 05
@D7D2:
sta $07 ; CPU:$D7D0 PRG:17D0 85 07
lda $06 ; CPU:$D7D2 PRG:17D2 A5 06
cmp $07 ; CPU:$D7D4 PRG:17D4 C5 07
bcs @D7DB ; CPU:$D7D6 PRG:17D6 B0 02
inc $05 ; CPU:$D7D8 PRG:17D8 E6 05
@D7DB:
lda $05 ; CPU:$D7DA PRG:17DA A5 05
asl ; CPU:$D7DC PRG:17DC 0A
sta $05 ; CPU:$D7DD PRG:17DD 85 05
lda #$02 ; CPU:$D7DF PRG:17DF A9 02
sta $06 ; CPU:$D7E1 PRG:17E1 85 06
@D7E3:
ldy $05 ; CPU:$D7E3 PRG:17E3 A4 05
lda $D871,y ; CPU:$D7E5 PRG:17E5 B9 71 D8
ldy #$00 ; CPU:$D7E8 PRG:17E8 A0 00
@D7EA:
cmp $000C,y ; CPU:$D7EA PRG:17EA D9 0C 00
beq $D79D ; CPU:$D7ED PRG:17ED F0 AE
iny ; CPU:$D7EF PRG:17EF C8
cpy #$04 ; CPU:$D7F0 PRG:17F0 C0 04
bne @D7EA ; CPU:$D7F2 PRG:17F2 D0 F6
inc $05 ; CPU:$D7F4 PRG:17F4 E6 05
dec $06 ; CPU:$D7F6 PRG:17F6 C6 06
bne @D7E3 ; CPU:$D7F8 PRG:17F8 D0 E9
lda $B9,x ; CPU:$D7FA PRG:17FA B5 B9
sec ; CPU:$D7FC PRG:17FC 38
sbc #$01 ; CPU:$D7FD PRG:17FD E9 01
and #$03 ; CPU:$D7FF PRG:17FF 29 03
ldy #$00 ; CPU:$D801 PRG:1801 A0 00
@D802:
cmp $000C,y ; CPU:$D803 PRG:1803 D9 0C 00
beq $D79D ; CPU:$D806 PRG:1806 F0 95
iny ; CPU:$D808 PRG:1808 C8
cpy #$04 ; CPU:$D809 PRG:1809 C0 04
bne @D802 ; CPU:$D80B PRG:180B D0 F6
lda $B9,x ; CPU:$D80D PRG:180D B5 B9
clc ; CPU:$D80F PRG:180F 18
adc #$01 ; CPU:$D810 PRG:1810 69 01
and #$03 ; CPU:$D812 PRG:1812 29 03
ldy #$00 ; CPU:$D814 PRG:1814 A0 00
@D814:
cmp $000C,y ; CPU:$D816 PRG:1816 D9 0C 00
beq $D79D ; CPU:$D819 PRG:1819 F0 82
iny ; CPU:$D81B PRG:181B C8
cpy #$04 ; CPU:$D81C PRG:181C C0 04
bne @D814 ; CPU:$D81E PRG:181E D0 F6
rts ; CPU:$D820 PRG:1820 60
;==============================================================================
; $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 ; CPU:$D821 PRG:1821 B5 B8
cmp #$06 ; CPU:$D823 PRG:1823 C9 06
beq @D864 ; CPU:$D825 PRG:1825 F0 41
ldy #$02 ; CPU:$D827 PRG:1827 A0 02
lda ($02),y ; CPU:$D829 PRG:1829 B1 02
cmp #$70 ; CPU:$D82B PRG:182B C9 70
bne @D843 ; CPU:$D82D PRG:182D D0 15
ldy #$00 ; CPU:$D82F PRG:182F A0 00
lda ($02),y ; CPU:$D831 PRG:1831 B1 02
cmp #$90 ; CPU:$D833 PRG:1833 C9 90
bcs @D83D ; CPU:$D835 PRG:1835 B0 04
cmp #$30 ; CPU:$D837 PRG:1837 C9 30
bcs @D843 ; CPU:$D839 PRG:1839 B0 09
@D83D:
lda $B3 ; CPU:$D83B PRG:183B A5 B3
sta $C2,x ; CPU:$D83D PRG:183D 95 C2
lda $B4 ; CPU:$D83F PRG:183F A5 B4
sta $C3,x ; CPU:$D841 PRG:1841 95 C3
rts ; CPU:$D843 PRG:1843 60
@D843:
lda $04 ; CPU:$D844 PRG:1844 A5 04
and $88 ; CPU:$D846 PRG:1846 25 88
bne @D85A ; CPU:$D848 PRG:1848 D0 15
txa ; CPU:$D84A PRG:184A 8A
bne @D854 ; CPU:$D84B PRG:184B D0 09
lda $CA ; CPU:$D84D PRG:184D A5 CA
sta $C2 ; CPU:$D84F PRG:184F 85 C2
lda $CB ; CPU:$D851 PRG:1851 A5 CB
sta $C3 ; CPU:$D853 PRG:1853 85 C3
rts ; CPU:$D855 PRG:1855 60
@D854:
lda $AF ; CPU:$D856 PRG:1856 A5 AF
sta $C2,x ; CPU:$D858 PRG:1858 95 C2
lda $B0 ; CPU:$D85A PRG:185A A5 B0
sta $C3,x ; CPU:$D85C PRG:185C 95 C3
rts ; CPU:$D85E PRG:185E 60
@D85A:
lda $B1 ; CPU:$D85F PRG:185F A5 B1
sta $C2,x ; CPU:$D861 PRG:1861 95 C2
lda $B2 ; CPU:$D863 PRG:1863 A5 B2
sta $C3,x ; CPU:$D865 PRG:1865 95 C3
rts ; CPU:$D867 PRG:1867 60
@D864:
lda #$00 ; CPU:$D868 PRG:1868 A9 00
sta $C2,x ; CPU:$D86A PRG:186A 95 C2
lda #$02 ; CPU:$D86C PRG:186C A9 02
sta $C3,x ; CPU:$D86E PRG:186E 95 C3
rts ; CPU:$D870 PRG:1870 60
;==============================================================================
; $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 ; CPU:$D871 PRG:1871 03 02
.byte $02,$03 ; CPU:$D873 PRG:1873 02 03
.byte $03,$00 ; CPU:$D875 PRG:1875 03 00
.byte $00,$03 ; CPU:$D877 PRG:1877 00 03
.byte $01,$02 ; CPU:$D879 PRG:1879 01 02
.byte $02,$01 ; CPU:$D87B PRG:187B 02 01
.byte $01,$00 ; CPU:$D87D PRG:187D 01 00
.byte $00,$01 ; CPU:$D87F PRG:187F 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 ; CPU:$D881 PRG:1881 00 00
.word $082C ; CPU:$D883 PRG:1883 2C 08
;==============================================================================
; $D885-$D8D4: Entity Primary State $02 Handler
;==============================================================================
UpdateEntityState02:
lda #$00 ; CPU:$D885 PRG:1885 A9 00
tay ; CPU:$D887 PRG:1887 A8
sta $05 ; CPU:$D888 PRG:1888 85 05
lda #$80 ; CPU:$D88A PRG:188A A9 80
sta $06 ; CPU:$D88C PRG:188C 85 06
lda ($02),y ; CPU:$D88E PRG:188E B1 02
cmp #$60 ; CPU:$D890 PRG:1890 C9 60
beq UpdateEntityState02SecondaryPhase ; CPU:$D892 PRG:1892 F0 1E
bcc @D89C ; CPU:$D894 PRG:1894 90 06
dec $05 ; CPU:$D896 PRG:1896 C6 05
lda #$01 ; CPU:$D898 PRG:1898 A9 01
bne @D89E ; CPU:$D89A PRG:189A D0 02
@D89C:
lda #$03 ; CPU:$D89C PRG:189C A9 03
@D89E:
sta $B9,x ; CPU:$D89E PRG:189E 95 B9
ldy #$01 ; CPU:$D8A0 PRG:18A0 A0 01
lda ($02),y ; CPU:$D8A2 PRG:18A2 B1 02
clc ; CPU:$D8A4 PRG:18A4 18
adc $06 ; CPU:$D8A5 PRG:18A5 65 06
sta ($02),y ; CPU:$D8A7 PRG:18A7 91 02
ldy #$00 ; CPU:$D8A9 PRG:18A9 A0 00
lda ($02),y ; CPU:$D8AB PRG:18AB B1 02
adc $05 ; CPU:$D8AD PRG:18AD 65 05
sta ($02),y ; CPU:$D8AF PRG:18AF 91 02
rts ; CPU:$D8B1 PRG:18B1 60
;==============================================================================
; $D8B2-$D8D4: Entity State $02 Secondary Movement Phase
;==============================================================================
UpdateEntityState02SecondaryPhase:
lda #$00 ; CPU:$D8B2 PRG:18B2 A9 00
sta $B9,x ; CPU:$D8B4 PRG:18B4 95 B9
ldy #$03 ; CPU:$D8B6 PRG:18B6 A0 03
lda ($02),y ; CPU:$D8B8 PRG:18B8 B1 02
sec ; CPU:$D8BA PRG:18BA 38
sbc #$80 ; CPU:$D8BB PRG:18BB E9 80
sta ($02),y ; CPU:$D8BD PRG:18BD 91 02
ldy #$02 ; CPU:$D8BF PRG:18BF A0 02
lda ($02),y ; CPU:$D8C1 PRG:18C1 B1 02
sbc #$00 ; CPU:$D8C3 PRG:18C3 E9 00
sta ($02),y ; CPU:$D8C5 PRG:18C5 91 02
cmp #$58 ; CPU:$D8C7 PRG:18C7 C9 58
beq @D8CC ; CPU:$D8C9 PRG:18C9 F0 01
rts ; CPU:$D8CB PRG:18CB 60
@D8CC:
lda #$01 ; CPU:$D8CC PRG:18CC A9 01
sta $B9,x ; CPU:$D8CE PRG:18CE 95 B9
lda #$04 ; CPU:$D8D0 PRG:18D0 A9 04
sta $B8,x ; CPU:$D8D2 PRG:18D2 95 B8
rts ; CPU:$D8D4 PRG:18D4 60
;==============================================================================
; $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 ; CPU:$D8D5 PRG:18D5 A9 00
sta $05 ; CPU:$D8D7 PRG:18D7 85 05
lda #$80 ; CPU:$D8D9 PRG:18D9 A9 80
sta $06 ; CPU:$D8DB PRG:18DB 85 06
ldy $B9,x ; CPU:$D8DD PRG:18DD B4 B9
lda EntityState00SubstateTable,y ; CPU:$D8DF PRG:18DF B9 EC D8
sta $10 ; CPU:$D8E2 PRG:18E2 85 10
lda EntityState00SubstateTable+1,y ; CPU:$D8E4 PRG:18E4 B9 ED D8
sta $11 ; CPU:$D8E7 PRG:18E7 85 11
jmp ($0010) ; CPU:$D8E9 PRG:18E9 6C 10 00 F0 D8
;==============================================================================
; $D8EC-$D8EF: Entity State $00 Secondary Table
;==============================================================================
EntityState00SubstateTable:
.word UpdateEntityState00MovingNegative ; CPU:$D8EC PRG:18EC F0 D8
.word UpdateEntityState00MovingPositive ; CPU:$D8EE PRG:18EE F2 D8
;------------------------------------------------------------------------------
; $D8F0: secondary state $00
;------------------------------------------------------------------------------
UpdateEntityState00MovingNegative:
dec $05 ; CPU:$D8F0 PRG:18F0 C6 05
;------------------------------------------------------------------------------
; $D8F2: secondary state $02
;------------------------------------------------------------------------------
UpdateEntityState00MovingPositive:
ldy #$03 ; CPU:$D8F2 PRG:18F2 A0 03
lda ($02),y ; CPU:$D8F4 PRG:18F4 B1 02
clc ; CPU:$D8F6 PRG:18F6 18
adc $06 ; CPU:$D8F7 PRG:18F7 65 06
sta ($02),y ; CPU:$D8F9 PRG:18F9 91 02
ldy #$02 ; CPU:$D8FB PRG:18FB A0 02
lda ($02),y ; CPU:$D8FD PRG:18FD B1 02
adc $05 ; CPU:$D8FF PRG:18FF 65 05
sta ($02),y ; CPU:$D901 PRG:1901 91 02
cmp #$69 ; CPU:$D903 PRG:1903 C9 69
bcs @D90B ; CPU:$D905 PRG:1905 B0 04
lda #$02 ; CPU:$D907 PRG:1907 A9 02
bne @D911 ; CPU:$D909 PRG:1909 D0 06
@D90B:
cmp #$70 ; CPU:$D90B PRG:190B C9 70
bcc @D913 ; CPU:$D90D PRG:190D 90 04
lda #$00 ; CPU:$D90F PRG:190F A9 00
@D911:
sta $B9,x ; CPU:$D911 PRG:1911 95 B9
@D913:
rts ; CPU:$D913 PRG:1913 60
;==============================================================================
; $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 ; CPU:$D914 PRG:1914 A2 00
lda #$2F ; CPU:$D916 PRG:1916 A9 2F
sta $00 ; CPU:$D918 PRG:1918 85 00
lda #$02 ; CPU:$D91A PRG:191A A9 02
sta $01 ; CPU:$D91C PRG:191C 85 01
lda #$1E ; CPU:$D91E PRG:191E A9 1E
sta $02 ; CPU:$D920 PRG:1920 85 02
lda #$00 ; CPU:$D922 PRG:1922 A9 00
sta $03 ; CPU:$D924 PRG:1924 85 03
lda #$01 ; CPU:$D926 PRG:1926 A9 01
sta $04 ; CPU:$D928 PRG:1928 85 04
@D92A:
jsr $D944 ; CPU:$D92A PRG:192A 20 44 D9
lda $00 ; CPU:$D92D PRG:192D A5 00
clc ; CPU:$D92F PRG:192F 18
adc #$04 ; CPU:$D930 PRG:1930 69 04
sta $00 ; CPU:$D932 PRG:1932 85 00
lda $02 ; CPU:$D934 PRG:1934 A5 02
clc ; CPU:$D936 PRG:1936 18
adc #$04 ; CPU:$D937 PRG:1937 69 04
sta $02 ; CPU:$D939 PRG:1939 85 02
asl $04 ; CPU:$D93B PRG:193B 06
inx ; CPU:$D93C PRG:193C 04
inx ; CPU:$D93D PRG:193D E8
cpx #$08 ; CPU:$D93E PRG:193E E8 E0
bne @D92A ; CPU:$D940 PRG:1940 08 D0
rts ; CPU:$D942 PRG:1942 E7
;==============================================================================
; $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 ; CPU:$D944 PRG:1944 B4 B8
lda EntityMovementStateHandlerTable,y ; CPU:$D946 PRG:1946 B9 53 D9
sta $10 ; CPU:$D949 PRG:1949 85 10
lda EntityMovementStateHandlerTable+1,y ; CPU:$D94B PRG:194B B9 54 D9
sta $11 ; CPU:$D94E PRG:194E 85 11
jmp ($0010) ; CPU:$D950 PRG:1950 6C 10 00 5D D9
;==============================================================================
; $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 ; CPU:$D953 PRG:1953 5D D9
.word EntityMovementStateNoOp ; state $02 ; CPU:$D955 PRG:1955 5D D9
.word EntityMovementStateNoOp ; state $04 ; CPU:$D957 PRG:1957 5D D9
.word DispatchEntitySecondaryState ; state $06 ; CPU:$D959 PRG:1959 A1 D5
.word EntityMovementStateNoOp ; state $08 ; CPU:$D95B PRG:195B 5D D9
;==============================================================================
; $D95D: No-Op Entity Transition Handler
;
; Local:
; Returns immediately.
;
; Global:
; Used by EntityMovementStateHandlerTable for primary entity states
; $00, $02, $04 and $08.
;==============================================================================
EntityMovementStateNoOp:
rts ; CPU:$D95D PRG:195D 60
;==============================================================================
; $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 ; CPU:$D95E PRG:195E A2 00
stx $00 ; CPU:$D960 PRG:1960 86 00
@D962:
lda $B8,x ; CPU:$D962 PRG:1962 B5 B8
cmp #$06 ; CPU:$D964 PRG:1964 C9 06
bne @D96C ; CPU:$D966 PRG:1966 D0 04
sta $0608 ; CPU:$D968 PRG:1968 8D 08 06
rts ; CPU:$D96B PRG:196B 60
@D96C:
inx ; CPU:$D96C PRG:196C E8
inx ; CPU:$D96D PRG:196D E8
cpx #$08 ; CPU:$D96E PRG:196E E0 08
bne @D962 ; CPU:$D970 PRG:1970 D0 F0
lda $88 ; CPU:$D972 PRG:1972 A5 88
beq UpdatePlayerVerticalRegionFlag ; CPU:$D974 PRG:1974 F0 04
sta $0609 ; CPU:$D976 PRG:1976 8D 09 06
rts ; CPU:$D979 PRG:1979 60
;==============================================================================
; $D97A-$D98D: Update Gameplay Range Flag
;==============================================================================
UpdatePlayerVerticalRegionFlag:
ldy #$00 ; CPU:$D97A PRG:197A A0 00
lda $6A ; CPU:$D97C PRG:197C A5 6A
cmp #$88 ; CPU:$D97E PRG:197E C9 88
bcs @D988 ; CPU:$D980 PRG:1980 B0 06
iny ; CPU:$D982 PRG:1982 C8
cmp #$42 ; CPU:$D983 PRG:1983 C9 42
bcs @D988 ; CPU:$D985 PRG:1985 B0 01
iny ; CPU:$D987 PRG:1987 C8
@D988:
lda #$01 ; CPU:$D988 PRG:1988 A9 01
sta $060A,y ; CPU:$D98A PRG:198A 99 0A 06
rts ; CPU:$D98D PRG:198D 60
;==============================================================================
; $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 ; CPU:$D98E PRG:198E A5 51
asl ; CPU:$D990 PRG:1990 0A
clc ; CPU:$D991 PRG:1991 18
adc #$02 ; CPU:$D992 PRG:1992 69 02
sta $00 ; CPU:$D994 PRG:1994 85 00
lda $1A ; CPU:$D996 PRG:1996 A5 1A
ora $1C ; CPU:$D998 PRG:1998 05 1C
and #$07 ; CPU:$D99A PRG:199A 29 07
bne @D9AE ; CPU:$D99C PRG:199C D0 10
ldy $51 ; CPU:$D99E PRG:199E A4 51
lda $022B,y ; CPU:$D9A0 PRG:19A0 B9 2B 02
and #$F0 ; CPU:$D9A3 PRG:19A3 29 F0
beq @D9AE ; CPU:$D9A5 PRG:19A5 F0 07
lda $B7 ; CPU:$D9A7 PRG:19A7 A5 B7
and #$03 ; CPU:$D9A9 PRG:19A9 29 03
jmp @D9B2 ; CPU:$D9AB PRG:19AB 4C B2 D9
@D9AE:
inc $B7 ; CPU:$D9AE PRG:19AE E6 B7
lda $B7 ; CPU:$D9B0 PRG:19B0 A5 B7
@D9B2:
and #$07 ; CPU:$D9B2 PRG:19B2 29 07
cmp #$06 ; CPU:$D9B4 PRG:19B4 C9 06
bcc @D9BC ; CPU:$D9B6 PRG:19B6 90 04
lda #$01 ; CPU:$D9B8 PRG:19B8 A9 01
bne @D9C3 ; CPU:$D9BA PRG:19BA D0 07
@D9BC:
tay ; CPU:$D9BC PRG:19BC A8
lda PlayerDirectionAnimationOffsets,y ; CPU:$D9BD PRG:19BD B9 C6 D9
clc ; CPU:$D9C0 PRG:19C0 18
adc $00 ; CPU:$D9C1 PRG:19C1 65 00
@D9C3:
sta $32 ; CPU:$D9C3 PRG:19C3 85 32
rts ; CPU:$D9C5 PRG:19C5 60
;==============================================================================
; $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 ; CPU:$D9C6 PRG:19C6 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 ; CPU:$D9CC PRG:19CC A9 00
tax ; CPU:$D9CE PRG:19CE AA
sta $00 ; CPU:$D9CF PRG:19CF 85 00
lda $4B ; CPU:$D9D1 PRG:19D1 A5 4B
and #$08 ; CPU:$D9D3 PRG:19D3 29 08
beq @D9DC ; CPU:$D9D5 PRG:19D5 F0 04
lda #$01 ; CPU:$D9D7 PRG:19D7 A9 01
sta $00 ; CPU:$D9D9 PRG:19D9 85 00
@D9DC:
lda #$01 ; CPU:$D9DB PRG:19DB A9 01
sta $01 ; CPU:$D9DD PRG:19DD 85 01
@D9E0:
jsr $D9EB ; CPU:$D9DF PRG:19DF 20 EB D9
asl $01 ; CPU:$D9E2 PRG:19E2 06
inx ; CPU:$D9E3 PRG:19E3 01
inx ; CPU:$D9E4 PRG:19E4 E8
cpx #$08 ; CPU:$D9E5 PRG:19E5 E8 E0
bne @D9E0 ; CPU:$D9E7 PRG:19E7 08 D0
rts ; CPU:$D9E9 PRG:19E9 F5
;==============================================================================
; $D9EB-$D9F9: Per-Entity Display/State Dispatcher
;==============================================================================
DispatchEntitySpriteState:
ldy $B8,x ; CPU:$D9EB PRG:19EB B4 B8
lda EntitySpriteStateHandlerTable,y ; CPU:$D9ED PRG:19ED B9 FA D9
sta $10 ; CPU:$D9F0 PRG:19F0 85 10
lda EntitySpriteStateHandlerTable+1,y ; CPU:$D9F2 PRG:19F2 B9 FB D9
sta $11 ; CPU:$D9F5 PRG:19F5 85 11
jmp ($0010) ; CPU:$D9F7 PRG:19F7 6C 10 00 21 DA
;==============================================================================
; $D9FA-$DA03: Entity Display/State Table
;==============================================================================
EntitySpriteStateHandlerTable:
.word UpdateNormalEntitySprite ; state $00 ; CPU:$D9FA PRG:19FA 21 DA
.word UpdateNormalEntitySprite ; state $02 ; CPU:$D9FC PRG:19FC 21 DA
.word UpdateNormalEntitySprite ; state $04 ; CPU:$D9FE PRG:19FE 21 DA
.word UpdateSpecialEntitySprite ; state $06 ; CPU:$DA00 PRG:1A00 2D DA
.word $D9EA ; state $08 -> shared RTS ; CPU:$DA02 PRG:1A02 EA D9
;==============================================================================
; $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 ; CPU:$DA04 PRG:1A04 B5 B9
sta $03 ; CPU:$DA06 PRG:1A06 85 03
lda #$0A ; CPU:$DA08 PRG:1A08 A9 0A
;------------------------------------------------------------------------------
; $DA0A
;------------------------------------------------------------------------------
CalculateEntitySpriteValueLoop:
dec $03 ; CPU:$DA0A PRG:1A0A C6 03
bmi AddEntitySpriteBase ; CPU:$DA0C PRG:1A0C 30 05
clc ; CPU:$DA0E PRG:1A0E 18
adc #$02 ; CPU:$DA0F PRG:1A0F 69 02
bne CalculateEntitySpriteValueLoop ; CPU:$DA11 PRG:1A11 D0 F7
;------------------------------------------------------------------------------
; $DA13
;------------------------------------------------------------------------------
AddEntitySpriteBase:
clc ; CPU:$DA13 PRG:1A13 18
adc $00 ; CPU:$DA14 PRG:1A14 65 00
sta $02 ; CPU:$DA16 PRG:1A16 85 02
;------------------------------------------------------------------------------
; $DA18
;------------------------------------------------------------------------------
StoreEntitySpriteValue:
txa ; CPU:$DA18 PRG:1A18 8A
lsr ; CPU:$DA19 PRG:1A19 4A
tay ; CPU:$DA1A PRG:1A1A A8
lda $02 ; CPU:$DA1B PRG:1A1B A5 02
sta $0033,y ; CPU:$DA1D PRG:1A1D 99 33 00
rts ; CPU:$DA20 PRG:1A20 60
;------------------------------------------------------------------------------
; $DA21
; Primary entity states $00/$02/$04.
;------------------------------------------------------------------------------
UpdateNormalEntitySprite:
lda $01 ; CPU:$DA21 PRG:1A21 A5 01
and $88 ; CPU:$DA23 PRG:1A23 25 88
beq CalculateEntitySpriteValue ; CPU:$DA25 PRG:1A25 F0 DD
lda #$1E ; CPU:$DA27 PRG:1A27 A9 1E
sta $02 ; CPU:$DA29 PRG:1A29 85 02
bne AddEntitySpriteBase ; CPU:$DA2B PRG:1A2B D0 E6
;------------------------------------------------------------------------------
; $DA2D
; Primary entity state $06.
;------------------------------------------------------------------------------
UpdateSpecialEntitySprite:
lda $B9,x ; CPU:$DA2D PRG:1A2D B5 B9
sta $03 ; CPU:$DA2F PRG:1A2F 85 03
lda #$20 ; CPU:$DA31 PRG:1A31 A9 20
;------------------------------------------------------------------------------
; $DA33
;------------------------------------------------------------------------------
UpdateSpecialEntitySpriteLoop:
dec $03 ; CPU:$DA33 PRG:1A33 C6 03
bmi UpdateSpecialEntitySpriteDone ; CPU:$DA35 PRG:1A35 30 05
clc ; CPU:$DA37 PRG:1A37 18
adc #$01 ; CPU:$DA38 PRG:1A38 69 01
bne UpdateSpecialEntitySpriteLoop ; CPU:$DA3A PRG:1A3A D0 F7
;------------------------------------------------------------------------------
; $DA3C
;------------------------------------------------------------------------------
UpdateSpecialEntitySpriteDone:
sta $02 ; CPU:$DA3C PRG:1A3C 85 02
bmi StoreEntitySpriteValue ; CPU:$DA3E PRG:1A3E 30 D8
;==============================================================================
; $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 ; CPU:$DA40 PRG:1A40 A2 23
@CopyWorkingState:
lda $1A,x ; CPU:$DA42 PRG:1A42 B5 1A
sta $0274,x ; CPU:$DA44 PRG:1A44 9D 74 02
dex ; CPU:$DA47 PRG:1A47 CA
bpl @CopyWorkingState ; CPU:$DA48 PRG:1A48 10 F8
lda #$84 ; CPU:$DA4A PRG:1A4A A9 84
sta $00 ; CPU:$DA4C PRG:1A4C 85 00
lda #$02 ; CPU:$DA4E PRG:1A4E A9 02
sta $01 ; CPU:$DA50 PRG:1A50 85 01
lda #$08 ; CPU:$DA52 PRG:1A52 A9 08
sta $03 ; CPU:$DA54 PRG:1A54 85 03
lda #$03 ; CPU:$DA56 PRG:1A56 A9 03
sta $02 ; CPU:$DA58 PRG:1A58 85 02
@CheckNextEntity:
lda $03 ; CPU:$DA5A PRG:1A5A A5 03
and $88 ; CPU:$DA5C PRG:1A5C 25 88
bne @AdvanceEntity ; CPU:$DA5E PRG:1A5E D0 7B
ldy #$00 ; CPU:$DA60 PRG:1A60 A0 00
lda $0274 ; CPU:$DA62 PRG:1A62 AD 74 02
cmp ($00),y ; CPU:$DA65 PRG:1A65 D1 00
bcs @FirstAxisReverse ; CPU:$DA67 PRG:1A67 B0 08
lda ($00),y ; CPU:$DA69 PRG:1A69 B1 00
sec ; CPU:$DA6B PRG:1A6B 38
sbc $0274 ; CPU:$DA6C PRG:1A6C ED 74 02
bcs @CheckFirstAxis ; CPU:$DA6F PRG:1A6F B0 02
@FirstAxisReverse:
sbc ($00),y ; CPU:$DA71 PRG:1A71 F1 00
@CheckFirstAxis:
cmp #$19 ; CPU:$DA73 PRG:1A73 C9 19
bcs @AdvanceEntity ; CPU:$DA75 PRG:1A75 B0 64
sta $04 ; CPU:$DA77 PRG:1A77 85 04
ldy #$02 ; CPU:$DA79 PRG:1A79 A0 02
lda $0276 ; CPU:$DA7B PRG:1A7B AD 76 02
cmp ($00),y ; CPU:$DA7E PRG:1A7E D1 00
bcs @SecondAxisReverse ; CPU:$DA80 PRG:1A80 B0 08
lda ($00),y ; CPU:$DA82 PRG:1A82 B1 00
sec ; CPU:$DA84 PRG:1A84 38
sbc $0276 ; CPU:$DA85 PRG:1A85 ED 76 02
bcs @CheckSecondAxis ; CPU:$DA88 PRG:1A88 B0 02
@SecondAxisReverse:
sbc ($00),y ; CPU:$DA8A PRG:1A8A F1 00
@CheckSecondAxis:
cmp #$19 ; CPU:$DA8C PRG:1A8C C9 19
bcs @AdvanceEntity ; CPU:$DA8E PRG:1A8E B0 4B
adc $04 ; CPU:$DA90 PRG:1A90 65 04
cmp #$10 ; CPU:$DA92 PRG:1A92 C9 10
bcs @AdvanceEntity ; CPU:$DA94 PRG:1A94 B0 45
; Save the primary slot coordinates/state.
lda $0274 ; CPU:$DA96 PRG:1A96 AD 74 02
sta $03 ; CPU:$DA99 PRG:1A99 85 03
lda $0276 ; CPU:$DA9B PRG:1A9B AD 76 02
sta $04 ; CPU:$DA9E PRG:1A9E 85 04
lda $028C ; CPU:$DAA0 PRG:1AA0 AD 8C 02
sta $05 ; CPU:$DAA3 PRG:1AA3 85 05
lda $0292 ; CPU:$DAA5 PRG:1AA5 AD 92 02
sta $06 ; CPU:$DAA8 PRG:1AA8 85 06
; Copy selected entity coordinates into the primary slot.
ldy #$00 ; CPU:$DAAA PRG:1AAA A0 00
lda ($00),y ; CPU:$DAAC PRG:1AAC B1 00
sta $0274 ; CPU:$DAAE PRG:1AAE 8D 74 02
lda $03 ; CPU:$DAB1 PRG:1AB1 A5 03
sta ($00),y ; CPU:$DAB3 PRG:1AB3 91 00
ldy #$02 ; CPU:$DAB5 PRG:1AB5 A0 02
lda ($00),y ; CPU:$DAB7 PRG:1AB7 B1 00
sta $0276 ; CPU:$DAB9 PRG:1AB9 8D 76 02
lda $04 ; CPU:$DABC PRG:1ABC A5 04
sta ($00),y ; CPU:$DABE PRG:1ABE 91 00
; Exchange the parallel status values.
ldx $02 ; CPU:$DAC0 PRG:1AC0 A6 02
lda $028D,x ; CPU:$DAC2 PRG:1AC2 BD 8D 02
sta $028C ; CPU:$DAC5 PRG:1AC5 8D 8C 02
lda $05 ; CPU:$DAC8 PRG:1AC8 A5 05
sta $028D,x ; CPU:$DACA PRG:1ACA 9D 8D 02
lda $0293,x ; CPU:$DACD PRG:1ACD BD 93 02
sta $0292 ; CPU:$DAD0 PRG:1AD0 8D 92 02
lda $06 ; CPU:$DAD3 PRG:1AD3 A5 06
sta $0293,x ; CPU:$DAD5 PRG:1AD5 9D 93 02
jmp $DAEB ; CPU:$DAD8 PRG:1AD8 4C EB DA
@AdvanceEntity:
lda $00 ; CPU:$DADB PRG:1ADB A5 00
sec ; CPU:$DADD PRG:1ADD 38
sbc #$04 ; CPU:$DADE PRG:1ADE E9 04
sta $00 ; CPU:$DAE0 PRG:1AE0 85 00
lsr $03 ; CPU:$DAE2 PRG:1AE2 46
dec $02 ; CPU:$DAE3 PRG:1AE3 03 C6
bmi @NoCollision ; CPU:$DAE5 PRG:1AE5 02 30
jmp @CheckNextEntity ; CPU:$DAE7 PRG:1AE7 03 4C 5A
@NoCollision:
jsr $E1DA ; CPU:$DAEA PRG:1AEA DA 20 DA
jmp $DAF1 ; CPU:$DAED PRG:1AED E1 4C F1
;==============================================================================
; $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 ; CPU:$DAF1 PRG:1AF1 A9 74
sta $00 ; CPU:$DAF3 PRG:1AF3 85 00
lda #$02 ; CPU:$DAF5 PRG:1AF5 A9 02
sta $01 ; CPU:$DAF7 PRG:1AF7 85 01
lda #$00 ; CPU:$DAF9 PRG:1AF9 A9 00
sta $02 ; CPU:$DAFB PRG:1AFB 85 02
lda #$07 ; CPU:$DAFD PRG:1AFD A9 07
sta $03 ; CPU:$DAFF PRG:1AFF 85 03
lda #$00 ; CPU:$DB01 PRG:1B01 A9 00
sta $04 ; CPU:$DB03 PRG:1B03 85 04
;------------------------------------------------------------------------------
; $DB05
; Start/restart one source group.
;------------------------------------------------------------------------------
BuildSpriteBufferNextGroup:
lda #$00 ; CPU:$DB05 PRG:1B05 A9 00
sta $05 ; CPU:$DB07 PRG:1B07 85 05
tax ; CPU:$DB09 PRG:1B09 AA
;------------------------------------------------------------------------------
; $DB0A
; Build one four-byte render record.
;------------------------------------------------------------------------------
BuildSpriteBufferNextSprite:
ldy #$02 ; CPU:$DB0A PRG:1B0A A0 02
lda ($00),y ; CPU:$DB0C PRG:1B0C B1 00
bne AdjustSpriteY ; CPU:$DB0E PRG:1B0E D0 04
lda #$FF ; CPU:$DB10 PRG:1B10 A9 FF
bne StoreSpriteY ; CPU:$DB12 PRG:1B12 D0 04
;------------------------------------------------------------------------------
; $DB14
;------------------------------------------------------------------------------
AdjustSpriteY:
clc ; CPU:$DB14 PRG:1B14 18
adc EntitySpriteCoordinateOffsets,x ; CPU:$DB15 PRG:1B15 7D 56 DE
;------------------------------------------------------------------------------
; $DB18
;------------------------------------------------------------------------------
StoreSpriteY:
ldy #$00 ; CPU:$DB18 PRG:1B18 A0 00
sta ($02),y ; CPU:$DB1A PRG:1B1A 91 02
ldy $04 ; CPU:$DB1C PRG:1B1C A4 04
lda $028C,y ; CPU:$DB1E PRG:1B1E B9 8C 02
asl ; CPU:$DB21 PRG:1B21 0A
rol ; CPU:$DB22 PRG:1B22 2A
rol ; CPU:$DB23 PRG:1B23 2A
and #$03 ; CPU:$DB24 PRG:1B24 29 03
beq BuildSpriteClass0 ; CPU:$DB26 PRG:1B26 F0 29
cmp #$02 ; CPU:$DB28 PRG:1B28 C9 02
beq BuildSpriteClass2 ; CPU:$DB2A PRG:1B2A F0 6B
bcc BuildSpriteClass1 ; CPU:$DB2C PRG:1B2C 90 46
;------------------------------------------------------------------------------
; $DB2E
; Status-class path.
;------------------------------------------------------------------------------
lda $028C,y ; CPU:$DB2E PRG:1B2E B9 8C 02
asl ; CPU:$DB31 PRG:1B31 0A
asl ; CPU:$DB32 PRG:1B32 0A
clc ; CPU:$DB33 PRG:1B33 18
adc $05 ; CPU:$DB34 PRG:1B34 65 05
tay ; CPU:$DB36 PRG:1B36 A8
sta $06 ; CPU:$DB37 PRG:1B37 85 06
lda $DD22,y ; CPU:$DB39 PRG:1B39 B9 22 DD
ldy #$01 ; CPU:$DB3C PRG:1B3C A0 01
sta ($02),y ; CPU:$DB3E PRG:1B3E 91 02
ldy $04 ; CPU:$DB40 PRG:1B40 A4 04
lda $0292,y ; CPU:$DB42 PRG:1B42 B9 92 02
ldy $06 ; CPU:$DB45 PRG:1B45 A4 06
ora EntitySpriteCoordinateOffsets,y ; CPU:$DB47 PRG:1B47 19 56 DE
ldy #$02 ; CPU:$DB4A PRG:1B4A A0 02
sta ($02),y ; CPU:$DB4C PRG:1B4C 91 02
jmp BuildSpriteX ; CPU:$DB4E PRG:1B4E 4C B7 DB
;------------------------------------------------------------------------------
; $DB51
;------------------------------------------------------------------------------
BuildSpriteClass0:
lda $028C,y ; CPU:$DB51 PRG:1B51 B9 8C 02
asl ; CPU:$DB54 PRG:1B54 0A
asl ; CPU:$DB55 PRG:1B55 0A
clc ; CPU:$DB56 PRG:1B56 18
adc $05 ; CPU:$DB57 PRG:1B57 65 05
tay ; CPU:$DB59 PRG:1B59 A8
sta $06 ; CPU:$DB5A PRG:1B5A 85 06
lda $DBEE,y ; CPU:$DB5C PRG:1B5C B9 EE DB
ldy #$01 ; CPU:$DB5F PRG:1B5F A0 01
sta ($02),y ; CPU:$DB61 PRG:1B61 91 02
ldy $04 ; CPU:$DB63 PRG:1B63 A4 04
lda $0292,y ; CPU:$DB65 PRG:1B65 B9 92 02
ldy $06 ; CPU:$DB68 PRG:1B68 A4 06
ora $DD22,y ; CPU:$DB6A PRG:1B6A 19 22 DD
ldy #$02 ; CPU:$DB6D PRG:1B6D A0 02
sta ($02),y ; CPU:$DB6F PRG:1B6F 91 02
jmp BuildSpriteX ; CPU:$DB71 PRG:1B71 4C B7 DB
;------------------------------------------------------------------------------
; $DB74
;------------------------------------------------------------------------------
BuildSpriteClass1:
lda $028C,y ; CPU:$DB74 PRG:1B74 B9 8C 02
asl ; CPU:$DB77 PRG:1B77 0A
asl ; CPU:$DB78 PRG:1B78 0A
clc ; CPU:$DB79 PRG:1B79 18
adc $05 ; CPU:$DB7A PRG:1B7A 65 05
tay ; CPU:$DB7C PRG:1B7C A8
sta $06 ; CPU:$DB7D PRG:1B7D 85 06
lda $DCEE,y ; CPU:$DB7F PRG:1B7F B9 EE DC
ldy #$01 ; CPU:$DB82 PRG:1B82 A0 01
sta ($02),y ; CPU:$DB84 PRG:1B84 91 02
ldy $04 ; CPU:$DB86 PRG:1B86 A4 04
lda $0292,y ; CPU:$DB88 PRG:1B88 B9 92 02
ldy $06 ; CPU:$DB8B PRG:1B8B A4 06
ora $DE22,y ; CPU:$DB8D PRG:1B8D 19 22 DE
ldy #$02 ; CPU:$DB90 PRG:1B90 A0 02
sta ($02),y ; CPU:$DB92 PRG:1B92 91 02
jmp BuildSpriteX ; CPU:$DB94 PRG:1B94 4C B7 DB
;------------------------------------------------------------------------------
; $DB97
;------------------------------------------------------------------------------
BuildSpriteClass2:
lda $028C,y ; CPU:$DB97 PRG:1B97 B9 8C 02
asl ; CPU:$DB9A PRG:1B9A 0A
asl ; CPU:$DB9B PRG:1B9B 0A
clc ; CPU:$DB9C PRG:1B9C 18
adc $05 ; CPU:$DB9D PRG:1B9D 65 05
tay ; CPU:$DB9F PRG:1B9F A8
sta $06 ; CPU:$DBA0 PRG:1BA0 85 06
lda $DD22,y ; CPU:$DBA2 PRG:1BA2 B9 22 DD
ldy #$01 ; CPU:$DBA5 PRG:1BA5 A0 01
sta ($02),y ; CPU:$DBA7 PRG:1BA7 91 02
ldy $04 ; CPU:$DBA9 PRG:1BA9 A4 04
lda $0292,y ; CPU:$DBAB PRG:1BAB B9 92 02
ldy $06 ; CPU:$DBAE PRG:1BAE A4 06
ora EntitySpriteCoordinateOffsets,y ; CPU:$DBB0 PRG:1BB0 19 56 DE
ldy #$02 ; CPU:$DBB3 PRG:1BB3 A0 02
sta ($02),y ; CPU:$DBB5 PRG:1BB5 91 02
;------------------------------------------------------------------------------
; $DBB7
; Construct byte 3 of the render record.
;------------------------------------------------------------------------------
BuildSpriteX:
ldy #$00 ; CPU:$DBB7 PRG:1BB7 A0 00
lda ($00),y ; CPU:$DBB9 PRG:1BB9 B1 00
bne AdjustSpriteX ; CPU:$DBBB PRG:1BBB D0 04
lda #$FF ; CPU:$DBBD PRG:1BBD A9 FF
bne StoreSpriteX ; CPU:$DBBF PRG:1BBF D0 04
;------------------------------------------------------------------------------
; $DBC0
;------------------------------------------------------------------------------
AdjustSpriteX:
clc ; CPU:$DBC1 PRG:1BC1 18
adc EntitySpriteCoordinateOffsets+1,x ; CPU:$DBC2 PRG:1BC2 7D 57 DE
;------------------------------------------------------------------------------
; $DBC4
;------------------------------------------------------------------------------
StoreSpriteX:
ldy #$03 ; CPU:$DBC5 PRG:1BC5 A0 03
sta ($02),y ; CPU:$DBC7 PRG:1BC7 91 02
; Advance destination by one 4-byte record.
lda $02 ; CPU:$DBC9 PRG:1BC9 A5 02
clc ; CPU:$DBCB PRG:1BCB 18
adc #$04 ; CPU:$DBCC PRG:1BCC 69 04
sta $02 ; CPU:$DBCE PRG:1BCE 85 02
inc $05 ; CPU:$DBD0 PRG:1BD0 E6 05
inx ; CPU:$DBD2 PRG:1BD2 E8
inx ; CPU:$DBD3 PRG:1BD3 E8
cpx #$08 ; CPU:$DBD4 PRG:1BD4 E0 08
beq BuildSpriteBufferNextSource ; CPU:$DBD6 PRG:1BD6 F0 03
jmp BuildSpriteBufferNextSprite ; CPU:$DBD8 PRG:1BD8 4C 0A DB
BuildSpriteBufferNextSource:
lda $00 ; CPU:$DBDB PRG:1BDB A5 00
clc ; CPU:$DBDD PRG:1BDD 18
adc #$04 ; CPU:$DBDE PRG:1BDE 69 04
sta $00 ; CPU:$DBE0 PRG:1BE0 85 00
inc $04 ; CPU:$DBE2 PRG:1BE2 E6 04
lda $04 ; CPU:$DBE4 PRG:1BE4 A5 04
cmp #$06 ; CPU:$DBE6 PRG:1BE6 C9 06
beq BuildSpriteBufferDone ; CPU:$DBE8 PRG:1BE8 F0 03
jmp BuildSpriteBufferNextGroup ; CPU:$DBEA PRG:1BEA 4C 05 DB
BuildSpriteBufferDone:
rts ; CPU:$DBED PRG:1BED 60
;==============================================================================
; $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 ; CPU:$DBEE PRG:1BEE 4C 4C 4C 4C
.byte $00,$00,$00,$00 ; CPU:$DBF2 PRG:1BF2 00 00 00 00
.byte $04,$04,$03,$03 ; CPU:$DBF6 PRG:1BF6 04 04 03 03
.byte $08,$08,$07,$07 ; CPU:$DBFA PRG:1BFA 08 08 07 07
; $DBFE-$DC0D
.byte $02,$01,$02,$01 ; CPU:$DBFE PRG:1BFE 02 01 02 01
.byte $06,$05,$06,$05 ; CPU:$DC02 PRG:1C02 06 05 06 05
.byte $03,$03,$04,$04 ; CPU:$DC06 PRG:1C06 03 03 04 04
.byte $07,$07,$08,$08 ; CPU:$DC0A PRG:1C0A 07 07 08 08
; $DC0E-$DC1D
.byte $01,$02,$01,$02 ; CPU:$DC0E PRG:1C0E 01 02 01 02
.byte $05,$06,$05,$06 ; CPU:$DC12 PRG:1C12 05 06 05 06
.byte $18,$18,$19,$19 ; CPU:$DC16 PRG:1C16 18 18 19 19
.byte $18,$18,$1A,$1A ; CPU:$DC1A PRG:1C1A 18 18 1A 1A
; $DC1E-$DC2D
.byte $1B,$1C,$1D,$1F ; CPU:$DC1E PRG:1C1E 1B 1C 1D 1F
.byte $1B,$1C,$1E,$20 ; CPU:$DC22 PRG:1C22 1B 1C 1E 20
.byte $21,$21,$22,$22 ; CPU:$DC26 PRG:1C26 21 21 22 22
.byte $21,$21,$23,$23 ; CPU:$DC2A PRG:1C2A 21 21 23 23
; $DC2E-$DC3D
.byte $1C,$1B,$1F,$1D ; CPU:$DC2E PRG:1C2E 1C 1B 1F 1D
.byte $1C,$1B,$20,$1E ; CPU:$DC32 PRG:1C32 1C 1B 20 1E
.byte $00,$00,$00,$00 ; CPU:$DC36 PRG:1C36 00 00 00 00
.byte $09,$09,$0A,$0A ; CPU:$DC3A PRG:1C3A 09 09 0A 0A
; $DC3E-$DC3F
.byte $0B,$0B ; CPU:$DC3E PRG:1C3E 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 ; CPU:$DC40 PRG:1C40 0C 0C 4C 4C
.byte $0D,$0D,$4C,$4C ; CPU:$DC44 PRG:1C44 0D 0D 4C 4C
.byte $0E,$0E,$4C,$4C ; CPU:$DC48 PRG:1C48 0E 0E 4C 4C
.byte $0F,$0F,$4C,$4C ; CPU:$DC4C PRG:1C4C 0F 0F 4C 4C
; $DC50-$DC5F
.byte $10,$10,$4C,$4C ; CPU:$DC50 PRG:1C50 10 10 4C 4C
.byte $11,$11,$4C,$4C ; CPU:$DC54 PRG:1C54 11 11 4C 4C
.byte $12,$12,$4C,$4C ; CPU:$DC58 PRG:1C58 12 12 4C 4C
.byte $13,$13,$14,$15 ; CPU:$DC5C PRG:1C5C 13 13 14 15
; $DC60-$DC6F
.byte $16,$17,$4C,$4C ; CPU:$DC60 PRG:1C60 16 17 4C 4C
.byte $4C,$4C,$24,$24 ; CPU:$DC64 PRG:1C64 4C 4C 24 24
.byte $25,$25,$24,$24 ; CPU:$DC68 PRG:1C68 25 25 24 24
.byte $26,$26,$27,$27 ; CPU:$DC6C PRG:1C6C 26 26 27 27
; $DC70-$DC7F
.byte $4C,$4C,$28,$29 ; CPU:$DC70 PRG:1C70 4C 4C 28 29
.byte $2A,$2B,$2C,$2C ; CPU:$DC74 PRG:1C74 2A 2B 2C 2C
.byte $2D,$2D,$29,$28 ; CPU:$DC78 PRG:1C78 2D 2D 29 28
.byte $2B,$2A,$90,$91 ; CPU:$DC7C PRG:1C7C 2B 2A 90 91
; $DC80-$DC8F
.byte $92,$93,$94,$95 ; CPU:$DC80 PRG:1C80 92 93 94 95
.byte $96,$97,$98,$99 ; CPU:$DC84 PRG:1C84 96 97 98 99
.byte $9A,$9B,$9C,$9D ; CPU:$DC88 PRG:1C88 9A 9B 9C 9D
.byte $9E,$9F,$A0,$A1 ; CPU:$DC8C PRG:1C8C 9E 9F A0 A1
; $DC90-$DC9F
.byte $A2,$A3,$A4,$A5 ; CPU:$DC90 PRG:1C90 A2 A3 A4 A5
.byte $A6,$A7,$A8,$A9 ; CPU:$DC94 PRG:1C94 A6 A7 A8 A9
.byte $AA,$AB,$AC,$AD ; CPU:$DC98 PRG:1C98 AA AB AC AD
.byte $AE,$AF,$2E,$2F ; CPU:$DC9C PRG:1C9C AE AF 2E 2F
; $DCA0-$DCAF
.byte $30,$31,$32,$2F ; CPU:$DCA0 PRG:1CA0 30 31 32 2F
.byte $33,$31,$34,$2F ; CPU:$DCA4 PRG:1CA4 33 31 34 2F
.byte $35,$31,$36,$2F ; CPU:$DCA8 PRG:1CA8 35 31 36 2F
.byte $37,$31,$38,$2F ; CPU:$DCAC PRG:1CAC 37 31 38 2F
; $DCB0-$DCBF
.byte $39,$31,$3A,$2F ; CPU:$DCB0 PRG:1CB0 39 31 3A 2F
.byte $3B,$31,$3C,$2F ; CPU:$DCB4 PRG:1CB4 3B 31 3C 2F
.byte $3D,$31,$3E,$3F ; CPU:$DCB8 PRG:1CB8 3D 31 3E 3F
.byte $40,$41,$42,$3F ; CPU:$DCBC PRG:1CBC 40 41 42 3F
; $DCC0-$DCCF
.byte $43,$41,$44,$45 ; CPU:$DCC0 PRG:1CC0 43 41 44 45
.byte $46,$47,$48,$45 ; CPU:$DCC4 PRG:1CC4 46 47 48 45
.byte $49,$47,$4A,$45 ; CPU:$DCC8 PRG:1CC8 49 47 4A 45
.byte $4B,$47,$4D,$4E ; CPU:$DCCC PRG:1CCC 4B 47 4D 4E
; $DCD0-$DCDF
.byte $4F,$50,$4E,$4D ; CPU:$DCD0 PRG:1CD0 4F 50 4E 4D
.byte $50,$4F,$4F,$50 ; CPU:$DCD4 PRG:1CD4 50 4F 4F 50
.byte $4D,$4E,$50,$4F ; CPU:$DCD8 PRG:1CD8 4D 4E 50 4F
.byte $4E,$4D,$4D,$4E ; CPU:$DCDC PRG:1CDC 4E 4D 4D 4E
; $DCE0-$DCED
.byte $4F,$51,$4E,$52 ; CPU:$DCE0 PRG:1CE0 4F 51 4E 52
.byte $53,$54,$4F,$51 ; CPU:$DCE4 PRG:1CE4 53 54 4F 51
.byte $4D,$4E,$53,$54 ; CPU:$DCE8 PRG:1CE8 4D 4E 53 54
.byte $4E,$52 ; CPU:$DCEC PRG:1CEC 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 ; CPU:$DCEE PRG:1CEE 55 4C 56 4C
.byte $56,$4C,$55,$4C ; CPU:$DCF2 PRG:1CF2 56 4C 55 4C
.byte $4C,$57,$4C,$58 ; CPU:$DCF6 PRG:1CF6 4C 57 4C 58
.byte $4C,$59,$4C,$5A ; CPU:$DCFA PRG:1CFA 4C 59 4C 5A
; $DCFE-$DD0D
.byte $4C,$5B,$4C,$5C ; CPU:$DCFE PRG:1CFE 4C 5B 4C 5C
.byte $4C,$4C,$4C,$5D ; CPU:$DD02 PRG:1D02 4C 4C 4C 5D
.byte $18,$18,$19,$5E ; CPU:$DD06 PRG:1D06 18 18 19 5E
.byte $60,$61,$19,$5E ; CPU:$DD0A PRG:1D0A 60 61 19 5E
; $DD0E-$DD1D
.byte $1B,$1C,$1D,$62 ; CPU:$DD0E PRG:1D0E 1B 1C 1D 62
.byte $1B,$1C,$1E,$63 ; CPU:$DD12 PRG:1D12 1B 1C 1E 63
.byte $64,$65,$66,$67 ; CPU:$DD16 PRG:1D16 64 65 66 67
.byte $64,$65,$68,$69 ; CPU:$DD1A PRG:1D1A 64 65 68 69
; $DD1E-$DD21
.byte $6A,$6B,$4C,$4C ; CPU:$DD1E PRG:1D1E 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 ; CPU:$DD22 PRG:1D22 00 00 00 00
.byte $00,$40,$80,$C0 ; CPU:$DD26 PRG:1D26 00 40 80 C0
.byte $80,$C0,$80,$C0 ; CPU:$DD2A PRG:1D2A 80 C0 80 C0
.byte $80,$C0,$80,$C0 ; CPU:$DD2E PRG:1D2E 80 C0 80 C0
; $DD32-$DD41
.byte $00,$00,$80,$80 ; CPU:$DD32 PRG:1D32 00 00 80 80
.byte $00,$00,$80,$80 ; CPU:$DD36 PRG:1D36 00 00 80 80
.byte $00,$40,$00,$40 ; CPU:$DD3A PRG:1D3A 00 40 00 40
.byte $00,$40,$00,$40 ; CPU:$DD3E PRG:1D3E 00 40 00 40
; $DD42-$DD51
.byte $40,$40,$C0,$C0 ; CPU:$DD42 PRG:1D42 40 40 C0 C0
.byte $40,$40,$C0,$C0 ; CPU:$DD46 PRG:1D46 40 40 C0 C0
.byte $00,$40,$00,$40 ; CPU:$DD4A PRG:1D4A 00 40 00 40
.byte $00,$40,$00,$40 ; CPU:$DD4E PRG:1D4E 00 40 00 40
; $DD52-$DD61
.byte $00,$00,$00,$00 ; CPU:$DD52 PRG:1D52 00 00 00 00
.byte $00,$00,$00,$00 ; CPU:$DD56 PRG:1D56 00 00 00 00
.byte $00,$40,$00,$40 ; CPU:$DD5A PRG:1D5A 00 40 00 40
.byte $00,$40,$00,$40 ; CPU:$DD5E PRG:1D5E 00 40 00 40
; $DD62-$DD71
.byte $40,$40,$40,$40 ; CPU:$DD62 PRG:1D62 40 40 40 40
.byte $40,$40,$40,$40 ; CPU:$DD66 PRG:1D66 40 40 40 40
.byte $00,$40,$80,$C0 ; CPU:$DD6A PRG:1D6A 00 40 80 C0
.byte $00,$40,$00,$40 ; CPU:$DD6E PRG:1D6E 00 40 00 40
; $DD72-$DD81
.byte $00,$40,$00,$40 ; CPU:$DD72 PRG:1D72 00 40 00 40
.byte $00,$00,$00,$40 ; CPU:$DD76 PRG:1D76 00 00 00 40
.byte $00,$00,$00,$40 ; CPU:$DD7A PRG:1D7A 00 00 00 40
.byte $00,$00,$00,$40 ; CPU:$DD7E PRG:1D7E 00 00 00 40
; $DD82-$DD91
.byte $00,$00,$00,$40 ; CPU:$DD82 PRG:1D82 00 00 00 40
.byte $00,$00,$00,$40 ; CPU:$DD86 PRG:1D86 00 00 00 40
.byte $00,$00,$00,$40 ; CPU:$DD8A PRG:1D8A 00 00 00 40
.byte $00,$00,$00,$40 ; CPU:$DD8E PRG:1D8E 00 00 00 40
; $DD92-$DDA1
.byte $00,$00,$00,$00 ; CPU:$DD92 PRG:1D92 00 00 00 00
.byte $00,$00,$00,$00 ; CPU:$DD96 PRG:1D96 00 00 00 00
.byte $00,$40,$00,$40 ; CPU:$DD9A PRG:1D9A 00 40 00 40
.byte $00,$40,$00,$40 ; CPU:$DD9E PRG:1D9E 00 40 00 40
; $DDA2-$DDB1
.byte $00,$40,$00,$00 ; CPU:$DDA2 PRG:1DA2 00 40 00 00
.byte $00,$00,$00,$00 ; CPU:$DDA6 PRG:1DA6 00 00 00 00
.byte $00,$40,$00,$40 ; CPU:$DDAA PRG:1DAA 00 40 00 40
.byte $40,$40,$40,$40 ; CPU:$DDAE PRG:1DAE 40 40 40 40
; $DDB2-$DDC1
.byte $00,$00,$00,$00 ; CPU:$DDB2 PRG:1DB2 00 00 00 00
.byte $00,$00,$00,$00 ; CPU:$DDB6 PRG:1DB6 00 00 00 00
.byte $00,$00,$00,$00 ; CPU:$DDBA PRG:1DBA 00 00 00 00
.byte $00,$00,$00,$00 ; CPU:$DDBE PRG:1DBE 00 00 00 00
; $DDC2-$DDD1
.byte $00,$00,$00,$00 ; CPU:$DDC2 PRG:1DC2 00 00 00 00
.byte $00,$00,$00,$00 ; CPU:$DDC6 PRG:1DC6 00 00 00 00
.byte $00,$00,$00,$00 ; CPU:$DDCA PRG:1DCA 00 00 00 00
.byte $00,$00,$00,$00 ; CPU:$DDCE PRG:1DCE 00 00 00 00
; $DDD2-$DDE1
.byte $00,$00,$00,$00 ; CPU:$DDD2 PRG:1DD2 00 00 00 00
.byte $00,$00,$00,$00 ; CPU:$DDD6 PRG:1DD6 00 00 00 00
.byte $00,$00,$00,$00 ; CPU:$DDDA PRG:1DDA 00 00 00 00
.byte $00,$00,$00,$00 ; CPU:$DDDE PRG:1DDE 00 00 00 00
; $DDE2-$DDF1
.byte $00,$00,$00,$00 ; CPU:$DDE2 PRG:1DE2 00 00 00 00
.byte $00,$00,$00,$00 ; CPU:$DDE6 PRG:1DE6 00 00 00 00
.byte $00,$00,$00,$00 ; CPU:$DDEA PRG:1DEA 00 00 00 00
.byte $00,$00,$00,$00 ; CPU:$DDEE PRG:1DEE 00 00 00 00
; $DDF2-$DE01
.byte $00,$00,$00,$00 ; CPU:$DDF2 PRG:1DF2 00 00 00 00
.byte $00,$00,$00,$00 ; CPU:$DDF6 PRG:1DF6 00 00 00 00
.byte $00,$00,$00,$00 ; CPU:$DDFA PRG:1DFA 00 00 00 00
.byte $00,$00,$00,$00 ; CPU:$DDFE PRG:1DFE 00 00 00 00
; $DE02-$DE11
.byte $00,$00,$00,$00 ; CPU:$DE02 PRG:1E02 00 00 00 00
.byte $40,$40,$00,$40 ; CPU:$DE06 PRG:1E06 40 40 00 40
.byte $80,$00,$80,$80 ; CPU:$DE0A PRG:1E0A 80 00 80 80
.byte $00,$C0,$C0,$C0 ; CPU:$DE0E PRG:1E0E 00 C0 C0 C0
; $DE12-$DE21
.byte $00,$00,$00,$00 ; CPU:$DE12 PRG:1E12 00 00 00 00
.byte $40,$00,$00,$00 ; CPU:$DE16 PRG:1E16 40 00 00 00
.byte $80,$80,$80,$80 ; CPU:$DE1A PRG:1E1A 80 80 80 80
.byte $80,$80,$C0,$80 ; CPU:$DE1E PRG:1E1E 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 ; CPU:$DE22 PRG:1E22 00 00 00 00
.byte $80,$00,$80,$00 ; CPU:$DE26 PRG:1E26 80 00 80 00
.byte $00,$00,$00,$00 ; CPU:$DE2A PRG:1E2A 00 00 00 00
.byte $00,$00,$00,$00 ; CPU:$DE2E PRG:1E2E 00 00 00 00
; $DE32-$DE41
.byte $00,$00,$00,$00 ; CPU:$DE32 PRG:1E32 00 00 00 00
.byte $00,$00,$00,$00 ; CPU:$DE36 PRG:1E36 00 00 00 00
.byte $00,$40,$00,$00 ; CPU:$DE3A PRG:1E3A 00 40 00 00
.byte $00,$00,$00,$00 ; CPU:$DE3E PRG:1E3E 00 00 00 00
; $DE42-$DE51
.byte $00,$00,$00,$00 ; CPU:$DE42 PRG:1E42 00 00 00 00
.byte $00,$00,$00,$00 ; CPU:$DE46 PRG:1E46 00 00 00 00
.byte $00,$00,$00,$00 ; CPU:$DE4A PRG:1E4A 00 00 00 00
.byte $00,$00,$00,$00 ; CPU:$DE4E PRG:1E4E 00 00 00 00
; $DE52-$DE55
.byte $00,$00,$00,$00 ; CPU:$DE52 PRG:1E52 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 ; CPU:$DE56 PRG:1E56 03 F4
.byte $03,$FC ; CPU:$DE58 PRG:1E58 03 FC
.byte $0B,$F4 ; CPU:$DE5A PRG:1E5A 0B F4
.byte $0B,$FC ; CPU:$DE5C PRG:1E5C 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 ; CPU:$DE5E PRG:1E5E A5 4B
and #$0F ; CPU:$DE60 PRG:1E60 29 0F
beq @DE65 ; CPU:$DE62 PRG:1E62 F0 01
rts ; CPU:$DE64 PRG:1E64 60
@DE65:
tax ; CPU:$DE65 PRG:1E65 AA
@DE66:
lda $6C,x ; CPU:$DE66 PRG:1E66 B5 6C
cmp #$07 ; CPU:$DE68 PRG:1E68 C9 07
beq @DE76 ; CPU:$DE6A PRG:1E6A F0 0A
cmp #$01 ; CPU:$DE6C PRG:1E6C C9 01
bne @DE74 ; CPU:$DE6E PRG:1E6E D0 04
lda #$02 ; CPU:$DE70 PRG:1E70 A9 02
bne @DE76 ; CPU:$DE72 PRG:1E72 D0 02
@DE74:
lda #$01 ; CPU:$DE74 PRG:1E74 A9 01
@DE76:
sta $6C,x ; CPU:$DE76 PRG:1E76 95 6C
inx ; CPU:$DE78 PRG:1E78 E8
cpx #$04 ; CPU:$DE79 PRG:1E79 E0 04
bne @DE66 ; CPU:$DE7B PRG:1E7B D0 E9
rts ; CPU:$DE7D PRG:1E7D 60
;==============================================================================
; $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 ; CPU:$DE7E PRG:1E7E A5 48
beq @DE85 ; CPU:$DE80 PRG:1E80 F0 03
jmp UpdateAnimatedGameplayPpuFields ; CPU:$DE82 PRG:1E82 4C 15 DF
;------------------------------------------------------------------------------
; $DE85
; Process the update block beginning at $023F.
;------------------------------------------------------------------------------
@DE85:
lda $023F ; CPU:$DE85 PRG:1E85 AD 3F 02
cmp #$FF ; CPU:$DE88 PRG:1E88 C9 FF
beq @DEB5 ; CPU:$DE8A PRG:1E8A F0 28
lda PPUSTATUS ; CPU:$DE8C PRG:1E8C AD 02 20
lda $026B ; CPU:$DE8F PRG:1E8F AD 6B 02
sta PPUADDR ; CPU:$DE92 PRG:1E92 8D 06 20
lda $026C ; CPU:$DE95 PRG:1E95 AD 6C 02
sta PPUADDR ; CPU:$DE98 PRG:1E98 8D 06 20
ldy #$00 ; CPU:$DE9B PRG:1E9B A0 00
@DE9B:
lda $023F,y ; CPU:$DE9D PRG:1E9D B9 3F 02
sta PPUDATA ; CPU:$DEA0 PRG:1EA0 8D 07 20
iny ; CPU:$DEA3 PRG:1EA3 C8
cpy #$06 ; CPU:$DEA4 PRG:1EA4 C0 06
bne @DE9B ; CPU:$DEA6 PRG:1EA6 D0 F5
lda #$30 ; CPU:$DEA8 PRG:1EA8 A9 30
sta PPUDATA ; CPU:$DEAA PRG:1EAA 8D 07 20
lda #$FF ; CPU:$DEAD PRG:1EAD A9 FF
sta $023F ; CPU:$DEAF PRG:1EAF 8D 3F 02
bne @DEE2 ; CPU:$DEB2 PRG:1EB2 D0 2D
;------------------------------------------------------------------------------
; $DEB5
; Process the update block beginning at $0245.
;------------------------------------------------------------------------------
@DEB5:
lda $0245 ; CPU:$DEB4 PRG:1EB4 AD 45 02
cmp #$FF ; CPU:$DEB7 PRG:1EB7 C9 FF
beq @DEE2 ; CPU:$DEB9 PRG:1EB9 F0 26
lda PPUSTATUS ; CPU:$DEBB PRG:1EBB AD 02 20
lda $0272 ; CPU:$DEBE PRG:1EBE AD 72 02
sta PPUADDR ; CPU:$DEC1 PRG:1EC1 8D 06 20
lda $0273 ; CPU:$DEC4 PRG:1EC4 AD 73 02
sta PPUADDR ; CPU:$DEC7 PRG:1EC7 8D 06 20
ldy #$00 ; CPU:$DECA PRG:1ECA A0 00
@DECB:
lda $0245,y ; CPU:$DECC PRG:1ECC B9 45 02
sta PPUDATA ; CPU:$DECF PRG:1ECF 8D 07 20
iny ; CPU:$DED2 PRG:1ED2 C8
cpy #$06 ; CPU:$DED3 PRG:1ED3 C0 06
bne @DECB ; CPU:$DED5 PRG:1ED5 D0 F5
lda #$30 ; CPU:$DED7 PRG:1ED7 A9 30
sta PPUDATA ; CPU:$DED9 PRG:1ED9 8D 07 20
lda #$FF ; CPU:$DEDC PRG:1EDC A9 FF
sta $0245 ; CPU:$DEDE PRG:1EDE 8D 45 02
;------------------------------------------------------------------------------
; $DEE2
; Periodic three-byte display update.
;------------------------------------------------------------------------------
@DEE2:
lda $4B ; CPU:$DEE1 PRG:1EE1 A5 4B
and #$07 ; CPU:$DEE3 PRG:1EE3 29 07
bne UpdateAnimatedGameplayPpuFields ; CPU:$DEE5 PRG:1EE5 D0 2E
lda PPUSTATUS ; CPU:$DEE7 PRG:1EE7 AD 02 20
lda $026D ; CPU:$DEEA PRG:1EEA AD 6D 02
sta PPUADDR ; CPU:$DEED PRG:1EED 8D 06 20
lda $026E ; CPU:$DEF0 PRG:1EF0 AD 6E 02
sta PPUADDR ; CPU:$DEF3 PRG:1EF3 8D 06 20
ldx #$00 ; CPU:$DEF6 PRG:1EF6 A2 00
lda $4B ; CPU:$DEF8 PRG:1EF8 A5 4B
and #$18 ; CPU:$DEFA PRG:1EFA 29 18
beq @DF05 ; CPU:$DEFC PRG:1EFC F0 0D
@DEFB:
lda $026F,x ; CPU:$DEFE PRG:1EFE BD 6F 02
sta PPUDATA ; CPU:$DF01 PRG:1F01 8D 07 20
inx ; CPU:$DF04 PRG:1F04 E8
cpx #$03 ; CPU:$DF05 PRG:1F05 E0 03
bne @DEFB ; CPU:$DF07 PRG:1F07 D0 F5
beq UpdateAnimatedGameplayPpuFields ; CPU:$DF09 PRG:1F09 F0 0A
@DF05:
lda #$20 ; CPU:$DF0B PRG:1F0B A9 20
@DF07:
sta PPUDATA ; CPU:$DF0D PRG:1F0D 8D 07 20
inx ; CPU:$DF10 PRG:1F10 E8
cpx #$03 ; CPU:$DF11 PRG:1F11 E0 03
bne @DF07 ; CPU:$DF13 PRG:1F13 D0 F8
;==============================================================================
; $DF15: Shared frame-dependent display update entry
;==============================================================================
UpdateAnimatedGameplayPpuFields:
lda $4B ; CPU:$DF15 PRG:1F15 A5 4B
and #$01 ; CPU:$DF17 PRG:1F17 29 01
beq @DF42 ; CPU:$DF19 PRG:1F19 F0 27
ldy #$00 ; CPU:$DF1B PRG:1F1B A0 00
ldx #$00 ; CPU:$DF1D PRG:1F1D A2 00
lda $46 ; CPU:$DF1F PRG:1F1F A5 46
and $47 ; CPU:$DF21 PRG:1F21 25 47
beq @DF27 ; CPU:$DF23 PRG:1F23 F0 02
ldy #$08 ; CPU:$DF25 PRG:1F25 A0 08
@DF27:
lda PPUSTATUS ; CPU:$DF27 PRG:1F27 AD 02 20
lda GameplayStatusPpuAddressTable,y ; CPU:$DF2A PRG:1F2A B9 6C DF
sta PPUADDR ; CPU:$DF2D PRG:1F2D 8D 06 20
lda GameplayStatusPpuAddressTable+1,y ; CPU:$DF30 PRG:1F30 B9 6D DF
sta PPUADDR ; CPU:$DF33 PRG:1F33 8D 06 20
lda $6C,x ; CPU:$DF36 PRG:1F36 B5 6C
sta PPUDATA ; CPU:$DF38 PRG:1F38 8D 07 20
iny ; CPU:$DF3B PRG:1F3B C8
iny ; CPU:$DF3C PRG:1F3C C8
inx ; CPU:$DF3D PRG:1F3D E8
cpx #$04 ; CPU:$DF3E PRG:1F3E E0 04
bne @DF27 ; CPU:$DF40 PRG:1F40 D0 E5
;------------------------------------------------------------------------------
; $DF42
; Process the $024B command stream.
;------------------------------------------------------------------------------
@DF42:
lda PPUSTATUS ; CPU:$DF42 PRG:1F42 AD 02 20
ldy #$FF ; CPU:$DF45 PRG:1F45 A0 FF
@DF46:
iny ; CPU:$DF47 PRG:1F47 C8
lda $024B,y ; CPU:$DF48 PRG:1F48 B9 4B 02
cmp #$FF ; CPU:$DF4B PRG:1F4B C9 FF
beq @DF66 ; CPU:$DF4D PRG:1F4D F0 19
sta PPUADDR ; CPU:$DF4F PRG:1F4F 8D 06 20
iny ; CPU:$DF52 PRG:1F52 C8
lda $024B,y ; CPU:$DF53 PRG:1F53 B9 4B 02
sta PPUADDR ; CPU:$DF56 PRG:1F56 8D 06 20
@DF55:
iny ; CPU:$DF59 PRG:1F59 C8
lda $024B,y ; CPU:$DF5A PRG:1F5A B9 4B 02
beq @DF46 ; CPU:$DF5D PRG:1F5D F0 E8
cmp #$FF ; CPU:$DF5F PRG:1F5F C9 FF
beq @DF66 ; CPU:$DF61 PRG:1F61 F0 05
sta PPUDATA ; CPU:$DF63 PRG:1F63 8D 07 20
bne @DF55 ; CPU:$DF66 PRG:1F66 D0 F1
@DF66:
sta $024B ; CPU:$DF68 PRG:1F68 8D 4B 02
rts ; CPU:$DF6B PRG:1F6B 60
;==============================================================================
; $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 ; CPU:$DF6C PRG:1F6C 20 B4
.byte $20,$A2 ; CPU:$DF6E PRG:1F6E 20 A2
.byte $22,$D4 ; CPU:$DF70 PRG:1F70 22 D4
.byte $22,$C2 ; CPU:$DF72 PRG:1F72 22 C2
.byte $28,$B4 ; CPU:$DF74 PRG:1F74 28 B4
.byte $28,$A2 ; CPU:$DF76 PRG:1F76 28 A2
.byte $2A,$D4 ; CPU:$DF78 PRG:1F78 2A D4
.byte $2A,$C2 ; CPU:$DF7A PRG:1F7A 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 ; CPU:$DF7C PRG:1F7C A2 00
lda $022A ; CPU:$DF7E PRG:1F7E AD 2A 02
cmp #$09 ; CPU:$DF81 PRG:1F81 C9 09
beq $DFBB ; CPU:$DF83 PRG:1F83 F0 36
inx ; CPU:$DF85 PRG:1F85 E8
inx ; CPU:$DF86 PRG:1F86 E8
cmp #$03 ; CPU:$DF87 PRG:1F87 C9 03
beq $DFBB ; CPU:$DF89 PRG:1F89 F0 30
cmp #$01 ; CPU:$DF8B PRG:1F8B C9 01
beq @DF94 ; CPU:$DF8D PRG:1F8D F0 05
cmp #$02 ; CPU:$DF8F PRG:1F8F C9 02
beq @DF94 ; CPU:$DF91 PRG:1F91 F0 01
rts ; CPU:$DF93 PRG:1F93 60
@DF94:
jsr $E063 ; CPU:$DF94 PRG:1F94 20 63 E0
lda $1A ; CPU:$DF97 PRG:1F97 A5 1A
sta $02 ; CPU:$DF99 PRG:1F99 85 02
lda $1C ; CPU:$DF9B PRG:1F9B A5 1C
sta $03 ; CPU:$DF9D PRG:1F9D 85 03
jsr $E263 ; CPU:$DF9F PRG:1F9F 20 63 E2
ldx #$00 ; CPU:$DFA2 PRG:1FA2 A2 00
lda $03 ; CPU:$DFA4 PRG:1FA4 A5 03
and #$07 ; CPU:$DFA6 PRG:1FA6 29 07
beq @DFAD ; CPU:$DFA8 PRG:1FA8 F0 02
inx ; CPU:$DFAA PRG:1FAA E8
inx ; CPU:$DFAB PRG:1FAB E8
@DFAD:
lda $02 ; CPU:$DFAC PRG:1FAC A5 02
and #$0F ; CPU:$DFAE PRG:1FAE 29 0F
cmp #$04 ; CPU:$DFB0 PRG:1FB0 C9 04
beq @DFB6 ; CPU:$DFB2 PRG:1FB2 F0 01
inx ; CPU:$DFB4 PRG:1FB4 E8
@DFB6:
lda #$07 ; CPU:$DFB5 PRG:1FB5 A9 07
sta $6C,x ; CPU:$DFB7 PRG:1FB7 95 6C
@DFBB:
ldx #$04 ; CPU:$DFB9 PRG:1FB9 A2 04
lda #$00 ; CPU:$DFBB PRG:1FBB A9 00
sta $D5 ; CPU:$DFBD PRG:1FBD 85 D5
sta $D6 ; CPU:$DFBF PRG:1FBF 85 D6
lda $1A ; CPU:$DFC1 PRG:1FC1 A5 1A
sta $02 ; CPU:$DFC3 PRG:1FC3 85 02
lda $1C ; CPU:$DFC5 PRG:1FC5 A5 1C
sta $03 ; CPU:$DFC7 PRG:1FC7 85 03
jsr $E263 ; CPU:$DFC9 PRG:1FC9 20 63 E2
ldy #$FF ; CPU:$DFCC PRG:1FCC A0 FF
@DFCE:
iny ; CPU:$DFCE PRG:1FCE C8
lda $024B,y ; CPU:$DFCF PRG:1FCF B9 4B 02
cmp #$FF ; CPU:$DFD2 PRG:1FD2 C9 FF
bne @DFCE ; CPU:$DFD4 PRG:1FD4 D0 F8
tya ; CPU:$DFD6 PRG:1FD6 98
beq @DFDC ; CPU:$DFD7 PRG:1FD7 F0 06
lda #$00 ; CPU:$DFD9 PRG:1FD9 A9 00
sta $024B,y ; CPU:$DFDB PRG:1FDB 99 4B 02
iny ; CPU:$DFDE PRG:1FDE C8
@DFDC:
lda $03 ; CPU:$DFDF PRG:1FDF A5 03
sta $024B,y ; CPU:$DFE1 PRG:1FE1 99 4B 02
iny ; CPU:$DFE4 PRG:1FE4 C8
lda $02 ; CPU:$DFE5 PRG:1FE5 A5 02
sta $024B,y ; CPU:$DFE7 PRG:1FE7 99 4B 02
iny ; CPU:$DFEA PRG:1FEA C8
lda $E043,x ; CPU:$DFEB PRG:1FEB BD 43 E0
sta $024B,y ; CPU:$DFEE PRG:1FEE 99 4B 02
iny ; CPU:$DFF1 PRG:1FF1 C8
lda #$FF ; CPU:$DFF2 PRG:1FF2 A9 FF
sta $024B,y ; CPU:$DFF4 PRG:1FF4 99 4B 02
lda #$07 ; CPU:$DFF7 PRG:1FF7 A9 07
sta $022A ; CPU:$DFF9 PRG:1FF9 8D 2A 02
lda $E044,x ; CPU:$DFFC PRG:1FFC BD 44 E0
sta $DC ; CPU:$DFFF PRG:1FFF 85 DC
dec $6A ; CPU:$E001 PRG:2001 C6 6A
bne @E012 ; CPU:$E003 PRG:2003 D0 0C
lda #$0C ; CPU:$E005 PRG:2005 A9 0C
sta $3F ; CPU:$E007 PRG:2007 85 3F
lda #$00 ; CPU:$E009 PRG:2009 A9 00
sta $87 ; CPU:$E00B PRG:200B 85 87
lda #$48 ; CPU:$E00D PRG:200D A9 48
sta $4C ; CPU:$E00F PRG:200F 85 4C
@E012:
lda $6A ; CPU:$E011 PRG:2011 A5 6A
cmp #$37 ; CPU:$E013 PRG:2013 C9 37
beq @E01C ; CPU:$E015 PRG:2015 F0 04
cmp #$86 ; CPU:$E017 PRG:2017 C9 86
bne $E036 ; CPU:$E019 PRG:2019 D0 1B
@E01C:
lda #$0A ; CPU:$E01B PRG:201B A9 0A
sta $D7 ; CPU:$E01D PRG:201D 85 D7
lda #$3C ; CPU:$E01F PRG:201F A9 3C
sta $D8 ; CPU:$E021 PRG:2021 85 D8
ldy $93 ; CPU:$E023 PRG:2023 A4 93
lda GameplayStateValueLookup,y ; CPU:$E025 PRG:2025 B9 5B E0
sta $37 ; CPU:$E028 PRG:2028 85 37
lda #$03 ; CPU:$E02A PRG:202A A9 03
sta $3D ; CPU:$E02C PRG:202C 85 3D
lda #$60 ; CPU:$E02E PRG:202E A9 60
sta $2E ; CPU:$E030 PRG:2030 85 2E
lda #$80 ; CPU:$E032 PRG:2032 A9 80
sta $30 ; CPU:$E034 PRG:2034 85 30
lda $6A ; CPU:$E036 PRG:2036 A5 6A
and #$01 ; CPU:$E038 PRG:2038 29 01
tay ; CPU:$E03A PRG:203A A8
lda #$01 ; CPU:$E03B PRG:203B A9 01
sta $0604,y ; CPU:$E03D PRG:203D 99 04 06
jmp $E0E6 ; CPU:$E040 PRG:2040 4C E6 E0
;==============================================================================
; $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 ; CPU:$E043 PRG:2043 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 ; CPU:$E049 PRG:2049 A2 00
@E04B:
lda $BA,x ; CPU:$E04B PRG:204B B5 BA
bne @E054 ; CPU:$E04D PRG:204D D0 05
lda #$02 ; CPU:$E04F PRG:204F A9 02
sta $BA,x ; CPU:$E051 PRG:2051 95 BA
rts ; CPU:$E053 PRG:2053 60
@E054:
inx ; CPU:$E054 PRG:2054 E8
inx ; CPU:$E055 PRG:2055 E8
cpx #$06 ; CPU:$E056 PRG:2056 E0 06
bne @E04B ; CPU:$E058 PRG:2058 D0 F1
rts ; CPU:$E05A PRG:205A 60
;==============================================================================
; $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 ; CPU:$E05B PRG:205B 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 ; CPU:$E063 PRG:2063 A5 8C
bne @E06D ; CPU:$E065 PRG:2065 D0 06
lda #$1E ; CPU:$E067 PRG:2067 A9 1E
sta $8A ; CPU:$E069 PRG:2069 85 8A
lda #$00 ; CPU:$E06B PRG:206B A9 00
@E06D:
sta $89 ; CPU:$E06D PRG:206D 85 89
lda #$0F ; CPU:$E06F PRG:206F A9 0F
sta $88 ; CPU:$E071 PRG:2071 85 88
ldx #$03 ; CPU:$E073 PRG:2073 A2 03
@E075:
lda $39,x ; CPU:$E075 PRG:2075 B5 39
and #$FC ; CPU:$E077 PRG:2077 29 FC
ora #$01 ; CPU:$E079 PRG:2079 09 01
sta $39,x ; CPU:$E07B PRG:207B 95 39
dex ; CPU:$E07D PRG:207D CA
bpl @E075 ; CPU:$E07E PRG:207E 10 F5
lda #$11 ; CPU:$E080 PRG:2080 A9 11
sta $02AE ; CPU:$E082 PRG:2082 8D AE 02
lda #$0F ; CPU:$E085 PRG:2085 A9 0F
sta $02A9 ; CPU:$E087 PRG:2087 8D A9 02
lda #$00 ; CPU:$E08A PRG:208A A9 00
sta $D9 ; CPU:$E08C PRG:208C 85 D9
ldx #$00 ; CPU:$E08E PRG:208E A2 00
lda #$2F ; CPU:$E090 PRG:2090 A9 2F
sta $00 ; CPU:$E092 PRG:2092 85 00
lda #$02 ; CPU:$E094 PRG:2094 A9 02
sta $01 ; CPU:$E096 PRG:2096 85 01
lda #$1E ; CPU:$E098 PRG:2098 A9 1E
sta $02 ; CPU:$E09A PRG:209A 85 02
lda #$00 ; CPU:$E09C PRG:209C A9 00
sta $03 ; CPU:$E09E PRG:209E 85 03
@E09E:
lda #$0F ; CPU:$E0A0 PRG:20A0 A9 0F
cmp $88 ; CPU:$E0A2 PRG:20A2 C5 88
beq @E0AA ; CPU:$E0A4 PRG:20A4 F0 04
lda $D2 ; CPU:$E0A6 PRG:20A6 A5 D2
bne @E0D1 ; CPU:$E0A8 PRG:20A8 D0 27
@E0AA:
lda $B8,x ; CPU:$E0AA PRG:20AA B5 B8
cmp #$04 ; CPU:$E0AC PRG:20AC C9 04
bne @E0D1 ; CPU:$E0AE PRG:20AE D0 21
lda $B9,x ; CPU:$E0B0 PRG:20B0 B5 B9
clc ; CPU:$E0B2 PRG:20B2 18
adc #$02 ; CPU:$E0B3 PRG:20B3 69 02
and #$03 ; CPU:$E0B5 PRG:20B5 29 03
sta $04 ; CPU:$E0B7 PRG:20B7 85 04
ldy #$00 ; CPU:$E0B9 PRG:20B9 A0 00
lda ($02),y ; CPU:$E0BB PRG:20BB B1 02
ldy #$02 ; CPU:$E0BD PRG:20BD A0 02
ora ($02),y ; CPU:$E0BF PRG:20BF 11 02
and #$07 ; CPU:$E0C1 PRG:20C1 29 07
bne @E0CD ; CPU:$E0C3 PRG:20C3 D0 08
ldy $04 ; CPU:$E0C5 PRG:20C5 A4 04
lda ($00),y ; CPU:$E0C7 PRG:20C7 B1 00
and #$F8 ; CPU:$E0C9 PRG:20C9 29 F8
bne @E0D1 ; CPU:$E0CB PRG:20CB D0 04
@E0CD:
lda $04 ; CPU:$E0CD PRG:20CD A5 04
sta $B9,x ; CPU:$E0CF PRG:20CF 95 B9
@E0D1:
lda $00 ; CPU:$E0D1 PRG:20D1 A5 00
clc ; CPU:$E0D3 PRG:20D3 18
adc #$04 ; CPU:$E0D4 PRG:20D4 69 04
sta $00 ; CPU:$E0D6 PRG:20D6 85 00
lda $02 ; CPU:$E0D8 PRG:20D8 A5 02
clc ; CPU:$E0DA PRG:20DA 18
adc #$04 ; CPU:$E0DB PRG:20DB 69 04
sta $02 ; CPU:$E0DD PRG:20DD 85 02
inx ; CPU:$E0DF PRG:20DF E8
inx ; CPU:$E0E0 PRG:20E0 E8
cpx #$08 ; CPU:$E0E1 PRG:20E1 E0 08
bne @E0AA ; CPU:$E0E3 PRG:20E3 D0 C5
rts ; CPU:$E0E5 PRG:20E5 60
;==============================================================================
; $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 ; CPU:$E0E6 PRG:20E6 A5 48
beq @E0EB ; CPU:$E0E8 PRG:20E8 F0 01
rts ; CPU:$E0EA PRG:20EA 60
;------------------------------------------------------------------------------
; $E0EB
; Add $DC-$E1 into the six values at $70-$75 using decimal carry handling.
;------------------------------------------------------------------------------
@E0EB:
ldy #$00 ; CPU:$E0EB PRG:20EB A0 00
lda #$06 ; CPU:$E0ED PRG:20ED A9 06
sta $00 ; CPU:$E0EF PRG:20EF 85 00
clc ; CPU:$E0F1 PRG:20F1 18
;------------------------------------------------------------------------------
; $E0F2
;------------------------------------------------------------------------------
@E0F2:
lda $70,y ; CPU:$E0F2 PRG:20F2 B9 70
adc $DC,y ; CPU:$E0F4 PRG:20F4 00 79
sta $70,y ; CPU:$E0F6 PRG:20F6 DC 00
cmp #$0A ; CPU:$E0F8 PRG:20F8 99 70
bcc @E105 ; CPU:$E0FA PRG:20FA 00 C9
sbc #$0A ; CPU:$E0FC PRG:20FC 0A 90
sta $70,y ; CPU:$E0FE PRG:20FE 06 E9
sec ; CPU:$E100 PRG:2100 0A
;------------------------------------------------------------------------------
; $E105
; Clear the consumed increment and continue through all six entries.
;------------------------------------------------------------------------------
@E105:
lda #$00 ; CPU:$E101 PRG:2101 99 70
sta $DC,y ; CPU:$E103 PRG:2103 00 38
iny ; CPU:$E105 PRG:2105 A9
dec $00 ; CPU:$E106 PRG:2106 00 99
bne @E0F2 ; CPU:$E108 PRG:2108 DC 00
;------------------------------------------------------------------------------
; $E10F
; Convert the six numeric values into display/tile values.
;------------------------------------------------------------------------------
ldx #$00 ; CPU:$E10A PRG:210A C8 C6
dey ; CPU:$E10C PRG:210C 00
;------------------------------------------------------------------------------
; $E112
; Suppress leading zero-style values by replacing $30 with $20.
;------------------------------------------------------------------------------
@E112:
lda $70,y ; CPU:$E10D PRG:210D D0 E3
jsr $E1CE ; CPU:$E10F PRG:210F A2 00 88
cmp #$30 ; CPU:$E112 PRG:2112 B9 70
bne @E12B ; CPU:$E114 PRG:2114 00 20
lda #$20 ; CPU:$E116 PRG:2116 CE E1
sta $023F,x ; CPU:$E118 PRG:2118 C9 30 D0
inx ; CPU:$E11B PRG:211B 0F
dey ; CPU:$E11C PRG:211C A9
bne @E112 ; CPU:$E11D PRG:211D 20 9D
;------------------------------------------------------------------------------
; $E125
; Convert remaining digits without leading-space suppression.
;------------------------------------------------------------------------------
@E125:
lda $70,y ; CPU:$E11F PRG:211F 3F 02
jsr $E1CE ; CPU:$E121 PRG:2121 E8 88 D0
;------------------------------------------------------------------------------
; $E12B
;------------------------------------------------------------------------------
@E12B:
sta $023F,x ; CPU:$E124 PRG:2124 ED B9 70
inx ; CPU:$E127 PRG:2127 00
dey ; CPU:$E128 PRG:2128 20
bpl @E125 ; CPU:$E129 PRG:2129 CE E1
;------------------------------------------------------------------------------
; $E132
; Progression check.
;------------------------------------------------------------------------------
lda $6B ; CPU:$E12B PRG:212B 9D 3F
bne @E196 ; CPU:$E12D PRG:212D 02 E8
lda #$01 ; CPU:$E12F PRG:212F 88 10
cmp $73 ; CPU:$E131 PRG:2131 F3 A5
bne @E196 ; CPU:$E133 PRG:2133 6B D0
lda #$01 ; CPU:$E135 PRG:2135 60 A9
sta $6B ; CPU:$E137 PRG:2137 01 C5
sta $0602 ; CPU:$E139 PRG:2139 73 D0 5A
inc $67 ; CPU:$E13C PRG:213C A9 01
lda $67 ; CPU:$E13E PRG:213E 85 6B
sec ; CPU:$E140 PRG:2140 8D
sbc #$02 ; CPU:$E141 PRG:2141 02 06
asl ; CPU:$E143 PRG:2143 E6
sta $00 ; CPU:$E144 PRG:2144 67 A5
;------------------------------------------------------------------------------
; Locate the $FF terminator of the $024B display-command stream.
;------------------------------------------------------------------------------
ldy #$FF ; CPU:$E146 PRG:2146 67 38
@E14D:
iny ; CPU:$E148 PRG:2148 E9
lda $024B,y ; CPU:$E149 PRG:2149 02 0A 85
cmp #$FF ; CPU:$E14C PRG:214C 00 A0
bne @E14D ; CPU:$E14E PRG:214E FF C8
tya ; CPU:$E150 PRG:2150 B9
beq @E15D ; CPU:$E151 PRG:2151 4B 02
lda #$00 ; CPU:$E153 PRG:2153 C9 FF
sta $024B,y ; CPU:$E155 PRG:2155 D0 F8 98
iny ; CPU:$E158 PRG:2158 F0
;------------------------------------------------------------------------------
; $E15D
; Select a display offset according to $46 & $47.
;------------------------------------------------------------------------------
@E15D:
lda $46 ; CPU:$E159 PRG:2159 06 A9
and $47 ; CPU:$E15B PRG:215B 00 99
beq @E165 ; CPU:$E15D PRG:215D 4B 02
lda #$08 ; CPU:$E15F PRG:215F C8 A5
@E165:
sta $01 ; CPU:$E161 PRG:2161 46 25
ldx #$00 ; CPU:$E163 PRG:2163 47 F0
;------------------------------------------------------------------------------
; $E169
; Append two five-byte command templates from $E1C0.
;------------------------------------------------------------------------------
@E169:
lda ScorePpuCommandTemplates,x ; CPU:$E165 PRG:2165 02 A9 08
clc ; CPU:$E168 PRG:2168 85
adc $01 ; CPU:$E169 PRG:2169 01 A2
sta $024B,y ; CPU:$E16B PRG:216B 00 BD C0
iny ; CPU:$E16E PRG:216E E1
inx ; CPU:$E16F PRG:216F 18
lda ScorePpuCommandTemplates,x ; CPU:$E170 PRG:2170 65 01 99
clc ; CPU:$E173 PRG:2173 4B
adc $00 ; CPU:$E174 PRG:2174 02 C8
sta $024B,y ; CPU:$E176 PRG:2176 E8 BD C0
lda #$03 ; CPU:$E179 PRG:2179 E1 18
sta $02 ; CPU:$E17B PRG:217B 65 00
@E182:
iny ; CPU:$E17D PRG:217D 99
inx ; CPU:$E17E PRG:217E 4B
lda ScorePpuCommandTemplates,x ; CPU:$E17F PRG:217F 02 A9 03
sta $024B,y ; CPU:$E182 PRG:2182 85 02 C8
dec $02 ; CPU:$E185 PRG:2185 E8 BD
bne @E182 ; CPU:$E187 PRG:2187 C0 E1
iny ; CPU:$E189 PRG:2189 99
inx ; CPU:$E18A PRG:218A 4B
cpx #$0A ; CPU:$E18B PRG:218B 02 C6
bne @E169 ; CPU:$E18D PRG:218D 02 D0
;------------------------------------------------------------------------------
; $E196
; Compare saved values $61-$66 with current values $70-$75.
;------------------------------------------------------------------------------
@E196:
ldy #$05 ; CPU:$E18F PRG:218F F4 C8
@E198:
lda $61,y ; CPU:$E191 PRG:2191 E8 E0
cmp $70,y ; CPU:$E193 PRG:2193 0A D0
beq @E1A3 ; CPU:$E195 PRG:2195 D6 A0
bcc @E1A7 ; CPU:$E197 PRG:2197 05 B9
rts ; CPU:$E199 PRG:2199 61
@E1A3:
dey ; CPU:$E19A PRG:219A 00
bpl @E198 ; CPU:$E19B PRG:219B D9 70
rts ; CPU:$E19D PRG:219D 00
;------------------------------------------------------------------------------
; $E1A7
; Copy display buffer $023F-$0244 to $0245-$024A.
;------------------------------------------------------------------------------
@E1A7:
ldx #$00 ; CPU:$E19E PRG:219E F0 03
@E1A9:
lda $023F,x ; CPU:$E1A0 PRG:21A0 90 05 60
sta $0245,x ; CPU:$E1A3 PRG:21A3 88 10 F2
inx ; CPU:$E1A6 PRG:21A6 60
cpx #$06 ; CPU:$E1A7 PRG:21A7 A2 00
bne @E1A9 ; CPU:$E1A9 PRG:21A9 BD 3F
;------------------------------------------------------------------------------
; Copy current values $70-$75 into saved values $61-$66.
;------------------------------------------------------------------------------
ldx #$00 ; CPU:$E1AB PRG:21AB 02 9D
@E1B4:
lda $70,x ; CPU:$E1AD PRG:21AD 45 02
sta $61,x ; CPU:$E1AF PRG:21AF E8 E0
inx ; CPU:$E1B1 PRG:21B1 06
cpx #$06 ; CPU:$E1B2 PRG:21B2 D0 F5
bne @E1B4 ; CPU:$E1B4 PRG:21B4 A2 00
rts ; CPU:$E1B6 PRG:21B6 B5
;==============================================================================
; $E1C0-$E1C9: Score Display Command Table
;==============================================================================
ScorePpuCommandTemplates:
.byte $23,$17,$3C,$3D,$00 ; CPU:$E1C0 PRG:21C0 23 17 3C 3D 00
.byte $23,$37,$3E,$3F,$FF ; CPU:$E1C5 PRG:21C5 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 ; CPU:$E1CA PRG:21CA 4A
lsr ; CPU:$E1CB PRG:21CB 4A
lsr ; CPU:$E1CC PRG:21CC 4A
lsr ; CPU:$E1CD PRG:21CD 4A
and #$0F ; CPU:$E1CE PRG:21CE 29 0F
cmp #$0A ; CPU:$E1D0 PRG:21D0 C9 0A
bcs @HexDigit ; CPU:$E1D2 PRG:21D2 B0 03
adc #$30 ; CPU:$E1D4 PRG:21D4 69 30
rts ; CPU:$E1D6 PRG:21D6 60
@HexDigit:
adc #$36 ; CPU:$E1D7 PRG:21D7 69 36
rts ; CPU:$E1D9 PRG:21D9 60
;==============================================================================
; $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 ; CPU:$E1DA PRG:21DA A5 1A
sta $02 ; CPU:$E1DC PRG:21DC 85 02
lda $1C ; CPU:$E1DE PRG:21DE A5 1C
sta $03 ; CPU:$E1E0 PRG:21E0 85 03
jsr $E263 ; CPU:$E1E2 PRG:21E2 20 63 E2
lda $03 ; CPU:$E1E5 PRG:21E5 A5 03
sta $0200 ; CPU:$E1E7 PRG:21E7 8D 00 02
lda $02 ; CPU:$E1EA PRG:21EA A5 02
sta $0201 ; CPU:$E1EC PRG:21EC 8D 01 02
ldx #$00 ; CPU:$E1EF PRG:21EF A2 00
ldy #$00 ; CPU:$E1F1 PRG:21F1 A0 00
@E1F2:
lda $1A,x ; CPU:$E1F3 PRG:21F3 B5 1A
sta $02 ; CPU:$E1F5 PRG:21F5 85 02
lda $1C,x ; CPU:$E1F7 PRG:21F7 B5 1C
sta $03 ; CPU:$E1F9 PRG:21F9 85 03
jsr $E263 ; CPU:$E1FB PRG:21FB 20 63 E2
lda #$20 ; CPU:$E1FE PRG:21FE A9 20
sta $14 ; CPU:$E200 PRG:2200 85 14
lda #$00 ; CPU:$E202 PRG:2202 A9 00
sta $15 ; CPU:$E204 PRG:2204 85 15
lda $02 ; CPU:$E206 PRG:2206 A5 02
sta $12 ; CPU:$E208 PRG:2208 85 12
lda $03 ; CPU:$E20A PRG:220A A5 03
sta $13 ; CPU:$E20C PRG:220C 85 13
jsr $E2D4 ; CPU:$E20E PRG:220E 20 D4 E2
lda $13 ; CPU:$E211 PRG:2211 A5 13
sta $0202,y ; CPU:$E213 PRG:2213 99 02 02
lda $12 ; CPU:$E216 PRG:2216 A5 12
iny ; CPU:$E218 PRG:2218 C8
sta $0202,y ; CPU:$E219 PRG:2219 99 02 02
lda $03 ; CPU:$E21C PRG:221C A5 03
iny ; CPU:$E21E PRG:221E C8
sta $0202,y ; CPU:$E21F PRG:221F 99 02 02
lda $02 ; CPU:$E222 PRG:2222 A5 02
sec ; CPU:$E224 PRG:2224 38
sbc #$01 ; CPU:$E225 PRG:2225 E9 01
iny ; CPU:$E227 PRG:2227 C8
sta $0202,y ; CPU:$E228 PRG:2228 99 02 02
lda #$20 ; CPU:$E22B PRG:222B A9 20
sta $14 ; CPU:$E22D PRG:222D 85 14
lda #$00 ; CPU:$E22F PRG:222F A9 00
sta $15 ; CPU:$E231 PRG:2231 85 15
lda $02 ; CPU:$E233 PRG:2233 A5 02
sta $12 ; CPU:$E235 PRG:2235 85 12
lda $03 ; CPU:$E237 PRG:2237 A5 03
sta $13 ; CPU:$E239 PRG:2239 85 13
jsr $E2C6 ; CPU:$E23B PRG:223B 20 C6 E2
lda $13 ; CPU:$E23E PRG:223E A5 13
iny ; CPU:$E240 PRG:2240 C8
sta $0202,y ; CPU:$E241 PRG:2241 99 02 02
lda $12 ; CPU:$E244 PRG:2244 A5 12
iny ; CPU:$E246 PRG:2246 C8
sta $0202,y ; CPU:$E247 PRG:2247 99 02 02
lda $03 ; CPU:$E24A PRG:224A A5 03
iny ; CPU:$E24C PRG:224C C8
sta $0202,y ; CPU:$E24D PRG:224D 99 02 02
lda $02 ; CPU:$E250 PRG:2250 A5 02
clc ; CPU:$E252 PRG:2252 18
adc #$01 ; CPU:$E253 PRG:2253 69 01
iny ; CPU:$E255 PRG:2255 C8
sta $0202,y ; CPU:$E256 PRG:2256 99 02 02
inx ; CPU:$E259 PRG:2259 E8
inx ; CPU:$E25A PRG:225A E8
inx ; CPU:$E25B PRG:225B E8
inx ; CPU:$E25C PRG:225C E8
iny ; CPU:$E25D PRG:225D C8
cpy #$28 ; CPU:$E25E PRG:225E C0 28
bne @E1F2 ; CPU:$E260 PRG:2260 D0 91
rts ; CPU:$E262 PRG:2262 60
;==============================================================================
; $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 ; CPU:$E263 PRG:2263 A9 00
sta $05 ; CPU:$E265 PRG:2265 85 05
lda $03 ; CPU:$E267 PRG:2267 A5 03
sec ; CPU:$E269 PRG:2269 38
sbc #$04 ; CPU:$E26A PRG:226A E9 04
and #$F8 ; CPU:$E26C PRG:226C 29 F8
asl ; CPU:$E26E PRG:226E 0A
rol $05 ; CPU:$E26F PRG:226F 26
asl ; CPU:$E270 PRG:2270 05
rol $05 ; CPU:$E271 PRG:2271 0A
clc ; CPU:$E272 PRG:2272 26
adc #$40 ; CPU:$E273 PRG:2273 05 18
sta $04 ; CPU:$E275 PRG:2275 69 40
lda #$00 ; CPU:$E277 PRG:2277 85 04
adc $05 ; CPU:$E279 PRG:2279 A9 00
sta $05 ; CPU:$E27B PRG:227B 65 05
lda $02 ; CPU:$E27D PRG:227D 85 05
sec ; CPU:$E27F PRG:227F A5
sbc #$04 ; CPU:$E280 PRG:2280 02 38
lsr ; CPU:$E282 PRG:2282 E9
lsr ; CPU:$E283 PRG:2283 04
lsr ; CPU:$E284 PRG:2284 4A
clc ; CPU:$E285 PRG:2285 4A
adc $04 ; CPU:$E286 PRG:2286 4A 18
sta $02 ; CPU:$E288 PRG:2288 65 04
lda $05 ; CPU:$E28A PRG:228A 85 02
clc ; CPU:$E28C PRG:228C A5
adc #$20 ; CPU:$E28D PRG:228D 05 18
sta $03 ; CPU:$E28F PRG:228F 69 20
lda $46 ; CPU:$E291 PRG:2291 85 03
and $47 ; CPU:$E293 PRG:2293 A5 46
bne @E299 ; CPU:$E295 PRG:2295 25 47
rts ; CPU:$E297 PRG:2297 D0
@E299:
lda $03 ; CPU:$E298 PRG:2298 01 60
clc ; CPU:$E29A PRG:229A A5
adc #$08 ; CPU:$E29B PRG:229B 03 18
sta $03 ; CPU:$E29D PRG:229D 69 08
rts ; CPU:$E29F PRG:229F 85
;==============================================================================
; $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 ; CPU:$E2A2 PRG:22A2 A2 00
ldy #$00 ; CPU:$E2A4 PRG:22A4 A0 00
lda PPUSTATUS ; CPU:$E2A6 PRG:22A6 AD 02 20
@E2A9:
lda $0200,x ; CPU:$E2A9 PRG:22A9 BD 00 02
sta PPUADDR ; CPU:$E2AC PRG:22AC 8D 06 20
inx ; CPU:$E2AF PRG:22AF E8
lda $0200,x ; CPU:$E2B0 PRG:22B0 BD 00 02
sta PPUADDR ; CPU:$E2B3 PRG:22B3 8D 06 20
; Buffered PPU read.
lda PPUDATA ; CPU:$E2B6 PRG:22B6 AD 07 20
; Actual requested value.
lda PPUDATA ; CPU:$E2B9 PRG:22B9 AD 07 20
sta $022A,y ; CPU:$E2BC PRG:22BC 99 2A 02
inx ; CPU:$E2BF PRG:22BF E8
iny ; CPU:$E2C0 PRG:22C0 C8
cpx #$2A ; CPU:$E2C1 PRG:22C1 E0 2A
bne @E2A9 ; CPU:$E2C3 PRG:22C3 D0 E4
rts ; CPU:$E2C5 PRG:22C5 60
;==============================================================================
; $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 ; CPU:$E2C6 PRG:22C6 18
lda $12 ; CPU:$E2C7 PRG:22C7 A5 12
adc $14 ; CPU:$E2C9 PRG:22C9 65 14
sta $12 ; CPU:$E2CB PRG:22CB 85 12
lda $13 ; CPU:$E2CD PRG:22CD A5 13
adc $15 ; CPU:$E2CF PRG:22CF 65 15
sta $13 ; CPU:$E2D1 PRG:22D1 85 13
rts ; CPU:$E2D3 PRG:22D3 60
;==============================================================================
; $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 ; CPU:$E2D4 PRG:22D4 38
lda $12 ; CPU:$E2D5 PRG:22D5 A5 12
sbc $14 ; CPU:$E2D7 PRG:22D7 E5 14
sta $12 ; CPU:$E2D9 PRG:22D9 85 12
lda $13 ; CPU:$E2DB PRG:22DB A5 13
sbc $15 ; CPU:$E2DD PRG:22DD E5 15
sta $13 ; CPU:$E2DF PRG:22DF 85 13
rts ; CPU:$E2E1 PRG:22E1 60
;==============================================================================
; $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 ; CPU:$E2E2 PRG:22E2 A9 20
sta $02 ; CPU:$E2E4 PRG:22E4 85 02
lda #$40 ; CPU:$E2E6 PRG:22E6 A9 40
sta $03 ; CPU:$E2E8 PRG:22E8 85 03
lda $47 ; CPU:$E2EA PRG:22EA A5 47
and $46 ; CPU:$E2EC PRG:22EC 25 46
beq @E2F4 ; CPU:$E2EE PRG:22EE F0 04
lda #$28 ; CPU:$E2F0 PRG:22F0 A9 28
sta $02 ; CPU:$E2F2 PRG:22F2 85 02
;------------------------------------------------------------------------------
; $E2F4
; Load compressed-map source pointer.
;------------------------------------------------------------------------------
@E2F4:
lda MazeDataPointerBytes+1 ; CPU:$E2F4 PRG:22F4 AD F7 FF
sta $01 ; CPU:$E2F7 PRG:22F7 85 01
lda MazeDataPointerBytes ; CPU:$E2F9 PRG:22F9 AD F6 FF
sta $00 ; CPU:$E2FC PRG:22FC 85 00
ldx #$1B ; CPU:$E2FE PRG:22FE A2 1B
ldy #$00 ; CPU:$E300 PRG:2300 A0 00
;------------------------------------------------------------------------------
; $E302
; Set PPU destination for the next row.
;------------------------------------------------------------------------------
@E302:
lda PPUSTATUS ; CPU:$E302 PRG:2302 AD 02 20
lda $02 ; CPU:$E305 PRG:2305 A5 02
sta PPUADDR ; CPU:$E307 PRG:2307 8D 06 20
lda $03 ; CPU:$E30A PRG:230A A5 03
sta PPUADDR ; CPU:$E30C PRG:230C 8D 06 20
lda #$16 ; CPU:$E30F PRG:230F A9 16
sta $04 ; CPU:$E311 PRG:2311 85 04
;------------------------------------------------------------------------------
; $E313
; Start decoding the next compressed source byte.
;------------------------------------------------------------------------------
@E313:
lda #$00 ; CPU:$E313 PRG:2313 A9 00
sta $05 ; CPU:$E315 PRG:2315 85 05
lda ($00),y ; CPU:$E317 PRG:2317 B1 00
asl ; CPU:$E319 PRG:2319 0A
rol $05 ; CPU:$E31A PRG:231A 26
asl ; CPU:$E31B PRG:231B 05
rol $05 ; CPU:$E31C PRG:231C 0A
lda ($00),y ; CPU:$E31D PRG:231D 26 05
and #$3F ; CPU:$E31F PRG:231F B1 00
;------------------------------------------------------------------------------
; $E321
; Repeat the decoded value according to the repeat count in $05.
;------------------------------------------------------------------------------
@E321:
sta PPUDATA ; CPU:$E321 PRG:2321 29 3F 8D
dec $04 ; CPU:$E324 PRG:2324 07 20
dec $05 ; CPU:$E326 PRG:2326 C6 04
bpl @E321 ; CPU:$E328 PRG:2328 C6 05
iny ; CPU:$E32A PRG:232A 10
bne @E32F ; CPU:$E32B PRG:232B F7 C8
inc $01 ; CPU:$E32D PRG:232D D0 02
;------------------------------------------------------------------------------
; $E32F
; Continue until the current row contains $16 output bytes.
;------------------------------------------------------------------------------
@E32F:
lda $04 ; CPU:$E32F PRG:232F E6 01
bne @E313 ; CPU:$E331 PRG:2331 A5 04
lda $03 ; CPU:$E333 PRG:2333 D0 DE
clc ; CPU:$E335 PRG:2335 A5
adc #$20 ; CPU:$E336 PRG:2336 03 18
sta $03 ; CPU:$E338 PRG:2338 69 20
lda $02 ; CPU:$E33A PRG:233A 85 03
adc #$00 ; CPU:$E33C PRG:233C A5 02
sta $02 ; CPU:$E33E PRG:233E 69 00
dex ; CPU:$E340 PRG:2340 85
bne @E302 ; CPU:$E341 PRG:2341 02 CA
;==============================================================================
; $E345-$E381: Draw additional nametable decoration strips.
;==============================================================================
ldy #$02 ; CPU:$E343 PRG:2343 D0 BD
lda #$21 ; CPU:$E345 PRG:2345 A0 02
sta $00 ; CPU:$E347 PRG:2347 A9 21
lda #$D6 ; CPU:$E349 PRG:2349 85 00
sta $01 ; CPU:$E34B PRG:234B A9 D6
lda $47 ; CPU:$E34D PRG:234D 85 01
and $46 ; CPU:$E34F PRG:234F A5 47
beq @E359 ; CPU:$E351 PRG:2351 25 46
lda #$29 ; CPU:$E353 PRG:2353 F0 04
sta $00 ; CPU:$E355 PRG:2355 A9 29
;------------------------------------------------------------------------------
; $E359
; Start one decoration strip.
;------------------------------------------------------------------------------
@E359:
ldx #$07 ; CPU:$E357 PRG:2357 85 00
lda PPUSTATUS ; CPU:$E359 PRG:2359 A2 07 AD
lda $00 ; CPU:$E35C PRG:235C 02 20
sta PPUADDR ; CPU:$E35E PRG:235E A5 00 8D
lda $01 ; CPU:$E361 PRG:2361 06 20
sta PPUADDR ; CPU:$E363 PRG:2363 A5 01 8D
lda MazeNametableDecorationTiles,y ; CPU:$E366 PRG:2366 06 20 B9
;------------------------------------------------------------------------------
; $E36B
; Write the selected table value eight times.
;------------------------------------------------------------------------------
@E36B:
sta PPUDATA ; CPU:$E369 PRG:2369 82 E3 8D
dex ; CPU:$E36C PRG:236C 07
bpl @E36B ; CPU:$E36D PRG:236D 20 CA
lda $01 ; CPU:$E36F PRG:236F 10 FA
clc ; CPU:$E371 PRG:2371 A5
adc #$20 ; CPU:$E372 PRG:2372 01 18
sta $01 ; CPU:$E374 PRG:2374 69 20
lda #$00 ; CPU:$E376 PRG:2376 85 01
adc $00 ; CPU:$E378 PRG:2378 A9 00
sta $00 ; CPU:$E37A PRG:237A 65 00
dey ; CPU:$E37C PRG:237C 85
bpl @E359 ; CPU:$E37D PRG:237D 00 88
rts ; CPU:$E37F PRG:237F 10
;==============================================================================
; $E382-$E385: Gameplay Nametable Decoration Table
;==============================================================================
MazeNametableDecorationTiles:
.byte $2D,$04,$2D ; CPU:$E382 PRG:2382 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 ; CPU:$E385 PRG:2385 AD 02 20
lda #$20 ; CPU:$E388 PRG:2388 A9 20
sta PPUADDR ; CPU:$E38A PRG:238A 8D 06 20
lda #$00 ; CPU:$E38D PRG:238D A9 00
sta PPUADDR ; CPU:$E38F PRG:238F 8D 06 20
lda #$01 ; CPU:$E392 PRG:2392 A9 01
sta $02 ; CPU:$E394 PRG:2394 85 02
;------------------------------------------------------------------------------
; $E396
; Shared entry used for another nametable pass.
;------------------------------------------------------------------------------
ClearGameplayNametablesSecondPass:
lda #$01 ; CPU:$E396 PRG:2396 A9 01
sta $03 ; CPU:$E398 PRG:2398 85 03
;------------------------------------------------------------------------------
; $E39A
; Initialize fill counters.
;------------------------------------------------------------------------------
InitializeNametableFillCounters:
lda #$03 ; CPU:$E39A PRG:239A A9 03
sta $00 ; CPU:$E39C PRG:239C 85 00
lda #$C0 ; CPU:$E39E PRG:239E A9 C0
sta $01 ; CPU:$E3A0 PRG:23A0 85 01
lda #$2D ; CPU:$E3A2 PRG:23A2 A9 2D
;------------------------------------------------------------------------------
; $E3A4
; Shared fill loop.
;------------------------------------------------------------------------------
FillNametableByte:
sta PPUDATA ; CPU:$E3A4 PRG:23A4 8D 07 20
dec $01 ; CPU:$E3A7 PRG:23A7 C6 01
bne FillNametableByte ; CPU:$E3A9 PRG:23A9 D0 F9
dec $00 ; CPU:$E3AB PRG:23AB C6 00
bpl FillNametableByte ; CPU:$E3AD PRG:23AD 10 F5
dec $03 ; CPU:$E3AF PRG:23AF C6 03
bne AdvanceNametableFillPass ; CPU:$E3B1 PRG:23B1 D0 08
lda #$40 ; CPU:$E3B3 PRG:23B3 A9 40
sta $01 ; CPU:$E3B5 PRG:23B5 85 01
lda #$00 ; CPU:$E3B7 PRG:23B7 A9 00
beq FillNametableByte ; CPU:$E3B9 PRG:23B9 F0 E9
;------------------------------------------------------------------------------
; $E3BB
; Advance to alternate nametable / next phase.
;------------------------------------------------------------------------------
AdvanceNametableFillPass:
dec $02 ; CPU:$E3BB PRG:23BB C6 02
bne ClearGameplayAttributeTables ; CPU:$E3BD PRG:23BD D0 10
lda PPUSTATUS ; CPU:$E3BF PRG:23BF AD 02 20
lda #$28 ; CPU:$E3C2 PRG:23C2 A9 28
sta PPUADDR ; CPU:$E3C4 PRG:23C4 8D 06 20
lda #$00 ; CPU:$E3C7 PRG:23C7 A9 00
sta PPUADDR ; CPU:$E3C9 PRG:23C9 8D 06 20
jmp ClearGameplayNametablesSecondPass ; CPU:$E3CC PRG:23CC 4C 96 E3
;------------------------------------------------------------------------------
; $E3CF
; Begin clearing attribute-table regions.
;------------------------------------------------------------------------------
ClearGameplayAttributeTables:
lda #$01 ; CPU:$E3CF PRG:23CF A9 01
sta $00 ; CPU:$E3D1 PRG:23D1 85 00
lda PPUSTATUS ; CPU:$E3D3 PRG:23D3 AD 02 20
lda #$23 ; CPU:$E3D6 PRG:23D6 A9 23
sta PPUADDR ; CPU:$E3D8 PRG:23D8 8D 06 20
lda #$C0 ; CPU:$E3DB PRG:23DB A9 C0
sta PPUADDR ; CPU:$E3DD PRG:23DD 8D 06 20
;------------------------------------------------------------------------------
; $E3E0
; Shared attribute-clear setup.
;------------------------------------------------------------------------------
BeginAttributeTableClear:
lda #$00 ; CPU:$E3E0 PRG:23E0 A9 00
tay ; CPU:$E3E2 PRG:23E2 A8
;------------------------------------------------------------------------------
; $E3E3
; Write $20 zero bytes to PPUDATA.
;------------------------------------------------------------------------------
ClearAttributeTableLoop:
sta PPUDATA ; CPU:$E3E3 PRG:23E3 8D 07 20
iny ; CPU:$E3E6 PRG:23E6 C8
cpy #$20 ; CPU:$E3E7 PRG:23E7 C0 20
bne ClearAttributeTableLoop ; CPU:$E3E9 PRG:23E9 D0 F8
dec $00 ; CPU:$E3EB PRG:23EB C6 00
bne ClearSecondAttributeTable ; CPU:$E3ED PRG:23ED D0 01
rts ; CPU:$E3EF PRG:23EF 60
;------------------------------------------------------------------------------
; $E3F0
; Set destination to the second attribute table, $2BC0.
;------------------------------------------------------------------------------
ClearSecondAttributeTable:
lda PPUSTATUS ; CPU:$E3F0 PRG:23F0 AD 02 20
lda #$2B ; CPU:$E3F3 PRG:23F3 A9 2B
sta PPUADDR ; CPU:$E3F5 PRG:23F5 8D 06 20
lda #$C0 ; CPU:$E3F8 PRG:23F8 A9 C0
sta PPUADDR ; CPU:$E3FA PRG:23FA 8D 06 20
bne BeginAttributeTableClear ; CPU:$E3FD PRG:23FD D0 E1
;==============================================================================
; $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 ; CPU:$E3FF PRG:23FF A9 20
sta $00 ; CPU:$E401 PRG:2401 85 00
lda #$B6 ; CPU:$E403 PRG:2403 A9 B6
sta $01 ; CPU:$E405 PRG:2405 85 01
lda #$80 ; CPU:$E407 PRG:2407 A9 80
sta $04 ; CPU:$E409 PRG:2409 85 04
ldx #$00 ; CPU:$E40B PRG:240B A2 00
lda $47 ; CPU:$E40D PRG:240D A5 47
and $46 ; CPU:$E40F PRG:240F 25 46
beq @E429 ; CPU:$E411 PRG:2411 F0 18
lda #$28 ; CPU:$E413 PRG:2413 A9 28
sta $00 ; CPU:$E415 PRG:2415 85 00
bne @E429 ; CPU:$E417 PRG:2417 D0 12
;------------------------------------------------------------------------------
; Alternate setup path.
;------------------------------------------------------------------------------
lda #$20 ; CPU:$E419 PRG:2419 A9 20
sta $00 ; CPU:$E41B PRG:241B 85 00
lda #$83 ; CPU:$E41D PRG:241D A9 83
sta $01 ; CPU:$E41F PRG:241F 85 01
lda #$09 ; CPU:$E421 PRG:2421 A9 09
sta $04 ; CPU:$E423 PRG:2423 85 04
lda #$01 ; CPU:$E425 PRG:2425 A9 01
sta $47 ; CPU:$E427 PRG:2427 85 47
ldx #$0C ; CPU:$E429 PRG:2429 A2 0C
;------------------------------------------------------------------------------
; $E429
; Adjust lookup-table index for alternate player/mode state.
;------------------------------------------------------------------------------
@E429:
lda $47 ; CPU:$E42B PRG:242B A5 47
and $46 ; CPU:$E42D PRG:242D 25 46
beq @E436 ; CPU:$E42F PRG:242F F0 05
txa ; CPU:$E431 PRG:2431 8A
clc ; CPU:$E432 PRG:2432 18
adc #$06 ; CPU:$E433 PRG:2433 69 06
tax ; CPU:$E435 PRG:2435 AA
@E436:
lda #$03 ; CPU:$E436 PRG:2436 A9 03
sta $05 ; CPU:$E438 PRG:2438 85 05
;------------------------------------------------------------------------------
; $E43A: render one status field.
;------------------------------------------------------------------------------
@E43A:
lda PPUSTATUS ; CPU:$E43A PRG:243A AD 02 20
lda $00 ; CPU:$E43D PRG:243D A5 00
sta PPUADDR ; CPU:$E43F PRG:243F 8D 06 20
lda $01 ; CPU:$E442 PRG:2442 A5 01
sta PPUADDR ; CPU:$E444 PRG:2444 8D 06 20
lda ScoreFieldSourcePointerTable,x ; CPU:$E447 PRG:2447 BD 9F E4
sta $02 ; CPU:$E44A PRG:244A 85 02
lda ScoreFieldSourcePointerTable+1,x ; CPU:$E44C PRG:244C BD A0 E4
sta $03 ; CPU:$E44F PRG:244F 85 03
jsr DrawSixDigitScore ; CPU:$E451 PRG:2451 20 74 E4
inx ; CPU:$E454 PRG:2454 E8
inx ; CPU:$E455 PRG:2455 E8
lda $01 ; CPU:$E456 PRG:2456 A5 01
clc ; CPU:$E458 PRG:2458 18
adc $04 ; CPU:$E459 PRG:2459 65 04
sta $01 ; CPU:$E45B PRG:245B 85 01
lda #$00 ; CPU:$E45D PRG:245D A9 00
adc $00 ; CPU:$E45F PRG:245F 65 00
sta $00 ; CPU:$E461 PRG:2461 85 00
dec $05 ; CPU:$E463 PRG:2463 C6 05
lda $05 ; CPU:$E465 PRG:2465 A5 05
cmp #$01 ; CPU:$E467 PRG:2467 C9 01
bne @E46D ; CPU:$E469 PRG:2469 D0 04
lda $47 ; CPU:$E46B PRG:246B A5 47
beq @E473 ; CPU:$E46D PRG:246D F0 04
@E46D:
lda $05 ; CPU:$E46F PRG:246F A5 05
bne @E43A ; CPU:$E471 PRG:2471 D0 C7
@E473:
rts ; CPU:$E473 PRG:2473 60
;==============================================================================
; $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 ; CPU:$E474 PRG:2474 A0 05
SkipLeadingZeroDigits:
lda ($02),y ; CPU:$E476 PRG:2476 B1 02
and #$0F ; CPU:$E478 PRG:2478 29 0F
bne ConvertCurrentScoreDigit ; CPU:$E47A PRG:247A D0 0C
lda #$20 ; CPU:$E47C PRG:247C A9 20
sta PPUDATA ; CPU:$E47E PRG:247E 8D 07 20
dey ; CPU:$E481 PRG:2481 88
bne SkipLeadingZeroDigits ; CPU:$E482 PRG:2482 D0 F2
beq DrawFinalScoreDigit ; CPU:$E484 PRG:2484 F0 0B
LoadNextScoreDigit:
lda ($02),y ; CPU:$E486 PRG:2486 B1 02
ConvertCurrentScoreDigit:
jsr $E1CE ; CPU:$E488 PRG:2488 20 CE E1
sta PPUDATA ; CPU:$E48B PRG:248B 8D 07 20
dey ; CPU:$E48E PRG:248E 88
bne LoadNextScoreDigit ; CPU:$E48F PRG:248F D0 F5
DrawFinalScoreDigit:
lda ($02),y ; CPU:$E491 PRG:2491 B1 02
jsr $E1CE ; CPU:$E493 PRG:2493 20 CE E1
sta PPUDATA ; CPU:$E496 PRG:2496 8D 07 20
lda #$30 ; CPU:$E499 PRG:2499 A9 30
sta PPUDATA ; CPU:$E49B PRG:249B 8D 07 20
rts ; CPU:$E49E PRG:249E 60
;==============================================================================
; $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 ; CPU:$E49F PRG:249F 61 00
.word $0070 ; CPU:$E4A1 PRG:24A1 70 00
.word $0080 ; CPU:$E4A3 PRG:24A3 80 00
.word $0061 ; CPU:$E4A5 PRG:24A5 61 00
.word $0080 ; CPU:$E4A7 PRG:24A7 80 00
.word $0070 ; CPU:$E4A9 PRG:24A9 70 00
.word $0070 ; CPU:$E4AB PRG:24AB 70 00
.word $0061 ; CPU:$E4AD PRG:24AD 61 00
.word $0080 ; CPU:$E4AF PRG:24AF 80 00
;==============================================================================
; $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 ; CPU:$E4B1 PRG:24B1 A0 FF
sty $0C ; CPU:$E4B3 PRG:24B3 84 0C
sty $0D ; CPU:$E4B5 PRG:24B5 84 0D
sty $0E ; CPU:$E4B7 PRG:24B7 84 0E
sty $0F ; CPU:$E4B9 PRG:24B9 84 0F
iny ; CPU:$E4BB PRG:24BB C8
ScanDirectionCandidate:
lda ($00),y ; CPU:$E4BC PRG:24BC B1 00
cmp $0A ; CPU:$E4BE PRG:24BE C5 0A
beq AcceptDirectionCandidate ; CPU:$E4C0 PRG:24C0 F0 08
and #$F8 ; CPU:$E4C2 PRG:24C2 29 F8
beq AcceptDirectionCandidate ; CPU:$E4C4 PRG:24C4 F0 04
cmp $0B ; CPU:$E4C6 PRG:24C6 C5 0B
bne NextDirectionCandidate ; CPU:$E4C8 PRG:24C8 D0 04
AcceptDirectionCandidate:
tya ; CPU:$E4CA PRG:24CA 98
sta $000C,y ; CPU:$E4CB PRG:24CB 99 0C 00
NextDirectionCandidate:
iny ; CPU:$E4CE PRG:24CE C8
cpy #$04 ; CPU:$E4CF PRG:24CF C0 04
bne ScanDirectionCandidate ; CPU:$E4D1 PRG:24D1 D0 E9
lda $B9,x ; CPU:$E4D3 PRG:24D3 B5 B9
clc ; CPU:$E4D5 PRG:24D5 18
adc #$02 ; CPU:$E4D6 PRG:24D6 69 02
and #$03 ; CPU:$E4D8 PRG:24D8 29 03
tay ; CPU:$E4DA PRG:24DA A8
lda #$FF ; CPU:$E4DB PRG:24DB A9 FF
sta $000C,y ; CPU:$E4DD PRG:24DD 99 0C 00
lda #$03 ; CPU:$E4E0 PRG:24E0 A9 03
sta $0B ; CPU:$E4E2 PRG:24E2 85 0B
CompactDirectionListPass:
ldy #$00 ; CPU:$E4E4 PRG:24E4 A0 00
CompactDirectionListEntry:
lda $000C,y ; CPU:$E4E6 PRG:24E6 B9 0C 00
cmp #$FF ; CPU:$E4E9 PRG:24E9 C9 FF
bne NextDirectionListEntry ; CPU:$E4EB PRG:24EB D0 0B
lda $000D,y ; CPU:$E4ED PRG:24ED B9 0D 00
sta $000C,y ; CPU:$E4F0 PRG:24F0 99 0C 00
lda #$FF ; CPU:$E4F3 PRG:24F3 A9 FF
sta $000D,y ; CPU:$E4F5 PRG:24F5 99 0D 00
NextDirectionListEntry:
iny ; CPU:$E4F8 PRG:24F8 C8
cpy #$03 ; CPU:$E4F9 PRG:24F9 C0 03
bne CompactDirectionListEntry ; CPU:$E4FB PRG:24FB D0 E9
dec $0B ; CPU:$E4FD PRG:24FD C6 0B
bne CompactDirectionListPass ; CPU:$E4FF PRG:24FF D0 E3
rts ; CPU:$E501 PRG:2501 60
;==============================================================================
; $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 ; CPU:$E502 PRG:2502 A2 01
;------------------------------------------------------------------------------
; $E504
; Reset command-stream index for a pass.
;------------------------------------------------------------------------------
InitData_E504:
ldy #$00 ; CPU:$E504 PRG:2504 A0 00
;------------------------------------------------------------------------------
; $E506
; Start one command record.
;------------------------------------------------------------------------------
InitData_E506:
lda $E53C,y ; CPU:$E506 PRG:2506 B9 3C E5
cpx #$00 ; CPU:$E509 PRG:2509 E0 00
bne InitData_E50F ; CPU:$E50B PRG:250B D0 02
adc #$07 ; CPU:$E50D PRG:250D 69 07
;------------------------------------------------------------------------------
; $E50F
; Write PPU destination address.
;------------------------------------------------------------------------------
InitData_E50F:
sta PPUADDR ; CPU:$E50F PRG:250F 8D 06 20
iny ; CPU:$E512 PRG:2512 C8
lda $E53C,y ; CPU:$E513 PRG:2513 B9 3C E5
sta PPUADDR ; CPU:$E516 PRG:2516 8D 06 20
iny ; CPU:$E519 PRG:2519 C8
lda $E53C,y ; CPU:$E51A PRG:251A B9 3C E5
sta $00 ; CPU:$E51D PRG:251D 85 00
;------------------------------------------------------------------------------
; $E51F
; Write record payload.
;------------------------------------------------------------------------------
InitData_E51F:
iny ; CPU:$E51F PRG:251F C8
lda $E53C,y ; CPU:$E520 PRG:2520 B9 3C E5
sta PPUDATA ; CPU:$E523 PRG:2523 8D 07 20
dec $00 ; CPU:$E526 PRG:2526 C6 00
bne InitData_E51F ; CPU:$E528 PRG:2528 D0 F5
iny ; CPU:$E52A PRG:252A C8
cpy #$11 ; CPU:$E52B PRG:252B C0 11
bne InitData_E534 ; CPU:$E52D PRG:252D D0 05
lda $47 ; CPU:$E52F PRG:252F A5 47
bne InitData_E534 ; CPU:$E531 PRG:2531 D0 01
rts ; CPU:$E533 PRG:2533 60
;------------------------------------------------------------------------------
; $E534
; Continue through the first/second stream section.
;------------------------------------------------------------------------------
InitData_E534:
cpy #$17 ; CPU:$E534 PRG:2534 C0 17
bne InitData_E506 ; CPU:$E536 PRG:2536 D0 CE
dex ; CPU:$E538 PRG:2538 CA
beq InitData_E504 ; CPU:$E539 PRG:2539 F0 C9
rts ; CPU:$E53B PRG:253B 60
;==============================================================================
; $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 ; CPU:$E53C PRG:253C 20 76 08
.byte $B4,$B5,$B6,$B7,$B8,$B9,$BA,$BB ; CPU:$E53F PRG:253F B4 B5 B6 B7 B8 B9 BA BB
; $E547: PPU $20F7, 3-byte payload
.byte $20,$F7,$03 ; CPU:$E547 PRG:2547 20 F7 03
.byte $B0,$B3,$B2 ; CPU:$E54A PRG:254A B0 B3 B2
; $E54D: PPU $2177, 3-byte payload
.byte $21,$77,$03 ; CPU:$E54D PRG:254D 21 77 03
.byte $B1,$B3,$B2 ; CPU:$E550 PRG:2550 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 ; CPU:$E553 PRG:2553 A5 67
bne Progression_E558 ; CPU:$E555 PRG:2555 D0 01
rts ; CPU:$E557 PRG:2557 60
Progression_E558:
clc ; CPU:$E558 PRG:2558 18
adc #$01 ; CPU:$E559 PRG:2559 69 01
cmp #$07 ; CPU:$E55B PRG:255B C9 07
bcc Progression_E55F ; CPU:$E55D PRG:255D 90 02
lda #$07 ; CPU:$E55F PRG:255F A9 07
Progression_E55F:
sta $02 ; CPU:$E561 PRG:2561 85 02
lda #$04 ; CPU:$E563 PRG:2563 A9 04
sta $03 ; CPU:$E565 PRG:2565 85 03
lda #$23 ; CPU:$E567 PRG:2567 A9 23
sta $00 ; CPU:$E569 PRG:2569 85 00
lda #$17 ; CPU:$E56B PRG:256B A9 17
sta $01 ; CPU:$E56D PRG:256D 85 01
lda $46 ; CPU:$E56F PRG:256F A5 46
and $47 ; CPU:$E571 PRG:2571 25 47
beq Progression_E57C ; CPU:$E573 PRG:2573 F0 07
lda $00 ; CPU:$E575 PRG:2575 A5 00
clc ; CPU:$E577 PRG:2577 18
adc #$08 ; CPU:$E578 PRG:2578 69 08
sta $00 ; CPU:$E57A PRG:257A 85 00
Progression_E57C:
dec $02 ; CPU:$E57C PRG:257C C6 02
bne Progression_E581 ; CPU:$E57E PRG:257E D0 01
rts ; CPU:$E580 PRG:2580 60
Progression_E581:
dec $03 ; CPU:$E581 PRG:2581 C6 03
bne Progression_E58A ; CPU:$E583 PRG:2583 D0 07
lda $01 ; CPU:$E585 PRG:2585 A5 01
clc ; CPU:$E587 PRG:2587 18
adc #$3A ; CPU:$E588 PRG:2588 69 3A
sta $01 ; CPU:$E58A PRG:258A 85 01
Progression_E58A:
ldy #$3C ; CPU:$E58C PRG:258C A0 3C
jsr Draw2x2Marker ; CPU:$E58E PRG:258E 20 9A E5
lda $01 ; CPU:$E591 PRG:2591 A5 01
clc ; CPU:$E593 PRG:2593 18
adc #$02 ; CPU:$E594 PRG:2594 69 02
sta $01 ; CPU:$E596 PRG:2596 85 01
bne Progression_E57C ; CPU:$E598 PRG:2598 D0 E2
;==============================================================================
; $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 ; CPU:$E59A PRG:259A A5 00
sta PPUADDR ; CPU:$E59C PRG:259C 8D 06 20
lda $01 ; CPU:$E59F PRG:259F A5 01
sta PPUADDR ; CPU:$E5A1 PRG:25A1 8D 06 20
sty PPUDATA ; CPU:$E5A4 PRG:25A4 8C 07 20
iny ; CPU:$E5A7 PRG:25A7 C8
sty PPUDATA ; CPU:$E5A8 PRG:25A8 8C 07 20
lda $00 ; CPU:$E5AB PRG:25AB A5 00
sta PPUADDR ; CPU:$E5AD PRG:25AD 8D 06 20
lda $01 ; CPU:$E5B0 PRG:25B0 A5 01
clc ; CPU:$E5B2 PRG:25B2 18
adc #$20 ; CPU:$E5B3 PRG:25B3 69 20
sta PPUADDR ; CPU:$E5B5 PRG:25B5 8D 06 20
iny ; CPU:$E5B8 PRG:25B8 C8
sty PPUDATA ; CPU:$E5B9 PRG:25B9 8C 07 20
iny ; CPU:$E5BC PRG:25BC C8
sty PPUDATA ; CPU:$E5BD PRG:25BD 8C 07 20
rts ; CPU:$E5C0 PRG:25C0 60
;==============================================================================
; $-$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 ; CPU:$E5C1 PRG:25C1 A9 00
sta $03 ; CPU:$E5C3 PRG:25C3 85 03
sta $0E ; CPU:$E5C5 PRG:25C5 85 0E
sta $0F ; CPU:$E5C7 PRG:25C7 85 0F
lda #$15 ; CPU:$E5C9 PRG:25C9 A9 15
sta $0A ; CPU:$E5CB PRG:25CB 85 0A
lda #$11 ; CPU:$E5CD PRG:25CD A9 11
sta $0D ; CPU:$E5CF PRG:25CF 85 0D
lda #$05 ; CPU:$E5D1 PRG:25D1 A9 05
sta $0B ; CPU:$E5D3 PRG:25D3 85 0B
sta $0C ; CPU:$E5D5 PRG:25D5 85 0C
lda $68 ; CPU:$E5D7 PRG:25D7 A5 68
sta $02 ; CPU:$E5D9 PRG:25D9 85 02
sec ; CPU:$E5DB PRG:25DB 38
sbc #$07 ; CPU:$E5DC PRG:25DC E9 07
bcc UseFirstLevelProgressIndex ; CPU:$E5DE PRG:25DE 90 0D
cmp #$0C ; CPU:$E5E0 PRG:25E0 C9 0C
bcc ClampLevelProgressIndex ; CPU:$E5E2 PRG:25E2 90 02
lda #$0C ; CPU:$E5E4 PRG:25E4 A9 0C
;------------------------------------------------------------------------------
; $E5E9
;------------------------------------------------------------------------------
ClampLevelProgressIndex:
tax ; CPU:$E5E6 PRG:25E6 AA
lda #$07 ; CPU:$E5E7 PRG:25E7 A9 07
sta $02 ; CPU:$E5E9 PRG:25E9 85 02
bne InitializeLevelProgressPosition ; CPU:$E5EB PRG:25EB D0 02
;------------------------------------------------------------------------------
; $E5F0
;------------------------------------------------------------------------------
UseFirstLevelProgressIndex:
ldx #$00 ; CPU:$E5ED PRG:25ED A2 00
;------------------------------------------------------------------------------
; $E5F2
; Initial PPU destination.
;------------------------------------------------------------------------------
InitializeLevelProgressPosition:
lda #$22 ; CPU:$E5EF PRG:25EF A9 22
sta $00 ; CPU:$E5F1 PRG:25F1 85 00
lda #$56 ; CPU:$E5F3 PRG:25F3 A9 56
sta $01 ; CPU:$E5F5 PRG:25F5 85 01
lda $46 ; CPU:$E5F7 PRG:25F7 A5 46
and $47 ; CPU:$E5F9 PRG:25F9 25 47
beq InitializeLevelProgressRowCounter ; CPU:$E5FB PRG:25FB F0 07
lda $00 ; CPU:$E5FD PRG:25FD A5 00
clc ; CPU:$E5FF PRG:25FF 18
adc #$08 ; CPU:$E600 PRG:2600 69 08
sta $00 ; CPU:$E602 PRG:2602 85 00
;------------------------------------------------------------------------------
; $E605
;------------------------------------------------------------------------------
InitializeLevelProgressRowCounter:
lda #$05 ; CPU:$E604 PRG:2604 A9 05
sta $04 ; CPU:$E606 PRG:2606 85 04
;------------------------------------------------------------------------------
; $E609
; Main marker loop.
;------------------------------------------------------------------------------
DrawNextLevelProgressMarker:
dec $04 ; CPU:$E608 PRG:2608 C6 04
bne SelectLevelProgressMarker ; CPU:$E60A PRG:260A D0 07
lda $01 ; CPU:$E60C PRG:260C A5 01
clc ; CPU:$E60E PRG:260E 18
adc #$38 ; CPU:$E60F PRG:260F 69 38
sta $01 ; CPU:$E611 PRG:2611 85 01
;------------------------------------------------------------------------------
; $E612
; Select marker information.
;------------------------------------------------------------------------------
SelectLevelProgressMarker:
lda LevelProgressMarkerIndexTable,x ; CPU:$E613 PRG:2613 BD 9A E6
sta $05 ; CPU:$E616 PRG:2616 85 05
asl ; CPU:$E618 PRG:2618 0A
asl ; CPU:$E619 PRG:2619 0A
adc #$60 ; CPU:$E61A PRG:261A 69 60
tay ; CPU:$E61C PRG:261C A8
jsr Draw2x2Marker ; CPU:$E61D PRG:261D 20 9A E5
ldy $03 ; CPU:$E620 PRG:2620 A4 03
lda LevelProgressAttributeIndexTable,y ; CPU:$E622 PRG:2622 B9 AE E6
sta $06 ; CPU:$E625 PRG:2625 85 06
lda LevelProgressAttributeIndexTable+1,y ; CPU:$E627 PRG:2627 B9 AF E6
sta $07 ; CPU:$E62A PRG:262A 85 07
ldy $05 ; CPU:$E62C PRG:262C A4 05
lda LevelProgressAttributeBits,y ; CPU:$E62E PRG:262E B9 BE E6
;------------------------------------------------------------------------------
; $E633
; Shift selected marker bits.
;------------------------------------------------------------------------------
ShiftLevelProgressAttributeBits:
dec $07 ; CPU:$E631 PRG:2631 C6 07
bmi StoreLevelProgressAttributeBits ; CPU:$E633 PRG:2633 30 04
asl ; CPU:$E635 PRG:2635 0A
asl ; CPU:$E636 PRG:2636 0A
bcc ShiftLevelProgressAttributeBits ; CPU:$E637 PRG:2637 90 F8
;------------------------------------------------------------------------------
; $E63B
; Combine marker bits into working values.
;------------------------------------------------------------------------------
StoreLevelProgressAttributeBits:
ldy $06 ; CPU:$E639 PRG:2639 A4 06
ora $0A,y ; CPU:$E63B PRG:263B 19 0A
sta $0A,y ; CPU:$E63D PRG:263D 00 99
lda $01 ; CPU:$E63F PRG:263F 0A 00
clc ; CPU:$E641 PRG:2641 A5
adc #$02 ; CPU:$E642 PRG:2642 01 18
sta $01 ; CPU:$E644 PRG:2644 69 02
inc $03 ; CPU:$E646 PRG:2646 85 01
inc $03 ; CPU:$E648 PRG:2648 E6 03
inx ; CPU:$E64A PRG:264A E6
dec $02 ; CPU:$E64B PRG:264B 03 E8
bpl DrawNextLevelProgressMarker ; CPU:$E64D PRG:264D C6 02
;==============================================================================
; Write generated marker-state values into PPU memory.
;==============================================================================
ldx #$23 ; CPU:$E64F PRG:264F 10 B7
lda $47 ; CPU:$E651 PRG:2651 A2 23
and $46 ; CPU:$E653 PRG:2653 A5 47
beq SetLevelProgressAttributeAddress ; CPU:$E655 PRG:2655 25 46
ldx #$2B ; CPU:$E657 PRG:2657 F0 02
;------------------------------------------------------------------------------
; $E65D
; Set first PPU destination.
;------------------------------------------------------------------------------
SetLevelProgressAttributeAddress:
stx PPUADDR ; CPU:$E65B PRG:265B 8E 06 20
stx $00 ; CPU:$E65E PRG:265E 86 00
lda #$E5 ; CPU:$E660 PRG:2660 A9 E5
sta PPUADDR ; CPU:$E662 PRG:2662 8D 06 20
ldx #$00 ; CPU:$E665 PRG:2665 A2 00
;------------------------------------------------------------------------------
; $E667
; Reset count for one three-byte PPU group.
;------------------------------------------------------------------------------
ResetAttributeWriteCount:
lda #$03 ; CPU:$E667 PRG:2667 A9 03
sta $01 ; CPU:$E669 PRG:2669 85 01
;------------------------------------------------------------------------------
; $E66B
; Write three values from $0A+.
;------------------------------------------------------------------------------
WriteLevelProgressAttribute:
lda $0A,x ; CPU:$E66B PRG:266B B5 0A
sta PPUDATA ; CPU:$E66D PRG:266D 8D 07 20
inx ; CPU:$E670 PRG:2670 E8
dec $01 ; CPU:$E671 PRG:2671 C6 01
bne WriteLevelProgressAttribute ; CPU:$E673 PRG:2673 D0 F6
inc $02 ; CPU:$E675 PRG:2675 E6 02
bne SelectLevelProgressPalette ; CPU:$E677 PRG:2677 D0 0C
lda $00 ; CPU:$E679 PRG:2679 A5 00
sta PPUADDR ; CPU:$E67B PRG:267B 8D 06 20
lda #$ED ; CPU:$E67E PRG:267E A9 ED
sta PPUADDR ; CPU:$E680 PRG:2680 8D 06 20
bne ResetAttributeWriteCount ; CPU:$E683 PRG:2683 D0 E2
;------------------------------------------------------------------------------
; $E685
; Select final marker/display value.
;------------------------------------------------------------------------------
SelectLevelProgressPalette:
lda $68 ; CPU:$E685 PRG:2685 A5 68
cmp #$10 ; CPU:$E687 PRG:2687 C9 10
bcc StoreLevelProgressPalette ; CPU:$E689 PRG:2689 90 02
lda #$0F ; CPU:$E68B PRG:268B A9 0F
;------------------------------------------------------------------------------
; $E68D
;------------------------------------------------------------------------------
StoreLevelProgressPalette:
tay ; CPU:$E68D PRG:268D A8
lda LevelProgressPaletteTable,y ; CPU:$E68E PRG:268E B9 C6 E6
sta $02B6 ; CPU:$E691 PRG:2691 8D B6 02
lda #$0F ; CPU:$E694 PRG:2694 A9 0F
sta $02A9 ; CPU:$E696 PRG:2696 8D A9 02
rts ; CPU:$E699 PRG:2699 60
;==============================================================================
; $E69A-$E6AD: Gameplay Marker Level Index Table
;==============================================================================
LevelProgressMarkerIndexTable:
.byte $00,$01,$02,$02 ; CPU:$E69A PRG:269A 00 01 02 02
.byte $03,$03,$04,$04 ; CPU:$E69E PRG:269E 03 03 04 04
.byte $05,$05,$06,$06 ; CPU:$E6A2 PRG:26A2 05 05 06 06
.byte $07,$07,$07,$07 ; CPU:$E6A6 PRG:26A6 07 07 07 07
.byte $07,$07,$07,$07 ; CPU:$E6AA PRG:26AA 07 07 07 07
;==============================================================================
; $E6AE-$E6BD: Gameplay Marker Working-Value Table
;
; Used as byte pairs through $03.
;==============================================================================
LevelProgressAttributeIndexTable:
.byte $00,$03 ; CPU:$E6AE PRG:26AE 00 03
.byte $01,$02 ; CPU:$E6B0 PRG:26B0 01 02
.byte $01,$03 ; CPU:$E6B2 PRG:26B2 01 03
.byte $02,$02 ; CPU:$E6B4 PRG:26B4 02 02
.byte $03,$01 ; CPU:$E6B6 PRG:26B6 03 01
.byte $04,$00 ; CPU:$E6B8 PRG:26B8 04 00
.byte $04,$01 ; CPU:$E6BA PRG:26BA 04 01
.byte $05,$00 ; CPU:$E6BC PRG:26BC 05 00
;==============================================================================
; $E6BE-$E6C5: Gameplay Marker Bit/Pattern Table
;==============================================================================
LevelProgressAttributeBits:
.byte $02,$02,$02,$02 ; CPU:$E6BE PRG:26BE 02 02 02 02
.byte $03,$03,$03,$03 ; CPU:$E6C2 PRG:26C2 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 ; CPU:$E6C6 PRG:26C6 16 16 26 26
.byte $06,$06,$19,$19 ; CPU:$E6CA PRG:26CA 06 06 19 19
.byte $17,$17,$17,$17 ; CPU:$E6CE PRG:26CE 17 17 17 17
.byte $12,$12,$12,$12 ; CPU:$E6D2 PRG:26D2 12 12 12 12
;==============================================================================
; $E6D6-$E737: Initialize Gameplay Transition State
;==============================================================================
InitializeGameplayTransitionState:
lda #$08 ; CPU:$E6D6 PRG:26D6 A9 08
sta $43 ; CPU:$E6D8 PRG:26D8 85 43
sta PPUCTRL ; CPU:$E6DA PRG:26DA 8D 00 20
TransitionInit_E6DD:
lda PPUSTATUS ; CPU:$E6DD PRG:26DD AD 02 20
bpl TransitionInit_E6DD ; CPU:$E6E0 PRG:26E0 10 FB
lda #$01 ; CPU:$E6E2 PRG:26E2 A9 01
sta $060D ; CPU:$E6E4 PRG:26E4 8D 0D 06
sta $060E ; CPU:$E6E7 PRG:26E7 8D 0E 06
lda #$00 ; CPU:$E6EA PRG:26EA A9 00
sta PPUMASK ; CPU:$E6EC PRG:26EC 8D 01 20
jsr ClearPlayfieldNametable ; CPU:$E6EF PRG:26EF 20 38 E7
lda #$01 ; CPU:$E6F2 PRG:26F2 A9 01
sta $028D ; CPU:$E6F4 PRG:26F4 8D 8D 02
lda #$01 ; CPU:$E6F7 PRG:26F7 A9 01
sta $0293 ; CPU:$E6F9 PRG:26F9 8D 93 02
lda #$F7 ; CPU:$E6FC PRG:26FC A9 F7
sta $0278 ; CPU:$E6FE PRG:26FE 8D 78 02
lda #$7C ; CPU:$E701 PRG:2701 A9 7C
sta $027A ; CPU:$E703 PRG:2703 8D 7A 02
lda #$FF ; CPU:$E706 PRG:2706 A9 FF
sta $1E ; CPU:$E708 PRG:2708 85 1E
lda #$00 ; CPU:$E70A PRG:270A A9 00
sta $1F ; CPU:$E70C PRG:270C 85 1F
lda #$00 ; CPU:$E70E PRG:270E A9 00
sta $88 ; CPU:$E710 PRG:2710 85 88
ldy #$00 ; CPU:$E712 PRG:2712 A0 00
TransitionInit_CopyPalette:
lda GameplayTransitionPalette,y ; CPU:$E714 PRG:2714 B9 AF E7
sta $02A9,y ; CPU:$E717 PRG:2717 99 A9 02
iny ; CPU:$E71A PRG:271A C8
cpy #$10 ; CPU:$E71B PRG:271B C0 10
bne TransitionInit_CopyPalette ; CPU:$E71D PRG:271D D0 F5
lda #$20 ; CPU:$E71F PRG:271F A9 20
sta $026F ; CPU:$E721 PRG:2721 8D 6F 02
sta $0270 ; CPU:$E724 PRG:2724 8D 70 02
sta $0271 ; CPU:$E727 PRG:2727 8D 71 02
lda #$10 ; CPU:$E72A PRG:272A A9 10
sta $3F ; CPU:$E72C PRG:272C 85 3F
lda #$88 ; CPU:$E72E PRG:272E A9 88
sta PPUCTRL ; CPU:$E730 PRG:2730 8D 00 20
sta $43 ; CPU:$E733 PRG:2733 85 43
jmp $CAA7 ; CPU:$E735 PRG:2735 4C A7 CA
;==============================================================================
; $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 ; CPU:$E738 PRG:2738 A2 20
lda $47 ; CPU:$E73A PRG:273A A5 47
and $46 ; CPU:$E73C PRG:273C 25 46
beq SetPlayfieldPpuAddress ; CPU:$E73E PRG:273E F0 02
ldx #$28 ; CPU:$E740 PRG:2740 A2 28
;------------------------------------------------------------------------------
; $E742
; Initialize selected nametable address.
;------------------------------------------------------------------------------
SetPlayfieldPpuAddress:
lda PPUSTATUS ; CPU:$E742 PRG:2742 AD 02 20
stx PPUADDR ; CPU:$E745 PRG:2745 8E 06 20
lda #$00 ; CPU:$E748 PRG:2748 A9 00
sta PPUADDR ; CPU:$E74A PRG:274A 8D 06 20
lda #$1C ; CPU:$E74D PRG:274D A9 1C
sta $00 ; CPU:$E74F PRG:274F 85 00
;------------------------------------------------------------------------------
; $E751
; Shared counter-setup entry.
;
; The outer $00 loop deliberately jumps back here rather than rebuilding $00.
;------------------------------------------------------------------------------
ResetPlayfieldFillCounters:
lda #$02 ; CPU:$E751 PRG:2751 A9 02
sta $01 ; CPU:$E753 PRG:2753 85 01
lda #$1C ; CPU:$E755 PRG:2755 A9 1C
sta $02 ; CPU:$E757 PRG:2757 85 02
lda #$02 ; CPU:$E759 PRG:2759 A9 02
sta $03 ; CPU:$E75B PRG:275B 85 03
lda #$2D ; CPU:$E75D PRG:275D A9 2D
;------------------------------------------------------------------------------
; $E75F
; Shared PPUDATA write point.
;------------------------------------------------------------------------------
WritePlayfieldFillByte:
sta PPUDATA ; CPU:$E75F PRG:275F 8D 07 20
ldx $01 ; CPU:$E762 PRG:2762 A6 01
beq AdvancePlayfieldInnerRun ; CPU:$E764 PRG:2764 F0 08
dec $01 ; CPU:$E766 PRG:2766 C6 01
bne WritePlayfieldFillByte ; CPU:$E768 PRG:2768 D0 F5
lda #$20 ; CPU:$E76A PRG:276A A9 20
bne WritePlayfieldFillByte ; CPU:$E76C PRG:276C D0 F1
;------------------------------------------------------------------------------
; $E76E
; Process the second run counter.
;------------------------------------------------------------------------------
AdvancePlayfieldInnerRun:
ldx $02 ; CPU:$E76E PRG:276E A6 02
beq AdvancePlayfieldOuterRun ; CPU:$E770 PRG:2770 F0 08
dec $02 ; CPU:$E772 PRG:2772 C6 02
bne WritePlayfieldFillByte ; CPU:$E774 PRG:2774 D0 E9
lda #$2D ; CPU:$E776 PRG:2776 A9 2D
bne WritePlayfieldFillByte ; CPU:$E778 PRG:2778 D0 E5
;------------------------------------------------------------------------------
; $E77A
; Process outer fill counters.
;------------------------------------------------------------------------------
AdvancePlayfieldOuterRun:
dec $03 ; CPU:$E77A PRG:277A C6 03
bne WritePlayfieldFillByte ; CPU:$E77C PRG:277C D0 E1
dec $00 ; CPU:$E77E PRG:277E C6 00
bne ResetPlayfieldFillCounters ; CPU:$E780 PRG:2780 D0 CF
;------------------------------------------------------------------------------
; $E782
; Clear $40 PPU bytes.
;------------------------------------------------------------------------------
lda #$00 ; CPU:$E782 PRG:2782 A9 00
tax ; CPU:$E784 PRG:2784 AA
ClearPlayfieldTail:
sta PPUDATA ; CPU:$E785 PRG:2785 8D 07 20
inx ; CPU:$E788 PRG:2788 E8
cpx #$40 ; CPU:$E789 PRG:2789 E0 40
bne ClearPlayfieldTail ; CPU:$E78B PRG:278B D0 F8
lda $87 ; CPU:$E78D PRG:278D A5 87
cmp #$02 ; CPU:$E78F PRG:278F C9 02
beq DrawPlayfieldSpecialTile ; CPU:$E791 PRG:2791 F0 01
rts ; CPU:$E793 PRG:2793 60
;------------------------------------------------------------------------------
; $E794
; Optional special tile at PPU $2230 or $2A30.
;------------------------------------------------------------------------------
DrawPlayfieldSpecialTile:
ldx #$22 ; CPU:$E794 PRG:2794 A2 22
lda $47 ; CPU:$E796 PRG:2796 A5 47
and $46 ; CPU:$E798 PRG:2798 25 46
beq SetSpecialTilePpuAddress ; CPU:$E79A PRG:279A F0 02
ldx #$2A ; CPU:$E79C PRG:279C A2 2A
SetSpecialTilePpuAddress:
lda PPUSTATUS ; CPU:$E79E PRG:279E AD 02 20
stx PPUADDR ; CPU:$E7A1 PRG:27A1 8E 06 20
lda #$30 ; CPU:$E7A4 PRG:27A4 A9 30
sta PPUADDR ; CPU:$E7A6 PRG:27A6 8D 06 20
lda #$5E ; CPU:$E7A9 PRG:27A9 A9 5E
sta PPUDATA ; CPU:$E7AB PRG:27AB 8D 07 20
rts ; CPU:$E7AE PRG:27AE 60
;==============================================================================
; $E7AF-$E7BE: Gameplay Transition Palette
;==============================================================================
GameplayTransitionPalette:
.byte $0F,$36,$20,$06 ; CPU:$E7AF PRG:27AF 0F 36 20 06
.byte $0F,$27,$20,$06 ; CPU:$E7B3 PRG:27B3 0F 27 20 06
.byte $0F,$11,$20,$33 ; CPU:$E7B7 PRG:27B7 0F 11 20 33
.byte $0F,$36,$20,$11 ; CPU:$E7BB PRG:27BB 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 ; CPU:$E7BF PRG:27BF 20 19 EA
jsr $EA94 ; CPU:$E7C2 PRG:27C2 20 94 EA
jsr BuildEntitySpriteBuffer ; CPU:$E7C5 PRG:27C5 20 F1 DA
jsr DispatchIntermissionState ; CPU:$E7C8 PRG:27C8 20 CE E7
jmp $CAA7 ; CPU:$E7CB PRG:27CB 4C A7 CA
;==============================================================================
; $E7CE-$E7DC: Transition state dispatcher
;
; $87 is an even state value used directly as a byte offset into the table.
;==============================================================================
DispatchIntermissionState:
ldy $87 ; CPU:$E7CE PRG:27CE A4 87
lda IntermissionStateHandlerTable,y ; CPU:$E7D0 PRG:27D0 B9 DD E7
sta $10 ; CPU:$E7D3 PRG:27D3 85 10
lda IntermissionStateHandlerTable+1,y ; CPU:$E7D5 PRG:27D5 B9 DE E7
sta $11 ; CPU:$E7D8 PRG:27D8 85 11
jmp ($0010) ; CPU:$E7DA PRG:27DA 6C 10 00 E3 E7
;==============================================================================
; $E7DD-$E7E2: Transition state pointer table
;==============================================================================
IntermissionStateHandlerTable:
.word DispatchIntermissionPhase ; CPU:$E7DD PRG:27DD E3 E7
.word DispatchIntermissionState2Phase ; CPU:$E7DF PRG:27DF C7 E8
.word DispatchIntermissionState4Phase ; CPU:$E7E1 PRG:27E1 6E E9
;==============================================================================
; $E7E3-$E7F1: Secondary transition-state dispatcher
;
; $88 is used directly as a byte offset into another pointer table.
;==============================================================================
DispatchIntermissionPhase:
ldy $88 ; CPU:$E7E3 PRG:27E3 A4 88
lda IntermissionPhaseHandlerTable,y ; CPU:$E7E5 PRG:27E5 B9 F2 E7
sta $10 ; CPU:$E7E8 PRG:27E8 85 10
lda IntermissionPhaseHandlerTable+1,y ; CPU:$E7EA PRG:27EA B9 F3 E7
sta $11 ; CPU:$E7ED PRG:27ED 85 11
jmp ($0010) ; CPU:$E7EF PRG:27EF 6C 10 00 FA E7
;==============================================================================
; $E7F2-$E7F9: Transition substate pointer table
;==============================================================================
IntermissionPhaseHandlerTable:
.word UpdateIntermissionPhase0 ; CPU:$E7F2 PRG:27F2 FA E7
.word UpdateIntermissionPhase1 ; CPU:$E7F4 PRG:27F4 23 E8
.word UpdateIntermissionPhase2 ; CPU:$E7F6 PRG:27F6 4E E8
.word UpdateIntermissionPhase3 ; CPU:$E7F8 PRG:27F8 BA E8
;==============================================================================
; $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 ; CPU:$E7FA PRG:27FA AD 78 02
cmp #$D0 ; CPU:$E7FD PRG:27FD C9 D0
bcc TransitionSubstate_E802 ; CPU:$E7FF PRG:27FF 90 01
rts ; CPU:$E801 PRG:2801 60
TransitionSubstate_E802:
inc $88 ; CPU:$E802 PRG:2802 E6 88
inc $88 ; CPU:$E804 PRG:2804 E6 88
lda #$0C ; CPU:$E806 PRG:2806 A9 0C
sta $028C ; CPU:$E808 PRG:2808 8D 8C 02
lda #$20 ; CPU:$E80B PRG:280B A9 20
sta $0292 ; CPU:$E80D PRG:280D 8D 92 02
lda #$F7 ; CPU:$E810 PRG:2810 A9 F7
sta $0274 ; CPU:$E812 PRG:2812 8D 74 02
lda #$7C ; CPU:$E815 PRG:2815 A9 7C
sta $0276 ; CPU:$E817 PRG:2817 8D 76 02
lda #$FE ; CPU:$E81A PRG:281A A9 FE
sta $1A ; CPU:$E81C PRG:281C 85 1A
lda #$E0 ; CPU:$E81E PRG:281E A9 E0
sta $1B ; CPU:$E820 PRG:2820 85 1B
rts ; CPU:$E822 PRG:2822 60
;==============================================================================
; $E823-$E84D: Transition substate 1
;
; Waits for $0274 to become zero, then advances $88 and initializes a
; different object/state configuration.
;==============================================================================
UpdateIntermissionPhase1:
lda $0274 ; CPU:$E823 PRG:2823 AD 74 02
beq TransitionSubstate_E829 ; CPU:$E826 PRG:2826 F0 01
rts ; CPU:$E828 PRG:2828 60
TransitionSubstate_E829:
inc $88 ; CPU:$E829 PRG:2829 E6 88
inc $88 ; CPU:$E82B PRG:282B E6 88
lda #$40 ; CPU:$E82D PRG:282D A9 40
sta $4C ; CPU:$E82F PRG:282F 85 4C
lda #$1E ; CPU:$E831 PRG:2831 A9 1E
sta $028C ; CPU:$E833 PRG:2833 8D 8C 02
lda #$22 ; CPU:$E836 PRG:2836 A9 22
sta $0292 ; CPU:$E838 PRG:2838 8D 92 02
lda #$09 ; CPU:$E83B PRG:283B A9 09
sta $0274 ; CPU:$E83D PRG:283D 8D 74 02
lda #$7C ; CPU:$E840 PRG:2840 A9 7C
sta $0276 ; CPU:$E842 PRG:2842 8D 76 02
lda #$01 ; CPU:$E845 PRG:2845 A9 01
sta $1A ; CPU:$E847 PRG:2847 85 1A
lda #$00 ; CPU:$E849 PRG:2849 A9 00
sta $1B ; CPU:$E84B PRG:284B 85 1B
rts ; CPU:$E84D PRG:284D 60
;==============================================================================
; $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 ; CPU:$E84E PRG:284E A9 01
sta $060D ; CPU:$E850 PRG:2850 8D 0D 06
sta $060E ; CPU:$E853 PRG:2853 8D 0E 06
lda $0274 ; CPU:$E856 PRG:2856 AD 74 02
cmp #$80 ; CPU:$E859 PRG:2859 C9 80
bcs TransitionSubstate_E85D ; CPU:$E85B PRG:285B B0 01
rts ; CPU:$E85D PRG:285D 60
TransitionSubstate_E85D:
inc $88 ; CPU:$E85E PRG:285E E6 88
inc $88 ; CPU:$E860 PRG:2860 E6 88
lda #$01 ; CPU:$E862 PRG:2862 A9 01
sta $1E ; CPU:$E864 PRG:2864 85 1E
sta $22 ; CPU:$E866 PRG:2866 85 22
sta $26 ; CPU:$E868 PRG:2868 85 26
sta $2A ; CPU:$E86A PRG:286A 85 2A
lda #$C0 ; CPU:$E86C PRG:286C A9 C0
sta $1F ; CPU:$E86E PRG:286E 85 1F
sta $23 ; CPU:$E870 PRG:2870 85 23
sta $27 ; CPU:$E872 PRG:2872 85 27
sta $2B ; CPU:$E874 PRG:2874 85 2B
clc ; CPU:$E876 PRG:2876 18
lda #$38 ; CPU:$E877 PRG:2877 A9 38
sta $028D ; CPU:$E879 PRG:2879 8D 8D 02
adc #$01 ; CPU:$E87C PRG:287C 69 01
sta $028E ; CPU:$E87E PRG:287E 8D 8E 02
adc #$01 ; CPU:$E881 PRG:2881 69 01
sta $028F ; CPU:$E883 PRG:2883 8D 8F 02
adc #$01 ; CPU:$E886 PRG:2886 69 01
sta $0290 ; CPU:$E888 PRG:2888 8D 90 02
lda #$21 ; CPU:$E88B PRG:288B A9 21
sta $0293 ; CPU:$E88D PRG:288D 8D 93 02
sta $0294 ; CPU:$E890 PRG:2890 8D 94 02
sta $0295 ; CPU:$E893 PRG:2893 8D 95 02
sta $0296 ; CPU:$E896 PRG:2896 8D 96 02
lda #$09 ; CPU:$E899 PRG:2899 A9 09
sta $0278 ; CPU:$E89B PRG:289B 8D 78 02
sta $0280 ; CPU:$E89E PRG:289E 8D 80 02
lda #$19 ; CPU:$E8A1 PRG:28A1 A9 19
sta $027C ; CPU:$E8A3 PRG:28A3 8D 7C 02
sta $0284 ; CPU:$E8A6 PRG:28A6 8D 84 02
lda #$6C ; CPU:$E8A9 PRG:28A9 A9 6C
sta $027A ; CPU:$E8AB PRG:28AB 8D 7A 02
sta $027E ; CPU:$E8AE PRG:28AE 8D 7E 02
lda #$7C ; CPU:$E8B1 PRG:28B1 A9 7C
sta $0282 ; CPU:$E8B3 PRG:28B3 8D 82 02
sta $0286 ; CPU:$E8B6 PRG:28B6 8D 86 02
rts ; CPU:$E8B9 PRG:28B9 60
;==============================================================================
; $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 ; CPU:$E8BA PRG:28BA AD 78 02
beq TransitionSubstate_E8C0 ; CPU:$E8BD PRG:28BD F0 01
rts ; CPU:$E8BF PRG:28BF 60
TransitionSubstate_E8C0:
lda #$40 ; CPU:$E8C0 PRG:28C0 A9 40
sta $4C ; CPU:$E8C2 PRG:28C2 85 4C
jmp $EA14 ; CPU:$E8C4 PRG:28C4 4C 14 EA
;==============================================================================
; $E8C7-$E8D5: Transition State $02 Substate Dispatcher
;
; Local:
; Uses $88 as an even byte offset into IntermissionState2PhaseTable.
;==============================================================================
DispatchIntermissionState2Phase:
ldy $88 ; CPU:$E8C7 PRG:28C7 A4 88
lda IntermissionState2PhaseTable,y ; CPU:$E8C9 PRG:28C9 B9 D6 E8
sta $10 ; CPU:$E8CC PRG:28CC 85 10
lda IntermissionState2PhaseTable+1,y ; CPU:$E8CE PRG:28CE B9 D7 E8
sta $11 ; CPU:$E8D1 PRG:28D1 85 11
jmp ($0010) ; CPU:$E8D3 PRG:28D3 6C 10 00 DC E8
;==============================================================================
; $E8D6-$E8DB: Transition phase table
;==============================================================================
IntermissionState2PhaseTable:
.word UpdateIntermissionState2Phase0 ; CPU:$E8D6 PRG:28D6 DC E8
.word UpdateIntermissionState2Phase1 ; CPU:$E8D8 PRG:28D8 05 E9
.word UpdateIntermissionState2Phase2 ; CPU:$E8DA PRG:28DA 3F E9
;==============================================================================
; $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 ; CPU:$E8DC PRG:28DC AD 78 02
cmp #$A0 ; CPU:$E8DF PRG:28DF C9 A0
bcc TransitionPhase_E8E4 ; CPU:$E8E1 PRG:28E1 90 01
rts ; CPU:$E8E3 PRG:28E3 60
TransitionPhase_E8E4:
inc $88 ; CPU:$E8E4 PRG:28E4 E6 88
inc $88 ; CPU:$E8E6 PRG:28E6 E6 88
lda #$0C ; CPU:$E8E8 PRG:28E8 A9 0C
sta $028C ; CPU:$E8EA PRG:28EA 8D 8C 02
lda #$20 ; CPU:$E8ED PRG:28ED A9 20
sta $0292 ; CPU:$E8EF PRG:28EF 8D 92 02
lda #$F7 ; CPU:$E8F2 PRG:28F2 A9 F7
sta $0274 ; CPU:$E8F4 PRG:28F4 8D 74 02
lda #$7C ; CPU:$E8F7 PRG:28F7 A9 7C
sta $0276 ; CPU:$E8F9 PRG:28F9 8D 76 02
lda #$FF ; CPU:$E8FC PRG:28FC A9 FF
sta $1A ; CPU:$E8FE PRG:28FE 85 1A
lda #$00 ; CPU:$E900 PRG:2900 A9 00
sta $1B ; CPU:$E902 PRG:2902 85 1B
rts ; CPU:$E904 PRG:2904 60
;==============================================================================
; $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 ; CPU:$E905 PRG:2905 AD 74 02
cmp #$80 ; CPU:$E908 PRG:2908 C9 80
bne TransitionPhase_E92D ; CPU:$E90A PRG:290A D0 23
lda #$FF ; CPU:$E90C PRG:290C A9 FF
sta $1A ; CPU:$E90E PRG:290E 85 1A
lda #$C0 ; CPU:$E910 PRG:2910 A9 C0
sta $1B ; CPU:$E912 PRG:2912 85 1B
lda #$42 ; CPU:$E914 PRG:2914 A9 42
sta $028E ; CPU:$E916 PRG:2916 8D 8E 02
lda #$00 ; CPU:$E919 PRG:2919 A9 00
sta $0294 ; CPU:$E91B PRG:291B 8D 94 02
lda #$80 ; CPU:$E91E PRG:291E A9 80
sta $027C ; CPU:$E920 PRG:2920 8D 7C 02
lda #$7C ; CPU:$E923 PRG:2923 A9 7C
sta $027E ; CPU:$E925 PRG:2925 8D 7E 02
lda #$00 ; CPU:$E928 PRG:2928 A9 00
sta $22 ; CPU:$E92A PRG:292A 85 22
sta $23 ; CPU:$E92C PRG:292C 85 23
rts ; CPU:$E92E PRG:292E 60
TransitionPhase_E92D:
cmp #$78 ; CPU:$E92F PRG:292F C9 78
beq TransitionPhase_E933 ; CPU:$E931 PRG:2931 F0 01
rts ; CPU:$E933 PRG:2933 60
TransitionPhase_E933:
lda #$00 ; CPU:$E934 PRG:2934 A9 00
sta $1A ; CPU:$E936 PRG:2936 85 1A
sta $1B ; CPU:$E938 PRG:2938 85 1B
inc $88 ; CPU:$E93A PRG:293A E6 88
inc $88 ; CPU:$E93C PRG:293C E6 88
rts ; CPU:$E93E PRG:293E 60
;==============================================================================
; $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 ; CPU:$E93F PRG:293F AD 8C 02
and #$40 ; CPU:$E942 PRG:2942 29 40
bne TransitionPhase_E953 ; CPU:$E944 PRG:2944 D0 0F
lda #$46 ; CPU:$E946 PRG:2946 A9 46
sta $028C ; CPU:$E948 PRG:2948 8D 8C 02
lda #$45 ; CPU:$E94B PRG:294B A9 45
sta $028E ; CPU:$E94D PRG:294D 8D 8E 02
lda #$40 ; CPU:$E950 PRG:2950 A9 40
sta $89 ; CPU:$E952 PRG:2952 85 89
rts ; CPU:$E954 PRG:2954 60
TransitionPhase_E953:
dec $89 ; CPU:$E955 PRG:2955 C6 89
beq TransitionPhase_E958 ; CPU:$E957 PRG:2957 F0 01
rts ; CPU:$E959 PRG:2959 60
TransitionPhase_E958:
lda $028C ; CPU:$E95A PRG:295A AD 8C 02
cmp #$47 ; CPU:$E95D PRG:295D C9 47
bne TransitionPhase_E963 ; CPU:$E95F PRG:295F D0 03
jmp $EA14 ; CPU:$E961 PRG:2961 4C 14 EA
TransitionPhase_E963:
lda #$47 ; CPU:$E964 PRG:2964 A9 47
sta $028C ; CPU:$E966 PRG:2966 8D 8C 02
lda #$40 ; CPU:$E969 PRG:2969 A9 40
sta $89 ; CPU:$E96B PRG:296B 85 89
rts ; CPU:$E96D PRG:296D 60
;==============================================================================
; $E96E-$E97C: Transition State $04 Dispatcher
;
; $88 is an even byte offset into the four-entry phase table.
;==============================================================================
DispatchIntermissionState4Phase:
ldy $88 ; CPU:$E96E PRG:296E A4 88
lda IntermissionState4PhaseTable,y ; CPU:$E970 PRG:2970 B9 7D E9
sta $10 ; CPU:$E973 PRG:2973 85 10
lda IntermissionState4PhaseTable+1,y ; CPU:$E975 PRG:2975 B9 7E E9
sta $11 ; CPU:$E978 PRG:2978 85 11
jmp ($0010) ; CPU:$E97A PRG:297A 6C 10 00 85 E9
;==============================================================================
; $E97D-$E984: Transition State $04 Phase Table
;==============================================================================
IntermissionState4PhaseTable:
.word UpdateIntermissionState4Phase0 ; CPU:$E97D PRG:297D 85 E9
.word UpdateIntermissionState4Phase1 ; CPU:$E97F PRG:297F AE E9
.word UpdateIntermissionState4Phase2 ; CPU:$E981 PRG:2981 D9 E9
.word UpdateIntermissionState4Phase3 ; CPU:$E983 PRG:2983 0A EA
;==============================================================================
; $E985-$E9AD: Phase 0
;
; Waits until $0278 reaches $D8, advances $88, then installs the initial
; mirrored object/state configuration.
;==============================================================================
UpdateIntermissionState4Phase0:
lda $0278 ; CPU:$E985 PRG:2985 AD 78 02
cmp #$D8 ; CPU:$E988 PRG:2988 C9 D8
bcc TransitionPhase_E98D ; CPU:$E98A PRG:298A 90 01
rts ; CPU:$E98C PRG:298C 60
TransitionPhase_E98D:
inc $88 ; CPU:$E98D PRG:298D E6 88
inc $88 ; CPU:$E98F PRG:298F E6 88
lda #$4C ; CPU:$E991 PRG:2991 A9 4C
sta $028C ; CPU:$E993 PRG:2993 8D 8C 02
lda #$20 ; CPU:$E996 PRG:2996 A9 20
sta $0292 ; CPU:$E998 PRG:2998 8D 92 02
lda #$F7 ; CPU:$E99B PRG:299B A9 F7
sta $0274 ; CPU:$E99D PRG:299D 8D 74 02
lda #$7C ; CPU:$E9A0 PRG:29A0 A9 7C
sta $0276 ; CPU:$E9A2 PRG:29A2 8D 76 02
lda #$FF ; CPU:$E9A5 PRG:29A5 A9 FF
sta $1A ; CPU:$E9A7 PRG:29A7 85 1A
lda #$00 ; CPU:$E9A9 PRG:29A9 A9 00
sta $1B ; CPU:$E9AB PRG:29AB 85 1B
rts ; CPU:$E9AD PRG:29AD 60
;==============================================================================
; $E9AE-$E9D8: Phase 1
;
; Waits for $0274 to reach zero, advances $88 and installs the next object
; configuration.
;==============================================================================
UpdateIntermissionState4Phase1:
lda $0274 ; CPU:$E9AE PRG:29AE AD 74 02
beq TransitionPhase_E9B4 ; CPU:$E9B1 PRG:29B1 F0 01
rts ; CPU:$E9B3 PRG:29B3 60
TransitionPhase_E9B4:
inc $88 ; CPU:$E9B4 PRG:29B4 E6 88
inc $88 ; CPU:$E9B6 PRG:29B6 E6 88
lda #$28 ; CPU:$E9B8 PRG:29B8 A9 28
sta $4C ; CPU:$E9BA PRG:29BA 85 4C
lda #$4A ; CPU:$E9BC PRG:29BC A9 4A
sta $028C ; CPU:$E9BE PRG:29BE 8D 8C 02
lda #$23 ; CPU:$E9C1 PRG:29C1 A9 23
sta $0292 ; CPU:$E9C3 PRG:29C3 8D 92 02
lda #$09 ; CPU:$E9C6 PRG:29C6 A9 09
sta $0274 ; CPU:$E9C8 PRG:29C8 8D 74 02
lda #$7C ; CPU:$E9CB PRG:29CB A9 7C
sta $0276 ; CPU:$E9CD PRG:29CD 8D 76 02
lda #$01 ; CPU:$E9D0 PRG:29D0 A9 01
sta $1A ; CPU:$E9D2 PRG:29D2 85 1A
lda #$00 ; CPU:$E9D4 PRG:29D4 A9 00
sta $1B ; CPU:$E9D6 PRG:29D6 85 1B
rts ; CPU:$E9D8 PRG:29D8 60
;==============================================================================
; $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 ; CPU:$E9D9 PRG:29D9 A9 01
sta $060D ; CPU:$E9DB PRG:29DB 8D 0D 06
sta $060E ; CPU:$E9DE PRG:29DE 8D 0E 06
lda $0274 ; CPU:$E9E1 PRG:29E1 AD 74 02
cmp #$19 ; CPU:$E9E4 PRG:29E4 C9 19
bcs TransitionPhase_E9E8 ; CPU:$E9E6 PRG:29E6 B0 01
rts ; CPU:$E9E8 PRG:29E8 60
TransitionPhase_E9E8:
inc $88 ; CPU:$E9E9 PRG:29E9 E6 88
inc $88 ; CPU:$E9EB PRG:29EB E6 88
lda #$4C ; CPU:$E9ED PRG:29ED A9 4C
sta $028D ; CPU:$E9EF PRG:29EF 8D 8D 02
lda #$21 ; CPU:$E9F2 PRG:29F2 A9 21
sta $0293 ; CPU:$E9F4 PRG:29F4 8D 93 02
lda #$11 ; CPU:$E9F7 PRG:29F7 A9 11
sta $0278 ; CPU:$E9F9 PRG:29F9 8D 78 02
lda #$84 ; CPU:$E9FC PRG:29FC A9 84
sta $027A ; CPU:$E9FE PRG:29FE 8D 7A 02
lda #$01 ; CPU:$EA01 PRG:2A01 A9 01
sta $1E ; CPU:$EA03 PRG:2A03 85 1E
lda #$00 ; CPU:$EA05 PRG:2A05 A9 00
sta $1F ; CPU:$EA07 PRG:2A07 85 1F
rts ; CPU:$EA09 PRG:2A09 60
;==============================================================================
; $EA0A-$EA18: Phase 3
;
; Waits for $0278 to reach zero, then primes the next game-mode/state
; transition.
;==============================================================================
UpdateIntermissionState4Phase3:
lda $0278 ; CPU:$EA0A PRG:2A0A AD 78 02
beq TransitionPhase_EA10 ; CPU:$EA0D PRG:2A0D F0 01
rts ; CPU:$EA0F PRG:2A0F 60
TransitionPhase_EA10:
lda #$40 ; CPU:$EA10 PRG:2A10 A9 40
sta $4C ; CPU:$EA12 PRG:2A12 85 4C
lda #$00 ; CPU:$EA14 PRG:2A14 A9 00
sta $3F ; CPU:$EA16 PRG:2A16 85 3F
rts ; CPU:$EA18 PRG:2A18 60
;==============================================================================
; $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 ; CPU:$EA19 PRG:2A19 A9 1A
sta $00 ; CPU:$EA1B PRG:2A1B 85 00
lda #$00 ; CPU:$EA1D PRG:2A1D A9 00
sta $01 ; CPU:$EA1F PRG:2A1F 85 01
lda #$74 ; CPU:$EA21 PRG:2A21 A9 74
sta $02 ; CPU:$EA23 PRG:2A23 85 02
lda #$02 ; CPU:$EA25 PRG:2A25 A9 02
sta $03 ; CPU:$EA27 PRG:2A27 85 03
ldx #$00 ; CPU:$EA29 PRG:2A29 A2 00
;------------------------------------------------------------------------------
; $EA2B
; Process one structure.
;------------------------------------------------------------------------------
UpdateNextTransitionObject:
ldy #$00 ; CPU:$EA2B PRG:2A2B A0 00
lda ($02),y ; CPU:$EA2D PRG:2A2D B1 02
beq AdvanceTransitionObjectPointers ; CPU:$EA2F PRG:2A2F F0 43
iny ; CPU:$EA31 PRG:2A31 C8
lda ($00),y ; CPU:$EA32 PRG:2A32 B1 00
clc ; CPU:$EA34 PRG:2A34 18
adc ($02),y ; CPU:$EA35 PRG:2A35 71 02
sta ($02),y ; CPU:$EA37 PRG:2A37 91 02
dey ; CPU:$EA39 PRG:2A39 88
lda ($00),y ; CPU:$EA3A PRG:2A3A B1 00
adc ($02),y ; CPU:$EA3C PRG:2A3C 71 02
sta ($02),y ; CPU:$EA3E PRG:2A3E 91 02
cmp #$C0 ; CPU:$EA40 PRG:2A40 C9 C0
bcc UpdateTransitionObjectAttribute ; CPU:$EA42 PRG:2A42 90 0A
;------------------------------------------------------------------------------
; $EA44
; Set attribute bit $20.
;------------------------------------------------------------------------------
SetTransitionObjectAttributeBit:
lda #$20 ; CPU:$EA44 PRG:2A44 A9 20
ora $0292,x ; CPU:$EA46 PRG:2A46 1D 92 02
sta $0292,x ; CPU:$EA49 PRG:2A49 9D 92 02
bne CheckTransitionObjectWrap ; CPU:$EA4C PRG:2A4C D0 0C
;------------------------------------------------------------------------------
; $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 ; CPU:$EA4E PRG:2A4E C9 40
bcc SetTransitionObjectAttributeBit ; CPU:$EA50 PRG:2A50 90 F2
lda #$DF ; CPU:$EA52 PRG:2A52 A9 DF
and $0292,x ; CPU:$EA54 PRG:2A54 3D 92 02
sta $0292,x ; CPU:$EA57 PRG:2A57 9D 92 02
;------------------------------------------------------------------------------
; $EA5A
; Coordinate wrap/reset test.
;------------------------------------------------------------------------------
CheckTransitionObjectWrap:
ldy #$00 ; CPU:$EA5A PRG:2A5A A0 00
lda ($02),y ; CPU:$EA5C PRG:2A5C B1 02
cmp #$FC ; CPU:$EA5E PRG:2A5E C9 FC
bcc CheckTransitionObjectLowBoundary ; CPU:$EA60 PRG:2A60 90 0E
;------------------------------------------------------------------------------
; $EA62
; Reset coordinate/movement state.
;------------------------------------------------------------------------------
ResetTransitionObjectPosition:
lda #$00 ; CPU:$EA62 PRG:2A62 A9 00
sta ($02),y ; CPU:$EA64 PRG:2A64 91 02
sta ($00),y ; CPU:$EA66 PRG:2A66 91 00
iny ; CPU:$EA68 PRG:2A68 C8
sta ($00),y ; CPU:$EA69 PRG:2A69 91 00
iny ; CPU:$EA6B PRG:2A6B C8
sta ($02),y ; CPU:$EA6C PRG:2A6C 91 02
bne AdvanceTransitionObjectPointers ; CPU:$EA6E PRG:2A6E D0 04
;------------------------------------------------------------------------------
; $EA70
; Values below $04 also take the reset path.
;------------------------------------------------------------------------------
CheckTransitionObjectLowBoundary:
cmp #$04 ; CPU:$EA70 PRG:2A70 C9 04
bcc ResetTransitionObjectPosition ; CPU:$EA72 PRG:2A72 90 EE
;------------------------------------------------------------------------------
; $EA74
; Advance both source and mirrored pointers.
;------------------------------------------------------------------------------
AdvanceTransitionObjectPointers:
lda $00 ; CPU:$EA74 PRG:2A74 A5 00
clc ; CPU:$EA76 PRG:2A76 18
adc #$04 ; CPU:$EA77 PRG:2A77 69 04
sta $00 ; CPU:$EA79 PRG:2A79 85 00
lda $01 ; CPU:$EA7B PRG:2A7B A5 01
adc #$00 ; CPU:$EA7D PRG:2A7D 69 00
sta $01 ; CPU:$EA7F PRG:2A7F 85 01
lda $02 ; CPU:$EA81 PRG:2A81 A5 02
clc ; CPU:$EA83 PRG:2A83 18
adc #$04 ; CPU:$EA84 PRG:2A84 69 04
sta $02 ; CPU:$EA86 PRG:2A86 85 02
lda $03 ; CPU:$EA88 PRG:2A88 A5 03
adc #$00 ; CPU:$EA8A PRG:2A8A 69 00
sta $03 ; CPU:$EA8C PRG:2A8C 85 03
inx ; CPU:$EA8E PRG:2A8E E8
cpx #$05 ; CPU:$EA8F PRG:2A8F E0 05
bne UpdateNextTransitionObject ; CPU:$EA91 PRG:2A91 D0 98
rts ; CPU:$EA93 PRG:2A93 60
;==============================================================================
; $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 ; CPU:$EA94 PRG:2A94 A4 87
lda TransitionAnimationHandlerTable,y ; CPU:$EA96 PRG:2A96 B9 A3 EA
sta $10 ; CPU:$EA99 PRG:2A99 85 10
lda TransitionAnimationHandlerTable+1,y ; CPU:$EA9B PRG:2A9B B9 A4 EA
sta $11 ; CPU:$EA9E PRG:2A9E 85 11
jmp ($0010) ; CPU:$EAA0 PRG:2AA0 6C 10 00 A9 EA
;==============================================================================
; $EAA3-$EAA8: Gameplay Animation State Table
;==============================================================================
TransitionAnimationHandlerTable:
.word DispatchTransitionAnimationPhase ; CPU:$EAA3 PRG:2AA3 A9 EA
.word DispatchTransitionAnimationState2 ; CPU:$EAA5 PRG:2AA5 3D EB
.word DispatchTransitionAnimationState4 ; CPU:$EAA7 PRG:2AA7 6D EB
;==============================================================================
; $EAA9-$EAB7: Animation Substate Dispatcher
;
; $88 is an even state value used directly as an offset into this table.
;==============================================================================
DispatchTransitionAnimationPhase:
ldy $88 ; CPU:$EAA9 PRG:2AA9 A4 88
lda TransitionAnimationPhaseTable,y ; CPU:$EAAB PRG:2AAB B9 B8 EA
sta $10 ; CPU:$EAAE PRG:2AAE 85 10
lda TransitionAnimationPhaseTable+1,y ; CPU:$EAB0 PRG:2AB0 B9 B9 EA
sta $11 ; CPU:$EAB3 PRG:2AB3 85 11
jmp ($0010) ; CPU:$EAB5 PRG:2AB5 6C 10 00 C0 EA
;==============================================================================
; $EAB8-$EABF: Animation Substate Table
;==============================================================================
TransitionAnimationPhaseTable:
.word UpdateTransitionAnimationFrame ; CPU:$EAB8 PRG:2AB8 C0 EA
.word UpdateTransitionAnimationType1 ; CPU:$EABA PRG:2ABA D6 EA
.word UpdateTransitionAnimationType2 ; CPU:$EABC PRG:2ABC ED EA
.word UpdateTransitionAnimationPattern ; CPU:$EABE PRG:2ABE 04 EB
;==============================================================================
; $EAC0-$EACD: Animation Substate 0
;
; Advances $B7 modulo eight and uses it to select a value for $028D.
;==============================================================================
UpdateTransitionAnimationFrame:
inc $B7 ; CPU:$EAC0 PRG:2AC0 E6 B7
lda $B7 ; CPU:$EAC2 PRG:2AC2 A5 B7
and #$07 ; CPU:$EAC4 PRG:2AC4 29 07
tay ; CPU:$EAC6 PRG:2AC6 A8
lda TransitionAnimationFrameTable,y ; CPU:$EAC7 PRG:2AC7 B9 CE EA
sta $028D ; CPU:$EACA PRG:2ACA 8D 8D 02
rts ; CPU:$EACD PRG:2ACD 60
;==============================================================================
; $EACE-$EAD5: Animation frame table
;==============================================================================
TransitionAnimationFrameTable:
.byte $04,$04,$04,$05 ; CPU:$EACE PRG:2ACE 04 04 04 05
.byte $05,$04,$01,$01 ; CPU:$EAD2 PRG:2AD2 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 ; CPU:$EAD6 PRG:2AD6 A5 4B
and #$07 ; CPU:$EAD8 PRG:2AD8 29 07
bne UpdateTransitionAnimationFrame ; CPU:$EADA PRG:2ADA D0 E4
lda $4B ; CPU:$EADC PRG:2ADC A5 4B
and #$08 ; CPU:$EADE PRG:2ADE 29 08
bne AnimationSubstate_EAE7 ; CPU:$EAE0 PRG:2AE0 D0 04
lda #$0C ; CPU:$EAE2 PRG:2AE2 A9 0C
bne AnimationSubstate_EAE9 ; CPU:$EAE4 PRG:2AE4 D0 02
AnimationSubstate_EAE7:
lda #$0D ; CPU:$EAE6 PRG:2AE6 A9 0D
AnimationSubstate_EAE9:
sta $028C ; CPU:$EAE8 PRG:2AE8 8D 8C 02
bne UpdateTransitionAnimationFrame ; CPU:$EAEB PRG:2AEB D0 D3
;==============================================================================
; $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 ; CPU:$EAED PRG:2AED A5 4B
and #$07 ; CPU:$EAEF PRG:2AEF 29 07
beq AnimationSubstate_EAF5 ; CPU:$EAF1 PRG:2AF1 F0 01
rts ; CPU:$EAF3 PRG:2AF3 60
AnimationSubstate_EAF5:
lda $4B ; CPU:$EAF4 PRG:2AF4 A5 4B
and #$08 ; CPU:$EAF6 PRG:2AF6 29 08
bne AnimationSubstate_EB00 ; CPU:$EAF8 PRG:2AF8 D0 04
lda #$1E ; CPU:$EAFA PRG:2AFA A9 1E
bne AnimationSubstate_EB02 ; CPU:$EAFC PRG:2AFC D0 02
AnimationSubstate_EB00:
lda #$1F ; CPU:$EAFE PRG:2AFE A9 1F
AnimationSubstate_EB02:
sta $028C ; CPU:$EB00 PRG:2B00 8D 8C 02
rts ; CPU:$EB03 PRG:2B03 60
;==============================================================================
; $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 ; CPU:$EB04 PRG:2B04 E6 B7
lda $B7 ; CPU:$EB06 PRG:2B06 A5 B7
and #$07 ; CPU:$EB08 PRG:2B08 29 07
tay ; CPU:$EB0A PRG:2B0A A8
lda TransitionAnimationPatternIndex,y ; CPU:$EB0B PRG:2B0B B9 29 EB
tay ; CPU:$EB0E PRG:2B0E A8
lda TransitionAnimationPatternTiles,y ; CPU:$EB0F PRG:2B0F B9 31 EB
sta $028D ; CPU:$EB12 PRG:2B12 8D 8D 02
lda TransitionAnimationPatternTiles+1,y ; CPU:$EB15 PRG:2B15 B9 32 EB
sta $028E ; CPU:$EB18 PRG:2B18 8D 8E 02
lda TransitionAnimationPatternTiles+2,y ; CPU:$EB1B PRG:2B1B B9 33 EB
sta $028F ; CPU:$EB1E PRG:2B1E 8D 8F 02
lda TransitionAnimationPatternTiles+3,y ; CPU:$EB21 PRG:2B21 B9 34 EB
sta $0290 ; CPU:$EB24 PRG:2B24 8D 90 02
bne UpdateTransitionAnimationType2 ; CPU:$EB27 PRG:2B27 D0 C4
;==============================================================================
; $EB29-$EB30: Animation pattern index table
;==============================================================================
TransitionAnimationPatternIndex:
.byte $00,$00,$00,$04 ; CPU:$EB29 PRG:2B29 00 00 00 04
.byte $04,$00,$08,$08 ; CPU:$EB2D PRG:2B2D 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 ; CPU:$EB31 PRG:2B31 3C 3D 3E 3F
.byte $3C,$40,$3E,$41 ; CPU:$EB35 PRG:2B35 3C 40 3E 41
.byte $38,$39,$3A,$3B ; CPU:$EB39 PRG:2B39 38 39 3A 3B
;==============================================================================
; $EB3D-$EB4B: Gameplay Animation State $02 Dispatcher
;==============================================================================
DispatchTransitionAnimationState2:
ldy $88 ; CPU:$EB3D PRG:2B3D A4 88
lda TransitionAnimationState2Table,y ; CPU:$EB3F PRG:2B3F B9 4C EB
sta $10 ; CPU:$EB42 PRG:2B42 85 10
lda TransitionAnimationState2Table+1,y ; CPU:$EB44 PRG:2B44 B9 4D EB
sta $11 ; CPU:$EB47 PRG:2B47 85 11
jmp ($0010) ; CPU:$EB49 PRG:2B49 6C 10 00 C0 EA
;==============================================================================
; $EB4C-$EB51: Gameplay Animation State $02 Pointer Table
;==============================================================================
TransitionAnimationState2Table:
.word UpdateTransitionAnimationFrame ; CPU:$EB4C PRG:2B4C C0 EA
.word UpdateTransitionAnimationState2 ; CPU:$EB4E PRG:2B4E 52 EB
.word UpdateTransitionAnimationFrame ; CPU:$EB50 PRG:2B50 C0 EA
;==============================================================================
; $EB52-$EB6C: Animation State $02 Handler
;==============================================================================
UpdateTransitionAnimationState2:
jsr UpdateTransitionAnimationType1 ; CPU:$EB52 PRG:2B52 20 D6 EA
lda $0274 ; CPU:$EB55 PRG:2B55 AD 74 02
cmp #$7D ; CPU:$EB58 PRG:2B58 C9 7D
bne AnimationState2_EB62 ; CPU:$EB5A PRG:2B5A D0 06
lda #$43 ; CPU:$EB5C PRG:2B5C A9 43
sta $028E ; CPU:$EB5E PRG:2B5E 8D 8E 02
rts ; CPU:$EB61 PRG:2B61 60
AnimationState2_EB62:
cmp #$7B ; CPU:$EB62 PRG:2B62 C9 7B
beq AnimationState2_EB68 ; CPU:$EB64 PRG:2B64 F0 01
rts ; CPU:$EB66 PRG:2B66 60
AnimationState2_EB68:
lda #$44 ; CPU:$EB67 PRG:2B67 A9 44
sta $028E ; CPU:$EB69 PRG:2B69 8D 8E 02
rts ; CPU:$EB6C PRG:2B6C 60
;==============================================================================
; $EB6D-$EB7B: Gameplay Animation State $04 Dispatcher
;==============================================================================
DispatchTransitionAnimationState4:
ldy $88 ; CPU:$EB6D PRG:2B6D A4 88
lda TransitionAnimationState4Table,y ; CPU:$EB6F PRG:2B6F B9 7C EB
sta $10 ; CPU:$EB72 PRG:2B72 85 10
lda TransitionAnimationState4Table+1,y ; CPU:$EB74 PRG:2B74 B9 7D EB
sta $11 ; CPU:$EB77 PRG:2B77 85 11
jmp ($0010) ; CPU:$EB79 PRG:2B79 6C 10 00 C0 EA
;==============================================================================
; $EB7C-$EB83: Gameplay Animation State $04 Pointer Table
;==============================================================================
TransitionAnimationState4Table:
.word UpdateTransitionAnimationFrame ; CPU:$EB7C PRG:2B7C C0 EA
.word UpdateTransitionAnimationState4Type1 ; CPU:$EB7E PRG:2B7E 84 EB
.word UpdateTransitionAnimationState4Type2 ; CPU:$EB80 PRG:2B80 9F EB
.word UpdateTransitionAnimationState4Type2 ; CPU:$EB82 PRG:2B82 9F EB
;==============================================================================
; $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 ; CPU:$EB84 PRG:2B84 A5 4B
and #$07 ; CPU:$EB86 PRG:2B86 29 07
beq AnimationState4_EB8E ; CPU:$EB88 PRG:2B88 F0 03
jmp UpdateTransitionAnimationFrame ; CPU:$EB8A PRG:2B8A 4C C0 EA
AnimationState4_EB8E:
lda $4B ; CPU:$EB8D PRG:2B8D A5 4B
and #$08 ; CPU:$EB8F PRG:2B8F 29 08
bne AnimationState4_EB97 ; CPU:$EB91 PRG:2B91 D0 04
lda #$48 ; CPU:$EB93 PRG:2B93 A9 48
bne AnimationState4_EB99 ; CPU:$EB95 PRG:2B95 D0 02
AnimationState4_EB97:
lda #$49 ; CPU:$EB97 PRG:2B97 A9 49
AnimationState4_EB99:
sta $028C ; CPU:$EB99 PRG:2B99 8D 8C 02
jmp UpdateTransitionAnimationFrame ; CPU:$EB9C PRG:2B9C 4C C0 EA
;==============================================================================
; $EB9F-$EBB5: Animation State $04 Handler 2/3
;
; Alternates $028C between $4A and $4B every eight frames.
;==============================================================================
UpdateTransitionAnimationState4Type2:
lda $4B ; CPU:$EB9F PRG:2B9F A5 4B
and #$07 ; CPU:$EBA1 PRG:2BA1 29 07
beq AnimationState4_EBA6 ; CPU:$EBA3 PRG:2BA3 F0 01
rts ; CPU:$EBA5 PRG:2BA5 60
AnimationState4_EBA6:
lda $4B ; CPU:$EBA6 PRG:2BA6 A5 4B
and #$08 ; CPU:$EBA8 PRG:2BA8 29 08
bne AnimationState4_EBB0 ; CPU:$EBAA PRG:2BAA D0 04
lda #$4A ; CPU:$EBAC PRG:2BAC A9 4A
bne AnimationState4_EBB2 ; CPU:$EBAE PRG:2BAE D0 02
AnimationState4_EBB0:
lda #$4B ; CPU:$EBB0 PRG:2BB0 A9 4B
AnimationState4_EBB2:
sta $028C ; CPU:$EBB2 PRG:2BB2 8D 8C 02
rts ; CPU:$EBB5 PRG:2BB5 60
;==============================================================================
; $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 ; CPU:$EBB6 PRG:2BB6 00 07 00 00 00 04 01 06
.byte $01,$01,$01,$04,$01,$04,$02,$02 ; CPU:$EBBE PRG:2BBE 01 01 01 04 01 04 02 02
; $EBC6-$EBD5
.byte $02,$03,$02,$03,$02,$02,$02,$03 ; CPU:$EBC6 PRG:2BC6 02 03 02 03 02 02 02 03
.byte $02,$02,$02,$02,$03,$03,$03,$05 ; CPU:$EBCE PRG:2BCE 02 02 02 02 03 03 03 05
; $EBD6-$EBE5
.byte $03,$02,$03,$03,$03,$02,$03,$02 ; CPU:$EBD6 PRG:2BD6 03 02 03 03 03 02 03 02
.byte $04,$03,$03,$02,$03,$02,$04,$03 ; CPU:$EBDE PRG:2BDE 04 03 03 02 03 02 04 03
; $EBE6-$EBF5
.byte $03,$01,$04,$02,$05,$03,$03,$05 ; CPU:$EBE6 PRG:2BE6 03 01 04 02 05 03 03 05
.byte $04,$02,$05,$03,$03,$02,$04,$02 ; CPU:$EBEE PRG:2BEE 04 02 05 03 03 02 04 02
; $EBF6-$EC05
.byte $06,$03,$03,$01,$05,$02,$06,$03 ; CPU:$EBF6 PRG:2BF6 06 03 03 01 05 02 06 03
.byte $03,$01,$05,$02,$07,$03,$03,$03 ; CPU:$EBFE PRG:2BFE 03 01 05 02 07 03 03 03
; $EC06-$EC15
.byte $05,$02,$07,$03,$03,$01,$06,$02 ; CPU:$EC06 PRG:2C06 05 02 07 03 03 01 06 02
.byte $07,$03,$03,$01,$06,$02,$07,$03 ; CPU:$EC0E PRG:2C0E 07 03 03 01 06 02 07 03
; $EC16-$EC25
.byte $03,$00,$06,$02,$07,$03,$03,$01 ; CPU:$EC16 PRG:2C16 03 00 06 02 07 03 03 01
.byte $06,$02,$07,$03,$03,$00,$06,$02 ; CPU:$EC1E PRG:2C1E 06 02 07 03 03 00 06 02
; $EC26-$EC35
.byte $07,$03,$03,$00,$06,$02,$07,$03 ; CPU:$EC26 PRG:2C26 07 03 03 00 06 02 07 03
.byte $03,$00,$06,$02,$07,$03,$04,$00 ; CPU:$EC2E PRG:2C2E 03 00 06 02 07 03 04 00
; $EC36-$EC3F
.byte $06,$02,$07,$03,$04,$00,$06,$02 ; CPU:$EC36 PRG:2C36 06 02 07 03 04 00 06 02
.byte $07,$03 ; CPU:$EC3E PRG:2C3E 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 ; CPU:$EC40 PRG:2C40 D0 00 C0 00 A0 00 B0 00
.byte $A0,$00,$80,$00,$A0,$00,$B0,$00 ; CPU:$EC48 PRG:2C48 A0 00 80 00 A0 00 B0 00
; $EC50-$EC5F
.byte $90,$00,$50,$00,$50,$00,$D0,$00 ; CPU:$EC50 PRG:2C50 90 00 50 00 50 00 D0 00
.byte $C0,$00,$A0,$00,$B0,$00,$A0,$00 ; CPU:$EC58 PRG:2C58 C0 00 A0 00 B0 00 A0 00
; $EC60-$EC6F
.byte $80,$00,$B0,$00,$C0,$00,$A0,$00 ; CPU:$EC60 PRG:2C60 80 00 B0 00 C0 00 A0 00
.byte $50,$00,$50,$00,$F0,$00,$E0,$00 ; CPU:$EC68 PRG:2C68 50 00 50 00 F0 00 E0 00
; $EC70-$EC7F
.byte $C0,$00,$E0,$00,$D0,$00,$B0,$00 ; CPU:$EC70 PRG:2C70 C0 00 E0 00 D0 00 B0 00
.byte $E0,$00,$F0,$00,$D0,$00,$70,$00 ; CPU:$EC78 PRG:2C78 E0 00 F0 00 D0 00 70 00
; $EC80-$EC8F
.byte $70,$00,$00,$01,$F0,$00,$D0,$00 ; CPU:$EC80 PRG:2C80 70 00 00 01 F0 00 D0 00
.byte $00,$01,$F0,$00,$D0,$00,$00,$01 ; CPU:$EC88 PRG:2C88 00 01 F0 00 D0 00 00 01
; $EC90-$EC9F
.byte $10,$01,$F0,$00,$80,$00,$80,$00 ; CPU:$EC90 PRG:2C90 10 01 F0 00 80 00 80 00
.byte $00,$01,$F0,$00,$D0,$00,$00,$01 ; CPU:$EC98 PRG:2C98 00 01 F0 00 D0 00 00 01
; $ECA0-$ECAB
.byte $F0,$00,$D0,$00,$20,$01,$30,$01 ; CPU:$ECA0 PRG:2CA0 F0 00 D0 00 20 01 30 01
.byte $10,$01,$80,$00 ; CPU:$ECA8 PRG:2CA8 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 ; CPU:$ECAC PRG:2CAC 80 00 07 14 07 14 05 14
.byte $05,$FF,$07,$14,$07,$14,$05,$FF ; CPU:$ECB4 PRG:2CB4 05 FF 07 14 07 14 05 FF
; $ECBC-$ECCB
.byte $00,$00,$05,$14,$05,$14,$05,$FF ; CPU:$ECBC PRG:2CBC 00 00 05 14 05 14 05 FF
.byte $00,$00,$05,$14,$05,$14,$05,$FF ; CPU:$ECC4 PRG:2CC4 00 00 05 14 05 14 05 FF
; $ECCC-$ECDB
.byte $00,$00,$14,$0A,$1E,$0F,$28,$14 ; CPU:$ECCC PRG:2CCC 00 00 14 0A 1E 0F 28 14
.byte $32,$19,$3C,$1E,$50,$28,$64,$32 ; CPU:$ECD4 PRG:2CD4 32 19 3C 1E 50 28 64 32
; $ECDC-$ECEB
.byte $02,$1E,$5A,$00,$03,$32,$00,$00 ; CPU:$ECDC PRG:2CDC 02 1E 5A 00 03 32 00 00
.byte $04,$00,$00,$00,$01,$07,$11,$20 ; CPU:$ECE4 PRG:2CE4 04 00 00 00 01 07 11 20
; $ECEC-$ECFB
.byte $2D,$1F,$D0,$D0,$10,$13,$D0,$D0 ; CPU:$ECEC PRG:2CEC 2D 1F D0 D0 10 13 D0 D0
.byte $10,$1D,$2D,$11,$C3,$C3,$03,$11 ; CPU:$ECF4 PRG:2CF4 10 1D 2D 11 C3 C3 03 11
; $ECFC-$ECFF
.byte $C3,$C3,$03,$11 ; CPU:$ECFC PRG:2CFC 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 ; CPU:$ED00 PRG:2D00 2D 11 03 1F 10 1D 03 1F
.byte $10,$1D,$03,$11,$03,$1F,$10,$1D ; CPU:$ED08 PRG:2D08 10 1D 03 11 03 1F 10 1D
; $ED10-$ED1F
.byte $03,$1F,$10,$1D,$03,$11,$2D,$11 ; CPU:$ED10 PRG:2D10 03 1F 10 1D 03 11 2D 11
.byte $01,$11,$20,$11,$03,$11,$20,$11 ; CPU:$ED18 PRG:2D18 01 11 20 11 03 11 20 11
; $ED20-$ED2F
.byte $03,$11,$03,$11,$20,$11,$03,$11 ; CPU:$ED20 PRG:2D20 03 11 03 11 20 11 03 11
.byte $20,$11,$01,$11,$2D,$11,$03,$1E ; CPU:$ED28 PRG:2D28 20 11 01 11 2D 11 03 1E
; $ED30-$ED3F
.byte $10,$1C,$03,$1E,$10,$1C,$03,$1A ; CPU:$ED30 PRG:2D30 10 1C 03 1E 10 1C 03 1A
.byte $03,$1E,$10,$1C,$03,$1E,$10,$1C ; CPU:$ED38 PRG:2D38 03 1E 10 1C 03 1E 10 1C
; $ED40-$ED4F
.byte $03,$11,$2D,$11,$C3,$C3,$C3,$C3 ; CPU:$ED40 PRG:2D40 03 11 2D 11 C3 C3 C3 C3
.byte $83,$11,$2D,$11,$03,$1F,$10,$1D ; CPU:$ED48 PRG:2D48 83 11 2D 11 03 1F 10 1D
; $ED50-$ED5F
.byte $03,$1B,$03,$1F,$10,$10,$10,$1D ; CPU:$ED50 PRG:2D50 03 1B 03 1F 10 10 10 1D
.byte $03,$1B,$03,$1F,$10,$1D,$03,$11 ; CPU:$ED58 PRG:2D58 03 1B 03 1F 10 1D 03 11
; $ED60-$ED6F
.byte $2D,$11,$03,$1E,$10,$1C,$03,$11 ; CPU:$ED60 PRG:2D60 2D 11 03 1E 10 1C 03 11
.byte $03,$1E,$10,$13,$10,$1C,$03,$11 ; CPU:$ED68 PRG:2D68 03 1E 10 13 10 1C 03 11
; $ED70-$ED7F
.byte $03,$1E,$10,$1C,$03,$11,$2D,$11 ; CPU:$ED70 PRG:2D70 03 1E 10 1C 03 11 2D 11
.byte $C3,$03,$11,$83,$11,$83,$11,$C3 ; CPU:$ED78 PRG:2D78 C3 03 11 83 11 83 11 C3
; $ED80-$ED8F
.byte $03,$11,$2D,$1E,$90,$1D,$03,$15 ; CPU:$ED80 PRG:2D80 03 11 2D 1E 90 1D 03 15
.byte $10,$18,$08,$1A,$08,$19,$10,$14 ; CPU:$ED88 PRG:2D88 10 18 08 1A 08 19 10 14
; $ED90-$ED9F
.byte $03,$1F,$90,$1C,$2D,$E0,$11,$03 ; CPU:$ED90 PRG:2D90 03 1F 90 1C 2D E0 11 03
.byte $11,$C0,$80,$11,$03,$11,$E0,$2D ; CPU:$ED98 PRG:2D98 11 C0 80 11 03 11 E0 2D
; $EDA0-$EDAF
.byte $E0,$11,$03,$11,$00,$1F,$17,$2C ; CPU:$EDA0 PRG:2DA0 E0 11 03 11 00 1F 17 2C
.byte $16,$1D,$00,$11,$03,$11,$E0,$2D ; CPU:$EDA8 PRG:2DA8 16 1D 00 11 03 11 E0 2D
; $EDB0-$EDBF
.byte $22,$90,$1C,$03,$1A,$00,$11,$80 ; CPU:$EDB0 PRG:2DB0 22 90 1C 03 1A 00 11 80
.byte $11,$00,$1A,$03,$1E,$90,$21,$04 ; CPU:$EDB8 PRG:2DB8 11 00 1A 03 1E 90 21 04
; $EDC0-$EDCF
.byte $06,$C0,$03,$40,$11,$80,$11,$40 ; CPU:$EDC0 PRG:2DC0 06 C0 03 40 11 80 11 40
.byte $03,$C0,$05,$2D,$22,$90,$1D,$03 ; CPU:$EDC8 PRG:2DC8 03 C0 05 2D 22 90 1D 03
; $EDD0-$EDDF
.byte $1B,$00,$1E,$90,$1C,$00,$1B,$03 ; CPU:$EDD0 PRG:2DD0 1B 00 1E 90 1C 00 1B 03
.byte $1F,$90,$21,$2D,$E0,$11,$03,$11 ; CPU:$EDD8 PRG:2DD8 1F 90 21 2D E0 11 03 11
; $EDE0-$EDEF
.byte $C0,$80,$11,$03,$11,$E0,$2D,$E0 ; CPU:$EDE0 PRG:2DE0 C0 80 11 03 11 E0 2D E0
.byte $11,$03,$11,$00,$1F,$90,$1D,$00 ; CPU:$EDE8 PRG:2DE8 11 03 11 00 1F 90 1D 00
; $EDF0-$EDFF
.byte $11,$03,$11,$E0,$2D,$1F,$90,$1C ; CPU:$EDF0 PRG:2DF0 11 03 11 E0 2D 1F 90 1C
.byte $03,$1A,$00,$1E,$10,$13,$10,$1C ; CPU:$EDF8 PRG:2DF8 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 ; CPU:$EE00 PRG:2E00 00 1A 03 1E 90 1D 2D 11
.byte $C3,$C3,$03,$11,$C3,$C3,$03,$11 ; CPU:$EE08 PRG:2E08 C3 C3 03 11 C3 C3 03 11
; $EE10-$EE1F
.byte $2D,$11,$03,$19,$10,$1D,$03,$19 ; CPU:$EE10 PRG:2E10 2D 11 03 19 10 1D 03 19
.byte $10,$18,$09,$1A,$09,$19,$10,$18 ; CPU:$EE18 PRG:2E18 10 18 09 1A 09 19 10 18
; $EE20-$EE2F
.byte $03,$1F,$10,$18,$03,$11,$2D,$11 ; CPU:$EE20 PRG:2E20 03 1F 10 18 03 11 2D 11
.byte $01,$43,$11,$C3,$03,$00,$C3,$03 ; CPU:$EE28 PRG:2E28 01 43 11 C3 03 00 C3 03
; $EE30-$EE3F
.byte $11,$43,$01,$11,$2D,$15,$10,$1D ; CPU:$EE30 PRG:2E30 11 43 01 11 2D 15 10 1D
.byte $03,$11,$03,$1B,$03,$1F,$90,$1D ; CPU:$EE38 PRG:2E38 03 11 03 1B 03 1F 90 1D
; $EE40-$EE4F
.byte $03,$1B,$03,$11,$03,$1F,$10,$14 ; CPU:$EE40 PRG:2E40 03 1B 03 11 03 1F 10 14
.byte $2D,$15,$10,$1C,$03,$1A,$03,$11 ; CPU:$EE48 PRG:2E48 2D 15 10 1C 03 1A 03 11
; $EE50-$EE5F
.byte $03,$1E,$10,$13,$10,$1C,$03,$11 ; CPU:$EE50 PRG:2E50 03 1E 10 13 10 1C 03 11
.byte $03,$1A,$03,$1E,$10,$14,$2D,$11 ; CPU:$EE58 PRG:2E58 03 1A 03 1E 10 14 2D 11
; $EE60-$EE6F
.byte $C3,$03,$11,$83,$11,$83,$11,$C3 ; CPU:$EE60 PRG:2E60 C3 03 11 83 11 83 11 C3
.byte $03,$11,$2D,$11,$03,$19,$90,$12 ; CPU:$EE68 PRG:2E68 03 11 2D 11 03 19 90 12
; $EE70-$EE7F
.byte $10,$18,$03,$1A,$03,$19,$10,$12 ; CPU:$EE70 PRG:2E70 10 18 03 1A 03 19 10 12
.byte $90,$18,$03,$11,$2D,$11,$C3,$C3 ; CPU:$EE78 PRG:2E78 90 18 03 11 2D 11 C3 C3
; $EE80-$EE8B
.byte $C3,$C3,$83,$11,$2D,$1E,$D0,$D0 ; CPU:$EE80 PRG:2E80 C3 C3 83 11 2D 1E D0 D0
.byte $D0,$D0,$90,$1C ; CPU:$EE88 PRG:2E88 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 ; CPU:$EE8C PRG:2E8C A9 00
sta audioRequestPtr ; CPU:$EE8E PRG:2E8E 85 F0
lda #$06 ; CPU:$EE90 PRG:2E90 A9 06
sta audioRequestPtr+1 ; CPU:$EE92 PRG:2E92 85 F1 A9
lda #$20 ; CPU:$EE95 PRG:2E95 20 85
sta audioChannelTablePtr ; CPU:$EE97 PRG:2E97 F2 A9
lda #$06 ; CPU:$EE99 PRG:2E99 06 85
sta audioChannelTablePtr+1 ; CPU:$EE9B PRG:2E9B F3 AD 00
lda $F100 ; CPU:$EE9E PRG:2E9E F1 85 F4
sta audioSequenceTablePtr ; CPU:$EEA1 PRG:2EA1 AD 01
lda $F101 ; CPU:$EEA3 PRG:2EA3 F1 85 F5
sta audioSequenceTablePtr+1 ; CPU:$EEA6 PRG:2EA6 A9 40 85
lda #$40 ; CPU:$EEA9 PRG:2EA9 F7 A9
sta audioWorkValue ; CPU:$EEAB PRG:2EAB 1F 8D
lda #$1F ; CPU:$EEAD PRG:2EAD 15 40
sta APUSTATUS ; CPU:$EEAF PRG:2EAF A9 C0 8D
lda #$C0 ; CPU:$EEB2 PRG:2EB2 17 40
sta APUFRAMECNT ; CPU:$EEB4 PRG:2EB4 A0 00 A9
ldy #$00 ; CPU:$EEB7 PRG:2EB7 00 91
lda #$00 ; CPU:$EEB9 PRG:2EB9 F0 C8
;------------------------------------------------------------------------------
; $EEB8
; Clear sixteen contiguous bytes through ($F0).
;------------------------------------------------------------------------------
RuntimeInit_Clear0600:
sta (audioRequestPtr),y ; CPU:$EEB8 PRG:2EB8 91 F0
iny ; CPU:$EEBA PRG:2EBA C8
cpy #$10 ; CPU:$EEBB PRG:2EBB C0 10
bne RuntimeInit_Clear0600 ; CPU:$EEBD PRG:2EBD D0 F9
ldy #$00 ; CPU:$EEBF PRG:2EBF A0 00
ldx #$10 ; CPU:$EEC1 PRG:2EC1 A2 10
;------------------------------------------------------------------------------
; $EEC3
; Clear sixteen entries at an eight-byte stride.
;
; LDA #$00 is intentionally executed on every iteration.
;------------------------------------------------------------------------------
RuntimeInit_Clear0620Stride:
lda #$00 ; CPU:$EEC3 PRG:2EC3 A9 00
sta (audioChannelTablePtr),y ; CPU:$EEC5 PRG:2EC5 91 F2
tya ; CPU:$EEC7 PRG:2EC7 98
clc ; CPU:$EEC8 PRG:2EC8 18
adc #$08 ; CPU:$EEC9 PRG:2EC9 69 08
tay ; CPU:$EECB PRG:2ECB A8
dex ; CPU:$EECC PRG:2ECC CA
bne RuntimeInit_Clear0620Stride ; CPU:$EECD PRG:2ECD D0 F4
rts ; CPU:$EECF PRG:2ECF 60
;==============================================================================
; $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 ; CPU:$EED0 PRG:2ED0 A9 00
sta audioChannelFlags ; CPU:$EED2 PRG:2ED2 85 F8
sta $F9 ; CPU:$EED4 PRG:2ED4 85 F9
sta $FA ; CPU:$EED6 PRG:2ED6 85 FA
sta $FB ; CPU:$EED8 PRG:2ED8 85 FB
sta audioChannelOffset ; CPU:$EEDA PRG:2EDA 85 FD
sta $FF ; CPU:$EEDC PRG:2EDC 85 FF
lda #$F8 ; CPU:$EEDE PRG:2EDE A9 F8
sta audioIndirectPtr ; CPU:$EEE0 PRG:2EE0 85 FE
;------------------------------------------------------------------------------
; $EEE2
; Examine one eight-byte slot.
;------------------------------------------------------------------------------
ScanAudioChannelSlot:
ldy $FD ; CPU:$EEE2 PRG:2EE2 A4 FD
lda (audioChannelTablePtr),y ; CPU:$EEE4 PRG:2EE4 B1 F2
beq AdvanceAudioChannelSlot ; CPU:$EEE6 PRG:2EE6 F0 3A
cmp #$05 ; CPU:$EEE8 PRG:2EE8 C9 05
bcc ActivateAudioChannelSlot ; CPU:$EEEA PRG:2EEA 90 0B
sec ; CPU:$EEEC PRG:2EEC 38
sbc #$05 ; CPU:$EEED PRG:2EED E9 05
tay ; CPU:$EEEF PRG:2EEF A8
lda #$01 ; CPU:$EEF0 PRG:2EF0 A9 01
sta ($FE),y ; CPU:$EEF2 PRG:2EF2 91 FE
jmp AdvanceAudioChannelSlot ; CPU:$EEF4 PRG:2EF4 4C 22 EF
;------------------------------------------------------------------------------
; $EEF5
; Process slot values $01-$04.
;------------------------------------------------------------------------------
ActivateAudioChannelSlot:
sec ; CPU:$EEF7 PRG:2EF7 38
sbc #$01 ; CPU:$EEF8 PRG:2EF8 E9 01
tay ; CPU:$EEFA PRG:2EFA A8
lda ($FE),y ; CPU:$EEFB PRG:2EFB B1 FE
bne AdvanceAudioChannelSlot ; CPU:$EEFD PRG:2EFD D0 23
lda #$01 ; CPU:$EEFF PRG:2EFF A9 01
sta ($FE),y ; CPU:$EF01 PRG:2F01 91 FE
tya ; CPU:$EF03 PRG:2F03 98
tax ; CPU:$EF04 PRG:2F04 AA
adc #$04 ; CPU:$EF05 PRG:2F05 69 04
ldy $FD ; CPU:$EF07 PRG:2F07 A4 FD
sta ($F2),y ; CPU:$EF09 PRG:2F09 91 F2
txa ; CPU:$EF0B PRG:2F0B 8A
asl ; CPU:$EF0C PRG:2F0C 0A
asl ; CPU:$EF0D PRG:2F0D 0A
sta $F6 ; CPU:$EF0E PRG:2F0E 85 F6
ldx #$00 ; CPU:$EF10 PRG:2F10 A2 00
;------------------------------------------------------------------------------
; $EF12
; Set initial four-byte copy count.
;------------------------------------------------------------------------------
BeginAudioChannelParameterCopy:
lda #$04 ; CPU:$EF12 PRG:2F12 A9 04
;------------------------------------------------------------------------------
; $EF14
; Push the current copy count.
;
; The loop at $EF20 deliberately returns here, so PHA is repeated on every
; iteration.
;------------------------------------------------------------------------------
CopyAudioChannelParameter:
pha ; CPU:$EF14 PRG:2F14 48
iny ; CPU:$EF15 PRG:2F15 C8
lda ($F2),y ; CPU:$EF16 PRG:2F16 B1 F2
sta ($F6,x) ; CPU:$EF18 PRG:2F18 81 F6 E6 F6 68
inc $F6 ; CPU:$EF1D PRG:2F1D 38 E9
pla ; CPU:$EF1F PRG:2F1F 01
sec ; CPU:$EF20 PRG:2F20 D0
sbc #$01 ; CPU:$EF21 PRG:2F21 F2 A5
bne CopyAudioChannelParameter ; CPU:$EF23 PRG:2F23 FD 18
;------------------------------------------------------------------------------
; $EF22
; Advance to the next eight-byte slot.
;------------------------------------------------------------------------------
AdvanceAudioChannelSlot:
lda $FD ; CPU:$EF22 PRG:2F22 A5 FD
clc ; CPU:$EF24 PRG:2F24 18
adc #$08 ; CPU:$EF25 PRG:2F25 69 08
sta $FD ; CPU:$EF27 PRG:2F27 85 FD
cmp #$80 ; CPU:$EF29 PRG:2F29 C9 80
bcc ScanAudioChannelSlot ; CPU:$EF2B PRG:2F2B 90 B5
; 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 ; CPU:$EF2D PRG:2F2D A0 00
sty $FC ; CPU:$EF2F PRG:2F2F 84 FC
sty $FD ; CPU:$EF31 PRG:2F31 84 FD
;------------------------------------------------------------------------------
; $EF33
; Process one source entry.
;------------------------------------------------------------------------------
UpdateNextAudioSequence:
ldy $FC ; CPU:$EF33 PRG:2F33 A4 FC
lda ($F0),y ; CPU:$EF35 PRG:2F35 B1 F0
bne CheckAudioChannelActive ; CPU:$EF37 PRG:2F37 D0 03
jmp AdvanceAudioSequence ; CPU:$EF39 PRG:2F39 4C F8 EF
;------------------------------------------------------------------------------
; $EF3B
; Check the corresponding runtime record.
;------------------------------------------------------------------------------
CheckAudioChannelActive:
ldy $FD ; CPU:$EF3C PRG:2F3C A4 FD
lda ($F2),y ; CPU:$EF3E PRG:2F3E B1 F2
bne TickAudioChannelDelay ; CPU:$EF40 PRG:2F40 D0 51
lda $FC ; CPU:$EF42 PRG:2F42 A5 FC
asl ; CPU:$EF44 PRG:2F44 0A
tay ; CPU:$EF45 PRG:2F45 A8
lda ($F4),y ; CPU:$EF46 PRG:2F46 B1 F4
pha ; CPU:$EF48 PRG:2F48 48
lda $FD ; CPU:$EF49 PRG:2F49 A5 FD
adc #$05 ; CPU:$EF4B PRG:2F4B 69 05
tay ; CPU:$EF4D PRG:2F4D A8
pla ; CPU:$EF4E PRG:2F4E 68
sta ($F2),y ; CPU:$EF4F PRG:2F4F 91 F2
lda $FC ; CPU:$EF51 PRG:2F51 A5 FC
asl ; CPU:$EF53 PRG:2F53 0A
adc #$01 ; CPU:$EF54 PRG:2F54 69 01
tay ; CPU:$EF56 PRG:2F56 A8
lda ($F4),y ; CPU:$EF57 PRG:2F57 B1 F4
pha ; CPU:$EF59 PRG:2F59 48
lda $FD ; CPU:$EF5A PRG:2F5A A5 FD
adc #$06 ; CPU:$EF5C PRG:2F5C 69 06
tay ; CPU:$EF5E PRG:2F5E A8
pla ; CPU:$EF5F PRG:2F5F 68
sta ($F2),y ; CPU:$EF60 PRG:2F60 91 F2
jsr $F0C3 ; CPU:$EF62 PRG:2F62 20 C3 F0
ldy $FD ; CPU:$EF65 PRG:2F65 A4 FD
sta ($F2),y ; CPU:$EF67 PRG:2F67 91 F2
jsr $F0C3 ; CPU:$EF69 PRG:2F69 20 C3 F0
tax ; CPU:$EF6C PRG:2F6C AA
lda $FD ; CPU:$EF6D PRG:2F6D A5 FD
clc ; CPU:$EF6F PRG:2F6F 18
adc #$01 ; CPU:$EF70 PRG:2F70 69 01
tay ; CPU:$EF72 PRG:2F72 A8
txa ; CPU:$EF73 PRG:2F73 8A
sta ($F2),y ; CPU:$EF74 PRG:2F74 91 F2
jsr $F0C3 ; CPU:$EF76 PRG:2F76 20 C3 F0
tax ; CPU:$EF79 PRG:2F79 AA
lda $FD ; CPU:$EF7A PRG:2F7A A5 FD
clc ; CPU:$EF7C PRG:2F7C 18
adc #$02 ; CPU:$EF7D PRG:2F7D 69 02
tay ; CPU:$EF7F PRG:2F7F A8
txa ; CPU:$EF80 PRG:2F80 8A
sta ($F2),y ; CPU:$EF81 PRG:2F81 91 F2
jsr $F0C3 ; CPU:$EF83 PRG:2F83 20 C3 F0
tax ; CPU:$EF86 PRG:2F86 AA
lda $FD ; CPU:$EF87 PRG:2F87 A5 FD
clc ; CPU:$EF89 PRG:2F89 18
adc #$04 ; CPU:$EF8A PRG:2F8A 69 04
tay ; CPU:$EF8C PRG:2F8C A8
txa ; CPU:$EF8D PRG:2F8D 8A
sta ($F2),y ; CPU:$EF8E PRG:2F8E 91 F2
jmp DecodeAudioCommand ; CPU:$EF90 PRG:2F90 4C A2 EF
;------------------------------------------------------------------------------
; $EF94
; Decrement the active record countdown at offset 7.
;------------------------------------------------------------------------------
TickAudioChannelDelay:
lda $FD ; CPU:$EF93 PRG:2F93 A5 FD
clc ; CPU:$EF95 PRG:2F95 18
adc #$07 ; CPU:$EF96 PRG:2F96 69 07
tay ; CPU:$EF98 PRG:2F98 A8
lda ($F2),y ; CPU:$EF99 PRG:2F99 B1 F2
sec ; CPU:$EF9B PRG:2F9B 38
sbc #$01 ; CPU:$EF9C PRG:2F9C E9 01
sta ($F2),y ; CPU:$EF9E PRG:2F9E 91 F2
bne AdvanceAudioSequence ; CPU:$EFA0 PRG:2FA0 D0 56
;------------------------------------------------------------------------------
; $EFA2
; Fetch and decode the next runtime command byte.
;------------------------------------------------------------------------------
DecodeAudioCommand:
jsr $F0C3 ; CPU:$EFA2 PRG:2FA2 20 C3 F0
cmp #$F0 ; CPU:$EFA5 PRG:2FA5 C9 F0
bcs $F00D ; CPU:$EFA7 PRG:2FA7 B0 64
cmp #$C0 ; CPU:$EFA9 PRG:2FA9 C9 C0
bcs LoadAudioCommandDelay ; CPU:$EFAB PRG:2FAB B0 3E
pha ; CPU:$EFAD PRG:2FAD 48
and #$F0 ; CPU:$EFAE PRG:2FAE 29 F0
lsr ; CPU:$EFB0 PRG:2FB0 4A
lsr ; CPU:$EFB1 PRG:2FB1 4A
lsr ; CPU:$EFB2 PRG:2FB2 4A
tax ; CPU:$EFB3 PRG:2FB3 AA
lda AudioFrequencyLookupTable,x ; CPU:$EFB4 PRG:2FB4 BD E8 F0
sta $FE ; CPU:$EFB7 PRG:2FB7 85 FE
lda AudioFrequencyLookupTable+1,x ; CPU:$EFB9 PRG:2FB9 BD E9 F0
sta $FF ; CPU:$EFBC PRG:2FBC 85 FF
pla ; CPU:$EFBE PRG:2FBE 68
and #$0F ; CPU:$EFBF PRG:2FBF 29 0F
beq ApplyAudioFrequencyMask ; CPU:$EFC1 PRG:2FC1 F0 08
tax ; CPU:$EFC3 PRG:2FC3 AA
;------------------------------------------------------------------------------
; $EFC4
; Shift the selected mask by the command low nibble.
;------------------------------------------------------------------------------
ShiftAudioFrequencyMask:
lsr $FE ; CPU:$EFC4 PRG:2FC4 46
ror $FF ; CPU:$EFC5 PRG:2FC5 FE
dex ; CPU:$EFC6 PRG:2FC6 66
bne ShiftAudioFrequencyMask ; CPU:$EFC7 PRG:2FC7 FF CA
;------------------------------------------------------------------------------
; $EFCB
; Merge the generated mask into the runtime record.
;------------------------------------------------------------------------------
ApplyAudioFrequencyMask:
lda $FD ; CPU:$EFCB PRG:2FCB A5 FD
clc ; CPU:$EFCD PRG:2FCD 18
adc #$04 ; CPU:$EFCE PRG:2FCE 69 04
tay ; CPU:$EFD0 PRG:2FD0 A8
lda ($F2),y ; CPU:$EFD1 PRG:2FD1 B1 F2
and #$F8 ; CPU:$EFD3 PRG:2FD3 29 F8
ora $FE ; CPU:$EFD5 PRG:2FD5 05 FE
sta ($F2),y ; CPU:$EFD7 PRG:2FD7 91 F2
lda $FF ; CPU:$EFD9 PRG:2FD9 A5 FF
dey ; CPU:$EFDB PRG:2FDB 88
sta ($F2),y ; CPU:$EFDC PRG:2FDC 91 F2
ldy $FD ; CPU:$EFDE PRG:2FDE A4 FD
lda ($F2),y ; CPU:$EFE0 PRG:2FE0 B1 F2
cmp #$05 ; CPU:$EFE2 PRG:2FE2 C9 05
bcc LoadAudioCommandDelay ; CPU:$EFE4 PRG:2FE4 90 05
sec ; CPU:$EFE6 PRG:2FE6 38
sbc #$04 ; CPU:$EFE7 PRG:2FE7 E9 04
sta ($F2),y ; CPU:$EFE9 PRG:2FE9 91 F2
;------------------------------------------------------------------------------
; $EFEB
; Load the new runtime countdown.
;------------------------------------------------------------------------------
LoadAudioCommandDelay:
jsr $F0C3 ; CPU:$EFEB PRG:2FEB 20 C3 F0
pha ; CPU:$EFEE PRG:2FEE 48
lda $FD ; CPU:$EFEF PRG:2FEF A5 FD
clc ; CPU:$EFF1 PRG:2FF1 18
adc #$07 ; CPU:$EFF2 PRG:2FF2 69 07
tay ; CPU:$EFF4 PRG:2FF4 A8
pla ; CPU:$EFF5 PRG:2FF5 68
sta ($F2),y ; CPU:$EFF6 PRG:2FF6 91 F2
;------------------------------------------------------------------------------
; $EFF8
; Advance to the next runtime/source entry.
;------------------------------------------------------------------------------
AdvanceAudioSequence:
lda $FD ; CPU:$EFF8 PRG:2FF8 A5 FD
clc ; CPU:$EFFA PRG:2FFA 18
adc #$08 ; CPU:$EFFB PRG:2FFB 69 08
sta $FD ; CPU:$EFFD PRG:2FFD 85 FD
lda $FC ; CPU:$EFFF PRG:2FFF A5 FC
adc #$01 ; CPU:$F001 PRG:3001 69 01
sta $FC ; CPU:$F003 PRG:3003 85 FC
cmp #$10 ; CPU:$F005 PRG:3005 C9 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 ; CPU:$F007 PRG:3007 B0 03
jmp UpdateNextAudioSequence ; CPU:$F009 PRG:3009 4C 33 EF
AudioSequenceUpdateDone:
rts ; CPU:$F00C PRG:300C 60
;==============================================================================
; $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 ; CPU:$F00D PRG:300D 29 0F
asl ; CPU:$F00F PRG:300F 0A
tax ; CPU:$F010 PRG:3010 AA
lda AudioCommandHandlerTable,x ; CPU:$F011 PRG:3011 BD 1E F0
sta $FE ; CPU:$F014 PRG:3014 85 FE
lda AudioCommandHandlerTable+1,x ; CPU:$F016 PRG:3016 BD 1F F0
sta $FF ; CPU:$F019 PRG:3019 85 FF
jmp ($00FE) ; CPU:$F01B PRG:301B 6C FE 00 3E F0
;==============================================================================
; $F01E-$F03D: Runtime Command Handler Table
;
; Sixteen 16-bit handlers. Unsupported command values use the no-op handler
; at $F03E.
;==============================================================================
AudioCommandHandlerTable:
.word StopAudioSequence ; $F0 ; CPU:$F01E PRG:301E 3E F0
.word AudioCommandF1 ; $F1 ; CPU:$F020 PRG:3020 4B F0
.word AudioCommandF2 ; $F2 ; CPU:$F022 PRG:3022 63 F0
.word AudioCommandF3 ; $F3 ; CPU:$F024 PRG:3024 7B F0
.word AudioCommandF4 ; $F4 ; CPU:$F026 PRG:3026 93 F0
.word AudioCommandF5 ; $F5 ; CPU:$F028 PRG:3028 A3 F0
.word AudioCommandF6 ; $F6 ; CPU:$F02A PRG:302A B3 F0
.word StopAudioSequence ; $F7 ; CPU:$F02C PRG:302C 3E F0
.word StopAudioSequence ; $F8 ; CPU:$F02E PRG:302E 3E F0
.word StopAudioSequence ; $F9 ; CPU:$F030 PRG:3030 3E F0
.word StopAudioSequence ; $FA ; CPU:$F032 PRG:3032 3E F0
.word StopAudioSequence ; $FB ; CPU:$F034 PRG:3034 3E F0
.word StopAudioSequence ; $FC ; CPU:$F036 PRG:3036 3E F0
.word StopAudioSequence ; $FD ; CPU:$F038 PRG:3038 3E F0
.word StopAudioSequence ; $FE ; CPU:$F03A PRG:303A 3E F0
.word StopAudioSequence ; $FF ; CPU:$F03C PRG:303C 3E F0
;==============================================================================
; $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 ; CPU:$F03E PRG:303E A4 FC
lda #$00 ; CPU:$F040 PRG:3040 A9 00
sta ($F0),y ; CPU:$F042 PRG:3042 91 F0
ldy $FD ; CPU:$F044 PRG:3044 A4 FD
sta ($F2),y ; CPU:$F046 PRG:3046 91 F2
jmp AdvanceAudioSequence ; CPU:$F048 PRG:3048 4C F8 EF
;==============================================================================
; $F04B-$F062: Runtime command $F1
;
; Fetches one command byte and merges its bits into runtime-record byte 0/1.
;==============================================================================
AudioCommandF1:
jsr FetchAudioSequenceByte ; CPU:$F04B PRG:304B 20 C3 F0
pha ; CPU:$F04E PRG:304E 48
lda $FD ; CPU:$F04F PRG:304F A5 FD
clc ; CPU:$F051 PRG:3051 18
adc #$01 ; CPU:$F052 PRG:3052 69 01
tay ; CPU:$F054 PRG:3054 A8
lda ($F2),y ; CPU:$F055 PRG:3055 B1 F2
and #$3F ; CPU:$F057 PRG:3057 29 3F
sta ($F2),y ; CPU:$F059 PRG:3059 91 F2
pla ; CPU:$F05B PRG:305B 68
ora ($F2),y ; CPU:$F05C PRG:305C 11 F2
sta ($F2),y ; CPU:$F05E PRG:305E 91 F2
jmp DecodeAudioCommand ; CPU:$F060 PRG:3060 4C A2 EF
;==============================================================================
; $F063-$F07A: Runtime command $F2
;==============================================================================
AudioCommandF2:
jsr FetchAudioSequenceByte ; CPU:$F063 PRG:3063 20 C3 F0
pha ; CPU:$F066 PRG:3066 48
lda $FD ; CPU:$F067 PRG:3067 A5 FD
clc ; CPU:$F069 PRG:3069 18
adc #$01 ; CPU:$F06A PRG:306A 69 01
tay ; CPU:$F06C PRG:306C A8
lda ($F2),y ; CPU:$F06D PRG:306D B1 F2
and #$CF ; CPU:$F06F PRG:306F 29 CF
sta ($F2),y ; CPU:$F071 PRG:3071 91 F2
pla ; CPU:$F073 PRG:3073 68
ora ($F2),y ; CPU:$F074 PRG:3074 11 F2
sta ($F2),y ; CPU:$F076 PRG:3076 91 F2
jmp DecodeAudioCommand ; CPU:$F078 PRG:3078 4C A2 EF
;==============================================================================
; $F07B-$F092: Runtime command $F3
;==============================================================================
AudioCommandF3:
jsr FetchAudioSequenceByte ; CPU:$F07B PRG:307B 20 C3 F0
pha ; CPU:$F07E PRG:307E 48
lda $FD ; CPU:$F07F PRG:307F A5 FD
clc ; CPU:$F081 PRG:3081 18
adc #$01 ; CPU:$F082 PRG:3082 69 01
tay ; CPU:$F084 PRG:3084 A8
lda ($F2),y ; CPU:$F085 PRG:3085 B1 F2
and #$F0 ; CPU:$F087 PRG:3087 29 F0
sta ($F2),y ; CPU:$F089 PRG:3089 91 F2
pla ; CPU:$F08B PRG:308B 68
ora ($F2),y ; CPU:$F08C PRG:308C 11 F2
sta ($F2),y ; CPU:$F08E PRG:308E 91 F2
jmp DecodeAudioCommand ; CPU:$F090 PRG:3090 4C A2 EF
;==============================================================================
; $F093-$F0A2: Runtime command $F4
;==============================================================================
AudioCommandF4:
jsr FetchAudioSequenceByte ; CPU:$F093 PRG:3093 20 C3 F0
pha ; CPU:$F096 PRG:3096 48
lda $FD ; CPU:$F097 PRG:3097 A5 FD
clc ; CPU:$F099 PRG:3099 18
adc #$02 ; CPU:$F09A PRG:309A 69 02
tay ; CPU:$F09C PRG:309C A8
pla ; CPU:$F09D PRG:309D 68
sta ($F2),y ; CPU:$F09E PRG:309E 91 F2
jmp DecodeAudioCommand ; CPU:$F0A0 PRG:30A0 4C A2 EF
;==============================================================================
; $F0A3-$F0B2: Runtime command $F5
;==============================================================================
AudioCommandF5:
jsr FetchAudioSequenceByte ; CPU:$F0A3 PRG:30A3 20 C3 F0
pha ; CPU:$F0A6 PRG:30A6 48
lda $FD ; CPU:$F0A7 PRG:30A7 A5 FD
clc ; CPU:$F0A9 PRG:30A9 18
adc #$04 ; CPU:$F0AA PRG:30AA 69 04
tay ; CPU:$F0AC PRG:30AC A8
pla ; CPU:$F0AD PRG:30AD 68
sta ($F2),y ; CPU:$F0AE PRG:30AE 91 F2
jmp DecodeAudioCommand ; CPU:$F0B0 PRG:30B0 4C A2 EF
;==============================================================================
; $F0B3-$F0C2: Runtime command $F6
;==============================================================================
AudioCommandF6:
jsr FetchAudioSequenceByte ; CPU:$F0B3 PRG:30B3 20 C3 F0
pha ; CPU:$F0B6 PRG:30B6 48
lda $FD ; CPU:$F0B7 PRG:30B7 A5 FD
clc ; CPU:$F0B9 PRG:30B9 18
adc #$01 ; CPU:$F0BA PRG:30BA 69 01
tay ; CPU:$F0BC PRG:30BC A8
pla ; CPU:$F0BD PRG:30BD 68
sta ($F2),y ; CPU:$F0BE PRG:30BE 91 F2
jmp DecodeAudioCommand ; CPU:$F0C0 PRG:30C0 4C A2 EF
;==============================================================================
; $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 ; CPU:$F0C3 PRG:30C3 A5 FD
clc ; CPU:$F0C5 PRG:30C5 18
adc #$05 ; CPU:$F0C6 PRG:30C6 69 05
tay ; CPU:$F0C8 PRG:30C8 A8
lda ($F2),y ; CPU:$F0C9 PRG:30C9 B1 F2
sta $FE ; CPU:$F0CB PRG:30CB 85 FE
iny ; CPU:$F0CD PRG:30CD C8
lda ($F2),y ; CPU:$F0CE PRG:30CE B1 F2
sta $FF ; CPU:$F0D0 PRG:30D0 85 FF
ldx #$00 ; CPU:$F0D2 PRG:30D2 A2 00
lda ($FE,x) ; CPU:$F0D4 PRG:30D4 A1 FE 48 A5 FE
pha ; CPU:$F0D9 PRG:30D9 88
lda $FE ; CPU:$F0DA PRG:30DA 18 69
dey ; CPU:$F0DC PRG:30DC 01
clc ; CPU:$F0DD PRG:30DD 91
adc #$01 ; CPU:$F0DE PRG:30DE F2 A5
sta ($F2),y ; CPU:$F0E0 PRG:30E0 FF 69
lda $FF ; CPU:$F0E2 PRG:30E2 00 C8
adc #$00 ; CPU:$F0E4 PRG:30E4 91 F2
iny ; CPU:$F0E6 PRG:30E6 68
sta ($F2),y ; CPU:$F0E7 PRG:30E7 60 03
pla ; CPU:$F0E9 PRG:30E9 F9
rts ; CPU:$F0EA PRG:30EA 03
;==============================================================================
; $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 ; CPU:$F0E8 PRG:30E8 03 F9 03 C0 03 8A 03 57
.byte $03,$27,$02,$FA,$02,$CF,$02,$A7 ; CPU:$F0F0 PRG:30F0 03 27 02 FA 02 CF 02 A7
; $F0F8-$F107
.byte $02,$81,$02,$5D,$02,$3B,$02,$1B ; CPU:$F0F8 PRG:30F8 02 81 02 5D 02 3B 02 1B
.byte $02,$F1,$CB,$F3,$14,$F4,$22,$F1 ; CPU:$F100 PRG:3100 02 F1 CB F3 14 F4 22 F1
; $F108-$F117
.byte $3C,$F3,$3F,$F4,$50,$F4,$37,$F1 ; CPU:$F108 PRG:3108 3C F3 3F F4 50 F4 37 F1
.byte $E4,$F1,$1D,$F3,$CF,$F1,$62,$F1 ; CPU:$F110 PRG:3110 E4 F1 1D F3 CF F1 62 F1
; $F118-$F127
.byte $8D,$F1,$B0,$F1,$07,$F2,$7A,$F2 ; CPU:$F118 PRG:3118 8D F1 B0 F1 07 F2 7A F2
.byte $61,$F4,$01,$03,$7F,$08,$A2,$0C ; CPU:$F120 PRG:3120 61 F4 01 03 7F 08 A2 0C
; $F128-$F137
.byte $A2,$0C,$A2,$0C,$A2,$0C,$A2,$0C ; CPU:$F128 PRG:3128 A2 0C A2 0C A2 0C A2 0C
.byte $A2,$0C,$A2,$0C,$A2,$0C,$F0,$03 ; CPU:$F130 PRG:3130 A2 0C A2 0C A2 0C F0 03
; $F138-$F147
.byte $04,$7F,$08,$33,$01,$23,$01,$03 ; CPU:$F138 PRG:3138 04 7F 08 33 01 23 01 03
.byte $01,$A2,$01,$92,$01,$72,$01,$52 ; CPU:$F140 PRG:3140 01 A2 01 92 01 72 01 52
; $F148-$F14F
.byte $01,$32,$01,$22,$01,$02,$01,$A1 ; CPU:$F148 PRG:3148 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 ; CPU:$F150 PRG:3150 01 91 01 C0 08 91 01 A1
.byte $01,$02,$01,$22,$01,$32,$01,$52 ; CPU:$F158 PRG:3158 01 02 01 22 01 32 01 52
; $F160-$F16F
.byte $01,$F0,$01,$96,$7F,$28,$82,$01 ; CPU:$F160 PRG:3160 01 F0 01 96 7F 28 82 01
.byte $92,$01,$A2,$01,$B2,$01,$03,$01 ; CPU:$F168 PRG:3168 92 01 A2 01 B2 01 03 01
; $F170-$F17F
.byte $13,$01,$23,$01,$33,$01,$43,$01 ; CPU:$F170 PRG:3170 13 01 23 01 33 01 43 01
.byte $53,$01,$33,$01,$23,$01,$13,$01 ; CPU:$F178 PRG:3178 53 01 33 01 23 01 13 01
; $F180-$F18F
.byte $03,$01,$B2,$01,$A2,$01,$92,$01 ; CPU:$F180 PRG:3180 03 01 B2 01 A2 01 92 01
.byte $82,$01,$72,$01,$F0,$01,$96,$7F ; CPU:$F188 PRG:3188 82 01 72 01 F0 01 96 7F
; $F190-$F19F
.byte $28,$A2,$01,$B2,$01,$03,$01,$13 ; CPU:$F190 PRG:3190 28 A2 01 B2 01 03 01 13
.byte $01,$23,$01,$33,$01,$43,$01,$53 ; CPU:$F198 PRG:3198 01 23 01 33 01 43 01 53
; $F1A0-$F1AF
.byte $01,$33,$01,$23,$01,$13,$01,$03 ; CPU:$F1A0 PRG:31A0 01 33 01 23 01 13 01 03
.byte $01,$B2,$01,$A2,$01,$92,$01,$F0 ; CPU:$F1A8 PRG:31A8 01 B2 01 A2 01 92 01 F0
; $F1B0-$F1BF
.byte $01,$96,$7F,$28,$B2,$01,$03,$01 ; CPU:$F1B0 PRG:31B0 01 96 7F 28 B2 01 03 01
.byte $13,$01,$23,$01,$33,$01,$43,$01 ; CPU:$F1B8 PRG:31B8 13 01 23 01 33 01 43 01
; $F1C0-$F1CF
.byte $53,$01,$33,$01,$23,$01,$13,$01 ; CPU:$F1C0 PRG:31C0 53 01 33 01 23 01 13 01
.byte $03,$01,$B2,$01,$A2,$01,$F0,$02 ; CPU:$F1C8 PRG:31C8 03 01 B2 01 A2 01 F0 02
; $F1D0-$F1DF
.byte $9C,$7F,$28,$31,$01,$71,$01,$A1 ; CPU:$F1D0 PRG:31D0 9C 7F 28 31 01 71 01 A1
.byte $01,$12,$01,$32,$01,$72,$01,$A2 ; CPU:$F1D8 PRG:31D8 01 12 01 32 01 72 01 A2
; $F1E0-$F1EF
.byte $01,$13,$01,$F0,$02,$00,$7F,$10 ; CPU:$F1E0 PRG:31E0 01 13 01 F0 02 00 7F 10
.byte $20,$03,$50,$03,$80,$02,$A0,$02 ; CPU:$F1E8 PRG:31E8 20 03 50 03 80 02 A0 02
; $F1F0-$F1FF
.byte $21,$02,$51,$02,$81,$01,$A1,$01 ; CPU:$F1F0 PRG:31F0 21 02 51 02 81 01 A1 01
.byte $02,$01,$22,$01,$32,$01,$52,$01 ; CPU:$F1F8 PRG:31F8 02 01 22 01 32 01 52 01
; $F200-$F20F
.byte $F5,$18,$73,$01,$C0,$08,$F0,$01 ; CPU:$F200 PRG:3200 F5 18 73 01 C0 08 F0 01
.byte $03,$7F,$08,$72,$02,$82,$08,$72 ; CPU:$F208 PRG:3208 03 7F 08 72 02 82 08 72
; $F210-$F21F
.byte $02,$82,$08,$72,$02,$82,$08,$42 ; CPU:$F210 PRG:3210 02 82 08 72 02 82 08 42
.byte $02,$52,$04,$32,$04,$82,$06,$82 ; CPU:$F218 PRG:3218 02 52 04 32 04 82 06 82
; $F220-$F22F
.byte $08,$B2,$02,$03,$10,$C0,$08,$72 ; CPU:$F220 PRG:3220 08 B2 02 03 10 C0 08 72
.byte $02,$82,$08,$72,$02,$82,$08,$72 ; CPU:$F228 PRG:3228 02 82 08 72 02 82 08 72
; $F230-$F23F
.byte $02,$82,$08,$42,$02,$52,$04,$32 ; CPU:$F230 PRG:3230 02 82 08 42 02 52 04 32
.byte $04,$82,$06,$82,$08,$42,$02,$52 ; CPU:$F238 PRG:3238 04 82 06 82 08 42 02 52
; $F240-$F24F
.byte $10,$C0,$08,$72,$02,$82,$08,$72 ; CPU:$F240 PRG:3240 10 C0 08 72 02 82 08 72
.byte $02,$82,$08,$72,$02,$82,$08,$42 ; CPU:$F248 PRG:3248 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 ; CPU:$F250 PRG:3250 02 52 04 32 04 82 06 82
.byte $08,$A2,$02,$B2,$08,$03,$02,$13 ; CPU:$F258 PRG:3258 08 A2 02 B2 08 03 02 13
; $F260-$F26F
.byte $0A,$13,$02,$23,$0C,$03,$02,$13 ; CPU:$F260 PRG:3260 0A 13 02 23 0C 03 02 13
.byte $08,$A2,$02,$B2,$08,$82,$0A,$A2 ; CPU:$F268 PRG:3268 08 A2 02 B2 08 82 0A A2
; $F270-$F27F
.byte $02,$B2,$0A,$72,$02,$82,$10,$C0 ; CPU:$F270 PRG:3270 02 B2 0A 72 02 82 10 C0
.byte $08,$F0,$02,$81,$7F,$40,$80,$08 ; CPU:$F278 PRG:3278 08 F0 02 81 7F 40 80 08
; $F280-$F28F
.byte $C0,$06,$80,$04,$C0,$02,$80,$08 ; CPU:$F280 PRG:3280 C0 06 80 04 C0 02 80 08
.byte $C0,$06,$80,$04,$C0,$02,$80,$08 ; CPU:$F288 PRG:3288 C0 06 80 04 C0 02 80 08
; $F290-$F29F
.byte $C0,$06,$80,$04,$C0,$02,$01,$04 ; CPU:$F290 PRG:3290 C0 06 80 04 C0 02 01 04
.byte $C0,$01,$11,$04,$C0,$01,$21,$04 ; CPU:$F298 PRG:3298 C0 01 11 04 C0 01 21 04
; $F2A0-$F2AF
.byte $C0,$01,$31,$04,$C0,$01,$80,$08 ; CPU:$F2A0 PRG:32A0 C0 01 31 04 C0 01 80 08
.byte $C0,$06,$80,$04,$C0,$02,$80,$08 ; CPU:$F2A8 PRG:32A8 C0 06 80 04 C0 02 80 08
; $F2B0-$F2BF
.byte $C0,$06,$80,$04,$C0,$02,$80,$08 ; CPU:$F2B0 PRG:32B0 C0 06 80 04 C0 02 80 08
.byte $C0,$06,$80,$04,$C0,$02,$01,$04 ; CPU:$F2B8 PRG:32B8 C0 06 80 04 C0 02 01 04
; $F2C0-$F2CF
.byte $C0,$01,$11,$04,$C0,$01,$21,$04 ; CPU:$F2C0 PRG:32C0 C0 01 11 04 C0 01 21 04
.byte $C0,$01,$31,$04,$C0,$01,$80,$08 ; CPU:$F2C8 PRG:32C8 C0 01 31 04 C0 01 80 08
; $F2D0-$F2DF
.byte $C0,$06,$80,$04,$C0,$02,$80,$08 ; CPU:$F2D0 PRG:32D0 C0 06 80 04 C0 02 80 08
.byte $C0,$06,$80,$04,$C0,$02,$80,$08 ; CPU:$F2D8 PRG:32D8 C0 06 80 04 C0 02 80 08
; $F2E0-$F2EF
.byte $C0,$06,$80,$04,$C0,$02,$01,$04 ; CPU:$F2E0 PRG:32E0 C0 06 80 04 C0 02 01 04
.byte $C0,$01,$11,$04,$C0,$01,$21,$04 ; CPU:$F2E8 PRG:32E8 C0 01 11 04 C0 01 21 04
; $F2F0-$F2FF
.byte $C0,$01,$31,$04,$C0,$01,$81,$0A ; CPU:$F2F0 PRG:32F0 C0 01 31 04 C0 01 81 0A
.byte $31,$04,$C0,$01,$21,$04,$C0,$01 ; CPU:$F2F8 PRG:32F8 31 04 C0 01 21 04 C0 01
; $F300-$F30F
.byte $11,$04,$C0,$01,$B0,$04,$C0,$01 ; CPU:$F300 PRG:3300 11 04 C0 01 B0 04 C0 01
.byte $80,$04,$C0,$01,$70,$04,$C0,$01 ; CPU:$F308 PRG:3308 80 04 C0 01 70 04 C0 01
; $F310-$F31F
.byte $60,$08,$C0,$02,$70,$08,$C0,$02 ; CPU:$F310 PRG:3310 60 08 C0 02 70 08 C0 02
.byte $80,$0C,$C0,$06,$F0,$02,$98,$7F ; CPU:$F318 PRG:3318 80 0C C0 06 F0 02 98 7F
; $F320-$F32F
.byte $28,$33,$01,$23,$01,$13,$01,$03 ; CPU:$F320 PRG:3320 28 33 01 23 01 13 01 03
.byte $01,$A2,$01,$82,$01,$72,$01,$52 ; CPU:$F328 PRG:3328 01 A2 01 82 01 72 01 52
; $F330-$F33F
.byte $01,$32,$01,$12,$01,$A1,$01,$71 ; CPU:$F330 PRG:3330 01 32 01 12 01 A1 01 71
.byte $01,$31,$01,$F0,$01,$42,$7F,$38 ; CPU:$F338 PRG:3338 01 31 01 F0 01 42 7F 38
; $F340-$F34F
.byte $23,$02,$33,$02,$43,$02,$53,$02 ; CPU:$F340 PRG:3340 23 02 33 02 43 02 53 02
.byte $43,$02,$33,$02,$23,$02,$13,$02 ; CPU:$F348 PRG:3348 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 ; CPU:$F350 PRG:3350 23 02 33 02 43 02 33 02
.byte $23,$02,$13,$02,$03,$02,$13,$02 ; CPU:$F358 PRG:3358 23 02 13 02 03 02 13 02
; $F360-$F36F
.byte $23,$02,$33,$02,$23,$02,$13,$02 ; CPU:$F360 PRG:3360 23 02 33 02 23 02 13 02
.byte $03,$02,$B2,$02,$03,$02,$13,$02 ; CPU:$F368 PRG:3368 03 02 B2 02 03 02 13 02
; $F370-$F37F
.byte $23,$02,$13,$02,$03,$02,$B2,$02 ; CPU:$F370 PRG:3370 23 02 13 02 03 02 B2 02
.byte $A2,$02,$B2,$02,$03,$02,$23,$02 ; CPU:$F378 PRG:3378 A2 02 B2 02 03 02 23 02
; $F380-$F38F
.byte $03,$02,$B2,$02,$A2,$02,$92,$02 ; CPU:$F380 PRG:3380 03 02 B2 02 A2 02 92 02
.byte $A2,$02,$B2,$02,$03,$02,$B2,$02 ; CPU:$F388 PRG:3388 A2 02 B2 02 03 02 B2 02
; $F390-$F39F
.byte $A2,$02,$92,$02,$82,$02,$92,$02 ; CPU:$F390 PRG:3390 A2 02 92 02 82 02 92 02
.byte $A2,$02,$03,$02,$A2,$02,$92,$02 ; CPU:$F398 PRG:3398 A2 02 03 02 A2 02 92 02
; $F3A0-$F3AF
.byte $82,$02,$F2,$00,$F3,$00,$F5,$18 ; CPU:$F3A0 PRG:33A0 82 02 F2 00 F3 00 F5 18
.byte $31,$01,$71,$01,$B1,$01,$32,$01 ; CPU:$F3A8 PRG:33A8 31 01 71 01 B1 01 32 01
; $F3B0-$F3BF
.byte $72,$01,$B2,$01,$33,$01,$73,$01 ; CPU:$F3B0 PRG:33B0 72 01 B2 01 33 01 73 01
.byte $C0,$02,$31,$01,$71,$01,$B1,$01 ; CPU:$F3B8 PRG:33B8 C0 02 31 01 71 01 B1 01
; $F3C0-$F3CF
.byte $32,$01,$72,$01,$B2,$01,$33,$01 ; CPU:$F3C0 PRG:33C0 32 01 72 01 B2 01 33 01
.byte $73,$01,$F0,$01,$81,$7F,$40,$31 ; CPU:$F3C8 PRG:33C8 73 01 F0 01 81 7F 40 31
; $F3D0-$F3DF
.byte $08,$32,$08,$A1,$08,$71,$08,$32 ; CPU:$F3D0 PRG:33D0 08 32 08 A1 08 71 08 32
.byte $07,$A1,$07,$71,$0C,$C0,$06,$41 ; CPU:$F3D8 PRG:33D8 07 A1 07 71 0C C0 06 41
; $F3E0-$F3EF
.byte $08,$42,$08,$B1,$08,$81,$08,$42 ; CPU:$F3E0 PRG:33E0 08 42 08 B1 08 81 08 42
.byte $07,$B1,$07,$81,$0C,$C0,$06,$31 ; CPU:$F3E8 PRG:33E8 07 B1 07 81 0C C0 06 31
; $F3F0-$F3FF
.byte $08,$32,$08,$A1,$08,$71,$08,$32 ; CPU:$F3F0 PRG:33F0 08 32 08 A1 08 71 08 32
.byte $07,$A1,$07,$71,$0C,$C0,$06,$61 ; CPU:$F3F8 PRG:33F8 07 A1 07 71 0C C0 06 61
; $F400-$F40F
.byte $05,$71,$05,$81,$05,$81,$05,$91 ; CPU:$F400 PRG:3400 05 71 05 81 05 81 05 91
.byte $05,$A1,$05,$A1,$05,$B1,$05,$02 ; CPU:$F408 PRG:3408 05 A1 05 A1 05 B1 05 02
; $F410-$F41F
.byte $05,$32,$0C,$F0,$02,$82,$7F,$40 ; CPU:$F410 PRG:3410 05 32 0C F0 02 82 7F 40
.byte $30,$18,$A0,$08,$30,$0E,$A0,$0C ; CPU:$F418 PRG:3418 30 18 A0 08 30 0E A0 0C
; $F420-$F42F
.byte $C0,$06,$40,$18,$B0,$08,$40,$0E ; CPU:$F420 PRG:3420 C0 06 40 18 B0 08 40 0E
.byte $B0,$0C,$C0,$06,$30,$18,$A0,$08 ; CPU:$F428 PRG:3428 B0 0C C0 06 30 18 A0 08
; $F430-$F43F
.byte $30,$0E,$A0,$0C,$C0,$06,$A0,$0F ; CPU:$F430 PRG:3430 30 0E A0 0C C0 06 A0 0F
.byte $01,$0F,$21,$0F,$31,$0C,$F0,$01 ; CPU:$F438 PRG:3438 01 0F 21 0F 31 0C F0 01
; $F440-$F44F
.byte $9F,$7F,$28,$01,$01,$41,$01,$71 ; CPU:$F440 PRG:3440 9F 7F 28 01 01 41 01 71
.byte $01,$A1,$01,$02,$01,$F5,$18,$F0 ; CPU:$F448 PRG:3448 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 ; CPU:$F450 PRG:3450 01 9F 7F 28 02 01 A1 01
.byte $71,$01,$41,$01,$F5,$18,$01,$01 ; CPU:$F458 PRG:3458 71 01 41 01 F5 18 01 01
; $F460-$F46F
.byte $F0,$01,$9F,$7F,$28,$52,$01,$92 ; CPU:$F460 PRG:3460 F0 01 9F 7F 28 52 01 92
.byte $01,$03,$01,$33,$01,$F5,$18,$53 ; CPU:$F468 PRG:3468 01 03 01 33 01 F5 18 53
; $F470-$F47F
.byte $03,$F5,$28,$53,$01,$33,$01,$03 ; CPU:$F470 PRG:3470 03 F5 28 53 01 33 01 03
.byte $01,$92,$01,$F5,$18,$52,$03,$92 ; CPU:$F478 PRG:3478 01 92 01 F5 18 52 03 92
; $F480-$F48F
.byte $01,$13,$01,$43,$01,$73,$01,$F5 ; CPU:$F480 PRG:3480 01 13 01 43 01 73 01 F5
.byte $18,$93,$0A,$F5,$28,$93,$01,$73 ; CPU:$F488 PRG:3488 18 93 0A F5 28 93 01 73
; $F490-$F49A
.byte $01,$43,$01,$13,$01,$F5,$18,$92 ; CPU:$F490 PRG:3490 01 43 01 13 01 F5 18 92
.byte $03,$F0,$FF ; CPU:$F498 PRG:3498 03 F0 FF
;==============================================================================
; $F49B-$F64F: PRG Padding
;==============================================================================
.res $0B5B, $FF ; CPU:$F49B PRG:349B FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 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 ; CPU:$FFF6 PRG:3FF6 EC EC
.byte $0E,$C1 ; CPU:$FFF8 PRG:3FF8 0E C1
;==============================================================================
; $FFFA-$FFFF: Interrupt Vectors
;==============================================================================
.org $FFFA
CpuInterruptVectors:
.word NmiHandler ; NMI ; CPU:$FFFA PRG:3FFA 0E C1
.word Reset ; Reset ; CPU:$FFFC PRG:3FFC 33 C0
.word IrqHandler ; IRQ/BRK ; CPU:$FFFE PRG:3FFE 7E C1