- Apply symbols.inc hardware register names to Defender 2 (U) (51 operands)
- Apply symbols.inc hardware register names to Donkey Kong 3 (JUE) (36 operands)
- Add APU register symbols (-) to Defender 2 (U) and Donkey Kong 3 (JUE) symbols.inc
- Apply symbols to Donkey Kong Jr. Math (U) (80 operands: 11 single + 69 hardware)
- Apply symbols to Excitebike (JU) (786 operands: 785 single + 1 hardware)
- Add promotion criteria to PROMPTS.md: symbol/local substitution,
ROM-specific semantic naming, and verification checklist
Add branch/jump target naming requirement to PROMPTS.md
All branches and jumps must target symbolic labels with descriptive names
derived from program flow role (e.g., _Loop, _Next, _Done, _Store, _Return),
never raw address literals. Adds criterion 8 to verification checklist.
Rename all OVERVIEW.md to README.md; add root README content to top-level
- Rename all OVERVIEW.md files to README.md throughout the repo (47 files)
- Prepend README.md content to top-level OVERVIEW.md before rename
- Fix apply_symbols.py NAME_RE regex to handle spaced assignments
- Apply symbols.inc to Defender 2 (U) (51 hardware operands)
- Apply symbols.inc to Donkey Kong 3 (JUE) (36 hardware operands)
- Apply symbols.inc to Donkey Kong Jr. Math (U) (80 operands: 11 single + 69 hardware)
- Apply symbols.inc to Excitebike (JU) (786 operands: 785 single + 1 hardware)
- Add missing Zp18/FrameCounter aliases to Excitebike prg.s
- Build all 27 top-level projects: byte-identical
Promote Donkey Kong Jr. Math back to _wip tier
Moves code from `copilot` folder and verifies each builds after
Add pre-commit hook for byte-identical verification
Add .git/hooks/pre-commit that runs 'make' then 'make clean' in each
project directory before committing. This ensures every project builds
byte-identical before any commit is accepted.
Also includes all file moves from the Donkey Kong Jr. Math (U) demotion
and other file restructuring from the session.
moves code out of copilot folder, its all AI generated.
Moves NROM games into NROM folder
removes copilot folder from Lunar Pool
Adds makefile to build all projects recursively
Updates docs to reflect changes in layout
Repromotes Donkey Kong Jr Math
Repromotes Excitebike
Promotes Popeye (JU) (PRG 1)
Updates Makefile to provide summary of build failure/success
Promote Raid on Bungeling Bay (U): Pass 2/3 partial, whole-ROM byte-identical
Move _wip/NROM/Raid on Bungeling Bay (U) to NROM/ and switch the build
from a PRG-only compare to a whole-ROM one:
- header.s/chr.s added (one-line .incbin of header.bin / chr.bin)
- linker.cfg gains HEADER ($0000, $0010) and CHR ($0000, $2000)
areas ahead of PRG ($C000, $4000)
- rom.nes symlink to the space-containing original ROM name
- Makefile builds header.o/prg.o/chr.o into reconstructed.nes and
compares it against rom.nes ('Byte-identical ROM verified.')
- one leftover neutral indirect operand jmp (Zp01) at $E2EC becomes
jmp (IndDispatch01); apply_symbols.py reports 0 substitutions pending
README.md / TODO.md / AGENTS.md updated: 29 promoted, 7 in _wip/.
Pac-Man (U): Pass 2 complete (label renaming) + Pass 3 partial (ZP aliases, table names)
Pass 2 — fresh map derived from the committed split, not from any drafted
map (the drafted maps in other projects were audited and found not
applicable):
- all 194 address-derived Label_XXXX definitions renamed to semantic
routine-entry names plus <Routine>_<Role>_<addr> internal branch
targets; zero Label_ remains
- all 49 jsr/jmp call sites resolved from raw $XXXX to labels; zero
raw $XXXX call operands remain
- routinemap.tsv / derived_names.tsv record the derivation
Pass 3 (partial):
- 15 proven semantic zero-page aliases added to locals.inc
(GameState, NmiFlag, ScrollX/Y, PpuCtrlShadow, OamDmaPage,
CocktailModeFlag, ActivePlayerFlag, GameplaySuspended, FrameCounter,
StateTimer, Player1/2Input, ActiveInput, CopyrightVerified)
- 112 operands substituted into prg.s (11 single + 101 hardware)
- key data tables named: ProgrammerSig ($C0EB), GameStateDispatchTable
($C253), TitleScreenData ($C2FD), EntityPtrTable ($D912),
AudioCommandTable ($EFDD)
Also corrects the README's claim that the RESET vector points at padding:
$FF00 holds real boot code (sei/cld, PPU off, double vblank wait, then
jmp ColdStart at $C042).
.gitignore: ignore reconstructed_prg.bin (build artifact of the _wip
Makefiles; '**/reconstructed.*' does not match the underscore form).
Promote Pac-Man (U): Pass 2/3 complete, whole-ROM byte-identical
Move _wip/NROM/Pac-Man (U) to NROM/ and switch the build from a PRG-only
compare to a whole-ROM one:
- header.s/chr.s added (one-line .incbin of header.bin / chr.bin)
- linker.cfg gains HEADER ($0000, $0010) and CHR ($0000, $2000)
areas ahead of PRG ($C000, $4000)
- rom.nes symlink to 'Pac-Man (U) [!].nes' (the original ROM name
contains a space and brackets)
- Makefile builds header.o/prg.o/chr.o into reconstructed.nes and
compares it against rom.nes
- reconstructed.nes is 24,592 bytes, MD5 a69d310f8cae9397fbd39f204672b5c7
- equal to the original ROM; the header/prg/chr splits were checked
against the original before promotion and are byte-exact
Pass 3 residue closed. The last 7 multi-alias zero-page operands are
resolved per site through a new sites.tsv, each proven from context
rather than guessed:
- jmp ($0010) at $C250/$D3CA/$D90F/$D9B6 -> (DispatchPtrLo); each
is immediately preceded by sta DispatchPtrLo/sta DispatchPtrHi
- jmp ($00FE) at $EFDA -> (AudioHandlerPtrLo); preceded by
sta AudioHandlerPtrLo/sta AudioHandlerPtrHi
- sta a:$0000,y at $C048/$C089 -> a:Zp00,y; the literal zero-page
base in the two ZP clear loops, so the neutral name is used rather
than the semantic WorkPtrLo. The 'a:' prefix survives the
substitution, so the bytes stay 99 00 00 (sta abs,Y)
apply_symbols.py now reports 119 operands substituted (101 hardware,
11 single-name, 7 site) and 0 residue.
New tool _tools/align_audit_comments.py: re-aligns the audit comment to
column 35 after a substitution lengthens an operand (nesdis.py pads each
instruction to 31 characters). Whitespace-only, so the byte identity
cannot change. 405 lines re-aligned in this project; all 2,387 audit
comments still match prg.bin at the stated PRG offset, 0 mismatches.
Docs: root README.md / TODO.md / AGENTS.md updated - 30 promoted, 6 in
_wip/; a per-project detail entry for Pac-Man (U) added; the stale
'Donkey Kong 3 (JUE) has no README.md' claim corrected (it has a
318-line one).
Promote Raid on Bungeling Bay (U) [a2]: Pass 3 complete, whole-ROM byte-identical
Move _wip/NROM/Raid on Bungeling Bay (U) [a2] to NROM/ and switch the build
from a PRG-only compare to a whole-ROM one:
- header.s/chr.s added (one-line .incbin of header.bin / chr.bin)
- linker.cfg gains HEADER ($0000, $0010) and CHR ($0000, $2000)
areas ahead of PRG ($C000, $4000)
- rom.nes symlink to 'Raid on Bungeling Bay (U) [a2].nes' (the original
ROM name contains spaces and brackets)
- reconstructed.nes is 24,592 bytes, MD5 659d340a1e9d420eee28df13319b0094
- equal to the original ROM; the header/prg/chr splits were checked
against the original before promotion and are byte-exact
Pass 3 - 15 semantic zero-page aliases, each applied only at the sites
where its role is proven:
- PpuCtrlShadow ($C2), 15 sites: the reset entry primes it right after
'sta PPUCTRL', and every other use is an ora/and/eor followed by
'sta PPUCTRL'
- NmiPathSelector ($C4), 5 sites: written 1 at $C3E9 and 0 at $C962
- GameState ($D6), 6 sites: 'cmp #$02' and used as an index at $C4C7
- FrameSubCounter ($55), 6 sites: set to $0A at $C520, decremented per
NMI at $C07B
- PrngPeriodCounter ($EA) / PrngSeedB ($EB) / PrngState ($EC), 13 sites:
the PRNG state
- PtrLo ($00) / PtrHi ($01), 8 sites: the 16-bit pair $1C13 and $1610
compared at $E785/$E791
- IndDispatch01 ($01) / IndDispatch02 ($02), 3 sites: the computed
dispatch at $E2EC
- IndDispatch1B ($1B) / IndDispatch1C ($1C), 6 sites: the dispatch at
$E7A3
- IndDispatch17 ($17) / IndDispatch19 ($19): the dispatches at $E79D
and $E7A0
Addresses that carry two names keep the neutral ZpXX name where the other
role applies - $01 is PtrHi at the 16-bit compare and IndDispatch01 at the
dispatch; $17 is IndDispatch17 at the dispatch and Zp17 for the absolute
RAM $0017 store in the copy loop at $E895/$E8D0.
New tool _tools/apply_zp_aliases.py does the per-site substitution:
apply_symbols.py only rewrites *numeric* operands, so it cannot rename an
operand that is already written as a neutral ZpXX name. The tool keeps the
ca65 'a:' prefix (dropping it would turn 'sta a:Zp17,y' into a zero-page
store and change the bytes) and rewrites only the operand token, so the
audit comment survives byte for byte.
Naming correction in the promoted sibling. Finishing this dump showed that
$EA was misnamed 'VBlankWaitCounter': the routine at $C412 is the game's
pseudo-random generator (the classic eor/asl/php/lsr/plp/rol scrambler,
called from thirteen gameplay sites, twice in a row at $CDF4/$CDF9 with the
second result masked #$07), so $EA is the scrambler's phase counter.
Renamed PrngPeriodCounter in both dumps and named $EB/$EC PrngSeedB /
PrngState. The sibling's two 'sta a:IndDispatch17,y' operands were also
wrong - they are absolute stores to RAM $0017, not the dispatch pointer -
and are now 'a:Zp17,y', matching the file's 'a:' = absolute convention.
Audit-comment alignment re-done with _tools/align_audit_comments.py (1,040
lines here, 1,080 in the sibling). Both files still match prg.bin at every
stated PRG offset: 5,467 and 5,483 audit comments, 0 mismatches.
Docs: root README.md / TODO.md / AGENTS.md updated - 31 promoted, 5 in
_wip/; per-project detail entries added for both Raid dumps.
Promote Pac-Man (Tengen) (U): Pass 2/3 from scratch, whole-ROM byte-identical
Move _wip/NROM/Pac-Man (Tengen) (U) to NROM/ and switch the build from a
PRG-only compare to a whole-ROM one:
- header.s/chr.s added (one-line .incbin of header.bin / chr.bin)
- linker.cfg gains HEADER ($0000, $0010) and CHR ($0000, $2000)
areas ahead of PRG ($C000, $4000)
- rom.nes symlink to 'Pac-Man (Tengen) (U) [!].nes'
- reconstructed.nes is 24,592 bytes, MD5 d34e7a74d8d2c231b6cc601210e28ad0
- equal to the original ROM; the header/prg/chr splits were checked
against the original before promotion and are byte-exact
Disassembled from scratch. No name, map or file was carried over from the
sibling 'Pac-Man (U)' dump; the map was derived from this dump's own
committed split and the two were only compared afterwards.
Pass 2 (new tool _tools/apply_pass2_map.py):
- all 194 Label_XXXX definitions renamed to semantic routine entries plus
<Routine>_<Role> branch targets; zero Label_ remains
- all 48 raw $XXXX jsr/jmp operands resolved to labels; zero raw $XXXX
call or branch operands remain
- the map is in routinemap.tsv
Pass 3:
- 30 semantic zero-page aliases, each applied only at the sites where its
role is proven (per-site choice in sites.tsv; the addresses that carry
two roles keep the neutral ZpXX name elsewhere). _tools/
derive_zp_aliases.py records how the set was derived, and locals.inc
records the reason for every remaining neutral slot
- 28 data tables named (new tool _tools/name_data_region.py), including
CharacterDataTable ($C66A) and CharacterNameStrings ($C67E), where the
ROM itself names Blinky, Pinky, Inky and Clyde - which is why the four
indexed entities are called ghosts and not 'actors'
- apply_symbols.py reports 0 substitutions pending and 0 residue
- audit-comment alignment re-done with _tools/align_audit_comments.py;
all 2,479 audit comments still match prg.bin at the stated PRG offset
Pass 1 correction - six command handlers recovered (new tool
_tools/recode_region.py). ScriptCommandTable ($EFDD) is read by the traced
instruction at $EFCC, and six of its entries point at $F00A, $F022, $F03A,
$F052, $F062 and $F072 - all of which the tracer had left as data, and two
of which it had mis-split across the 'jmp $EF61' at $F01F and $F04F.
Those 120 bytes are code here, decoded straight from the ROM; the six
handlers tile $F00A-$F081 exactly. The same gap exists in the promoted
'Pac-Man (U)' dump, which has not been corrected - recorded in both READMEs.
Residue (documented, not guessed): the unreached main game logic at
$C45A-$C55F is still .byte data. It is code - the tracer's own decoder
walks it cleanly and the dispatch table at $C511 points into it - but
nothing reaches it, so it cannot be entered without a guess. The same gap
exists in the promoted 'Pac-Man (U)' dump. Re-deriving it is a Pass 1 job;
a Mesen Code Data Logger capture is the tool the repo uses for it.
Docs: root README.md / TODO.md / AGENTS.md updated - 32 promoted, 4 in
_wip/; a per-project detail entry added for the Tengen dump.
Promote Pyramid (U): Pass 1 corrected, Pass 2/3 complete, whole-ROM byte-identical
Move _wip/NROM/Pyramid (U) to NROM/ and switch the build from a PRG-only
compare to a whole-ROM one:
- header.s/chr.s added (one-line .incbin of header.bin / chr.bin)
- linker.cfg gains HEADER ($0000, $0010) and CHR ($0000, $2000)
areas ahead of PRG ($C000, $4000)
- rom.nes symlink to 'Pyramid (U) (Sachen).nes'
- reconstructed.nes is 24,592 bytes, MD5 aa285ff17f25dd05da5996b7466c59e2
- equal to the original ROM; the header/prg/chr splits were checked
against the original before promotion and are byte-exact
Pass 1 correction - the committed split was a strict subset of the correct
one. This game dispatches through 'jmp' trampoline tables that live
*inside* the data regions, and the tracer cannot follow a jmp there, so
828 bytes of code were still marked as data. Four such tables were found
($C01E 3 entries, $C02A 6, $C042 2, $C054 5) plus ten more entries at
$C000-$C01B; all sixteen targets decode as valid instructions. Seeding
them, the $C800 boot mainline and six further code starts recovers the
whole lot, plus a five-byte stub at $DF89 (lda $33 / jmp $DECB) that sat
in a hole between two routines. The re-trace loses NO committed code byte
and takes the split from 34.5% to 39.6% (3,130 instructions / 6,493 code
bytes). 'make regen' reproduces it, so the split stays verifiable.
Pass 2 - a fresh map derived from this dump's own committed split:
- 428 Label_XXXX definitions renamed; zero Label_ residue
- 320 raw $XXXX jsr/jmp operands resolved; zero raw $XXXX branch
operands remain
- 431 routine entries and the 32 data blocks named from the code
- the internal branch-target names are derived mechanically from the
branch that reaches them by the new _tools/derive_branch_names.py
(beq -> OnZero, bne -> OnNonzero, bcc/bcs -> the carry cases, a
backwards branch -> Loop)
- recorded in routinemap.tsv
Pass 3:
- 24 semantic zero-page aliases, each applied only where its role is
proven; the 57 slots that stay neutral are each listed with the reason
in locals.inc (the neutral set lives in zp_aliases.inc so that
'make regen' can rebuild locals.inc from prg.bin)
- 32 data tables named - TaskVectorTable1/2, LevelScriptData,
MusicPeriodTable, SoundEnvelopeTable, the actor tables - recorded in
data_region_names.tsv
- apply_symbols.py reports 0 substitutions pending and 0 residue; no
hardware register is left as a raw literal
- the audit comments are now canonical on every line, data included
(the old file carried only 'PRG:$xxxx' on its 1,358 data lines);
all 3,762 audit comments match prg.bin at their stated PRG offset
Kept as-is, not 'cleaned up':
- sta $4100 stays a raw operand. The iNES header claims mapper 0 but
the boot code writes past the NES register space; the ROM does not
explain it, so it is recorded rather than guessed
- the 'A'/'V' check on RAM $0120/$0121 and its seed/clear routines
are named for what they do, not for what they are for
- the ninth entry of the $C3A6 task vector table ($D820) is a junk
slot and stays data
Docs: root README.md / TODO.md / AGENTS.md updated - 33 promoted, 3 in
_wip/; a per-project detail entry added.
Hogan's Alley (JU): Pass 1 correction, Pass 2, Pass 3, promoted to NROM/
The light-gun game whose engine dispatches through *inline* tables:
`IndirectCall` at $C34D pops the return address of the `jsr` that called
it and reads a 16-bit handler pointer from the word that follows, so all
six handler tables ($C124 19 entries, $C219 4, $C89C 14, $CDD1 1, $D234 2,
$D3D6 14) live inside the code stream and the static tracer cannot follow
them.
Pass 1 correction. The committed split was a strict subset of the correct
one -- 41.8% of the PRG was classified as code. A fresh Mesen Code Data
Logger capture was merged with the four captures already in the folder
(hogans_merged.cdl, the OR of five per-byte flag arrays, 6,544 code bytes)
and _tools/cdl_reclass.py rewrote the split to match what the CPU actually
fetched: 1,216 bytes moved from data to code, five the other way, 59 labels
emitted. The split is now 49.1% code (3,950 instructions, 8,041 bytes).
The four branch targets the reclassifier could not prove were turned into
labels by the new _tools/resolve_raw_branches.py.
Pass 2. 206 routine entries hand-named from this dump's own code and 413
internal branch targets derived mechanically by _tools/derive_branch_names.py:
630 Label_XXXX definitions gone, 484 raw $XXXX call operands resolved, 15
call targets the tracer had never labelled given a label. Recorded in
routinemap.tsv. No SubC<addr> residue was needed -- every entry the engine
reaches is named after what it does.
Pass 3. 60 semantic zero-page aliases, each applied only where its role is
proven (zp_aliases.inc, zp_alias_sites.tsv); the slots that stay neutral are
each listed with the reason. All 34 data blocks named
(data_region_names.tsv). apply_symbols.py reports 1 residue: `sta a:$00B4,y`
at $C203, the same address as Zp40/ActorPalette but forced to absolute
addressing, so it must stay numeric.
Promotion. header.s, chr.s and a HEADER/PRG/CHR linker.cfg added, rom.nes
symlinked to the original ROM; the whole-ROM cmp passes on the first
promoted build. There is deliberately no `make regen` target: the Pass 1
split here is the static trace corrected by a CDL capture, and the base the
correction was applied to is not what the current _tools/nesdis.py
produces, so prg.s is the maintained source of truth.
Tools changed:
nesdis.py --split/--note/--provenance options, so a data
region can carry its own name and explanation;
a forced-data address is no longer reported as a
recovered routine entry
apply_pass2_map.py can create the label for a call target the tracer
left unlabelled; no longer double-labels it
apply_zp_aliases.py --at-file, an address-based per-site list
derive_branch_names.py keeps the map's own header instead of writing a
fixed one
resolve_raw_branches.py new: turns `bXX *+$NN` operands into labels
build_hogans_map.py new: the hand-written Pass 2 map builder
The existing regen pipelines (MUSCLE (U), Urban Champion (JU)) still
reproduce prg.s byte for byte.
Apply the symbols.inc register names at Pass 1; fix a dropped byte in cdl_reclass
nesdis.py now names the hardware registers as it renders the operands, so a
project's Pass 1 output already reads `lda PPUSTATUS` instead of `lda $2002`
and the Pass 3 apply_symbols.py step has nothing left to do for them.
* nesdis.py --symbols FILE reads a symbols.inc-style file and substitutes
the register names. Only unambiguous entries in the $2000-$4017 window
are used: $4017 is both JOY2 and APUFRAMECOUNTER, so it stays numeric
and apply_symbols.py reports it as multi-alias residue, exactly as
before. The default is the symbols.inc next to --out, so a new project
gets the names without asking; --no-symbols opts out.
* The renderer records the operand's numeric value on the Insn, because
operand_value() used to re-parse the operand text and could no longer
read a name.
* The controller bit masks in symbols.inc (PAD_A and friends) are
constants, not addresses, and are still never substituted.
MUSCLE (U) and Urban Champion (JU) keep --no-symbols: their committed
prg.s was produced with the registers named by the Pass 3 apply_symbols.py
step, and the columns in those files reflect the in-place substitution.
Adding the missing apply_symbols.py step to both regen pipelines makes
them reproduce their committed prg.s byte for byte again - neither did
before this change (MUSCLE was 440 lines out, Urban Champion 772).
cdl_reclass.py had a bug that cost a byte: a region whose last source row
straddled the region's end was replaced by a regeneration of the region
only, so the tail of that row was dropped. Mario Bros (JU) hit it at
$C595, where the rebuild came out one byte short and every label after it
shifted. A region now covers the whole rows it replaces.
pass2.py reflow takes an optional column argument; the default is
unchanged (the ';' lands on the same column as before).
Mario Bros (JU): Pass 1 correction, Pass 2, Pass 3, promoted to NROM/
A two-player platformer whose handler tables are *inline*: the pointers sit
in the middle of the code stream, right after the `jsr` that reads them, so
the static tracer could never follow them.
Pass 1 correction. The committed split was a strict subset of the correct
one -- only 72.0% of the PRG was classified as code. A Mesen Code Data
Logger capture of this ROM (mario_mesen.cdl, 10,915 code bytes) showed
1,010 bytes the tracer had left as data were code; two branch targets the
capture never reached ($E4CB and $E639) were forced with --override for 57
more, so 1,067 bytes moved from data to code and 22 moved the other way.
The split is now 78.4% code (6,210 instructions, 12,847 bytes). The three
branch targets the reclassifier could not prove were turned into labels by
_resolve_raw_branches.py, which now refuses to put a label on a `.byte` row.
Pass 2. 206 routine entries and 519 internal branch targets: 931
Label_XXXX definitions gone, 51 raw $XXXX call operands resolved and 12 call
targets the tracer had never labelled given a label. Zero SubC residue --
the 185 entries a previous session had left as address-derived residue were
all named from this dump's own code. Recorded in routinemap.tsv.
Pass 3. 25 semantic zero-page aliases, each applied only where its role is
proven (zp_aliases.inc); the slots that stay neutral are each listed with the
reason. 35 data tables named -- GameStateHandlerTable, EnemyBehaviourTable,
EnemyScriptTable, EnemyTypePointerTable, SoundRoutineTable,
NoteFrequencyTable and the rest -- and recorded in
data_region_names.tsv. apply_symbols.py reports 0 residue.
Promotion. header.s, chr.s and a HEADER/PRG/CHR linker.cfg added, rom.nes
symlinked to the original ROM; the whole-ROM cmp passes on the first
promoted build. There is deliberately no `make regen` target: the Pass 1
split here is the static trace corrected by a CDL capture, and the base the
correction was applied to is not what the current _tools/nesdis.py
produces, so prg.s is the maintained source of truth.
Tools:
apply_pass2_map.py renames a label of any spelling -- SubC<addr> is
the honest residue form -- and its references
follow it; one combined pattern, so a 16,000-line
file does not need a substitution per label
resolve_raw_branches.py refuses to label a data row
build_mario_map.py new: the hand-written Pass 2 map builder
Remove the old _wip/NROM/Mario Bros (JU) folder (promoted to NROM/)
Mario Bros (JU): add the promoted-tier header, CHR, rom.nes symlink and zero-page aliases
Moves _ROMS/<ROM> into _wip/<MAPPER>/<ROM>
Sync the docs and the skeleton tool with the 857-project _wip tier
The _wip/ tier now holds 857 projects across 30 mapper folders, all
building byte-identical for the whole ROM. README.md, TODO.md and
AGENTS.md still described the old 39-project tier, so bring them in line
with WIP.md, which carries the tier's index.
The tier is no longer 39 projects of NROM-256 with a 16/32 KB PRG:
only two projects have a 16 KB PRG, 151 have 32 KB, 523 have 128 KB and
one has 1.5 MB, so most of it is a banked mapper whose image does not fit
the 6502's address space. Those projects link their MEMORY areas at .nes
file offsets rather than CPU addresses, which is the only option and the
honest model; the 39 older projects keep the CPU-address layout because
their PRG really is one contiguous window.
make_skeleton.py gains the two layouts (--layout flat|cpu), the board
name for the mapper, and a fix for find_rom() mistaking the build
output reconstructed.nes for the source ROM.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
14333 lines
301 KiB
Plaintext
14333 lines
301 KiB
Plaintext
;----------------------------------------------------
|
|
; NES Specific
|
|
;----------------------------------------------------
|
|
|
|
; PPU registers
|
|
PPUCTRL = $2000
|
|
PPUMASK = $2001
|
|
PPUSTATUS = $2002
|
|
OAMADDR = $2003
|
|
OAMDATA = $2004
|
|
PPUSCROLL = $2005
|
|
PPUADDR = $2006
|
|
PPUDATA = $2007
|
|
OAMDMA = $4014
|
|
JOY1 = $4016
|
|
|
|
APUPC1BASE = $4000
|
|
APUPC1SWEEP = $4001
|
|
APUPC1TLOW = $4002
|
|
APUPC1THIGH = $4003
|
|
|
|
APUPC2BASE = $4004
|
|
APUPC2SWEEP = $4005
|
|
APUPC2LOW = $4006
|
|
APUPC2HIGH = $4007
|
|
|
|
APUTRIBASE = $4008
|
|
APUTRILOW = $400A
|
|
APUTRIHIGH = $400B
|
|
|
|
APUNOISEBASE = $400C
|
|
APUNOISELOOP = $400E
|
|
APUNOISELENGTH = $400F
|
|
|
|
APUDMABASE = $4010
|
|
APUDMALOAD = $4011
|
|
APUDMAADDR = $4012
|
|
APUDMALEN = $4013
|
|
|
|
APUCTRL = $4015
|
|
APUSTATUS = $4015
|
|
APUFRAMECNT = $4017
|
|
|
|
|
|
PAD_RIGHT=$01
|
|
PAD_LEFT=$02
|
|
PAD_DOWN=$04
|
|
PAD_UP=$08
|
|
PAD_START=$10
|
|
PAD_SELECT=$20
|
|
PAD_B=$40
|
|
PAD_A=$80
|
|
PAD_HORIZONTAL=PAD_LEFT|PAD_RIGHT
|
|
PAD_VERTICAL=PAD_UP|PAD_DOWN
|
|
PAD_DPAD=PAD_HORIZONTAL|PAD_VERTICAL
|
|
PAD_MENU_INPUT=PAD_SELECT|PAD_START|PAD_VERTICAL
|
|
|
|
;----------------------------------------------------
|
|
; Pacman Specific
|
|
;----------------------------------------------------
|
|
|
|
NmiHandlerOffset = $C10E
|
|
ResetOffset = $C033
|
|
IrqHandlerOffset = $C17E
|
|
|
|
;==============================================================================
|
|
; Zero Page
|
|
;==============================================================================
|
|
|
|
;------------------------------------------------------------------------------
|
|
; General work pointers / scratch
|
|
;------------------------------------------------------------------------------
|
|
|
|
workPtr0 = $00
|
|
workPtr1 = $02
|
|
|
|
workValue0 = $04
|
|
workValue1 = $05
|
|
workValue2 = $06
|
|
workValue3 = $07
|
|
workValue4 = $08
|
|
workValue5 = $09
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Maze pathfinding / direction selection workspace
|
|
;------------------------------------------------------------------------------
|
|
|
|
pathCompareValue = $0A
|
|
pathFallbackValue = $0B
|
|
legalDirections = $0C
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Indirect dispatcher vector
|
|
;------------------------------------------------------------------------------
|
|
|
|
dispatchVector = $10
|
|
|
|
;------------------------------------------------------------------------------
|
|
; 16-bit arithmetic workspace
|
|
;------------------------------------------------------------------------------
|
|
|
|
arithmeticValue = $12
|
|
arithmeticOperand = $14
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Actor fixed-point/motion records
|
|
;
|
|
; Each actor record occupies four bytes.
|
|
;------------------------------------------------------------------------------
|
|
|
|
pacmanMotion = $1A
|
|
ghost1Motion = $1E
|
|
ghost2Motion = $22
|
|
ghost3Motion = $26
|
|
ghost4Motion = $2A
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Pac-Man maze targeting
|
|
;------------------------------------------------------------------------------
|
|
|
|
pacmanTargetRow = $2E
|
|
pacmanTargetColumn = $30
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Sprite/animation selection
|
|
;------------------------------------------------------------------------------
|
|
|
|
pacmanSpriteFrame = $32
|
|
ghostSpriteFrames = $33
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Ghost direction/control state
|
|
;------------------------------------------------------------------------------
|
|
|
|
ghostDirectionFlags = $39
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Main gameplay state
|
|
;------------------------------------------------------------------------------
|
|
|
|
gameState = $3F
|
|
|
|
;------------------------------------------------------------------------------
|
|
; PPU / player-screen state
|
|
;------------------------------------------------------------------------------
|
|
|
|
ppuCtrlShadow = $43
|
|
|
|
cocktailModeFlag = $46
|
|
activePlayerFlag = $47
|
|
gameplaySuspended = $48
|
|
|
|
frameCounter = $4B
|
|
stateTimer = $4C
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Input / Pac-Man movement
|
|
;------------------------------------------------------------------------------
|
|
|
|
currentInput = $4D
|
|
newlyPressedInput = $4E
|
|
previousInput = $4F
|
|
|
|
pacmanRequestedDirection = $50
|
|
pacmanDirection = $51
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Score / round / maze progression
|
|
;------------------------------------------------------------------------------
|
|
|
|
highScoreDigits = $61
|
|
|
|
roundNumber = $67
|
|
roundDisplayValue = $68
|
|
|
|
pelletsRemaining = $6A
|
|
extraLifeAwarded = $6B
|
|
|
|
actorStatusDisplay = $6C
|
|
|
|
playerScoreDigits = $70
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Audio Engine
|
|
;------------------------------------------------------------------------------
|
|
audioRequestPtr = $F0
|
|
audioChannelTablePtr = $F2
|
|
audioSequenceTablePtr = $F4
|
|
audioWorkPtr = $F6
|
|
audioWorkValue = $F7
|
|
audioChannelFlags = $F8
|
|
audioRequestIndex = $FC
|
|
audioChannelOffset = $FD
|
|
audioIndirectPtr = $FE
|
|
|
|
.segment "PRG"
|
|
|
|
.org $C000
|
|
|
|
CopyrightText:
|
|
.byte $43,$4F,$50,$59,$20,$52,$49,$47
|
|
.byte $48,$54,$20,$31,$39,$38,$34,$20
|
|
.byte $31,$39,$39,$33,$20,$4E,$41,$4D
|
|
.byte $43,$4F,$20,$4C,$54,$44,$2E,$20
|
|
.byte $41,$4C,$4C,$20,$52,$49,$47,$48
|
|
.byte $54,$53,$20,$52,$45,$53,$45,$52
|
|
.byte $56,$45,$44
|
|
|
|
Reset:
|
|
ldx #$00
|
|
stx PPUCTRL
|
|
sei
|
|
cld
|
|
dex
|
|
txs
|
|
nop
|
|
nop
|
|
nop
|
|
|
|
ldx #$02
|
|
|
|
@WaitForPpu:
|
|
lda #$06
|
|
sta PPUMASK
|
|
|
|
lda PPUSTATUS
|
|
|
|
@WaitVBlank:
|
|
lda PPUSTATUS
|
|
bpl @WaitVBlank
|
|
|
|
lda #$00
|
|
sta PPUSCROLL
|
|
sta PPUSCROLL
|
|
dex
|
|
bne @WaitForPpu
|
|
|
|
lda #$00
|
|
tay
|
|
|
|
@ClearLowRam:
|
|
sta $0000,y
|
|
iny
|
|
cpy #$3E
|
|
bne @ClearLowRam
|
|
|
|
ldx #$08
|
|
ldy #$87
|
|
|
|
@ClearRamPages:
|
|
sta ($00),y
|
|
iny
|
|
bne @ClearRamPages
|
|
inc $01
|
|
cpx $01
|
|
bne @ClearRamPages
|
|
|
|
lda #$06
|
|
sta PPUMASK
|
|
|
|
lda #$00
|
|
sta PPUSCROLL
|
|
sta PPUSCROLL
|
|
sta $41
|
|
sta $42
|
|
sta PPUCTRL
|
|
sta PPUMASK
|
|
tay
|
|
|
|
@CheckRamSignature:
|
|
lda RamSignature,y
|
|
cmp $0052,y
|
|
bne @InitializeRamSignature
|
|
|
|
iny
|
|
cpy #$0F
|
|
bne @CheckRamSignature
|
|
|
|
beq @SignatureAlreadyPresent
|
|
|
|
@InitializeRamSignature:
|
|
lda #$00
|
|
tay
|
|
|
|
@ClearZeroPage:
|
|
sta $0000,y
|
|
iny
|
|
bne @ClearZeroPage
|
|
|
|
ldy #$00
|
|
|
|
@CopyRamSignature:
|
|
lda RamSignature,y
|
|
sta $0052,y
|
|
iny
|
|
cpy #$0F
|
|
bne @CopyRamSignature
|
|
|
|
lda #$01
|
|
sta $64
|
|
|
|
@SignatureAlreadyPresent:
|
|
ldy #$00
|
|
sty $3F
|
|
|
|
lda #$07
|
|
sta $45
|
|
lda #$01
|
|
cmp $47
|
|
bne @SkipSwap
|
|
|
|
cmp $46
|
|
bne @SkipSwap
|
|
|
|
@SwapLoop:
|
|
lda $77,y
|
|
sta workPtr0
|
|
|
|
lda $67,y
|
|
sta $77,y
|
|
|
|
lda workPtr0
|
|
sta $67,y
|
|
|
|
iny
|
|
cpy #$10
|
|
bne @SwapLoop
|
|
|
|
@SkipSwap:
|
|
lda #$1F
|
|
sta APUCTRL
|
|
|
|
lda #$C0
|
|
sta APUFRAMECNT
|
|
|
|
jsr InitializeAudioEngine
|
|
jsr $EEB4
|
|
|
|
lda #$88
|
|
sta $43
|
|
sta PPUCTRL
|
|
|
|
lda #$FF
|
|
sta $48
|
|
sta $023F
|
|
sta $024B
|
|
|
|
jmp MainEntry
|
|
|
|
RamSignature:
|
|
.byte "HIROKI AOYAGI"
|
|
.byte $AA, $55
|
|
|
|
;==============================================================================
|
|
; $C10E-$C17E: NMI Handler
|
|
;
|
|
; Local:
|
|
; Handles the per-frame NMI. Saves the CPU registers, configures the PPU,
|
|
; performs sprite OAM DMA, calls several frame-processing routines, restores
|
|
; the current scroll and PPU control state, polls both controllers, selects
|
|
; the active controller input, and conditionally performs additional
|
|
; per-frame processing.
|
|
;
|
|
; Global:
|
|
; Primary VBlank/frame interrupt entry point. This routine ties together
|
|
; rendering updates, sprite DMA, controller polling, and other work that
|
|
; needs to occur once per video frame.
|
|
;
|
|
; Notes:
|
|
; $41/$42 are used as the two PPUSCROLL writes.
|
|
; $45 supplies the source page for OAM DMA.
|
|
; $4D/$4E receive controller 1/2 input bits.
|
|
; $4F receives the controller state selected by $46/$47.
|
|
;
|
|
; The purposes of $40-$48 and the called routines at FlushGameplayPpuUpdates
|
|
; ReadNearbyNametableTiles, UpdatePalettes, and InitializeAudioChannels will
|
|
; be refined during later passes.
|
|
;==============================================================================
|
|
|
|
NmiHandler:
|
|
pha
|
|
txa
|
|
pha
|
|
tya
|
|
pha
|
|
|
|
lda #$1E
|
|
sta PPUMASK
|
|
|
|
lda #$00
|
|
sta OAMADDR
|
|
sta $40
|
|
|
|
lda $45
|
|
sta OAMDMA
|
|
|
|
jsr FlushGameplayPpuUpdates
|
|
jsr ReadNearbyNametableTiles
|
|
jsr UpdatePalettes
|
|
|
|
; Restore the two PPU scroll components.
|
|
lda $41
|
|
sta PPUSCROLL
|
|
|
|
lda $42
|
|
sta PPUSCROLL
|
|
|
|
; Construct the PPUCTRL value for this frame.
|
|
lda $47
|
|
and $46
|
|
and #$01
|
|
asl
|
|
ora $43
|
|
sta PPUCTRL
|
|
|
|
; Strobe the controller ports.
|
|
lda #$01
|
|
sta JOY1
|
|
|
|
lda #$00
|
|
sta JOY1
|
|
|
|
; Read eight serial bits from both controllers.
|
|
ldx #$08
|
|
|
|
@ReadControllers:
|
|
lda JOY1
|
|
and #$03
|
|
cmp #$01
|
|
ror $4D
|
|
|
|
lda APUFRAMECNT
|
|
and #$03
|
|
cmp #$01
|
|
ror $4E
|
|
|
|
dex
|
|
bne @ReadControllers
|
|
|
|
; Controller 1 is the default input source.
|
|
ldx currentInput
|
|
|
|
; Under the condition controlled by $46/$47,
|
|
; use controller 2 instead.
|
|
lda cocktailModeFlag
|
|
and activePlayerFlag
|
|
beq @ControllerSelected
|
|
|
|
ldx newlyPressedInput
|
|
|
|
@ControllerSelected:
|
|
stx previousInput
|
|
|
|
; Advance a per-frame counter.
|
|
inc frameCounter
|
|
|
|
; $48 gates an additional per-frame routine.
|
|
lda $48
|
|
bne @NmiDone
|
|
|
|
jsr InitializeAudioChannels
|
|
|
|
@NmiDone:
|
|
pla
|
|
tay
|
|
pla
|
|
tax
|
|
pla
|
|
IrqHandler:
|
|
rti
|
|
|
|
UpdatePalettes:
|
|
lda $0299
|
|
cmp #$0F
|
|
bne @CheckSecondPalette
|
|
|
|
lda PPUSTATUS
|
|
lda #$3F
|
|
sta PPUADDR
|
|
lda #$00
|
|
sta PPUADDR
|
|
|
|
ldy #$00
|
|
|
|
@CopyFirstPalette:
|
|
lda $0299,y
|
|
sta PPUDATA
|
|
iny
|
|
cpy #$10
|
|
bne @CopyFirstPalette
|
|
|
|
@CheckSecondPalette:
|
|
lda $02A9
|
|
cmp #$0F
|
|
bne @CheckPaletteState
|
|
|
|
lda PPUSTATUS
|
|
lda #$3F
|
|
sta PPUADDR
|
|
lda #$10
|
|
sta PPUADDR
|
|
|
|
ldy #$00
|
|
|
|
@CopySecondPalette:
|
|
lda $02A9,y
|
|
sta PPUDATA
|
|
iny
|
|
cpy #$10
|
|
bne @CopySecondPalette
|
|
|
|
@CheckPaletteState:
|
|
lda $0299
|
|
cmp #$0F
|
|
beq @ResetPpuAddress
|
|
|
|
lda $02A9
|
|
cmp #$0F
|
|
beq @ResetPpuAddress
|
|
|
|
rts
|
|
|
|
@ResetPpuAddress:
|
|
lda #$30
|
|
sta PPUADDR
|
|
|
|
lda #$00
|
|
sta PPUADDR
|
|
sta PPUADDR
|
|
sta PPUADDR
|
|
|
|
sta $0299
|
|
sta $02A9
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $C1E7-$C266: Main Initialization and State Dispatch
|
|
;
|
|
; Local:
|
|
; Synchronizes with the NMI through $40, initializes PPU/OAM and several
|
|
; game-state variables, calls four initialization routines, initializes the
|
|
; two 16-byte palette buffers, then enters the main state-dispatch loop.
|
|
;
|
|
; The loop synchronizes with NMI again, uses $3F as an index into a table of
|
|
; five handler addresses, stores the selected address in $10/$11, and jumps
|
|
; to that handler indirectly.
|
|
;
|
|
; Global:
|
|
; This is the main program entry reached from Reset after hardware and RAM
|
|
; initialization. It transitions the game into its normal frame-driven state
|
|
; machine. NMI clears $40 each frame, allowing the foreground/main code to
|
|
; proceed through its next state-machine update.
|
|
;
|
|
; Notes:
|
|
; $40 clearly provides synchronization between foreground code and NMI.
|
|
; Writing $01 to $40 and spinning until NMI clears it forms a frame wait.
|
|
;
|
|
; $3F is used here as a state/dispatch index. Its exact semantic states will
|
|
; be named as the individual handlers are decoded.
|
|
;
|
|
; $10/$11 form a temporary indirect JMP pointer.
|
|
;
|
|
; $C267 begins the state-handler address table and is intentionally left for
|
|
; the next decoding pass.
|
|
;==============================================================================
|
|
|
|
MainEntry:
|
|
lda #$01
|
|
sta $40
|
|
|
|
@WaitForInitialNmi:
|
|
lda $40
|
|
bne @WaitForInitialNmi
|
|
|
|
lda #$08
|
|
sta PPUCTRL
|
|
sta ppuCtrlShadow
|
|
|
|
lda PPUSTATUS
|
|
|
|
lda #$00
|
|
sta PPUMASK
|
|
|
|
tax
|
|
|
|
@ClearOamPage:
|
|
sta $0700,x
|
|
inx
|
|
bne @ClearOamPage
|
|
|
|
sta cocktailModeFlag
|
|
|
|
jsr ClearGameplayNametables
|
|
jsr InitializeNametableAttributes
|
|
jsr InitializeNametableData
|
|
jsr $E419
|
|
|
|
ldy #$00
|
|
|
|
@InitializePaletteBuffers:
|
|
lda TitleScreenPalette,y
|
|
sta $0299,y
|
|
iny
|
|
cpy #$20
|
|
bne @InitializePaletteBuffers
|
|
|
|
lda #$2D
|
|
sta actorStatusDisplay
|
|
sta actorStatusDisplay+1
|
|
sta actorStatusDisplay+2
|
|
sta actorStatusDisplay+3
|
|
|
|
lda #$FF
|
|
sta $023F
|
|
sta gameplaySuspended
|
|
|
|
lda #$00
|
|
sta activePlayerFlag
|
|
sta cocktailModeFlag
|
|
sta $42
|
|
sta $41
|
|
sta stateTimer
|
|
sta $87
|
|
sta $88
|
|
|
|
lda gameState
|
|
bne @UseAlternatePpuCtrl
|
|
|
|
lda #$8A
|
|
bne @SetPpuCtrl
|
|
|
|
@UseAlternatePpuCtrl:
|
|
lda #$88
|
|
|
|
@SetPpuCtrl:
|
|
sta PPUCTRL
|
|
sta ppuCtrlShadow
|
|
|
|
MainDispatchLoop:
|
|
lda #$01
|
|
sta $40
|
|
|
|
@WaitForNmi:
|
|
lda $40
|
|
bne @WaitForNmi
|
|
|
|
ldy gameState
|
|
|
|
lda $C267,y
|
|
sta dispatchVector
|
|
|
|
lda $C268,y
|
|
sta dispatchVector+1
|
|
|
|
jmp ($0010)
|
|
|
|
;==============================================================================
|
|
; $C267-$C26E: Main State Dispatch Table
|
|
;
|
|
; Local:
|
|
; Four 16-bit addresses used by the indirect state dispatcher at the end of
|
|
; MainEntry. $3F is used directly as a byte offset into this table:
|
|
;
|
|
; lda MainStateHandlerTable,y
|
|
; sta $10
|
|
; lda MainStateHandlerTable+1,y
|
|
; sta $11
|
|
; jmp ($0010)
|
|
;
|
|
; This implies the normal state values in $3F are even byte offsets:
|
|
; $00, $02, $04, $06
|
|
;
|
|
; Global:
|
|
; Selects one of four major foreground/game-state handlers. This is the
|
|
; top-level state machine entered after Reset initialization and synchronized
|
|
; to the NMI-driven frame loop.
|
|
;
|
|
; Notes:
|
|
; The four targets are:
|
|
; InitialStateHandler
|
|
; PlayerSelectionState
|
|
; State04Handler
|
|
; TimedStateTransition
|
|
;
|
|
; Handler names remain provisional until each target is decoded.
|
|
;==============================================================================
|
|
|
|
MainStateHandlerTable:
|
|
.word InitialStateHandler
|
|
.word PlayerSelectionState
|
|
.word State04Handler
|
|
.word TimedStateTransition
|
|
|
|
;==============================================================================
|
|
; $C26F-$C279: Timed State Transition Handler
|
|
;
|
|
; Local:
|
|
; Decrements the counter at $0F once per frame. While the counter remains
|
|
; nonzero, control returns to the common NMI synchronization/dispatch loop
|
|
; at $C250.
|
|
;
|
|
; When the counter reaches zero, changes the main state offset at $3F to
|
|
; $02 and then returns to the same dispatch loop.
|
|
;
|
|
; Global:
|
|
; Implements the handler selected when the main state offset is $06.
|
|
; This appears to be a timed transitional state. Another state places a
|
|
; duration in $0F and selects state $06; this handler counts that duration
|
|
; down before advancing to state $02.
|
|
;
|
|
; Notes:
|
|
; $0F is clearly being used as a countdown timer here, but its broader use
|
|
; should be traced before assigning it a permanent global name.
|
|
;
|
|
; $3F is the byte offset into MainStateHandlerTable:
|
|
; $00 -> InitialStateHandler
|
|
; $02 -> PlayerSelectionState
|
|
; $04 -> State04Handler
|
|
; $06 -> this handler
|
|
;
|
|
; $C250 is inside MainEntry and is the common frame synchronization point.
|
|
;==============================================================================
|
|
|
|
TimedStateTransition:
|
|
dec $0F
|
|
bne MainDispatchLoop
|
|
|
|
lda #$02
|
|
sta gameState
|
|
|
|
jmp MainDispatchLoop
|
|
|
|
|
|
;==============================================================================
|
|
; $C27A-$C2A5: Initial/Input State Handler
|
|
;
|
|
; Local:
|
|
; Checks controller-1 state bits $0C. If either bit is set, selects state
|
|
; $06, initializes the countdown at $0F to $5A, and jumps back to MainEntry.
|
|
;
|
|
; Otherwise increments $42. When $42 reaches $F0, resets it to zero,
|
|
; changes the saved PPUCTRL value at $43 to $88, and selects state $06
|
|
; with the same $5A countdown.
|
|
;
|
|
; If $42 has not yet reached $F0, the initialization of state $06 is
|
|
; skipped and execution reaches the common JMP back to MainDispatchLoop.
|
|
;
|
|
; Global:
|
|
; Handler selected by main state offset $00. It appears to manage an early
|
|
; or attract/input-wait state, transitioning into the timed state either
|
|
; because of controller input or because the scrolling/progression value
|
|
; at $42 reaches $F0.
|
|
;
|
|
; Notes:
|
|
; $4D is controller-1 input assembled by NmiHandler.
|
|
; $42 is also used as the second PPUSCROLL write during NMI.
|
|
; Exact game-state semantics will be refined in later passes.
|
|
;==============================================================================
|
|
|
|
InitialStateHandler:
|
|
lda currentInput
|
|
and #$0C
|
|
beq @AdvanceScroll
|
|
|
|
lda #$06
|
|
sta gameState
|
|
|
|
lda #$5A
|
|
sta $0F
|
|
|
|
jmp MainEntry
|
|
|
|
@AdvanceScroll:
|
|
inc $42
|
|
|
|
lda #$F0
|
|
cmp $42
|
|
bne @ReturnToMainLoop
|
|
|
|
lda #$00
|
|
sta $42
|
|
|
|
lda #$88
|
|
sta ppuCtrlShadow
|
|
|
|
lda #$06
|
|
sta gameState
|
|
|
|
lda #$5A
|
|
sta $0F
|
|
|
|
@ReturnToMainLoop:
|
|
jmp MainDispatchLoop
|
|
|
|
;==============================================================================
|
|
; $C2A6-$C30A: Initialize Nametable Data
|
|
;
|
|
; Local:
|
|
; Performs two groups of PPU writes used during initial screen setup.
|
|
;
|
|
; First phase:
|
|
; - Begins at PPU address $20E5.
|
|
; - Copies $17 bytes from the ROM data at TitleScreenTileBlock
|
|
; - Repeats this for six rows.
|
|
; - Advances the destination PPU address by $20 after each row.
|
|
;
|
|
; Second phase:
|
|
; - Processes nine variable-length PPU update records beginning at $C3B0.
|
|
; - Each record supplies a two-byte PPU address followed by data bytes.
|
|
; - $FF terminates the data portion of each record.
|
|
;
|
|
; Global:
|
|
; Called from MainEntry during initial game setup. This routine constructs
|
|
; part of the initial nametable/display before normal state dispatch begins.
|
|
;
|
|
; Notes:
|
|
; $00/$01 are used here as a 16-bit PPU destination address.
|
|
; $02 counts the six repeated rows.
|
|
; $03 counts $17 bytes within each row.
|
|
;
|
|
; TitleScreenTileBlock is a repeated row of tile data.
|
|
; $C3B0 contains nine encoded PPU update records.
|
|
;
|
|
; These ROM data blocks will be named more precisely when their contents
|
|
; and resulting screen regions are decoded in later passes.
|
|
;==============================================================================
|
|
|
|
InitializeNametableData:
|
|
; Initial PPU destination = $20E5.
|
|
lda #$20
|
|
sta workPtr0
|
|
|
|
lda #$E5
|
|
sta workPtr0+1
|
|
|
|
; Write six rows.
|
|
lda #$06
|
|
sta workPtr1
|
|
|
|
ldy #$00
|
|
|
|
@WriteRow:
|
|
lda PPUSTATUS
|
|
|
|
lda workPtr0
|
|
sta PPUADDR
|
|
|
|
lda workPtr0+1
|
|
sta PPUADDR
|
|
|
|
; Each row contains $17 bytes.
|
|
lda #$17
|
|
sta workPtr1+1
|
|
|
|
@WriteRowBytes:
|
|
lda TitleScreenTileBlock,y
|
|
sta PPUDATA
|
|
|
|
iny
|
|
|
|
dec workPtr1+1
|
|
bne @WriteRowBytes
|
|
|
|
; Advance the PPU destination by $20.
|
|
lda workPtr0+1
|
|
clc
|
|
adc #$20
|
|
sta workPtr0+1
|
|
|
|
lda #$00
|
|
adc workPtr0
|
|
sta workPtr0
|
|
|
|
dec workPtr1
|
|
bne @WriteRow
|
|
|
|
; Process nine additional encoded PPU update records.
|
|
lda #$09
|
|
sta workPtr0
|
|
|
|
ldy #$00
|
|
|
|
@NextPpuRecord:
|
|
lda PPUSTATUS
|
|
|
|
; First two bytes of each record are the PPU destination address.
|
|
lda TitleScreenPpuRecords,y
|
|
sta PPUADDR
|
|
iny
|
|
|
|
lda TitleScreenPpuRecords,y
|
|
sta PPUADDR
|
|
iny
|
|
|
|
@WritePpuRecord:
|
|
lda TitleScreenPpuRecords,y
|
|
cmp #$FF
|
|
beq @EndPpuRecord
|
|
|
|
sta PPUDATA
|
|
iny
|
|
bne @WritePpuRecord
|
|
|
|
@EndPpuRecord:
|
|
iny
|
|
|
|
dec workPtr0
|
|
bne @NextPpuRecord
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $C30B-$C325: Initialize Nametable Attributes
|
|
;
|
|
; Local:
|
|
; Writes $18 bytes from TitleScreenAttributeData to PPU address $23C8.
|
|
;
|
|
; Global:
|
|
; Initializes a portion of the nametable attribute table during startup.
|
|
;==============================================================================
|
|
|
|
InitializeNametableAttributes:
|
|
lda PPUSTATUS
|
|
|
|
lda #$23
|
|
sta PPUADDR
|
|
|
|
lda #$C8
|
|
sta PPUADDR
|
|
|
|
ldy #$00
|
|
|
|
@CopyAttributes:
|
|
lda TitleScreenAttributeData,y
|
|
sta PPUDATA
|
|
|
|
iny
|
|
cpy #$18
|
|
bne @CopyAttributes
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $C326-$C3AF: Initial Nametable Tile Block
|
|
;
|
|
; Local:
|
|
; Contains six rows of $17 (23) tile indices. InitializeNametableData copies
|
|
; these rows sequentially to the PPU beginning at $20E5, advancing the PPU
|
|
; destination by $20 after each row.
|
|
;
|
|
; Destination layout:
|
|
; Row 0 -> $20E5-$20FB
|
|
; Row 1 -> $2105-$211B
|
|
; Row 2 -> $2125-$213B
|
|
; Row 3 -> $2145-$215B
|
|
; Row 4 -> $2165-$217B
|
|
; Row 5 -> $2185-$219B
|
|
;
|
|
; Global:
|
|
; Forms a rectangular portion of the initial nametable display constructed
|
|
; during MainEntry. The first and last rows consist primarily of border
|
|
; tiles, while the middle four rows contain the interior graphic/tile data.
|
|
;
|
|
; Notes:
|
|
; Each row is exactly $17 bytes.
|
|
;
|
|
; Tile values are left numeric during this pass. Their visual meanings can
|
|
; be determined later from the CHR-ROM and assigned symbolic tile names if
|
|
; useful.
|
|
;==============================================================================
|
|
|
|
TitleScreenTileBlock:
|
|
; Row 0 -> PPU $20E5-$20FB
|
|
.byte $E4,$E8,$E8,$E8,$E8,$E8,$E8,$E8
|
|
.byte $E8,$E8,$E8,$E8,$E8,$E8,$E8,$E8
|
|
.byte $E8,$E8,$E8,$E8,$E8,$E8,$E5
|
|
|
|
; Row 1 -> PPU $2105-$211B
|
|
.byte $EB,$88,$80,$81,$82,$83,$84,$85
|
|
.byte $86,$87,$88,$88,$89,$8A,$8B,$8C
|
|
.byte $8D,$8E,$8F,$90,$91,$A3,$E9
|
|
|
|
; Row 2 -> PPU $2125-$213B
|
|
.byte $EB,$88,$92,$93,$94,$95,$96,$97
|
|
.byte $98,$99,$9A,$9B,$9C,$9D,$9E,$9F
|
|
.byte $A0,$A1,$A2,$A3,$A4,$A3,$E9
|
|
|
|
; Row 3 -> PPU $2145-$215B
|
|
.byte $EB,$88,$92,$A5,$A6,$A7,$A8,$A9
|
|
.byte $AA,$AB,$AC,$AD,$AE,$A3,$AF,$D0
|
|
.byte $D1,$D2,$A3,$D3,$A4,$A3,$E9
|
|
|
|
; Row 4 -> PPU $2165-$217B
|
|
.byte $EB,$88,$D4,$D5,$D6,$D7,$D8,$D9
|
|
.byte $DA,$DB,$88,$88,$DC,$D7,$DD,$DE
|
|
.byte $DF,$E0,$E1,$E2,$E3,$A3,$E9
|
|
|
|
; Row 5 -> PPU $2185-$219B
|
|
.byte $E7,$EA,$EA,$EA,$EA,$EA,$EA,$EA
|
|
.byte $EA,$EA,$EA,$EA,$EA,$EA,$EA,$EA
|
|
.byte $EA,$EA,$EA,$EA,$EA,$EA,$E6
|
|
|
|
;==============================================================================
|
|
; $C3B0-$C43E: Initial Screen PPU Records
|
|
;
|
|
; Local:
|
|
; Nine variable-length PPU write records consumed by InitializeNametableData.
|
|
; Each record has the form:
|
|
;
|
|
; .byte PPU address high
|
|
; .byte PPU address low
|
|
; .byte tile data...
|
|
; .byte $FF
|
|
;
|
|
; InitializeNametableData processes exactly nine records. For each record it
|
|
; loads the two-byte destination into PPUADDR and copies tile values to
|
|
; PPUDATA until the $FF terminator is encountered.
|
|
;
|
|
; Global:
|
|
; Supplies additional initial-screen graphics and text after the main
|
|
; six-row tile block has been installed. These records include player-count
|
|
; selections and copyright/licensing text as represented by the ROM's
|
|
; nametable tile values.
|
|
;
|
|
; Notes:
|
|
; Many values correspond directly to ASCII character codes, but not all do.
|
|
; Preserve the original tile bytes rather than converting these records to
|
|
; assembler strings during this pass.
|
|
;
|
|
; $FF is structural and is not written to PPUDATA.
|
|
;==============================================================================
|
|
|
|
TitleScreenPpuRecords:
|
|
;------------------------------------------------------------------------------
|
|
; Record 0: $C3B0-$C3C7
|
|
; PPU destination: $2065
|
|
; Data length: $15 (21) tiles
|
|
;------------------------------------------------------------------------------
|
|
.byte $20,$65
|
|
.byte $B0,$B3,$B2,$20,$20,$20,$20
|
|
.byte $B4,$B5,$B6,$B7,$B8,$B9,$BA,$BB
|
|
.byte $20,$20,$20,$B1,$B3,$B2
|
|
.byte $FF
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Record 1: $C3C8-$C3D2
|
|
; PPU destination: $220C
|
|
; Data length: $08
|
|
;
|
|
; Visible tile values correspond to:
|
|
; "1 PLAYER"
|
|
;------------------------------------------------------------------------------
|
|
.byte $22,$0C
|
|
.byte $31,$20,$50,$4C,$41,$59,$45,$52
|
|
.byte $FF
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Record 2: $C3D3-$C3DE
|
|
; PPU destination: $224C
|
|
; Data length: $09
|
|
;
|
|
; Visible tile values correspond to:
|
|
; "2 PLAYERS"
|
|
;------------------------------------------------------------------------------
|
|
.byte $22,$4C
|
|
.byte $32,$20,$50,$4C,$41,$59,$45,$52,$53
|
|
.byte $FF
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Record 3: $C3DF-$C3FC
|
|
; PPU destination: $22E3
|
|
; Data length: $1B (27)
|
|
;
|
|
; Mostly text-like tile data containing the original copyright/date/NAMCO
|
|
; display. Special tile values are retained numerically.
|
|
;------------------------------------------------------------------------------
|
|
.byte $22,$E3
|
|
.byte $54,$4D,$20,$CC,$20,$5D
|
|
.byte $20,$31,$39,$38,$30
|
|
.byte $20,$31,$39,$39,$33
|
|
.byte $20,$4E,$41,$4D,$43,$4F
|
|
.byte $20,$4C,$54,$44,$5B
|
|
.byte $FF
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Record 4: $C3FD-$C411
|
|
; PPU destination: $2327
|
|
; Data length: $12 (18)
|
|
;
|
|
; Mostly text-like tile data containing:
|
|
; NAMCO HOMETEK ... INC
|
|
;
|
|
; Special tile values remain numeric.
|
|
;------------------------------------------------------------------------------
|
|
.byte $23,$27
|
|
.byte $4E,$41,$4D,$43,$4F,$20
|
|
.byte $48,$4F,$4D,$45,$54,$45,$4B
|
|
.byte $CD
|
|
.byte $49,$4E,$43
|
|
.byte $5B
|
|
.byte $FF
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Record 5: $C412-$C428
|
|
; PPU destination: $2366
|
|
; Data length: $14 (20)
|
|
;
|
|
; Tile values correspond to:
|
|
; "LICENSED BY NINTENDO"
|
|
;------------------------------------------------------------------------------
|
|
.byte $23,$66
|
|
.byte $4C,$49,$43,$45,$4E,$53,$45,$44
|
|
.byte $20
|
|
.byte $42,$59
|
|
.byte $20
|
|
.byte $4E,$49,$4E,$54,$45,$4E,$44,$4F
|
|
.byte $FF
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Record 6: $C429-$C42D
|
|
; PPU destination: $2293
|
|
; Data length: $02
|
|
;------------------------------------------------------------------------------
|
|
.byte $22,$93
|
|
.byte $CE,$CF
|
|
.byte $FF
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Record 7: $C42E-$C439
|
|
; PPU destination: $22AC
|
|
; Data length: $09
|
|
;------------------------------------------------------------------------------
|
|
.byte $22,$AC
|
|
.byte $23,$24,$25,$26,$27,$28,$29,$2A,$2B
|
|
.byte $FF
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Record 8: $C43A-$C43E
|
|
; PPU destination: $20FC
|
|
; Data length: $02
|
|
;------------------------------------------------------------------------------
|
|
.byte $20,$FC
|
|
.byte $0E,$0F
|
|
.byte $FF
|
|
|
|
|
|
;==============================================================================
|
|
; $C43F-$C45E: Initial Palette Data
|
|
;
|
|
; Local:
|
|
; Contains $20 bytes copied to RAM $0299-$02B8 during MainEntry. The first
|
|
; $10 bytes feed PPU palette $3F00-$3F0F and the second $10 bytes feed
|
|
; $3F10-$3F1F through UpdatePalettes.
|
|
;
|
|
; Global:
|
|
; Defines the initial background and sprite palette configuration.
|
|
;
|
|
; Notes:
|
|
; Palette values remain numeric during this pass.
|
|
;==============================================================================
|
|
|
|
TitleScreenPalette:
|
|
|
|
; Background palettes
|
|
.byte $0F,$20,$0F,$06
|
|
.byte $0F,$26,$20,$27
|
|
.byte $0F,$06,$0F,$26
|
|
.byte $0F,$06,$20,$26
|
|
|
|
; Sprite palettes
|
|
.byte $0F,$27,$20,$06
|
|
.byte $0F,$11,$20,$33
|
|
.byte $0F,$20,$20,$21
|
|
.byte $0F,$09,$20,$17
|
|
|
|
|
|
;==============================================================================
|
|
; $C45F-$C476: Initial Nametable Attribute Data
|
|
;
|
|
; Local:
|
|
; Contains $18 attribute bytes copied by InitializeNametableAttributes to
|
|
; PPU $23C8-$23DF.
|
|
;
|
|
; Global:
|
|
; Defines background-palette selections for part of the initial nametable
|
|
; display.
|
|
;
|
|
; Notes:
|
|
; Attribute bytes remain raw during this first pass.
|
|
;==============================================================================
|
|
|
|
TitleScreenAttributeData:
|
|
.byte $80,$A0,$A0,$A0,$A0,$A0,$A0,$00
|
|
.byte $00,$66,$55,$55,$55,$55,$DD,$00
|
|
.byte $08,$0A,$0A,$0A,$0A,$0A,$0A,$00
|
|
|
|
;==============================================================================
|
|
; $C477-$C506: Player Selection State Handler
|
|
;
|
|
; Local:
|
|
; Handles input and display updates for the player-count selection state.
|
|
;
|
|
; On first entry, identified by $87/$88 both being zero, copies a small
|
|
; display-data sequence from $C507 to RAM beginning at $024B and captures
|
|
; the current controller states for bits $04 and $08.
|
|
;
|
|
; $87/$88 form a 16-bit counter that advances once per frame. When its high
|
|
; byte reaches $02, the counter is reset and the main state changes to $04.
|
|
;
|
|
; During normal processing:
|
|
; - Detects changes to controller bit $04.
|
|
; - When that bit becomes active, toggles $47 between 0 and 1 and changes
|
|
; display data associated with the selected player count.
|
|
; - Detects changes to controller bit $08.
|
|
; - When bit $08 becomes active, clears $48, calls $EEB4, and jumps to
|
|
; GameModeEntry.
|
|
;
|
|
; Global:
|
|
; Handler selected by MainStateHandlerTable when $3F = $02. The surrounding PPU
|
|
; data and controller behavior strongly indicate that this state implements
|
|
; the "1 PLAYER" / "2 PLAYERS" selection screen.
|
|
;
|
|
; If no selection completes within the $87/$88 timeout, execution advances
|
|
; automatically to main state $04.
|
|
;
|
|
; Notes:
|
|
; $50 stores the previous masked state of controller bit $04.
|
|
; $51 stores the previous masked state of controller bit $08.
|
|
;
|
|
; $87/$88 act as a 16-bit frame counter in this state.
|
|
;
|
|
; $47 is toggled between 0 and 1 when the $04 input becomes active. This
|
|
; strongly suggests it represents the current 1-player/2-player selection,
|
|
; but the name should be confirmed through later consumers.
|
|
;
|
|
; $C507 begins an adjacent display-data table consumed during state entry.
|
|
;==============================================================================
|
|
|
|
PlayerSelectionState:
|
|
lda $87
|
|
ora $88
|
|
bne @AdvanceTimeout
|
|
|
|
ldy #$00
|
|
|
|
@InitializeDisplayData:
|
|
lda PlayerCountSelectionDisplayData,y
|
|
sta $024B,y
|
|
iny
|
|
cmp #$FF
|
|
bne @InitializeDisplayData
|
|
|
|
lda currentInput
|
|
and #$04
|
|
sta pacmanRequestedDirection
|
|
|
|
lda currentInput
|
|
and #$08
|
|
sta pacmanDirection
|
|
|
|
@AdvanceTimeout:
|
|
clc
|
|
lda #$01
|
|
adc $87
|
|
sta $87
|
|
|
|
lda $88
|
|
adc #$00
|
|
sta $88
|
|
|
|
cmp #$02
|
|
bne @CheckSelectionInput
|
|
|
|
lda #$00
|
|
sta $87
|
|
|
|
lda #$04
|
|
sta gameState
|
|
|
|
jmp MainDispatchLoop
|
|
|
|
@CheckSelectionInput:
|
|
lda currentInput
|
|
and #$04
|
|
cmp pacmanRequestedDirection
|
|
beq @CheckConfirmInput
|
|
|
|
sta pacmanRequestedDirection
|
|
|
|
lda #$00
|
|
sta $88
|
|
|
|
lda #$01
|
|
sta $87
|
|
|
|
lda pacmanRequestedDirection
|
|
beq @CheckConfirmInput
|
|
|
|
ldx #$00
|
|
|
|
inc activePlayerFlag
|
|
lda activePlayerFlag
|
|
and #$01
|
|
sta activePlayerFlag
|
|
beq @UseFirstSelectionData
|
|
|
|
inx
|
|
|
|
@UseFirstSelectionData:
|
|
lda $C50F,x
|
|
sta $024D
|
|
|
|
lda $C510,x
|
|
sta $0251
|
|
|
|
lda #$22
|
|
sta $024B
|
|
|
|
jmp MainDispatchLoop
|
|
|
|
@CheckConfirmInput:
|
|
lda currentInput
|
|
and #$08
|
|
cmp pacmanDirection
|
|
bne @ConfirmStateChanged
|
|
|
|
jmp MainDispatchLoop
|
|
|
|
@ConfirmStateChanged:
|
|
sta pacmanDirection
|
|
|
|
lda pacmanDirection
|
|
bne @ConfirmPressed
|
|
|
|
jmp MainDispatchLoop
|
|
|
|
@ConfirmPressed:
|
|
lda #$00
|
|
sta gameplaySuspended
|
|
|
|
jsr $EEB4
|
|
|
|
jmp GameModeEntry
|
|
|
|
;==============================================================================
|
|
; $C507-$C511: Player Selection Display Data
|
|
;
|
|
; Local:
|
|
; Contains display-update data used by PlayerSelectionState.
|
|
;
|
|
; The first eight bytes, $C507-$C50E, are copied to RAM beginning at $024B
|
|
; when the player-selection state is first entered. The copy terminates after
|
|
; the $FF byte has also been stored.
|
|
;
|
|
; The final three bytes, $C50F-$C511, form an overlapping pair table used
|
|
; when $47 toggles between its two selection values:
|
|
;
|
|
; X = 0 -> $5C, $20
|
|
; X = 1 -> $20, $5C
|
|
;
|
|
; These values are written to $024D and $0251, respectively.
|
|
;
|
|
; Global:
|
|
; Provides the display-update data for the "1 PLAYER" / "2 PLAYERS"
|
|
; selection state. The overlapping three-byte table moves a $5C tile
|
|
; between two display positions while placing $20 at the other position.
|
|
;
|
|
; Notes:
|
|
; $5C appears to be the selection-marker tile and $20 appears to clear the
|
|
; alternate position. Their exact visual appearance can be confirmed later
|
|
; against CHR-ROM.
|
|
;
|
|
; $FF terminates the initialization data copied to $024B.
|
|
;==============================================================================
|
|
|
|
PlayerCountSelectionDisplayData:
|
|
.byte $22,$0A,$5C,$00
|
|
.byte $22,$4A,$20,$FF
|
|
|
|
PlayerCountSelectionMarkerTiles:
|
|
.byte $5C,$20,$5C
|
|
|
|
|
|
;==============================================================================
|
|
; $C512-$C52D: State $04 Handler / Substate Dispatcher
|
|
;
|
|
; Local:
|
|
; Handles the top-level processing for main state $04.
|
|
;
|
|
; First checks controller-1 bits $0C. If either bit is active, changes the
|
|
; main state back to $02 and jumps to MainEntry, causing the main display
|
|
; initialization sequence to run again.
|
|
;
|
|
; Otherwise uses $87 as a byte offset into a table of 16-bit handler
|
|
; addresses beginning at $C52E. The selected address is placed in $10/$11
|
|
; and execution jumps to it indirectly.
|
|
;
|
|
; Global:
|
|
; This is the fourth major handler in MainStateHandlerTable. Unlike states $00,
|
|
; $02, and $06, state $04 contains its own secondary state machine driven
|
|
; by $87.
|
|
;
|
|
; $87 therefore has a different role depending on the current main state.
|
|
; In state $02 it participated in a 16-bit frame counter with $88. Here it
|
|
; acts as the byte offset into a secondary dispatch table.
|
|
;
|
|
; Notes:
|
|
; $87 appears to take even values because it indexes packed 16-bit addresses
|
|
; directly rather than multiplying a state number by two.
|
|
;
|
|
; The substate table begins immediately afterward at $C52E.
|
|
; We leave the individual substate handlers for following passes.
|
|
;==============================================================================
|
|
|
|
State04Handler:
|
|
lda currentInput
|
|
and #$0C
|
|
beq @DispatchSubstate
|
|
|
|
lda #$02
|
|
sta gameState
|
|
|
|
jmp MainEntry
|
|
|
|
@DispatchSubstate:
|
|
ldy $87
|
|
|
|
lda State04SubstateTable,y
|
|
sta dispatchVector
|
|
|
|
lda State04SubstateTable+1,y
|
|
sta dispatchVector+1
|
|
|
|
jmp ($0010)
|
|
|
|
;==============================================================================
|
|
; $C52E-$C545: State $04 Substate Dispatch Table
|
|
;
|
|
; Local:
|
|
; Twelve 16-bit handler addresses selected by State04Handler using $87 as
|
|
; a direct byte offset.
|
|
;
|
|
; Valid offsets observed from the table structure are:
|
|
; $00,$02,$04,$06,$08,$0A,$0C,$0E,$10,$12,$14,$16
|
|
;
|
|
; Global:
|
|
; Defines the secondary state machine used while the top-level game state
|
|
; is $04. Several intermediate substates deliberately share the same handler
|
|
; at $C573.
|
|
;
|
|
; Notes:
|
|
; Later code advances $87 using two INC instructions, confirming that $87
|
|
; is a byte offset into this table rather than an ordinal state number.
|
|
;==============================================================================
|
|
|
|
State04SubstateTable:
|
|
.word State04Initialize ; $00
|
|
.word State04TimedSubstate ; $02
|
|
.word State04TimedSubstate ; $04
|
|
.word State04TimedSubstate ; $06
|
|
.word State04TimedSubstate ; $08
|
|
.word State04TimedSubstate ; $0A
|
|
.word State04TimedSubstate ; $0C
|
|
.word State04TimedSubstate ; $0E
|
|
.word State04TimedSubstate ; $10
|
|
.word State04TimedSubstate ; $12
|
|
.word State04LongDelay ; $14
|
|
.word State04FinalPhase ; $16
|
|
|
|
;==============================================================================
|
|
; $C546-$C572: State $04 Initialization Substate
|
|
;
|
|
; Local:
|
|
; Performs the one-time initialization for state $04 when substate offset
|
|
; $87 is $00.
|
|
;
|
|
; First synchronizes with NMI using $40. It then sets PPUCTRL/$43 to $08,
|
|
; disables rendering through PPUMASK, clears $88, and calls three setup
|
|
; routines:
|
|
;
|
|
; $C5D8
|
|
; $C608
|
|
; SetSelectionFlagAndContinue
|
|
;
|
|
; After setup completes, advances $87 by two, selecting substate $02 on the
|
|
; following frame. PPUCTRL/$43 are then changed to $88 before returning to
|
|
; MainDispatchLoop.
|
|
;
|
|
; Global:
|
|
; Entry/initialization substate for the secondary state machine used by
|
|
; main state $04. It prepares the display and state-specific data before
|
|
; handing execution to the shared $C573 substate handler.
|
|
;
|
|
; Notes:
|
|
; $40 continues to act as the foreground/NMI synchronization flag.
|
|
;
|
|
; $87 is a byte offset into State04SubstateTable. The two INC instructions
|
|
; deliberately advance it from $00 to $02.
|
|
;
|
|
; The three called routines remain structurally named by address until they
|
|
; are decoded. $C5D8 and $C608 appear to perform direct PPU initialization,
|
|
; while SetSelectionFlagAndContinue operates on state/display data.
|
|
;==============================================================================
|
|
|
|
State04Initialize:
|
|
lda #$01
|
|
sta $40
|
|
|
|
@WaitForNmi:
|
|
lda $40
|
|
bne @WaitForNmi
|
|
|
|
lda #$08
|
|
sta PPUCTRL
|
|
sta ppuCtrlShadow
|
|
|
|
lda #$00
|
|
sta PPUMASK
|
|
sta $88
|
|
|
|
jsr $C5D8
|
|
jsr InitializeState04PpuData
|
|
jsr LoadState04DisplayData
|
|
|
|
inc $87
|
|
inc $87
|
|
|
|
lda #$88
|
|
sta PPUCTRL
|
|
sta ppuCtrlShadow
|
|
|
|
jmp MainDispatchLoop
|
|
|
|
;==============================================================================
|
|
; $C573-$C588: State $04 Shared Timed Substate Handler
|
|
;
|
|
; Local:
|
|
; Advances $88 once per frame. At $30 frames, clears $88, invokes the
|
|
; state-$04 display-data helper, and advances $87 by two to the next
|
|
; secondary state.
|
|
;
|
|
; Global:
|
|
; Shared timing handler used by state-$04 substates $02-$12.
|
|
;
|
|
; Notes:
|
|
; LoadState04DisplayData is kept as a raw address temporarily to guarantee
|
|
; byte identity while the overlapping $C5A6-$C5D8 region is being resolved.
|
|
;==============================================================================
|
|
|
|
State04TimedSubstate:
|
|
inc $88
|
|
|
|
lda $88
|
|
cmp #$30
|
|
bne @ReturnToMainLoop
|
|
|
|
lda #$00
|
|
sta $88
|
|
|
|
jsr $C5A6
|
|
|
|
inc $87
|
|
inc $87
|
|
|
|
@ReturnToMainLoop:
|
|
jmp MainDispatchLoop
|
|
|
|
;==============================================================================
|
|
; $C589-$C59F: State $04 Long Delay Substate
|
|
;
|
|
; Local:
|
|
; Increments $88 once per frame and waits until it reaches $80.
|
|
;
|
|
; While $88 is not $80, returns to MainDispatchLoop.
|
|
;
|
|
; When $88 reaches $80:
|
|
; - Advances $87 by two, selecting substate $16.
|
|
; - Clears $88.
|
|
; - Returns to MainDispatchLoop.
|
|
;
|
|
; Global:
|
|
; Implements substate $14 of the state $04 secondary state machine. It
|
|
; follows the series of $30-frame substates handled by
|
|
; State04TimedSubstate and introduces a longer delay before entering the
|
|
; final known substate at $16.
|
|
;
|
|
; Notes:
|
|
; $88 is the frame counter for this substate.
|
|
; $87 is the byte offset into State04SubstateTable.
|
|
;
|
|
; Unlike substates $02-$12, reaching the timeout here does not call
|
|
; SetSelectionFlagAndContinue. It simply advances from substate $14 to $16.
|
|
;==============================================================================
|
|
|
|
State04LongDelay:
|
|
inc $88
|
|
|
|
lda $88
|
|
cmp #$80
|
|
beq @AdvanceSubstate
|
|
|
|
jmp MainDispatchLoop
|
|
|
|
@AdvanceSubstate:
|
|
inc $87
|
|
inc $87
|
|
|
|
lda #$00
|
|
sta $88
|
|
|
|
jmp MainDispatchLoop
|
|
|
|
|
|
;==============================================================================
|
|
; $C59F-$C5A5: Select Alternate Player Mode and Continue
|
|
;
|
|
; Local:
|
|
; Sets $47 to $01 and tail-jumps to the routine at GameModeEntry.
|
|
;
|
|
; Global:
|
|
; Forces the same $47 flag that PlayerSelectionState toggles between $00
|
|
; and $01, then transfers control to GameModeEntry. This strongly links the routine
|
|
; to the player-count/player-mode selection logic.
|
|
;
|
|
; The exact global purpose of GameModeEntry has not yet been decoded, so the routine
|
|
; and $47 remain conservatively named during this pass.
|
|
;
|
|
; Notes:
|
|
; There is no RTS. Control is permanently transferred to GameModeEntry.
|
|
;
|
|
; $47 is known to be constrained to 0/1 by PlayerSelectionState and is also
|
|
; consulted by NmiHandler when selecting controller input and constructing
|
|
; PPUCTRL. We should trace GameModeEntry before assigning $47 a final semantic name.
|
|
;==============================================================================
|
|
|
|
SetSelectionFlagAndContinue:
|
|
lda #$01
|
|
sta activePlayerFlag
|
|
jmp GameModeEntry
|
|
|
|
|
|
;==============================================================================
|
|
; $C5A6-$C5D7: State $04 Display Data Loader
|
|
;
|
|
; Local:
|
|
; Uses $87 as a byte offset into a pointer table at $C687. The selected
|
|
; $FF-terminated stream is copied through $00/$01 into RAM beginning at
|
|
; $024B, including the $FF terminator.
|
|
;
|
|
; The byte following the terminator controls an optional secondary copy:
|
|
; nonzero -> return
|
|
; zero -> copy 16 bytes using a substate-derived offset
|
|
;
|
|
; Global:
|
|
; Supplies update/display data as the state-$04 secondary state machine
|
|
; progresses.
|
|
;
|
|
; Notes:
|
|
; $00/$01 form the temporary source pointer.
|
|
;==============================================================================
|
|
|
|
LoadState04DisplayData:
|
|
ldy $87
|
|
|
|
lda CharacterIntroDisplayDataTable,y
|
|
sta workPtr0
|
|
|
|
lda CharacterIntroDisplayDataTable+1,y
|
|
sta workPtr0+1
|
|
|
|
ldy #$00
|
|
|
|
@CopyDisplayData:
|
|
lda (workPtr0),y
|
|
sta $024B,y
|
|
|
|
iny
|
|
cmp #$FF
|
|
bne @CopyDisplayData
|
|
|
|
lda (workPtr0),y
|
|
beq @SecondaryCopy
|
|
|
|
rts
|
|
|
|
@SecondaryCopy:
|
|
lda $87
|
|
sec
|
|
sbc #$02
|
|
asl
|
|
asl
|
|
tay
|
|
|
|
ldx #$10
|
|
|
|
@CopySecondaryData:
|
|
lda CharacterIntroSpriteData,y
|
|
sta $0760,y
|
|
|
|
iny
|
|
dex
|
|
bne @CopySecondaryData
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $C5D8-$C607: Initialize Playfield Area
|
|
;
|
|
; Local:
|
|
; Sets the PPU destination to $20C0 and fills 24 complete 32-tile nametable
|
|
; rows.
|
|
;
|
|
; Each row consists of:
|
|
; 2 x $2D
|
|
; 28 x $20
|
|
; 2 x $2D
|
|
;
|
|
; The inner count at $01 is reinitialized to $1C at the beginning of every
|
|
; row. $00 begins at $17 and counts rows down through zero.
|
|
;
|
|
; Global:
|
|
; Called during State04Initialize with rendering disabled. Builds the large
|
|
; rectangular background area used by state $04.
|
|
;
|
|
; Notes:
|
|
; The BPL at $C605 intentionally returns to $C5E6, not directly to the first
|
|
; tile write. This reloads $01 with $1C for every row and must be preserved
|
|
; for byte identity.
|
|
;==============================================================================
|
|
|
|
InitializePlayfieldArea:
|
|
lda #$20
|
|
sta PPUADDR
|
|
|
|
lda #$C0
|
|
sta PPUADDR
|
|
|
|
lda #$17
|
|
sta workPtr0
|
|
|
|
@NextRow:
|
|
lda #$1C
|
|
sta workPtr0+1
|
|
|
|
lda #$2D
|
|
sta PPUDATA
|
|
sta PPUDATA
|
|
|
|
lda #$20
|
|
|
|
@ClearRowInterior:
|
|
sta PPUDATA
|
|
dec workPtr0+1
|
|
bne @ClearRowInterior
|
|
|
|
lda #$2D
|
|
sta PPUDATA
|
|
sta PPUDATA
|
|
|
|
dec workPtr0
|
|
bpl @NextRow
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $C608-$C666: Initialize State $04 PPU Data
|
|
;
|
|
; Local:
|
|
; Performs three groups of PPU initialization:
|
|
;
|
|
; 1. Writes $24 (36) bytes from $C76E to PPUDATA beginning at PPU $23C8.
|
|
;
|
|
; 2. Processes a sequence of variable-length PPU write records beginning
|
|
; at $C69B. Each record contains a two-byte PPU destination followed by
|
|
; data bytes terminated by $FF.
|
|
;
|
|
; 3. Writes a full $20-byte palette table from CharacterIntroPalette to PPU palette RAM
|
|
; beginning at $3F00.
|
|
;
|
|
; After the palette transfer, resets PPUADDR away from palette space and
|
|
; returns.
|
|
;
|
|
; Global:
|
|
; Called by State04Initialize while rendering is disabled. Together with
|
|
; InitializePlayfieldArea, this routine constructs the PPU state needed by
|
|
; the state-$04 display sequence.
|
|
;
|
|
; Notes:
|
|
; Unlike InitializeNametableData, the PPU-record loop at $C61D does not
|
|
; contain an explicit record count. The encoded data and Y wrap behavior
|
|
; determine when processing terminates. We should decode $C69B before
|
|
; assigning a more precise description to that stream.
|
|
;
|
|
; CharacterIntroPalette begins the 32-byte palette table.
|
|
; $C76E is the source of the 36-byte attribute-data transfer.
|
|
;==============================================================================
|
|
|
|
InitializeState04PpuData:
|
|
; Set PPU destination to $23C8.
|
|
lda #$23
|
|
sta PPUADDR
|
|
|
|
lda #$C8
|
|
sta PPUADDR
|
|
|
|
; Copy $24 bytes of attribute data.
|
|
ldy #$00
|
|
|
|
@CopyAttributeData:
|
|
lda $C76E,y
|
|
sta PPUDATA
|
|
|
|
iny
|
|
cpy #$24
|
|
bne @CopyAttributeData
|
|
|
|
; Process encoded PPU write data from $C69B.
|
|
ldy #$00
|
|
|
|
@NextPpuRecord:
|
|
lda CharacterNicknameHeaderData,y
|
|
sta PPUADDR
|
|
iny
|
|
|
|
lda CharacterNicknameHeaderData,y
|
|
sta PPUADDR
|
|
iny
|
|
|
|
@CopyPpuRecord:
|
|
lda CharacterNicknameHeaderData,y
|
|
cmp #$FF
|
|
beq @EndPpuRecord
|
|
|
|
sta PPUDATA
|
|
iny
|
|
bne @CopyPpuRecord
|
|
|
|
@EndPpuRecord:
|
|
lda PPUSTATUS
|
|
|
|
; Upload the complete 32-byte palette directly.
|
|
lda #$3F
|
|
sta PPUADDR
|
|
|
|
lda #$00
|
|
sta PPUADDR
|
|
|
|
ldy #$00
|
|
|
|
@CopyPalette:
|
|
lda CharacterIntroPalette,y
|
|
sta PPUDATA
|
|
|
|
iny
|
|
cpy #$20
|
|
bne @CopyPalette
|
|
|
|
; Reset the PPU address following palette access.
|
|
lda #$3F
|
|
sta PPUADDR
|
|
|
|
lda #$00
|
|
sta PPUADDR
|
|
sta PPUADDR
|
|
sta PPUADDR
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $C667-$C686: State $04 Palette Data
|
|
;
|
|
; Local:
|
|
; Complete 32-byte palette uploaded directly to PPU $3F00-$3F1F by
|
|
; InitializeState04PpuData.
|
|
;
|
|
; Global:
|
|
; Defines the background and sprite colors used by the state-$04 display.
|
|
;
|
|
; Notes:
|
|
; First 16 bytes are the four background palettes.
|
|
; Second 16 bytes are the four sprite palettes.
|
|
;==============================================================================
|
|
CharacterIntroPalette:
|
|
; Background palettes
|
|
.byte $0F,$20,$0F,$06
|
|
.byte $0F,$06,$0F,$33
|
|
.byte $0F,$33,$0F,$27
|
|
.byte $0F,$17,$0F,$21
|
|
|
|
; Sprite palettes
|
|
.byte $0F,$27,$20,$06
|
|
.byte $0F,$11,$20,$33
|
|
.byte $0F,$20,$20,$21
|
|
.byte $0F,$09,$20,$17
|
|
|
|
;==============================================================================
|
|
; $C687-$C69A: State $04 Display Data Pointer Table
|
|
;
|
|
; Local:
|
|
; Contains ten 16-bit pointers to display/update data streams. The helper at
|
|
; $C5A6 uses $87 directly as a byte offset into this table:
|
|
;
|
|
; ldy $87
|
|
; lda CharacterIntroDisplayDataTable,y
|
|
; sta $00
|
|
; lda CharacterIntroDisplayDataTable+1,y
|
|
; sta $01
|
|
;
|
|
; The valid table offsets are therefore:
|
|
; $00,$02,$04,$06,$08,$0A,$0C,$0E,$10,$12
|
|
;
|
|
; Global:
|
|
; Selects the display data used as the state-$04 secondary state machine
|
|
; progresses. State04Initialize uses offset $00, while the successive timed
|
|
; substates use offsets $02 through $12.
|
|
;
|
|
; Notes:
|
|
; Each target begins a $FF-terminated display/update stream copied into RAM
|
|
; at $024B by LoadState04DisplayData.
|
|
;
|
|
; Several streams contain an additional control byte following $FF. The
|
|
; helper uses that byte to decide whether to perform its secondary copy.
|
|
;==============================================================================
|
|
|
|
CharacterIntroDisplayDataTable:
|
|
.word CharacterNicknameHeaderData ; $87 = $00 Character; NICKNAME
|
|
.word ShadowNameData ; $87 = $02 : SHADOW
|
|
.word BlinkyNameData ; $87 = $04 _BLINKY_
|
|
.word SpeedyNameData ; $87 = $06 : SPEEDY
|
|
.word PinkyNameData ; $87 = $08 _PINKY_
|
|
.word CharacterIntroGraphicData0 ; $87 = $0A
|
|
.word CharacterIntroGraphicData1 ; $87 = $0C
|
|
.word PokeyNameData ; $87 = $0E
|
|
.word ClydeNameData ; $87 = $10
|
|
.word ScoringLegendData ; $87 = $12
|
|
|
|
;==============================================================================
|
|
; $C69B-$C72D: State $04 Display Update Streams
|
|
;
|
|
; Local:
|
|
; Contains ten display/update streams selected through
|
|
; CharacterIntroDisplayDataTable according to the state-$04 substate offset $87.
|
|
;
|
|
; LoadState04DisplayData copies the selected stream into RAM beginning at
|
|
; $024B until it encounters $FF. The $FF byte itself is also copied.
|
|
;
|
|
; For several streams, the byte immediately following $FF is $00. The
|
|
; loader examines this byte and uses it to trigger its optional secondary
|
|
; data copy.
|
|
;
|
|
; Global:
|
|
; Supplies the sequence of text and display changes shown during the timed
|
|
; state-$04 sequence. The data reveals that this portion of the attract/
|
|
; information display introduces game characters and later installs
|
|
; scoring/instruction-related display data.
|
|
;
|
|
; Notes:
|
|
; Many tile values correspond directly to ASCII-like character tiles, but
|
|
; special tile values are retained numerically.
|
|
;
|
|
; $00 bytes appearing after $FF belong to the control mechanism used by
|
|
; LoadState04DisplayData. They are not part of the $FF-terminated portion
|
|
; copied to $024B.
|
|
;
|
|
; The final stream at $C707 is structurally different: it contains multiple
|
|
; apparent PPU/update command groups before the final $FF.
|
|
;==============================================================================
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $C69B-$C6B2
|
|
; State04 substate offset: $00
|
|
;
|
|
; Destination prefix: $20E6
|
|
;
|
|
; Tile data corresponds approximately to:
|
|
; "CHARACTER ; NICKNAME"
|
|
;
|
|
; No explicit $00 control byte follows this stream before the next record.
|
|
;------------------------------------------------------------------------------
|
|
|
|
CharacterNicknameHeaderData:
|
|
.byte $20,$E6
|
|
.byte $43,$48,$41,$52,$41,$43,$54,$45,$52
|
|
.byte $20,$3B,$20,$20
|
|
.byte $4E,$49,$43,$4B,$4E,$41,$4D,$45
|
|
.byte $FF
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $C6B3-$C6BD
|
|
; State04 substate offset: $02
|
|
;
|
|
; Destination prefix: $2148
|
|
;
|
|
; Text-like tile data:
|
|
; ":SHADOW"
|
|
;
|
|
; $00 after $FF selects the loader's secondary-copy path.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ShadowNameData:
|
|
.byte $21,$48
|
|
.byte $3A,$53,$48,$41,$44,$4F,$57
|
|
.byte $FF
|
|
.byte $00
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $C6BE-$C6C8
|
|
; State04 substate offset: $04
|
|
;
|
|
; Destination prefix: $2153
|
|
;
|
|
; Text-like tile data:
|
|
; "_BLINKY_"
|
|
;
|
|
; No trailing $00 before the next stream.
|
|
;------------------------------------------------------------------------------
|
|
|
|
BlinkyNameData:
|
|
.byte $21,$53
|
|
.byte $5F,$42,$4C,$49,$4E,$4B,$59,$5F
|
|
.byte $FF
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $C6C9-$C6D3
|
|
; State04 substate offset: $06
|
|
;
|
|
; Destination prefix: $21A8
|
|
;
|
|
; Text-like tile data:
|
|
; ":SPEEDY"
|
|
;
|
|
; $00 after $FF selects the loader's secondary-copy path.
|
|
;------------------------------------------------------------------------------
|
|
SpeedyNameData:
|
|
.byte $21,$A8
|
|
.byte $3A,$53,$50,$45,$45,$44,$59
|
|
.byte $FF
|
|
.byte $00
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $C6D4-$C6DD
|
|
; State04 substate offset: $08
|
|
;
|
|
; Destination prefix: $21B3
|
|
;
|
|
; Text-like tile data:
|
|
; "_PINKY_"
|
|
;------------------------------------------------------------------------------
|
|
PinkyNameData:
|
|
.byte $21,$B3
|
|
.byte $5F,$50,$49,$4E,$4B,$59,$5F
|
|
.byte $FF
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $C6DE-$C6E9
|
|
; State04 substate offset: $0A
|
|
;
|
|
; Destination prefix: $2208
|
|
;
|
|
; Contains graphical/special tile values rather than plain character codes.
|
|
; $00 after $FF selects the loader's secondary-copy path.
|
|
;------------------------------------------------------------------------------
|
|
CharacterIntroGraphicData0:
|
|
.byte $22,$08
|
|
.byte $B6,$C1,$C3,$B7,$B4,$C2,$B3,$C4
|
|
.byte $FF
|
|
.byte $00
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $C6EA-$C6F2
|
|
; State04 substate offset: $0C
|
|
;
|
|
; Destination prefix: $2213
|
|
;
|
|
; Contains another set of special graphical tile values.
|
|
;------------------------------------------------------------------------------
|
|
CharacterIntroGraphicData1:
|
|
.byte $22,$13
|
|
.byte $C8,$B5,$C5,$C0,$C6,$C8
|
|
.byte $FF
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $C6F3-$C6FC
|
|
; State04 substate offset: $0E
|
|
;
|
|
; Destination prefix: $2268
|
|
;
|
|
; Text-like tile data:
|
|
; ":POKEY"
|
|
;
|
|
; $00 after $FF selects the loader's secondary-copy path.
|
|
;------------------------------------------------------------------------------
|
|
PokeyNameData:
|
|
.byte $22,$68
|
|
.byte $3A,$50,$4F,$4B,$45,$59
|
|
.byte $FF
|
|
.byte $00
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $C6FD-$C706
|
|
; State04 substate offset: $10
|
|
;
|
|
; Destination prefix: $2273
|
|
;
|
|
; Text-like tile data:
|
|
; "_CLYDE_"
|
|
;------------------------------------------------------------------------------
|
|
ClydeNameData:
|
|
.byte $22,$73
|
|
.byte $5F,$43,$4C,$59,$44,$45,$5F
|
|
.byte $FF
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $C707-$C72D
|
|
; State04 substate offset: $12
|
|
;
|
|
; Final composite display stream. Unlike the earlier simple records, this
|
|
; contains several apparent update groups separated by $00 bytes before the
|
|
; final $FF.
|
|
;
|
|
; Visible character-like portions include:
|
|
; "10 PTS"
|
|
; "50 PTS"
|
|
;
|
|
; The special tile values $CE,$CF and $23-$2B are preserved numerically.
|
|
;------------------------------------------------------------------------------
|
|
ScoringLegendData:
|
|
.byte $22,$AD
|
|
.byte $03,$20,$31,$30,$20,$50,$54,$53
|
|
.byte $00
|
|
|
|
.byte $22,$ED
|
|
.byte $01,$20,$35,$30,$20,$50,$54,$53
|
|
.byte $00
|
|
|
|
.byte $23,$34
|
|
.byte $CE,$CF
|
|
.byte $00
|
|
|
|
.byte $23,$4D
|
|
.byte $23,$24,$25,$26,$27,$28,$29,$2A,$2B
|
|
.byte $FF
|
|
|
|
|
|
;==============================================================================
|
|
; $C72E-$C76D: State $04 Secondary Object/Sprite Data
|
|
;
|
|
; Local:
|
|
; Contains 64 bytes of secondary display data used by
|
|
; LoadState04DisplayData.
|
|
;
|
|
; When a state-$04 display stream requests the secondary-copy path, the
|
|
; loader calculates:
|
|
;
|
|
; Y = ($87 - $02) * 4
|
|
;
|
|
; It then copies $10 (16) bytes from:
|
|
;
|
|
; CharacterIntroSpriteData,Y
|
|
;
|
|
; to:
|
|
;
|
|
; $0760,Y
|
|
;
|
|
; Because state-$04 substates advance by two, Y advances by eight bytes:
|
|
;
|
|
; $87 = $02 -> Y = $00
|
|
; $87 = $04 -> Y = $08
|
|
; $87 = $06 -> Y = $10
|
|
; $87 = $08 -> Y = $18
|
|
; ...
|
|
;
|
|
; The 16-byte transfers therefore intentionally overlap by eight bytes.
|
|
;
|
|
; Global:
|
|
; Supplies progressively updated object/sprite-related state during the
|
|
; state-$04 timed display sequence. The destination lies in RAM page $07,
|
|
; which is also used as an OAM DMA source elsewhere in the program.
|
|
;
|
|
; The repeated four-byte patterns strongly suggest sprite/OAM-style records,
|
|
; but exact field semantics should be confirmed against the code that
|
|
; consumes $0760 and the active OAM page before assigning field names.
|
|
;
|
|
; Notes:
|
|
; The table is safest to represent as 16 four-byte records during this pass.
|
|
; This preserves its natural repeated structure while allowing the loader's
|
|
; overlapping 16-byte windows to remain obvious.
|
|
;==============================================================================
|
|
|
|
CharacterIntroSpriteData:
|
|
; $C72E - record $00
|
|
.byte $48,$1C,$40,$26
|
|
|
|
; $C732 - record $01
|
|
.byte $48,$1B,$40,$2E
|
|
|
|
; $C736 - record $02
|
|
.byte $50,$1F,$40,$26
|
|
|
|
; $C73A - record $03
|
|
.byte $50,$1D,$40,$2E
|
|
|
|
; $C73E - record $04
|
|
.byte $60,$1C,$41,$26
|
|
|
|
; $C742 - record $05
|
|
.byte $60,$1B,$41,$2E
|
|
|
|
; $C746 - record $06
|
|
.byte $68,$1F,$41,$26
|
|
|
|
; $C74A - record $07
|
|
.byte $68,$1D,$41,$2E
|
|
|
|
; $C74E - record $08
|
|
.byte $78,$1C,$42,$26
|
|
|
|
; $C752 - record $09
|
|
.byte $78,$1B,$42,$2E
|
|
|
|
; $C756 - record $0A
|
|
.byte $80,$1F,$42,$26
|
|
|
|
; $C75A - record $0B
|
|
.byte $80,$1D,$42,$2E
|
|
|
|
; $C75E - record $0C
|
|
.byte $90,$1C,$43,$26
|
|
|
|
; $C762 - record $0D
|
|
.byte $90,$1B,$43,$2E
|
|
|
|
; $C766 - record $0E
|
|
.byte $98,$1F,$43,$26
|
|
|
|
; $C76A - record $0F
|
|
.byte $98,$1D,$43,$2E
|
|
|
|
|
|
;==============================================================================
|
|
; $C76E-$C791: State $04 Nametable Attribute Data
|
|
;
|
|
; Local:
|
|
; Contains $24 (36) bytes copied directly to PPUDATA by
|
|
; InitializeState04PpuData.
|
|
;
|
|
; The destination begins at PPU $23C8, so the complete transfer covers:
|
|
;
|
|
; $23C8-$23EB
|
|
;
|
|
; Global:
|
|
; Defines background palette selection attributes used by the state-$04
|
|
; display. The highly regular $00/$55/$AA/$FF pattern assigns repeating
|
|
; palette selections across large regions of the nametable.
|
|
;
|
|
; Notes:
|
|
; These are NES attribute-table bytes rather than tile indices.
|
|
;
|
|
; Each attribute byte contains four 2-bit palette selections. Values such
|
|
; as $00, $55, $AA and $FF therefore select the same palette throughout all
|
|
; four quadrants covered by that attribute byte:
|
|
;
|
|
; $00 -> palette 0 in all four quadrants
|
|
; $55 -> palette 1 in all four quadrants
|
|
; $AA -> palette 2 in all four quadrants
|
|
; $FF -> palette 3 in all four quadrants
|
|
;
|
|
; The final $22 mixes palette selections within its attribute regions.
|
|
;==============================================================================
|
|
|
|
CharacterIntroAttributeData:
|
|
.byte $00,$00,$00,$00,$00,$00,$00,$00
|
|
.byte $55,$55,$55,$55,$55,$55,$55,$55
|
|
.byte $AA,$AA,$AA,$AA,$AA,$AA,$AA,$AA
|
|
.byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
|
|
.byte $AA,$AA,$AA,$22
|
|
|
|
;==============================================================================
|
|
; $C792-$C7A0: State $04 Final-Phase Dispatcher
|
|
;
|
|
; Local:
|
|
; Uses $88 as a direct byte offset into a four-entry table of 16-bit
|
|
; addresses beginning at $C7A1.
|
|
;
|
|
; The selected address is stored in the temporary pointer $10/$11 and
|
|
; execution is transferred to it using an indirect JMP.
|
|
;
|
|
; Global:
|
|
; Implements state-$04 substate offset $16. Rather than performing the work
|
|
; directly, this substate introduces another secondary state machine.
|
|
;
|
|
; At this stage:
|
|
;
|
|
; $3F = $04 main state
|
|
; $87 = $16 state-$04 substate
|
|
; $88 final-phase dispatch offset
|
|
;
|
|
; This provides another level of progression within the final state-$04
|
|
; phase.
|
|
;
|
|
; Notes:
|
|
; $88 is used directly as a byte offset, so normal values are expected to
|
|
; advance by two:
|
|
;
|
|
; $00, $02, $04, $06
|
|
;
|
|
; The individual target handlers will be named as they are decoded.
|
|
;==============================================================================
|
|
State04FinalPhase:
|
|
ldy $88
|
|
|
|
lda State04FinalPhaseTable,y
|
|
sta dispatchVector
|
|
|
|
lda State04FinalPhaseTable+1,y
|
|
sta dispatchVector+1
|
|
|
|
jmp ($0010)
|
|
|
|
;==============================================================================
|
|
; $C7A1-$C7A6: State $04 Final-Phase Dispatch Table
|
|
;
|
|
; Local:
|
|
; Three 16-bit handler addresses indexed by $88.
|
|
;
|
|
; Global:
|
|
; Selects the processing stage used during State04FinalPhase.
|
|
;
|
|
; Notes:
|
|
; Valid byte offsets established by the table are $00, $02 and $04.
|
|
; $C7A7 is executable code and is not part of the pointer table.
|
|
;==============================================================================
|
|
|
|
State04FinalPhaseTable:
|
|
.word State04FinalPhaseInitialize ; $88 = $00
|
|
.word State04FinalPhaseActive ; $88 = $02
|
|
.word State04FinalPhaseComplete ; $88 = $04
|
|
|
|
;==============================================================================
|
|
; $C7A7-$C7F1: State $04 Final-Phase Initialization
|
|
;
|
|
; Local:
|
|
; Initializes the first stage of State04FinalPhase.
|
|
;
|
|
; Copies a $FF-terminated display/update stream from State04FinalDisplayData
|
|
; into RAM at $024B, including the terminator.
|
|
;
|
|
; Initializes several state variables and object/display values, clears
|
|
; $001E-$0031 and $0278-$028B, calls the helper at $DAF1, then advances
|
|
; $88 by two to select final-phase offset $02.
|
|
;
|
|
; Global:
|
|
; First handler selected by State04FinalPhase when $88 = $00. It prepares
|
|
; the RAM and display state required by the next final-phase handler at
|
|
; $C7F2.
|
|
;
|
|
; Notes:
|
|
; $1A is initialized to $FF.
|
|
; $1B, $89 and $8A are initialized to $00.
|
|
;
|
|
; $0274 = $F4
|
|
; $0276 = $A8
|
|
; $028C = $01
|
|
; $0292 = $20
|
|
;
|
|
; The exact semantics of these locations will be refined after tracing
|
|
; their consumers.
|
|
;
|
|
; State04FinalDisplayData is a display/update stream in the same general RAM
|
|
; command area used elsewhere through $024B.
|
|
;==============================================================================
|
|
|
|
State04FinalPhaseInitialize:
|
|
ldy #$00
|
|
|
|
@CopyDisplayData:
|
|
lda State04FinalDisplayData,y
|
|
sta $024B,y
|
|
iny
|
|
cmp #$FF
|
|
bne @CopyDisplayData
|
|
|
|
lda #$FF
|
|
sta pacmanMotion
|
|
|
|
lda #$00
|
|
sta $1B
|
|
sta $89
|
|
sta $8A
|
|
|
|
lda #$F4
|
|
sta $0274
|
|
|
|
lda #$A8
|
|
sta $0276
|
|
|
|
lda #$01
|
|
sta $028C
|
|
|
|
lda #$20
|
|
sta $0292
|
|
|
|
lda #$00
|
|
tay
|
|
|
|
@ClearLowRamBlock:
|
|
sta $001E,y
|
|
iny
|
|
cpy #$14
|
|
bne @ClearLowRamBlock
|
|
|
|
tay
|
|
|
|
@ClearObjectRamBlock:
|
|
sta $0278,y
|
|
iny
|
|
cpy #$14
|
|
bne @ClearObjectRamBlock
|
|
|
|
jsr $DAF1
|
|
|
|
inc $88
|
|
inc $88
|
|
|
|
jmp MainDispatchLoop
|
|
|
|
;==============================================================================
|
|
; $C7F2-$C856: State $04 Final-Phase Active Handler
|
|
;
|
|
; Local:
|
|
; Calls two per-frame helpers at UpdateState04Objects and
|
|
; AnimateState04DisplayPattern, then examines $0274.
|
|
;
|
|
; When $0274 equals one of:
|
|
;
|
|
; $E0
|
|
; $D1
|
|
; $C2
|
|
; $B3
|
|
;
|
|
; the routine calls InitializeState04ObjectSlot.
|
|
;
|
|
; Processing otherwise continues until $0274 reaches $40. While it has not
|
|
; reached $40, control returns to MainDispatchLoop.
|
|
;
|
|
; When $0274 reaches $40, the routine:
|
|
;
|
|
; - Initializes four 4-byte structures beginning at $001E.
|
|
; - Sets $1A = $01 and $1B = $50.
|
|
; - Sets $0293-$0296 to $01.
|
|
; - Clears $89.
|
|
; - Writes a short display/update sequence at $024B/$024D.
|
|
; - Advances $88 by two, selecting final-phase offset $04.
|
|
;
|
|
; Global:
|
|
; Active middle stage of State04FinalPhase. The handler appears to drive
|
|
; an animated sequence by calling UpdateState04Objects/AnimateState04DisplayPattern
|
|
; each frame and reacting when $0274 reaches several specific values.
|
|
;
|
|
; The milestone values $E0,$D1,$C2,$B3 invoke InitializeState04ObjectSlot. The exact meaning of
|
|
; those milestones should be assigned after the movement/update helpers are
|
|
; decoded.
|
|
;
|
|
; Notes:
|
|
; $0274 was initialized to $F4 by State04FinalPhaseInitialize, so the
|
|
; descending milestone tests strongly suggest $0274 is modified by one of
|
|
; the per-frame helper routines.
|
|
;
|
|
; The four low-RAM structures are $001E/$0022/$0026/$002A. Each receives
|
|
; $00 in its first byte and $C0 in its second byte. The remaining two bytes
|
|
; are not changed by this loop.
|
|
;==============================================================================
|
|
|
|
State04FinalPhaseActive:
|
|
jsr UpdateState04Objects
|
|
jsr AnimateState04DisplayPattern
|
|
|
|
lda $0274
|
|
|
|
cmp #$E0
|
|
beq @RunMilestoneUpdate
|
|
|
|
cmp #$D1
|
|
beq @RunMilestoneUpdate
|
|
|
|
cmp #$C2
|
|
beq @RunMilestoneUpdate
|
|
|
|
cmp #$B3
|
|
bne @CheckForCompletion
|
|
|
|
@RunMilestoneUpdate:
|
|
jsr InitializeState04ObjectSlot
|
|
|
|
@CheckForCompletion:
|
|
lda $0274
|
|
cmp #$40
|
|
beq @CompletePhase
|
|
|
|
jmp MainDispatchLoop
|
|
|
|
@CompletePhase:
|
|
ldy #$00
|
|
|
|
@InitializeStructures:
|
|
lda #$00
|
|
sta ghost1Motion,y
|
|
|
|
lda #$C0
|
|
sta ghost1Motion+1,y
|
|
|
|
iny
|
|
iny
|
|
iny
|
|
iny
|
|
|
|
cpy #$10
|
|
bne @InitializeStructures
|
|
|
|
lda #$01
|
|
sta pacmanMotion
|
|
|
|
lda #$50
|
|
sta pacmanMotion+1
|
|
|
|
lda #$01
|
|
sta $0293
|
|
sta $0294
|
|
sta $0295
|
|
sta $0296
|
|
|
|
lda #$00
|
|
sta $89
|
|
|
|
lda #$22
|
|
sta $024B
|
|
|
|
lda #$20
|
|
sta $024D
|
|
|
|
inc $88
|
|
inc $88
|
|
|
|
jmp MainDispatchLoop
|
|
|
|
;==============================================================================
|
|
; $C857-$C8A7: State $04 Final-Phase Completion Handler
|
|
;
|
|
; Local:
|
|
; Final handler for final-phase offset $88 = $04.
|
|
;
|
|
; If $8A is nonzero, calls RotateState04ObjectSlots and decrements the countdown. When the
|
|
; countdown reaches zero, scans status entries beginning at $028D until an
|
|
; entry with one or more upper-three status bits set is found.
|
|
;
|
|
; The matching entry and associated state are cleared. If $89 has reached
|
|
; $04, the routine sets $47 to $01 and transfers control to GameModeEntry.
|
|
;
|
|
; When $8A is already zero on entry, calls $C8DC and returns to the common
|
|
; main dispatch loop.
|
|
;
|
|
; Global:
|
|
; Final processing stage of the nested state-$04 sequence:
|
|
;
|
|
; $3F = $04
|
|
; $87 = $16
|
|
; $88 = $04
|
|
;
|
|
; The eventual transfer to GameModeEntry appears to leave this attract/display
|
|
; sequence and enter another major portion of the program.
|
|
;
|
|
; Notes:
|
|
; $8A acts as a countdown here.
|
|
; $89 is tested against $04 for completion.
|
|
;
|
|
; The scan at $028D looks for the first entry satisfying:
|
|
;
|
|
; ($028D,Y & $E0) != 0
|
|
;
|
|
; Exact object/state semantics remain for a later pass.
|
|
;==============================================================================
|
|
|
|
State04FinalPhaseComplete:
|
|
lda $8A
|
|
beq @RunRegularUpdate
|
|
|
|
jsr RotateState04ObjectSlots
|
|
|
|
dec $8A
|
|
beq @CountdownComplete
|
|
|
|
jmp MainDispatchLoop
|
|
|
|
@CountdownComplete:
|
|
ldy #$00
|
|
|
|
@FindEntry:
|
|
lda $028D,y
|
|
and #$E0
|
|
bne @EntryFound
|
|
|
|
iny
|
|
bne @FindEntry
|
|
|
|
@EntryFound:
|
|
lda #$00
|
|
sta $028D,y
|
|
|
|
lda #$00
|
|
sta $0293,y
|
|
|
|
tya
|
|
asl
|
|
asl
|
|
tay
|
|
|
|
lda #$00
|
|
sta $0278,y
|
|
sta $027A,y
|
|
sta ghost1Motion,y
|
|
sta ghost1Motion+1,y
|
|
|
|
lda #$A8
|
|
sta $0276
|
|
|
|
lda $89
|
|
cmp #$04
|
|
beq @FinishSequence
|
|
|
|
jmp MainDispatchLoop
|
|
|
|
@FinishSequence:
|
|
lda #$01
|
|
sta activePlayerFlag
|
|
|
|
jmp GameModeEntry
|
|
|
|
@RunRegularUpdate:
|
|
jsr UpdateState04Objects
|
|
|
|
jmp MainDispatchLoop
|
|
|
|
;==============================================================================
|
|
; $C8A8-$C8DB: Allocate/Initialize State $04 Object Slot
|
|
;
|
|
; Local:
|
|
; Searches four 4-byte structures beginning at $0278 for the first slot
|
|
; whose first byte is zero.
|
|
;
|
|
; During the search, $00 tracks the logical slot number while Y advances
|
|
; by four bytes per structure.
|
|
;
|
|
; Once a free slot is found, initializes that structure:
|
|
;
|
|
; +0 = $F4
|
|
; +2 = $A8
|
|
;
|
|
; It also initializes corresponding four-byte-strided zero-page state:
|
|
;
|
|
; $001E+Y = $FF
|
|
; $001F+Y = $00
|
|
;
|
|
; The logical slot number saved in $00 is then used to index two separate
|
|
; per-slot arrays:
|
|
;
|
|
; $0293+slot = current $89 value
|
|
; $028D+slot = $0C
|
|
;
|
|
; Finally increments $89 and returns.
|
|
;
|
|
; Global:
|
|
; Called by State04FinalPhaseActive whenever $0274 reaches the milestone
|
|
; values $E0, $D1, $C2, or $B3.
|
|
;
|
|
; This strongly suggests that the routine activates one additional object
|
|
; at each milestone during the state-$04 final sequence. Four slots are
|
|
; available, matching the four milestone values.
|
|
;
|
|
; Notes:
|
|
; $0278 appears to be the first field of a four-byte structure array.
|
|
; $027A is the third field of the same structure.
|
|
;
|
|
; $001E/$001F are parallel four-byte-strided state fields.
|
|
;
|
|
; $028D and $0293 are indexed by logical slot number rather than the
|
|
; four-byte structure offset.
|
|
;
|
|
; Exact object semantics remain deliberately unnamed until UpdateState04Objects
|
|
; and RotateState04ObjectSlots reveal how these structures are updated.
|
|
;==============================================================================
|
|
|
|
InitializeState04ObjectSlot:
|
|
ldy #$00
|
|
sty workPtr0
|
|
|
|
@FindFreeSlot:
|
|
lda $0278,y
|
|
beq @InitializeSlot
|
|
|
|
inc workPtr0
|
|
|
|
iny
|
|
iny
|
|
iny
|
|
iny
|
|
|
|
bne @FindFreeSlot
|
|
|
|
@InitializeSlot:
|
|
lda #$F4
|
|
sta $0278,y
|
|
|
|
lda #$A8
|
|
sta $027A,y
|
|
|
|
lda #$FF
|
|
sta ghost1Motion,y
|
|
|
|
lda #$00
|
|
sta $001F,y
|
|
|
|
ldy workPtr0
|
|
|
|
lda $89
|
|
sta $0293,y
|
|
|
|
lda #$0C
|
|
sta $028D,y
|
|
|
|
inc $89
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $C8DC-$C8EA: State $04 Per-Frame Object Update Coordinator
|
|
;
|
|
; Local:
|
|
; Runs four update stages in sequence:
|
|
;
|
|
; UpdateTransitionObjectPositions
|
|
; RotateState04ObjectSlots
|
|
; UpdateState04ObjectStatus
|
|
; CheckState04ObjectTrigger
|
|
;
|
|
; After those return, tail-jumps to $DAF1 rather than returning directly.
|
|
;
|
|
; Global:
|
|
; Called once per frame during portions of the state-$04 final sequence.
|
|
; This routine coordinates the lower-level movement/object/display work
|
|
; associated with that sequence.
|
|
;
|
|
; It is called from both State04FinalPhaseActive and
|
|
; State04FinalPhaseComplete.
|
|
;
|
|
; Notes:
|
|
; The exact responsibilities of $EA19, $C92E, $C9FA, CheckState04ObjectTrigger
|
|
; and $DAF1 will be refined as those routines are decoded.
|
|
;
|
|
; The JMP to $DAF1 is a tail call: $DAF1 ultimately returns directly to
|
|
; the original caller of this routine.
|
|
;==============================================================================
|
|
UpdateState04Objects:
|
|
jsr UpdateTransitionObjectPositions
|
|
jsr RotateState04ObjectSlots
|
|
jsr UpdateState04ObjectStatus
|
|
jsr CheckState04ObjectTrigger
|
|
jmp BuildEntitySpriteBuffer
|
|
|
|
;==============================================================================
|
|
; $C8EB-$C92D: Check State $04 Object Trigger
|
|
;
|
|
; Local:
|
|
; Returns immediately when $1A is negative.
|
|
;
|
|
; Otherwise computes:
|
|
;
|
|
; threshold = $0274 + $08
|
|
;
|
|
; and scans four 4-byte structures beginning at $0278.
|
|
;
|
|
; For each active structure, compares its first byte against the threshold.
|
|
; When a qualifying structure is found, uses $89 as an index into a ROM
|
|
; table at $C9EE, installs the resulting value into a per-slot status array,
|
|
; clears a related slot value, initializes $8A to $40, and clears $028C and
|
|
; $0276.
|
|
;
|
|
; Global:
|
|
; Part of UpdateState04Objects. Appears to detect when one of the active
|
|
; state-$04 objects crosses a position threshold relative to the primary
|
|
; value at $0274, then initiates a $40-frame/countdown event through $8A.
|
|
;
|
|
; Notes:
|
|
; $00 holds the comparison threshold ($0274 + $08).
|
|
; $01 tracks the logical object slot while Y steps through four-byte
|
|
; structures.
|
|
;
|
|
; $89 is incremented as part of the event setup.
|
|
;
|
|
; $C9EE is a small ROM lookup table that remains to be decoded.
|
|
;==============================================================================
|
|
|
|
CheckState04ObjectTrigger:
|
|
lda pacmanMotion
|
|
bpl @Continue
|
|
|
|
rts
|
|
|
|
@Continue:
|
|
lda $0274
|
|
clc
|
|
adc #$08
|
|
sta workPtr0
|
|
|
|
ldy #$00
|
|
sty workPtr0+1
|
|
|
|
@ScanObjects:
|
|
lda $0278,y
|
|
beq @NextObject
|
|
|
|
cmp workPtr0
|
|
bcc @TriggerEvent
|
|
|
|
@NextObject:
|
|
inc workPtr0+1
|
|
|
|
iny
|
|
iny
|
|
iny
|
|
iny
|
|
|
|
cpy #$10
|
|
bne @ScanObjects
|
|
|
|
rts
|
|
|
|
@TriggerEvent:
|
|
ldy $89
|
|
inc $89
|
|
|
|
lda #$40
|
|
sta $8A
|
|
|
|
lda $C9EE,y
|
|
|
|
ldy workPtr0+1
|
|
sta $028D,y
|
|
|
|
lda #$00
|
|
sta $0293,y
|
|
|
|
lda #$00
|
|
sta $028C
|
|
sta $0276
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $C92E-$C9B7: Rotate State $04 Object Slots
|
|
;
|
|
; Local:
|
|
; Rotates four related object/state entries across several parallel arrays.
|
|
;
|
|
; The routine operates on:
|
|
;
|
|
; $001E/$001F four-byte-strided zero-page structures
|
|
; $0278-$0287 four 4-byte object structures
|
|
; $028D-$0290 four object/status bytes
|
|
; $0293-$0296 four object/index bytes
|
|
;
|
|
; For each array, the first entry is saved temporarily, entries 1-3 are
|
|
; shifted toward entry 0, and the saved entry 0 is moved to entry 3.
|
|
;
|
|
; Global:
|
|
; Called by UpdateState04Objects every frame, and also directly from
|
|
; State04FinalPhaseComplete while its $8A countdown is active.
|
|
;
|
|
; This appears to cycle the four state-$04 object slots through a fixed
|
|
; ordering while keeping their parallel state/status arrays synchronized.
|
|
;
|
|
; Notes:
|
|
; $00-$03 are temporary storage.
|
|
;
|
|
; The zero-page structures use a four-byte stride but only the first two
|
|
; bytes of each structure are moved here.
|
|
;
|
|
; The $0278 array moves all four bytes of each structure.
|
|
;
|
|
; $028D-$0290 and $0293-$0296 are simple four-entry byte arrays.
|
|
;==============================================================================
|
|
RotateState04ObjectSlots:
|
|
; -------------------------------------------------------------------------
|
|
; Rotate the first two bytes of the four-byte-strided zero-page structures.
|
|
;
|
|
; Entries:
|
|
; 0 -> $001E/$001F
|
|
; 1 -> $0022/$0023
|
|
; 2 -> $0026/$0027
|
|
; 3 -> $002A/$002B
|
|
; -------------------------------------------------------------------------
|
|
|
|
lda ghost1Motion
|
|
sta workPtr0
|
|
|
|
lda ghost1Motion+1
|
|
sta workPtr0+1
|
|
|
|
ldy #$00
|
|
|
|
@ShiftLowRamStructures:
|
|
lda ghost2Motion,y
|
|
sta ghost1Motion,y
|
|
|
|
lda ghost2Motion+1,y
|
|
sta ghost1Motion+1,y
|
|
|
|
iny
|
|
iny
|
|
iny
|
|
iny
|
|
|
|
cpy #$0C
|
|
bne @ShiftLowRamStructures
|
|
|
|
lda workPtr0
|
|
sta ghost4Motion
|
|
|
|
lda workPtr0+1
|
|
sta ghost4Motion+1
|
|
|
|
; -------------------------------------------------------------------------
|
|
; Rotate four complete 4-byte structures at $0278-$0287.
|
|
; -------------------------------------------------------------------------
|
|
|
|
lda $0278
|
|
sta workPtr0
|
|
|
|
lda $0279
|
|
sta workPtr0+1
|
|
|
|
lda $027A
|
|
sta workPtr1
|
|
|
|
lda $027B
|
|
sta workPtr1+1
|
|
|
|
ldy #$00
|
|
|
|
@ShiftObjectStructures:
|
|
lda $027C,y
|
|
sta $0278,y
|
|
|
|
iny
|
|
cpy #$0C
|
|
bne @ShiftObjectStructures
|
|
|
|
lda workPtr0
|
|
sta $0284
|
|
|
|
lda workPtr0+1
|
|
sta $0285
|
|
|
|
lda workPtr1
|
|
sta $0286
|
|
|
|
lda workPtr1+1
|
|
sta $0287
|
|
|
|
; -------------------------------------------------------------------------
|
|
; Rotate the four status bytes at $028D-$0290.
|
|
; -------------------------------------------------------------------------
|
|
|
|
lda $028D
|
|
sta workPtr0
|
|
|
|
ldy #$00
|
|
|
|
@ShiftStatusArray:
|
|
lda $028E,y
|
|
sta $028D,y
|
|
|
|
iny
|
|
cpy #$03
|
|
bne @ShiftStatusArray
|
|
|
|
lda workPtr0
|
|
sta $0290
|
|
|
|
; -------------------------------------------------------------------------
|
|
; Rotate the four associated index/state bytes at $0293-$0296.
|
|
; -------------------------------------------------------------------------
|
|
|
|
lda $0293
|
|
sta workPtr0
|
|
|
|
ldy #$00
|
|
|
|
@ShiftIndexArray:
|
|
lda $0294,y
|
|
sta $0293,y
|
|
|
|
iny
|
|
cpy #$03
|
|
bne @ShiftIndexArray
|
|
|
|
lda workPtr0
|
|
sta $0296
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $C9B8-$C9D7: Animate State $04 Display Pattern
|
|
;
|
|
; Local:
|
|
; Uses the frame counter at $4B to periodically copy one of two four-byte
|
|
; patterns into RAM $024B-$024E.
|
|
;
|
|
; The routine runs only when the low three bits of $4B are zero:
|
|
;
|
|
; ($4B & $07) == 0
|
|
;
|
|
; so the display data is updated once every eight frames.
|
|
;
|
|
; Bit 3 of $4B selects between two adjacent four-byte patterns beginning
|
|
; at $C9F2:
|
|
;
|
|
; bit 3 = 0 -> source $C9F2-$C9F5
|
|
; bit 3 = 1 -> source $C9F6-$C9F9
|
|
;
|
|
; Global:
|
|
; Called by State04FinalPhaseActive once per frame. Provides a simple
|
|
; two-frame animation/blink effect by updating the command/display buffer
|
|
; at $024B according to the NMI-driven frame counter $4B.
|
|
;
|
|
; Notes:
|
|
; $4B is incremented by NmiHandler once per frame.
|
|
;
|
|
; The source data at $C9F2 overlaps the tail of nearby ROM data. We should
|
|
; decode the surrounding $C9D8-$C9F9 region before assigning a more
|
|
; specific visual meaning to the two animation frames.
|
|
;==============================================================================
|
|
AnimateState04DisplayPattern:
|
|
lda frameCounter
|
|
and #$07
|
|
beq @UpdatePattern
|
|
|
|
rts
|
|
|
|
@UpdatePattern:
|
|
ldx #$00
|
|
ldy #$00
|
|
|
|
lda frameCounter
|
|
and #$08
|
|
beq @CopyPattern
|
|
|
|
ldy #$04
|
|
|
|
@CopyPattern:
|
|
lda State04AnimationFrames,y
|
|
sta $024B,x
|
|
|
|
inx
|
|
iny
|
|
|
|
cpx #$04
|
|
bne @CopyPattern
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $C9D8-$C9ED: State $04 Final Display Data
|
|
;==============================================================================
|
|
|
|
State04FinalDisplayData:
|
|
.byte $22,$AD
|
|
.byte $2D,$2D,$2D,$2D,$2D,$2D,$2D,$2D
|
|
.byte $00
|
|
|
|
.byte $22,$ED
|
|
.byte $2D,$2D,$2D,$2D,$2D,$2D,$2D,$2D
|
|
.byte $FF
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $C9EE-$C9F1: Adjacent data, purpose not yet resolved.
|
|
;------------------------------------------------------------------------------
|
|
|
|
State04UnknownData:
|
|
.byte $2D,$2F,$32,$34
|
|
|
|
|
|
;==============================================================================
|
|
; $C9F2-$C9F9: State $04 Animation Frames
|
|
;
|
|
; Two four-byte animation/update frames.
|
|
;
|
|
; $4B bit 3 = 0 -> frame 0
|
|
; $4B bit 3 = 1 -> frame 1
|
|
;==============================================================================
|
|
|
|
State04AnimationFrames:
|
|
.byte $22,$C7,$20,$FF
|
|
.byte $22,$C7,$01,$FF
|
|
|
|
;==============================================================================
|
|
; $C9FA-$CA3F: Update State $04 Object Status Animation
|
|
;
|
|
; Local:
|
|
; Selects an animation/status value from a ROM table at State04ObjectStatusTable and writes
|
|
; the value into active entries of $028D-$0290.
|
|
;
|
|
; The selected table range depends on $1A:
|
|
;
|
|
; $1A negative -> base offset $00
|
|
; $1A nonnegative -> base offset $0A
|
|
;
|
|
; $B7 is incremented each call and its low three bits select an entry from
|
|
; the first lookup range. The resulting value is written to $028C.
|
|
;
|
|
; The routine then updates the four status entries $028D-$0290 only once
|
|
; every eight frames. Bit 3 of $4B selects between two animation phases.
|
|
;
|
|
; Global:
|
|
; Called by UpdateState04Objects during the active state-$04 final sequence.
|
|
; Provides periodic animation/status changes for the four object slots
|
|
; maintained in $028D-$0290.
|
|
;
|
|
; Notes:
|
|
; $B7 behaves as an additional animation counter here.
|
|
;
|
|
; $4B is the NMI-driven frame counter.
|
|
;
|
|
; $028C is updated on every call, while $028D-$0290 are changed only when
|
|
; ($4B & $07) == 0.
|
|
;
|
|
; The table beginning at State04ObjectStatusTable follows this routine immediately and can be
|
|
; decoded separately.
|
|
;==============================================================================
|
|
|
|
UpdateState04ObjectStatus:
|
|
ldx #$00
|
|
|
|
lda $1A
|
|
bmi @UseTableBase
|
|
|
|
ldx #$0A
|
|
|
|
@UseTableBase:
|
|
stx workPtr0
|
|
|
|
inc $B7
|
|
|
|
lda $B7
|
|
and #$07
|
|
clc
|
|
adc workPtr0
|
|
tay
|
|
|
|
lda State04ObjectStatusTable,y
|
|
sta $028C
|
|
|
|
; Only update the four object entries once every eight frames.
|
|
lda $4B
|
|
and #$07
|
|
beq @UpdateObjectEntries
|
|
|
|
rts
|
|
|
|
@UpdateObjectEntries:
|
|
lda frameCounter
|
|
and #$08
|
|
beq @SelectTableValue
|
|
|
|
lda #$01
|
|
|
|
@SelectTableValue:
|
|
clc
|
|
adc workPtr0
|
|
adc #$08
|
|
tay
|
|
|
|
lda State04ObjectStatusTable,y
|
|
sta workPtr0
|
|
|
|
ldy #$00
|
|
|
|
@UpdateStatusEntries:
|
|
lda $028D,y
|
|
beq @NextStatusEntry
|
|
|
|
lda workPtr0
|
|
sta $028D,y
|
|
|
|
@NextStatusEntry:
|
|
iny
|
|
cpy #$04
|
|
bne @UpdateStatusEntries
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $CA40-$CA53: State $04 Object Status/Animation Lookup
|
|
;
|
|
; Local:
|
|
; Twenty-byte lookup table used by UpdateState04ObjectStatus.
|
|
;
|
|
; The routine selects one of two 10-byte groups:
|
|
;
|
|
; $1A negative -> group at offset $00
|
|
; $1A nonnegative -> group at offset $0A
|
|
;
|
|
; Within each group:
|
|
;
|
|
; bytes 0-7 are selected by ($B7 & $07)
|
|
; bytes 8-9 are selected by the slower frame-animation state
|
|
;
|
|
; Global:
|
|
; Supplies animation/status values for the four objects used during the
|
|
; final state-$04 sequence.
|
|
;
|
|
; Notes:
|
|
; Exact meanings of the individual values remain intentionally unnamed
|
|
; until the consumers of $028C and $028D-$0290 are better understood.
|
|
;==============================================================================
|
|
State04ObjectStatusTable:
|
|
; Group 0, selected while $1A is negative.
|
|
.byte $04,$04,$04,$05,$05,$04,$01,$01
|
|
.byte $0C,$0D
|
|
|
|
; Group 1, selected while $1A is nonnegative.
|
|
.byte $08,$08,$08,$09,$09,$08,$01,$01
|
|
.byte $1E,$1F
|
|
|
|
;==============================================================================
|
|
; $CA54-$CAD6: Main Game/Mode Initialization and Dispatch Loop
|
|
;
|
|
; Local:
|
|
; Reconfigures the PPU, waits for VBlank, disables rendering, clears several
|
|
; state variables, and invokes three initialization helpers.
|
|
;
|
|
; Depending on $48, initializes or preserves parts of two parallel RAM
|
|
; regions beginning at $67 and $77. It then initializes additional state,
|
|
; re-enables NMI through PPUCTRL=$88, and synchronizes with NMI via $40.
|
|
;
|
|
; After initialization, enters a persistent foreground loop that:
|
|
;
|
|
; - optionally watches controller bits $0C and returns to MainEntry,
|
|
; - services the countdown at $4C,
|
|
; - uses $3F as a byte offset into an eight-entry dispatch table at $CAD7,
|
|
; - indirect-jumps through $10/$11 to the selected handler.
|
|
;
|
|
; Global:
|
|
; Multiple earlier state-machine paths converge here, making this a major
|
|
; transition point out of the initial/state-$04 sequence and into another
|
|
; top-level game-mode state machine.
|
|
;
|
|
; The routine contains both one-time initialization and the common dispatch
|
|
; loop used by the handlers selected from $CAD7.
|
|
;
|
|
; Notes:
|
|
; $3F is reused as a byte offset into this new dispatch table.
|
|
;
|
|
; $40 continues to provide foreground/NMI synchronization.
|
|
;
|
|
; $4C acts as a countdown/delay gate in the dispatch loop.
|
|
;
|
|
; The exact semantics of $48, $46, $67-$86 and the new dispatch states will
|
|
; be refined as their handlers are decoded.
|
|
;==============================================================================
|
|
GameModeEntry:
|
|
lda #$08
|
|
sta PPUCTRL
|
|
sta ppuCtrlShadow
|
|
|
|
@WaitForVBlank:
|
|
lda PPUSTATUS
|
|
bpl @WaitForVBlank
|
|
|
|
lda #$00
|
|
sta PPUMASK
|
|
sta gameState
|
|
sta cocktailModeFlag
|
|
sta $69
|
|
sta $4A
|
|
|
|
jsr ClearGameplayNametables
|
|
jsr DrawGameplayHudLabels
|
|
jsr DrawGameplayScoreFields
|
|
|
|
lda gameplaySuspended
|
|
beq @ClearPlayerState
|
|
|
|
lda #$01
|
|
sta roundNumber
|
|
|
|
bne @InitializeCommonState
|
|
|
|
@ClearPlayerState:
|
|
lda #$00
|
|
tay
|
|
|
|
@ClearPlayerStateLoop:
|
|
sta roundNumber,y
|
|
iny
|
|
cpy #$20
|
|
bne @ClearPlayerStateLoop
|
|
|
|
lda #$03
|
|
sta roundNumber
|
|
sta $77
|
|
|
|
sta $0600
|
|
sta $0601
|
|
|
|
@InitializeCommonState:
|
|
lda #$FF
|
|
sta roundDisplayValue
|
|
sta $78
|
|
sta $0245
|
|
|
|
lda #$88
|
|
sta ppuCtrlShadow
|
|
sta PPUCTRL
|
|
|
|
GameModeFrameSync:
|
|
@WaitForNextFrame:
|
|
lda #$01
|
|
sta $40
|
|
|
|
@WaitForNmi:
|
|
lda $40
|
|
bne @WaitForNmi
|
|
|
|
@DispatchLoop:
|
|
lda gameplaySuspended
|
|
beq @ProcessDelay
|
|
|
|
lda currentInput
|
|
and #$0C
|
|
beq @ProcessDelay
|
|
|
|
lda #$02 ; TODO: what is state $02?
|
|
sta gameState
|
|
|
|
jmp MainEntry
|
|
|
|
@ProcessDelay:
|
|
lda stateTimer
|
|
beq @DispatchState
|
|
|
|
dec stateTimer
|
|
bne @WaitForNextFrame
|
|
|
|
@DispatchState:
|
|
ldy gameState
|
|
|
|
lda GameModeStateTable,y
|
|
sta dispatchVector
|
|
|
|
lda GameModeStateTable+1,y
|
|
sta dispatchVector+1
|
|
|
|
jmp ($0010)
|
|
|
|
;==============================================================================
|
|
; $CAD7-$CAE6: Game Mode State Dispatch Table
|
|
;
|
|
; Local:
|
|
; Eight 16-bit handler addresses selected by GameModeEntry using $3F as a
|
|
; direct byte offset.
|
|
;
|
|
; Global:
|
|
; Defines the next major foreground state machine entered through GameModeEntry.
|
|
;
|
|
; Notes:
|
|
; Since $3F indexes raw bytes rather than words, expected state offsets are:
|
|
;
|
|
; $00,$02,$04,$06,$08,$0A,$0C,$0E
|
|
;
|
|
; Handler names remain unresolved until each target is decoded.
|
|
;==============================================================================
|
|
|
|
GameModeStateTable:
|
|
.word GameModeState00 ; $3F = $00
|
|
.word GameModeState02 ; $3F = $02
|
|
.word GameModeState04 ; $3F = $04
|
|
.word GameModeState06 ; $3F = $06
|
|
.word GameModeState08 ; $3F = $08
|
|
.word GameModeState0A ; $3F = $0A
|
|
.word GameModeState0C ; $3F = $0C
|
|
.word InitializeGameplayTransitionState
|
|
; $3F = $0E
|
|
|
|
;==============================================================================
|
|
; $CAE7-$CAE8: Game-Mode Auxiliary Pointer
|
|
;
|
|
; Local:
|
|
; Two-byte little-endian ROM value containing $E7BF.
|
|
;
|
|
; Global:
|
|
; Sits immediately between GameModeStateTable and the $3F=$04 handler.
|
|
; Its consumer has not yet been established during this pass.
|
|
;
|
|
; Notes:
|
|
; Keep this as data rather than attempting to decode it as 6502 code.
|
|
;==============================================================================
|
|
|
|
GameModeAuxPointer:
|
|
.word $E7BF
|
|
|
|
;==============================================================================
|
|
; $CAE9-$CB5A: Game-Mode State $04 / Pause and Per-Frame Processing
|
|
;
|
|
; Local:
|
|
; First checks $060F. If nonzero, immediately returns to the common
|
|
; NMI/frame synchronization point at $CAA7.
|
|
;
|
|
; Otherwise performs edge detection on controller bit $08 using $49 as
|
|
; the stored previous state.
|
|
;
|
|
; On a new active $08 input:
|
|
; - increments $4A,
|
|
; - installs a short update command at $024B onward,
|
|
; - selects between two command variants according to $47 & $46,
|
|
; - uses bit 0 of $4A to alternate the displayed data,
|
|
; - optionally clears $060F.
|
|
;
|
|
; When no new pause/input edge is being handled, and bit 0 of $4A is clear,
|
|
; calls a sequence of gameplay/update helpers before returning to the common
|
|
; frame synchronization point.
|
|
;
|
|
; Global:
|
|
; Handler selected when GameModeStateTable offset $3F = $04.
|
|
;
|
|
; The adjacent data beginning at $CB5B contains the tile values for the word
|
|
; "PAUSE", strongly indicating that this handler manages pause-state input
|
|
; and display updates while also running the normal per-frame gameplay
|
|
; helper chain when not paused.
|
|
;
|
|
; Notes:
|
|
; $49 stores the previous masked state of controller bit $08.
|
|
; $4A is incremented on each newly detected active edge and bit 0 is used
|
|
; here as a pause/run toggle.
|
|
;
|
|
; $060F is consulted as another gate associated with this handler.
|
|
;
|
|
; Helper routines remain address-named during this pass.
|
|
;==============================================================================
|
|
|
|
GameModeState04:
|
|
lda $060F
|
|
beq @CheckPauseInput
|
|
|
|
jmp GameModeFrameSync
|
|
|
|
@CheckPauseInput:
|
|
lda currentInput
|
|
and #$08
|
|
cmp $49
|
|
beq @ProcessCurrentMode
|
|
|
|
sta $49
|
|
|
|
lda $49
|
|
beq @ProcessCurrentMode
|
|
|
|
inc $4A
|
|
|
|
ldx #$22
|
|
|
|
lda activePlayerFlag
|
|
and cocktailModeFlag
|
|
beq @SetCommandAddress
|
|
|
|
ldx #$2A
|
|
|
|
@SetCommandAddress:
|
|
stx $024B
|
|
|
|
lda #$37
|
|
sta $024C
|
|
|
|
ldx #$06
|
|
ldy #$00
|
|
|
|
lda $4A
|
|
and #$01
|
|
beq @CopyPauseData
|
|
|
|
ldx #$00
|
|
sta $060F
|
|
|
|
@CopyPauseData:
|
|
lda PauseDisplayData,x
|
|
sta $024D,y
|
|
|
|
inx
|
|
iny
|
|
|
|
cpy #$06
|
|
bne @CopyPauseData
|
|
|
|
jmp GameModeFrameSync
|
|
|
|
@ProcessCurrentMode:
|
|
lda $4A
|
|
and #$01
|
|
beq @RunFrameUpdates
|
|
|
|
jmp GameModeFrameSync
|
|
|
|
@RunFrameUpdates:
|
|
jsr UpdateGameplayTimers
|
|
jsr UpdateGameplayTileState
|
|
jsr UpdatePlayerMovement
|
|
jsr UpdatePlayerDirectionAnimation
|
|
jsr UpdateGameplayEntities
|
|
jsr UpdateEntitySpriteStates
|
|
jsr UpdateEntityStatusFlags
|
|
jsr UpdatePeriodicFourEntryState
|
|
jsr CheckGameplayProximity
|
|
jsr CheckEntityCollisions
|
|
|
|
jmp GameModeFrameSync
|
|
|
|
;==============================================================================
|
|
; $CB5B-$CB66: Pause Display Data
|
|
;
|
|
; Local:
|
|
; Two six-byte display strings selected by GameModeState04.
|
|
;
|
|
; Offset $00:
|
|
; "PAUSE",$FF
|
|
;
|
|
; Offset $06:
|
|
; five $2D tiles followed by $FF, used to replace/clear the pause text.
|
|
;
|
|
; Global:
|
|
; Provides the visible pause-state update controlled by $4A bit 0.
|
|
;==============================================================================
|
|
|
|
PauseDisplayData:
|
|
.byte $50,$41,$55,$53,$45,$FF
|
|
.byte $2D,$2D,$2D,$2D,$2D,$FF
|
|
|
|
|
|
;==============================================================================
|
|
; $CB67-$CC9B: Game-Mode State $02 Handler
|
|
;
|
|
; Local:
|
|
; Implements a multi-phase initialization/progression state.
|
|
;
|
|
; When $87 is zero, constructs structured data in RAM page $07 using several
|
|
; ROM lookup tables. The construction is influenced by $48, $47, $46,
|
|
; $68 and $69.
|
|
;
|
|
; Once $87 is nonzero, it advances once per frame. At $87=$78, initializes
|
|
; a new group of RAM state and prepares display/update data in $024B-$0254.
|
|
;
|
|
; At $87=$C0, checks $0600/$0601. If both are zero, clears a large area of
|
|
; page $07 and advances the main game-mode state to $04.
|
|
;
|
|
; Global:
|
|
; Handler selected by GameModeStateTable when $3F=$02. This appears to be
|
|
; a substantial setup/transition state between game-mode phases, preparing
|
|
; object/OAM-related RAM, display command data, and other game state before
|
|
; handing control to GameModeState04.
|
|
;
|
|
; Notes:
|
|
; $87 serves as the phase timer/progression value.
|
|
;
|
|
; $00/$01 initially form a pointer to $0760 during the page-$07 build.
|
|
; The same locations are reused later as temporary display-address values.
|
|
;
|
|
; ROM tables $CC9C-$CCD8 immediately follow this routine and should be
|
|
; decoded next.
|
|
;==============================================================================
|
|
|
|
GameModeState02:
|
|
lda $87
|
|
beq @BuildInitialData
|
|
|
|
jmp @AdvancePhase
|
|
|
|
@BuildInitialData:
|
|
lda #$60
|
|
sta workPtr0
|
|
|
|
lda #$07
|
|
sta workPtr0+1
|
|
|
|
lda $48
|
|
bne @AdvancePhase
|
|
|
|
lda #$02
|
|
sta workValue0
|
|
|
|
ldy #$00
|
|
sty workValue1
|
|
sty workValue2
|
|
sty workValue3
|
|
|
|
@BuildOuterLoop:
|
|
ldx workValue2
|
|
|
|
lda State02PositionTable,x
|
|
sta workPtr1
|
|
|
|
lda State02PositionTable + 1,x
|
|
sta workPtr1+1
|
|
|
|
ldx workValue3
|
|
|
|
lda State02EntryCounts,x
|
|
sta workValue4
|
|
|
|
@BuildInnerLoop:
|
|
lda workPtr1+1
|
|
sta ($00),y
|
|
|
|
ldx workValue1
|
|
|
|
lda State02ValueTableA,x
|
|
iny
|
|
sta (workPtr0),y
|
|
|
|
lda State02ValueTableB,x
|
|
iny
|
|
sta (workPtr0),y
|
|
|
|
lda workPtr1
|
|
iny
|
|
sta ($00),y
|
|
|
|
lda workPtr1
|
|
clc
|
|
adc #$08
|
|
sta workPtr1
|
|
|
|
iny
|
|
inc workValue1
|
|
|
|
dec workValue4
|
|
bne @BuildInnerLoop
|
|
|
|
inc workValue2
|
|
inc workValue2
|
|
inc workValue3
|
|
|
|
lda $69
|
|
bne @ContinueBuild
|
|
|
|
lda roundDisplayValue
|
|
bne @AdvancePhase
|
|
|
|
@ContinueBuild:
|
|
dec workValue0
|
|
beq @CheckPlayerMode
|
|
|
|
bpl @BuildOuterLoop
|
|
bmi @AdvancePhase
|
|
|
|
@CheckPlayerMode:
|
|
lda activePlayerFlag
|
|
beq @AdvancePhase
|
|
|
|
lda cocktailModeFlag
|
|
beq @BuildOuterLoop
|
|
|
|
inc workValue1
|
|
inc workValue1
|
|
inc workValue1
|
|
|
|
bne @BuildOuterLoop
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $CBE4
|
|
; Frame-based progression portion of the same state.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@AdvancePhase:
|
|
lda $87
|
|
cmp #$C0
|
|
bne @IncrementPhase
|
|
|
|
jmp $CC7C
|
|
|
|
@IncrementPhase:
|
|
inc $87
|
|
|
|
lda $87
|
|
cmp #$78
|
|
beq @InitializeMidPhase
|
|
|
|
jmp $CC99
|
|
|
|
@InitializeMidPhase:
|
|
lda #$A8
|
|
sta $1C
|
|
|
|
lda #$60
|
|
sta pacmanMotion
|
|
sta ghost1Motion
|
|
sta ghost2Motion
|
|
|
|
lda #$58
|
|
sta ghost3Motion
|
|
sta $20
|
|
|
|
lda #$68
|
|
sta ghost4Motion
|
|
|
|
lda #$70
|
|
sta $24
|
|
sta $28
|
|
sta $2C
|
|
|
|
lda #$00
|
|
tay
|
|
|
|
@ClearOamRegion:
|
|
sta $0778,y
|
|
iny
|
|
cpy #$24
|
|
bne @ClearOamRegion
|
|
|
|
lda activePlayerFlag
|
|
and cocktailModeFlag
|
|
beq @NoPlayerOffset
|
|
|
|
lda #$08
|
|
|
|
@NoPlayerOffset:
|
|
sta $00
|
|
|
|
lda $67
|
|
sec
|
|
sbc #$01
|
|
asl
|
|
tay
|
|
|
|
lda State02DisplayAddressTable,y
|
|
clc
|
|
adc workPtr0
|
|
sta workPtr0
|
|
|
|
lda State02DisplayAddressTable+1,y
|
|
sta workPtr0+1
|
|
|
|
lda workPtr0
|
|
sta $024B
|
|
|
|
lda workPtr0+1
|
|
sta $024C
|
|
|
|
lda #$2D
|
|
sta $024D
|
|
sta $024E
|
|
|
|
lda #$00
|
|
sta $024F
|
|
|
|
lda $00
|
|
sta $0250
|
|
|
|
lda $01
|
|
clc
|
|
adc #$20
|
|
sta $0251
|
|
|
|
lda #$2D
|
|
sta $0252
|
|
sta $0253
|
|
|
|
lda #$FF
|
|
sta $0254
|
|
|
|
jsr UpdatePlayerDirectionAnimation
|
|
jsr UpdateEntitySpriteStates
|
|
jsr $DA40
|
|
|
|
jmp $CC99
|
|
|
|
@CheckCompletion:
|
|
lda $0600
|
|
ora $0601
|
|
bne $CC99
|
|
|
|
lda $48
|
|
bne @AdvanceMainState
|
|
|
|
lda #$00
|
|
sta $69
|
|
tay
|
|
|
|
@ClearPage07Region:
|
|
sta $0760,y
|
|
iny
|
|
cpy #$A0
|
|
bne @ClearPage07Region
|
|
|
|
@AdvanceMainState:
|
|
lda #$04
|
|
sta $3F
|
|
|
|
@ReturnToFrameLoop:
|
|
jmp GameModeFrameSync
|
|
|
|
;==============================================================================
|
|
; $CC9C-$CCD8: Game-Mode State $02 Lookup Tables
|
|
;
|
|
; Local:
|
|
; Collection of lookup tables consumed by GameModeState02 while constructing
|
|
; page-$07 object/display data and preparing the update command at $024B.
|
|
;
|
|
; Global:
|
|
; Supplies the tile/status/position/count/address parameters used by the
|
|
; state-$02 setup sequence.
|
|
;
|
|
; Notes:
|
|
; The tables are separated according to the exact addresses referenced by
|
|
; GameModeState02. Names remain structural during this first pass.
|
|
;==============================================================================
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $CC9C-$CCAD: State $02 tile/value table
|
|
;
|
|
; Indexed through $05:
|
|
;
|
|
; lda State02ValueTableA,x
|
|
;
|
|
; Written as the second byte of each 4-byte structure generated at $0760+.
|
|
; Length: $12 (18) bytes.
|
|
;------------------------------------------------------------------------------
|
|
|
|
State02ValueTableA:
|
|
.byte $C6,$C3,$C1,$BA,$C7,$BB
|
|
.byte $B0,$B1,$B2,$B3,$B4,$B5
|
|
.byte $B6,$B7,$B4,$B8,$B9,$B6
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $CCAE-$CCBF: State $02 secondary value table
|
|
;
|
|
; Indexed through the same $05 value as State02ValueTableA.
|
|
;
|
|
; Written as the third byte of each generated 4-byte structure.
|
|
; Length: $12 (18) bytes.
|
|
;------------------------------------------------------------------------------
|
|
|
|
State02ValueTableB:
|
|
.byte $00,$00,$00,$00,$00,$00
|
|
.byte $02,$02,$02,$02,$02,$02
|
|
.byte $02,$02,$02,$02,$02,$02
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $CCC0-$CCC5: State $02 position/parameter pairs
|
|
;
|
|
; GameModeState02 accesses this table as overlapping little groups:
|
|
;
|
|
; lda State02PositionTable,x
|
|
; lda State02PositionTable+1,x
|
|
;
|
|
; $06 advances by 2 each outer pass.
|
|
;
|
|
; Therefore the natural structure is three 2-byte pairs.
|
|
;------------------------------------------------------------------------------
|
|
|
|
State02PositionTable:
|
|
.byte $44,$88
|
|
.byte $44,$60
|
|
.byte $50,$70
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $CCC6-$CCC8: State $02 entry-count table
|
|
;
|
|
; Indexed by $07. Determines how many four-byte structures are emitted by
|
|
; each inner construction loop.
|
|
;------------------------------------------------------------------------------
|
|
|
|
State02EntryCounts:
|
|
.byte $06,$06,$03
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $CCC9-$CCD0: Additional state-$02 values
|
|
;
|
|
; No direct reference has yet been established in the portion decoded so far.
|
|
; Keep this data structurally separated until its consumer is found.
|
|
;------------------------------------------------------------------------------
|
|
|
|
State02UnknownData:
|
|
.byte $C0,$C1,$C2,$C3,$C4,$C5,$C3,$C6
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $CCD1-$CCD8: Display-address table
|
|
;
|
|
; Indexed by:
|
|
;
|
|
; ($67 - 1) * 2
|
|
;
|
|
; and read as two-byte values:
|
|
;
|
|
; lda State02DisplayAddressTable,y
|
|
; lda State02DisplayAddressTable+1,y
|
|
;
|
|
; The bytes form four PPU-style address pairs:
|
|
;
|
|
; $2317
|
|
; $2319
|
|
; $231B
|
|
; $2357
|
|
;
|
|
; When $47 & $46 is nonzero, $08 is added to the low byte before the command
|
|
; is placed into $024B/$024C.
|
|
;------------------------------------------------------------------------------
|
|
|
|
State02DisplayAddressTable:
|
|
.byte $23,$17
|
|
.byte $23,$19
|
|
.byte $23,$1B
|
|
.byte $23,$57
|
|
|
|
;==============================================================================
|
|
; $CCD9-$CD05: Game-Mode State $06 Handler
|
|
;
|
|
; Local:
|
|
; Increments $DA each frame. Normally falls through to a group of four
|
|
; per-frame update routines.
|
|
;
|
|
; When $DA reaches $28, resets $DA to $02, changes the main game-mode state
|
|
; to $04, finds an even-indexed entry in $B8+X containing $08, and changes
|
|
; that entry to $06 before continuing through the same update routines.
|
|
;
|
|
; Global:
|
|
; Handler selected by GameModeStateTable when $3F = $06. Implements a timed
|
|
; transition back to game-mode state $04 while continuing normal frame
|
|
; processing throughout the delay.
|
|
;
|
|
; Notes:
|
|
; $DA is used as a frame/progression counter.
|
|
; The $B8 array is searched only at even offsets.
|
|
;==============================================================================
|
|
|
|
GameModeState06:
|
|
inc $DA
|
|
|
|
lda #$28
|
|
cmp $DA
|
|
bne @RunFrameUpdates
|
|
|
|
lda #$02
|
|
sta $DA
|
|
|
|
lda #$04
|
|
sta $3F
|
|
|
|
lda #$08
|
|
|
|
ldx #$FE
|
|
|
|
@FindStateEntry:
|
|
inx
|
|
inx
|
|
cmp $B8,x
|
|
bne @FindStateEntry
|
|
|
|
lda #$06
|
|
sta $B8,x
|
|
|
|
@RunFrameUpdates:
|
|
jsr UpdatePeriodicFourEntryState
|
|
jsr UpdateEntityMovementStates
|
|
jsr UpdateEntitySpriteStates
|
|
jsr $DA40
|
|
|
|
jmp GameModeFrameSync
|
|
|
|
|
|
;==============================================================================
|
|
; $CD06-$CDAF: Game-Mode State $08 Handler
|
|
;
|
|
; Local:
|
|
; Multi-phase timed state using $87, $DB, and $32.
|
|
;
|
|
; During the initial phase, $DB counts down. When it expires, $87 advances,
|
|
; $DB and $0603 are initialized to $0A, and $001E-$0031 are cleared.
|
|
;
|
|
; During the active phase, $DB periodically advances $32 until $32 reaches
|
|
; $1E. The completion logic then updates the two parallel 16-byte state
|
|
; blocks at $67-$76 and $77-$86 and selects the next game-mode state.
|
|
;
|
|
; Global:
|
|
; Handler selected by GameModeStateTable when $3F = $08.
|
|
;
|
|
; Notes:
|
|
; $DB acts as a short-period timer.
|
|
; $87 distinguishes the initial and active phases.
|
|
; $67-$76 and $77-$86 are interchangeable 16-byte state structures.
|
|
;
|
|
; A few cross-flow destinations are kept as raw addresses during this pass
|
|
; to preserve the original control flow exactly.
|
|
;==============================================================================
|
|
|
|
GameModeState08:
|
|
lda $87
|
|
bne @ActivePhase
|
|
|
|
dec $DB
|
|
bne @InitialFrameUpdates
|
|
|
|
inc $87
|
|
|
|
lda #$0A
|
|
sta $DB
|
|
sta $0603
|
|
|
|
lda #$00
|
|
tax
|
|
|
|
@ClearLowRamState:
|
|
sta $1E,x
|
|
inx
|
|
cpx #$14
|
|
bne @ClearLowRamState
|
|
|
|
@InitialFrameUpdates:
|
|
jsr UpdatePeriodicFourEntryState
|
|
jsr UpdateEntitySpriteStates
|
|
jsr $DA40
|
|
|
|
jmp GameModeFrameSync
|
|
|
|
@ActivePhase:
|
|
dec $DB
|
|
bpl @ActiveFrameUpdates
|
|
|
|
lda #$0A
|
|
sta $DB
|
|
|
|
lda $32
|
|
clc
|
|
adc #$01
|
|
sta $32
|
|
|
|
cmp #$1E
|
|
beq @PhaseComplete
|
|
|
|
@ActiveFrameUpdates:
|
|
jsr UpdatePeriodicFourEntryState
|
|
jsr $DA40
|
|
|
|
jmp GameModeFrameSync
|
|
|
|
@PhaseComplete:
|
|
lda $48
|
|
bne @SinglePlayerRestart
|
|
|
|
dec $67
|
|
bne @ContinuePlayerHandling
|
|
|
|
lda #$00
|
|
sta $87
|
|
sta $69
|
|
|
|
lda #$0A
|
|
sta $3F
|
|
|
|
jmp GameModeFrameSync
|
|
|
|
@ContinuePlayerHandling:
|
|
lda #$00
|
|
sta $3F
|
|
|
|
lda #$01
|
|
sta $69
|
|
|
|
lda $47
|
|
beq @CheckPrimaryBlock
|
|
|
|
lda $77
|
|
bne @SwapBlocksAndToggle
|
|
|
|
@CheckPrimaryBlock:
|
|
lda $67
|
|
bne $CDAD
|
|
|
|
sta $69
|
|
|
|
lda $46
|
|
beq @SinglePlayerRestart
|
|
|
|
ldx #$0F
|
|
|
|
@SwapBlocksForMainEntry:
|
|
lda $67,x
|
|
sta $00
|
|
|
|
lda $77,x
|
|
sta $67,x
|
|
|
|
lda $00
|
|
sta $77,x
|
|
|
|
dex
|
|
bpl @SwapBlocksForMainEntry
|
|
|
|
@SinglePlayerRestart:
|
|
lda #$00
|
|
sta $46
|
|
|
|
lda #$00
|
|
sta $3F
|
|
|
|
jmp MainEntry
|
|
|
|
|
|
@SwapBlocksAndToggle:
|
|
ldx #$0F
|
|
|
|
@SwapBlocks:
|
|
lda $67,x
|
|
sta $00
|
|
|
|
lda $77,x
|
|
sta $67,x
|
|
|
|
lda $00
|
|
sta $77,x
|
|
|
|
dex
|
|
bpl @SwapBlocks
|
|
|
|
inc $46
|
|
|
|
lda $46
|
|
and #$01
|
|
sta $46
|
|
|
|
jmp GameModeFrameSync
|
|
|
|
|
|
;==============================================================================
|
|
; $CDB0-$CE1E: Game-Mode State $0C Handler
|
|
;
|
|
; Local:
|
|
; Uses $87 as a frame/progression counter.
|
|
;
|
|
; On first entry ($87 == 0):
|
|
; - Clears $001E-$0031.
|
|
; - Increments $87.
|
|
; - Initializes $32 to $01.
|
|
;
|
|
; On subsequent frames, processing is throttled by the low three bits of
|
|
; the NMI-driven frame counter $4B. Only once every eight frames does the
|
|
; handler:
|
|
;
|
|
; - Alternate a value written to $029E according to bit 0 of $87.
|
|
; - Set $0299 to $0F.
|
|
; - Increment $87.
|
|
;
|
|
; When $87 reaches $10, the routine clears $1A/$1C/$87 and selects a new
|
|
; main game-mode state according to the value at $68.
|
|
;
|
|
; Global:
|
|
; Handler selected by GameModeStateTable when $3F = $0C.
|
|
;
|
|
; This appears to implement a short visual/timed transition. The write of
|
|
; $0F to $0299 interacts directly with the palette-update mechanism decoded
|
|
; earlier, while $029E lies inside that first 16-byte palette/update buffer.
|
|
;
|
|
; Notes:
|
|
; $4B is the NMI-driven frame counter.
|
|
;
|
|
; $87 advances only once every eight frames after initialization.
|
|
;
|
|
; $68 controls which state is selected when the sequence completes.
|
|
;==============================================================================
|
|
|
|
GameModeState0C:
|
|
lda $87
|
|
bne @TimedPhase
|
|
|
|
ldx #$00
|
|
|
|
@ClearLowRam:
|
|
sta $1E,x
|
|
inx
|
|
cpx #$14
|
|
bne @ClearLowRam
|
|
|
|
inc $87
|
|
|
|
lda #$01
|
|
sta $32
|
|
|
|
bne @RunFrameUpdates
|
|
|
|
|
|
@TimedPhase:
|
|
lda $4B
|
|
and #$07
|
|
bne @RunFrameUpdates
|
|
|
|
ldx #$11
|
|
|
|
lda $87
|
|
and #$01
|
|
bne @SetPaletteValue
|
|
|
|
ldx #$20
|
|
|
|
@SetPaletteValue:
|
|
stx $029E
|
|
|
|
lda #$0F
|
|
sta $0299
|
|
|
|
inc $87
|
|
|
|
lda #$10
|
|
cmp $87
|
|
bne @RunFrameUpdates
|
|
|
|
lda #$00
|
|
sta $1A
|
|
sta $1C
|
|
sta $87
|
|
|
|
lda $68
|
|
cmp #$01
|
|
beq @SelectState0E
|
|
|
|
inc $87
|
|
inc $87
|
|
|
|
cmp #$04
|
|
beq @SelectState0E
|
|
|
|
inc $87
|
|
inc $87
|
|
|
|
cmp #$08
|
|
beq @SelectState0E
|
|
|
|
cmp #$0C
|
|
beq @SelectState0E
|
|
|
|
cmp #$10
|
|
bne @SelectState00
|
|
|
|
|
|
@SelectState0E:
|
|
lda #$0E
|
|
sta $3F
|
|
|
|
jmp @RunFrameUpdates
|
|
|
|
|
|
@SelectState00:
|
|
lda #$00
|
|
sta $3F
|
|
|
|
|
|
@RunFrameUpdates:
|
|
jsr UpdatePeriodicFourEntryState
|
|
jsr $DA40
|
|
|
|
jmp GameModeFrameSync
|
|
|
|
|
|
;==============================================================================
|
|
; $CE1F-$CEBE: Game-Mode State $0A Handler
|
|
;
|
|
; Local:
|
|
; Uses $87 to distinguish between initialization and subsequent processing.
|
|
;
|
|
; On initial entry:
|
|
; - Fills $0700-$075F with $FF.
|
|
; - Initializes $00/$01 as a pointer to $0760.
|
|
; - Builds structured four-byte records in page $07 from several ROM
|
|
; lookup tables beginning at $CEBF.
|
|
;
|
|
; The builder uses:
|
|
;
|
|
; $00/$01 destination pointer ($0760)
|
|
; $02/$03 per-group values
|
|
; $04 outer pass counter, initially $03
|
|
; $05 shared table index
|
|
; $06 index into the value-pair table
|
|
; $07 index into the entry-count table
|
|
; $08 inner record counter
|
|
;
|
|
; Player/mode variables $47, $77, and $46 influence whether passes repeat
|
|
; and whether the lookup index is advanced.
|
|
;
|
|
; After the construction phase, $87 is incremented. A later entry either
|
|
; clears $0760-$07FF and transitions to the code at $CD5E, or simply
|
|
; returns to the common frame loop.
|
|
;
|
|
; Global:
|
|
; Handler selected by GameModeStateTable when $3F = $0A.
|
|
;
|
|
; Structurally this is closely related to GameModeState02, but uses a
|
|
; different set of ROM tables and first clears $0700-$075F to $FF. Both
|
|
; handlers construct arrays of four-byte records in page $07.
|
|
;
|
|
; Notes:
|
|
; The tables at $CEBF-$CEF2 are decoded immediately after this routine.
|
|
; Semantic object names are deferred until the page-$07 consumers are
|
|
; understood more completely.
|
|
;==============================================================================
|
|
|
|
GameModeState0A:
|
|
lda $87
|
|
beq @Initialize
|
|
|
|
jmp $CEAA
|
|
|
|
@Initialize:
|
|
ldy #$00
|
|
|
|
lda #$FF
|
|
|
|
@FillPage07Prefix:
|
|
sta $0700,y
|
|
iny
|
|
cpy #$60
|
|
bne @FillPage07Prefix
|
|
|
|
lda #$60
|
|
sta $00
|
|
|
|
lda #$07
|
|
sta $01
|
|
|
|
lda #$03
|
|
sta $04
|
|
|
|
ldy #$00
|
|
sty $05
|
|
sty $06
|
|
sty $07
|
|
|
|
@BuildOuterLoop:
|
|
ldx $06
|
|
|
|
lda State0AParameterPairs,x
|
|
sta $02
|
|
|
|
lda State0AParameterPairs+1,x
|
|
sta $03
|
|
|
|
ldx $07
|
|
|
|
lda State0AEntryCounts,x
|
|
sta $08
|
|
|
|
|
|
@BuildInnerLoop:
|
|
lda $03
|
|
sta ($00),y
|
|
|
|
ldx $05
|
|
|
|
lda State0AValueTableA,x
|
|
iny
|
|
sta ($00),y
|
|
|
|
lda State0AValueTableB,x
|
|
iny
|
|
sta ($00),y
|
|
|
|
lda $02
|
|
iny
|
|
sta ($00),y
|
|
|
|
lda $02
|
|
clc
|
|
adc #$08
|
|
sta $02
|
|
|
|
iny
|
|
inc $05
|
|
|
|
dec $08
|
|
bne @BuildInnerLoop
|
|
|
|
inc $06
|
|
inc $06
|
|
|
|
inc $07
|
|
|
|
lda $47
|
|
beq @ContinueOuterPass
|
|
|
|
lda $77
|
|
bne @ContinueOuterPass
|
|
|
|
lda $04
|
|
cmp #$02
|
|
beq $CEAA
|
|
|
|
|
|
@ContinueOuterPass:
|
|
dec $04
|
|
beq @CheckPlayerMode
|
|
|
|
bpl @BuildOuterLoop
|
|
bmi @FinishInitialization
|
|
|
|
|
|
@CheckPlayerMode:
|
|
lda $47
|
|
beq @FinishInitialization
|
|
|
|
lda $46
|
|
beq @BuildOuterLoop
|
|
|
|
|
|
@AdjustTableIndex:
|
|
inc $05
|
|
inc $05
|
|
inc $05
|
|
|
|
bne @BuildOuterLoop
|
|
|
|
|
|
@FinishInitialization:
|
|
inc $87
|
|
bne @ReturnToFrameLoop
|
|
|
|
|
|
@PostInitialization:
|
|
lda #$00
|
|
tay
|
|
|
|
@ClearPage07Region:
|
|
sta $0760,y
|
|
iny
|
|
cpy #$A0
|
|
bne @ClearPage07Region
|
|
|
|
jmp $CD5E
|
|
|
|
|
|
@ReturnToFrameLoop:
|
|
jmp GameModeFrameSync
|
|
|
|
|
|
;==============================================================================
|
|
; $CEBF-$CEF2: Game-Mode State $0A Lookup Tables
|
|
;
|
|
; Local:
|
|
; Lookup data used by GameModeState0A to construct four-byte records in
|
|
; page $07.
|
|
;
|
|
; Global:
|
|
; Provides the object/tile/value and layout parameters for state $0A.
|
|
;==============================================================================
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $CEBF-$CED2: Primary value table
|
|
; Length: $14 (20) bytes
|
|
;------------------------------------------------------------------------------
|
|
|
|
State0AValueTableA:
|
|
.byte $BC,$B2,$BD,$B4,$B6,$BE,$B4,$B5
|
|
.byte $B0,$B1,$B2,$B3,$B4,$B5,$B6,$B7
|
|
.byte $B4,$B8,$B9,$B6
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $CED3-$CEE6: Secondary value table
|
|
; Length: $14 (20) bytes
|
|
;------------------------------------------------------------------------------
|
|
|
|
State0AValueTableB:
|
|
.byte $00,$00,$00,$00,$00,$00,$00,$00
|
|
.byte $02,$02,$02,$02,$02,$02,$02,$02
|
|
.byte $02,$02,$02,$02
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $CEE7-$CEEE: Parameter-pair table
|
|
;
|
|
; $06 advances by two, so represent this as four 2-byte pairs.
|
|
;------------------------------------------------------------------------------
|
|
|
|
State0AParameterPairs:
|
|
.byte $38,$88
|
|
.byte $60,$88
|
|
.byte $44,$60
|
|
.byte $50,$70
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $CEEF-$CEF2: Inner-loop entry counts
|
|
;------------------------------------------------------------------------------
|
|
|
|
State0AEntryCounts:
|
|
.byte $04,$04,$06,$03
|
|
|
|
;==============================================================================
|
|
; $CEF3-$D0AA: Game-Mode State $00 Initialization
|
|
;
|
|
; Local:
|
|
; Performs the main initialization for the game-mode state machine:
|
|
;
|
|
; - Synchronizes with NMI and disables rendering.
|
|
; - Clears working RAM $87-$EF.
|
|
; - Clears page $0700-$07FF.
|
|
; - Copies a 32-byte palette table from GameplayPaletteData to $0299-$02B8.
|
|
; - Selects game-mode state $02.
|
|
; - Initializes gameplay/state variables and invokes several setup helpers.
|
|
; - Loads numerous parameters from ROM lookup tables.
|
|
; - Initializes arrays and display/update data.
|
|
; - Re-enables NMI with PPUCTRL=$88.
|
|
; - Returns to GameModeFrameSync.
|
|
;
|
|
; Global:
|
|
; Primary initialization handler for GameModeStateTable offset $00.
|
|
; Establishes the working state used by the later $02/$04/etc. handlers.
|
|
;
|
|
; Notes:
|
|
; Many ROM tables referenced from $EBxx/$ECxx are intentionally left raw
|
|
; during this pass and will be named when those regions are reached.
|
|
;==============================================================================
|
|
|
|
GameModeState00:
|
|
lda #$01
|
|
sta $40
|
|
|
|
@WaitForNmi:
|
|
lda $40
|
|
bne @WaitForNmi
|
|
|
|
lda #$08
|
|
sta PPUCTRL
|
|
sta $43
|
|
|
|
lda #$00
|
|
sta PPUMASK
|
|
|
|
ldx #$00
|
|
|
|
@ClearWorkingRam:
|
|
sta $87,x
|
|
inx
|
|
cpx #$69
|
|
bne @ClearWorkingRam
|
|
|
|
tax
|
|
|
|
@ClearPage07:
|
|
sta $0700,x
|
|
inx
|
|
bne @ClearPage07
|
|
|
|
ldy #$00
|
|
|
|
@LoadPalette:
|
|
lda GameplayPaletteData,y
|
|
sta $0299,y
|
|
iny
|
|
cpy #$20
|
|
bne @LoadPalette
|
|
|
|
lda #$02
|
|
sta $3F
|
|
|
|
lda $69
|
|
bne $CF4A
|
|
|
|
sta $8B
|
|
|
|
lda #$01
|
|
sta $6C
|
|
sta $6D
|
|
sta $6E
|
|
sta $6F
|
|
|
|
lda #$C0
|
|
sta $6A
|
|
|
|
lda $68
|
|
cmp #$16
|
|
beq @SkipIncrement68
|
|
|
|
inc $68
|
|
|
|
@SkipIncrement68:
|
|
jsr InitializeGameplayAttributes
|
|
jsr DrawMazeNametable
|
|
jsr DrawGameplayScoreFields
|
|
jsr InitializeGameNametableRegion
|
|
jsr DrawLevelProgressMarkers
|
|
jsr $E5C1
|
|
jsr DrawGameplayHudLabels
|
|
|
|
@ContinueSetup:
|
|
ldx $68
|
|
|
|
lda #$00
|
|
clc
|
|
|
|
@MultiplyBy6:
|
|
dex
|
|
bmi @MultiplyBy6Done
|
|
|
|
adc #$06
|
|
bne @MultiplyBy6
|
|
|
|
@MultiplyBy6Done:
|
|
sta $00
|
|
tax
|
|
|
|
lda $EBB6,x
|
|
tax
|
|
|
|
lda #$00
|
|
clc
|
|
|
|
@MultiplyBy22:
|
|
dex
|
|
bmi @MultiplyBy22Done
|
|
|
|
adc #$16
|
|
bne @MultiplyBy22
|
|
|
|
@MultiplyBy22Done:
|
|
tay
|
|
|
|
ldx #$00
|
|
|
|
@CopyGameParameters:
|
|
lda $EC40,y
|
|
sta $9F,x
|
|
inx
|
|
iny
|
|
cpx #$16
|
|
bne @CopyGameParameters
|
|
|
|
ldx $00
|
|
|
|
lda $EBB6,x
|
|
asl
|
|
asl
|
|
asl
|
|
tax
|
|
|
|
ldy #$00
|
|
sty $D0
|
|
|
|
; Save the first selected table value separately.
|
|
lda $ECAE,x
|
|
sta $CF
|
|
|
|
@CopyTableECae:
|
|
lda $ECAE,x
|
|
sta $0097,y
|
|
|
|
inx
|
|
iny
|
|
cpy #$08
|
|
bne @CopyTableECae
|
|
|
|
inc $00
|
|
|
|
ldx $00
|
|
lda $EBB6,x
|
|
sta $8C
|
|
|
|
inc $00
|
|
|
|
ldx $00
|
|
lda $EBB6,x
|
|
asl
|
|
tax
|
|
|
|
lda $ECCE,x
|
|
sta $8D
|
|
inx
|
|
lda $ECCE,x
|
|
sta $8E
|
|
|
|
inc $00
|
|
|
|
lda $69
|
|
beq @UseAlternateData
|
|
|
|
ldx #$0C
|
|
ldy #$00
|
|
|
|
lda $ECDC,x
|
|
sta $008F,y
|
|
|
|
iny
|
|
inx
|
|
|
|
lda #$C0
|
|
sec
|
|
sbc $6A
|
|
sta $01
|
|
|
|
@CopyOffsetData:
|
|
lda $01
|
|
clc
|
|
adc $ECDC,x
|
|
sta $008F,y
|
|
|
|
iny
|
|
inx
|
|
|
|
cpy #$04
|
|
bne @CopyOffsetData
|
|
|
|
beq @InitializeArray
|
|
|
|
@UseAlternateData:
|
|
ldx $00
|
|
|
|
lda $EBB6,x
|
|
asl
|
|
asl
|
|
tax
|
|
|
|
ldy #$00
|
|
|
|
@CopyAlternateData:
|
|
lda $ECDC,x
|
|
sta $008F,y
|
|
|
|
inx
|
|
iny
|
|
cpy #$04
|
|
bne @CopyAlternateData
|
|
|
|
|
|
@InitializeArray:
|
|
lda #$04
|
|
sta $B8
|
|
|
|
lda #$01
|
|
sta $B9
|
|
|
|
lda $8F
|
|
sta $01
|
|
|
|
ldx #$00
|
|
|
|
@InitializeArrayLoop:
|
|
dec $01
|
|
beq @InitializeArrayTail
|
|
|
|
lda #$02
|
|
sta $BA,x
|
|
|
|
lda #$00
|
|
sta $BB,x
|
|
|
|
inx
|
|
inx
|
|
bne @InitializeArrayLoop
|
|
|
|
|
|
@InitializeArrayTail:
|
|
lda #$00
|
|
|
|
@ClearRemainingArray:
|
|
cpx #$06
|
|
beq @ContinueFinalSetup
|
|
|
|
sta $BA,x
|
|
sta $BB,x
|
|
|
|
inx
|
|
inx
|
|
bne @ClearRemainingArray
|
|
|
|
|
|
@ContinueFinalSetup:
|
|
lda $90
|
|
sta $D3
|
|
|
|
inc $00
|
|
|
|
ldx $00
|
|
lda $EBB6,x
|
|
sta $93
|
|
|
|
inc $00
|
|
|
|
ldx $00
|
|
lda $EBB6,x
|
|
sta $96
|
|
|
|
lda $A5
|
|
sta $B5
|
|
|
|
lda $A6
|
|
sta $B6
|
|
|
|
lda $AF
|
|
sta $C4
|
|
sta $C6
|
|
sta $C8
|
|
sta $CA
|
|
|
|
lda $B0
|
|
sta $C5
|
|
sta $C7
|
|
sta $C9
|
|
sta $CB
|
|
|
|
lda #$01
|
|
sta $50
|
|
sta $51
|
|
|
|
ldy #$00
|
|
ldx #$00
|
|
|
|
lda $46
|
|
and $47
|
|
beq @CopyDisplayInit
|
|
|
|
ldy #$09
|
|
|
|
@CopyDisplayInit:
|
|
lda GameDisplayInitialData,y
|
|
sta $026B,x
|
|
|
|
iny
|
|
inx
|
|
cpx #$09
|
|
bne @CopyDisplayInit
|
|
|
|
ldy #$00
|
|
|
|
@CopyStateData:
|
|
lda GameStateInitialValues,y
|
|
sta $0032,y
|
|
iny
|
|
cpy #$0C
|
|
bne @CopyStateData
|
|
|
|
ldy #$00
|
|
|
|
@NormalizeValues:
|
|
lda $006C,y
|
|
cmp #$02
|
|
bne @NextNormalizeValue
|
|
|
|
lda #$01
|
|
sta $006C,y
|
|
|
|
@NextNormalizeValue:
|
|
iny
|
|
cpy #$04
|
|
bne @NormalizeValues
|
|
|
|
sty $C0
|
|
|
|
lda #$FF
|
|
sta $89
|
|
|
|
lda #$88
|
|
sta PPUCTRL
|
|
sta $43
|
|
|
|
jmp GameModeFrameSync
|
|
|
|
;==============================================================================
|
|
; $D0AB-$D0F2: Initialize/Clear Repeated Nametable Region
|
|
;
|
|
; Local:
|
|
; Selects an initial PPU destination based on ($46 & $47):
|
|
;
|
|
; zero -> $2256
|
|
; nonzero -> $2A56
|
|
;
|
|
; It then performs 10 iterations. For each iteration:
|
|
;
|
|
; - Sets PPUADDR to the current destination.
|
|
; - Writes six $20 tiles.
|
|
; - Writes two $2D tiles.
|
|
; - Advances the destination address by $20.
|
|
;
|
|
; Global:
|
|
; Called from GameModeState00 during game/round initialization while
|
|
; rendering is disabled. This prepares the same rectangular display region
|
|
; in one of two nametable locations depending on the current player/mode
|
|
; state represented by $46/$47.
|
|
;
|
|
; Notes:
|
|
; $00/$01 form the current 16-bit PPU destination address.
|
|
; $02 counts 10 rows.
|
|
; $03 counts the six $20 tile writes in each row.
|
|
;
|
|
; $20 and $2D are retained as raw tile IDs during this pass.
|
|
;==============================================================================
|
|
|
|
InitializeGameNametableRegion:
|
|
ldy #$22
|
|
|
|
lda $46
|
|
and $47
|
|
beq @SetDestination
|
|
|
|
ldy #$2A
|
|
|
|
@SetDestination:
|
|
sty $00
|
|
|
|
lda #$56
|
|
sta $01
|
|
|
|
lda #$0A
|
|
sta $02
|
|
|
|
@NextRow:
|
|
lda PPUSTATUS
|
|
|
|
lda $00
|
|
sta PPUADDR
|
|
|
|
lda $01
|
|
sta PPUADDR
|
|
|
|
lda #$06
|
|
sta $03
|
|
|
|
lda #$20
|
|
|
|
@WriteInterior:
|
|
sta PPUDATA
|
|
|
|
dec $03
|
|
bne @WriteInterior
|
|
|
|
lda #$2D
|
|
sta PPUDATA
|
|
sta PPUDATA
|
|
|
|
; Advance the destination by one full nametable row ($20 bytes).
|
|
lda $01
|
|
clc
|
|
adc #$20
|
|
sta $01
|
|
|
|
lda $00
|
|
adc #$00
|
|
sta $00
|
|
|
|
dec $02
|
|
bne @NextRow
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $D0F3-$D130: Game-Mode State $00 Initialization Data
|
|
;
|
|
; Local:
|
|
; Contains three adjacent data blocks consumed during GameModeState00:
|
|
;
|
|
; $D0F3-$D0FE 12-byte state initialization table
|
|
; $D0FF-$D110 18-byte display/update table
|
|
; $D111-$D130 32-byte palette table
|
|
;
|
|
; Global:
|
|
; Supplies initial state, display-command, and palette data used when
|
|
; GameModeState00 prepares a new game/round state.
|
|
;
|
|
; Notes:
|
|
; The display table is intentionally kept as raw tile/command bytes during
|
|
; this pass. GameModeState00 selects either offset $00 or $09 from this
|
|
; table and copies nine bytes to $026B-$0273.
|
|
;
|
|
; The palette table is copied in full to $0299-$02B8.
|
|
;==============================================================================
|
|
|
|
|
|
;==============================================================================
|
|
; $D0F3-$D0FE: Game State Initialization Values
|
|
;
|
|
; Local:
|
|
; 12 bytes copied directly to zero-page RAM $32-$3D:
|
|
;
|
|
; ROM $D0F3-$D0FE -> RAM $0032-$003D
|
|
;
|
|
; Global:
|
|
; Establishes a compact block of initial game-state values during
|
|
; GameModeState00.
|
|
;
|
|
; Notes:
|
|
; Individual fields remain unnamed until their consumers are traced.
|
|
;==============================================================================
|
|
|
|
GameStateInitialValues:
|
|
.byte $04,$0C,$0A,$0A
|
|
.byte $0A,$00,$00,$00
|
|
.byte $01,$02,$03,$00
|
|
|
|
|
|
;==============================================================================
|
|
; $D0FF-$D110: Game Display Initialization Data
|
|
;
|
|
; Local:
|
|
; Contains two 9-byte records. GameModeState00 selects the first record when
|
|
; ($46 & $47) is zero and the second record when it is nonzero.
|
|
;
|
|
; The selected nine bytes are copied to RAM $026B-$0273.
|
|
;
|
|
; Global:
|
|
; Provides alternate display/update initialization according to the active
|
|
; player/mode state.
|
|
;
|
|
; Notes:
|
|
; These bytes appear to mix PPU/update-command values and tile IDs.
|
|
; Preserve them numerically until the consumer of $026B is decoded.
|
|
;==============================================================================
|
|
GameDisplayInitialData:
|
|
|
|
; Record 0, selected when ($46 & $47) == 0.
|
|
; $D0FF-$D107
|
|
.byte $21,$36,$20,$F7,$B0,$B3,$B2,$20,$B6
|
|
|
|
; Record 1, selected when ($46 & $47) != 0.
|
|
; $D108-$D110
|
|
.byte $29,$B6,$29,$77,$B1,$B3,$B2,$28,$B6
|
|
|
|
|
|
;==============================================================================
|
|
; $D111-$D130: Initial Gameplay Palette
|
|
;
|
|
; Local:
|
|
; Complete 32-byte palette copied to RAM $0299-$02B8 by GameModeState00.
|
|
; The NMI palette-update mechanism later transfers these buffers into PPU
|
|
; palette RAM.
|
|
;
|
|
; Global:
|
|
; Defines the initial background and sprite color palettes used for normal
|
|
; gameplay/game-mode initialization.
|
|
;
|
|
; Notes:
|
|
; $D111-$D120 contains four background palettes.
|
|
; $D121-$D130 contains four sprite palettes.
|
|
;
|
|
; Palette values are retained as NES color indices.
|
|
;==============================================================================
|
|
GameplayPaletteData:
|
|
; Background palette 0
|
|
.byte $0F,$20,$0F,$06
|
|
|
|
; Background palette 1
|
|
.byte $0F,$11,$0F,$27
|
|
|
|
; Background palette 2
|
|
.byte $0F,$16,$26,$06
|
|
|
|
; Background palette 3
|
|
.byte $0F,$19,$17,$12
|
|
|
|
; Sprite palette 0
|
|
.byte $0F,$27,$20,$06
|
|
|
|
; Sprite palette 1
|
|
.byte $0F,$11,$20,$33
|
|
|
|
; Sprite palette 2
|
|
.byte $0F,$21,$20,$21
|
|
|
|
; Sprite palette 3
|
|
.byte $0F,$09,$20,$17
|
|
|
|
;==============================================================================
|
|
; $D131-$D15F: Initialize Gameplay Nametable Attributes
|
|
;
|
|
; Local:
|
|
; Copies the 64-byte attribute table at $D160 to two PPU destinations:
|
|
;
|
|
; pass 1 -> PPU $23C0-$23FF
|
|
; pass 2 -> PPU $2BC0-$2BFF
|
|
;
|
|
; The first pass uses X=$01. After copying all $40 bytes, X is decremented.
|
|
; Since X becomes zero, execution falls through into the setup for the
|
|
; second destination at $2BC0.
|
|
;
|
|
; After the second copy, X decrements from $00 to $FF and the routine
|
|
; returns.
|
|
;
|
|
; Global:
|
|
; Called by GameModeState00 during game/round initialization. Initializes
|
|
; complete attribute tables for two nametables using identical palette-
|
|
; selection data.
|
|
;
|
|
; Notes:
|
|
; The branch at $D15E intentionally jumps back into the shared copy loop
|
|
; after selecting PPU address $2BC0.
|
|
;
|
|
; $D160 begins the 64-byte attribute source table and is not executable.
|
|
;==============================================================================
|
|
|
|
InitializeGameplayAttributes:
|
|
lda PPUSTATUS
|
|
|
|
lda #$23
|
|
sta PPUADDR
|
|
|
|
lda #$C0
|
|
sta PPUADDR
|
|
|
|
ldx #$01
|
|
|
|
@CopyAttributeTable:
|
|
ldy #$00
|
|
|
|
@CopyAttributeBytes:
|
|
lda GameplayAttributeData,y
|
|
sta PPUDATA
|
|
|
|
iny
|
|
cpy #$40
|
|
bne @CopyAttributeBytes
|
|
|
|
dex
|
|
beq @SetupSecondNametable
|
|
|
|
rts
|
|
|
|
@SetupSecondNametable:
|
|
lda PPUSTATUS
|
|
|
|
lda #$2B
|
|
sta PPUADDR
|
|
|
|
lda #$C0
|
|
sta PPUADDR
|
|
|
|
bne @CopyAttributeTable
|
|
|
|
;==============================================================================
|
|
; $D160-$D19F: Gameplay Nametable Attribute Data
|
|
;
|
|
; Local:
|
|
; Complete 64-byte NES attribute table copied to both PPU $23C0-$23FF and
|
|
; $2BC0-$2BFF by InitializeGameplayAttributes.
|
|
;
|
|
; Global:
|
|
; Defines background-palette selections for the gameplay nametables.
|
|
;
|
|
; Notes:
|
|
; Common values:
|
|
;
|
|
; $00 -> palette 0 in all four attribute quadrants
|
|
; $55 -> palette 1 in all four quadrants
|
|
;
|
|
; Values such as $11, $51, $50 and $05 combine different palette selections
|
|
; within the four quadrants of an attribute byte.
|
|
;==============================================================================
|
|
|
|
GameplayAttributeData:
|
|
.byte $55,$55,$55,$55,$55,$11,$00,$00
|
|
.byte $55,$55,$55,$55,$55,$11,$00,$00
|
|
.byte $55,$55,$55,$55,$55,$11,$00,$00
|
|
.byte $55,$55,$55,$55,$55,$51,$50,$50
|
|
.byte $55,$55,$55,$55,$55,$11,$05,$05
|
|
.byte $55,$55,$55,$55,$55,$11,$00,$00
|
|
.byte $55,$55,$55,$55,$55,$55,$55,$55
|
|
.byte $55,$55,$55,$55,$55,$55,$55,$55
|
|
|
|
;==============================================================================
|
|
; $D1A0-$D289: Gameplay Timers and State Progression
|
|
;
|
|
; Local:
|
|
; Updates several gameplay timers, palette-animation values, progression
|
|
; counters, and state variables.
|
|
;
|
|
; Global:
|
|
; Called once per active gameplay frame from GameModeState04. Coordinates
|
|
; several independent timing and progression systems.
|
|
;
|
|
; Notes:
|
|
; Address-based local labels are used during this pass to make the original
|
|
; branch destinations explicit and simplify byte-identical verification.
|
|
;==============================================================================
|
|
|
|
UpdateGameplayTimers:
|
|
lda $89
|
|
bmi @D1E1
|
|
|
|
inc $8A
|
|
|
|
lda #$3C
|
|
cmp $8A
|
|
bne @D1C9
|
|
|
|
lda #$00
|
|
sta $8A
|
|
|
|
dec $89
|
|
bpl @D1C9
|
|
|
|
sta $88
|
|
|
|
ldx #$00
|
|
|
|
@D1B7:
|
|
lda $39,x
|
|
and #$FC
|
|
sta $00
|
|
|
|
txa
|
|
ora $00
|
|
sta $39,x
|
|
|
|
inx
|
|
cpx #$04
|
|
bne @D1B7
|
|
|
|
@D1C9:
|
|
lda $89
|
|
cmp #$02
|
|
bcs @D1E1
|
|
|
|
ldx #$11
|
|
|
|
lda $8A
|
|
and #$08
|
|
bne @D1D9
|
|
|
|
ldx #$20
|
|
|
|
@D1D9:
|
|
stx $02AE
|
|
|
|
lda #$0F
|
|
sta $02A9
|
|
|
|
|
|
@D1E1:
|
|
lda $88
|
|
bne @D213
|
|
|
|
lda $CF
|
|
cmp #$FF
|
|
beq @D213
|
|
|
|
inc $D1
|
|
|
|
lda $D1
|
|
cmp #$3C
|
|
bne @D213
|
|
|
|
lda #$00
|
|
sta $D1
|
|
|
|
dec $CF
|
|
bpl @D213
|
|
|
|
inc $D0
|
|
|
|
lda $D0
|
|
and #$01
|
|
beq @D209
|
|
|
|
jsr $E08E
|
|
|
|
lda #$0F
|
|
bne @D20B
|
|
|
|
@D209:
|
|
lda $D2
|
|
|
|
@D20B:
|
|
sta $87
|
|
|
|
ldx $D0
|
|
lda $97,x
|
|
sta $CF
|
|
|
|
|
|
@D213:
|
|
lda $D3
|
|
beq @D236
|
|
|
|
clc
|
|
adc $6A
|
|
cmp #$C0
|
|
bne @D236
|
|
|
|
jsr ActivateNextStateEntry
|
|
|
|
lda $D3
|
|
ldx #$00
|
|
|
|
@D225:
|
|
cmp $8F,x
|
|
bne @D231
|
|
|
|
inx
|
|
lda $8F,x
|
|
sta $D3
|
|
|
|
jmp @D236
|
|
|
|
@D231:
|
|
inx
|
|
cpx #$04
|
|
bne @D225
|
|
|
|
|
|
@D236:
|
|
inc $D6
|
|
|
|
lda #$60
|
|
cmp $D6
|
|
bne @D251
|
|
|
|
lda #$00
|
|
sta $D6
|
|
|
|
inc $D5
|
|
|
|
lda $D5
|
|
cmp $96
|
|
bne @D251
|
|
|
|
lda #$00
|
|
sta $D5
|
|
|
|
jsr ActivateNextStateEntry
|
|
|
|
|
|
@D251:
|
|
ldx $D4
|
|
|
|
cpx #$02
|
|
beq @D26E
|
|
|
|
lda $8D,x
|
|
cmp $6A
|
|
bne @D26E
|
|
|
|
inc $D4
|
|
|
|
lda #$01
|
|
sta $D2
|
|
|
|
txa
|
|
asl
|
|
tax
|
|
|
|
lda $AB,x
|
|
sta $CA
|
|
|
|
lda $AC,x
|
|
sta $CB
|
|
|
|
|
|
@D26E:
|
|
ora $D7
|
|
ora $D8
|
|
beq @D289
|
|
|
|
dec $D8
|
|
bne @D289
|
|
|
|
lda $D7
|
|
beq @D283
|
|
|
|
dec $D7
|
|
|
|
lda #$3C
|
|
sta $D8
|
|
|
|
rts
|
|
|
|
|
|
@D283:
|
|
sta $2E
|
|
sta $30
|
|
sta $8B
|
|
|
|
|
|
@D289:
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $D28A-$D29B: Activate First Available State Entry
|
|
;
|
|
; Local:
|
|
; Searches the even-indexed entries at $BA, $BC, and $BE for the first
|
|
; zero value.
|
|
;
|
|
; When a zero entry is found, replaces it with $02 and returns.
|
|
;
|
|
; If all three entries are already nonzero, returns without modifying them.
|
|
;
|
|
; Global:
|
|
; Called by UpdateGameplayTimers when certain progression timers expire.
|
|
; This appears to activate the next available entry in a three-element
|
|
; state array.
|
|
;
|
|
; Notes:
|
|
; Only the even addresses $BA/$BC/$BE are examined. The interleaved bytes
|
|
; $BB/$BD/$BF form a parallel field initialized elsewhere.
|
|
;
|
|
; The meaning of state value $02 will be refined when the consumers of
|
|
; $BA-$BF are decoded.
|
|
;==============================================================================
|
|
ActivateNextStateEntry:
|
|
ldx #$00
|
|
|
|
@FindAvailableEntry:
|
|
lda $BA,x
|
|
bne @NextEntry
|
|
|
|
lda #$02
|
|
sta $BA,x
|
|
|
|
rts
|
|
|
|
@NextEntry:
|
|
inx
|
|
inx
|
|
|
|
cpx #$06
|
|
bne @FindAvailableEntry
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $D29C-$D2A3: Sequential Tile/Value Table
|
|
;
|
|
; Local:
|
|
; Eight sequential values from $24 through $2B.
|
|
;
|
|
; Global:
|
|
; Consumer has not yet been decoded during this pass. Given the sequential
|
|
; values and the surrounding graphics-oriented code, this may represent
|
|
; tile IDs or animation values.
|
|
;
|
|
; Notes:
|
|
; Keep the table generically named until a direct reference establishes its
|
|
; exact purpose.
|
|
;==============================================================================
|
|
|
|
SequentialValueTableD29C:
|
|
.byte $24,$25,$26,$27,$28,$29,$2A,$2B
|
|
|
|
|
|
|
|
;==============================================================================
|
|
; $D2A4-$D36B: Gameplay Proximity / State Transition Handler
|
|
;
|
|
; Local:
|
|
; Returns immediately when $6A is zero.
|
|
;
|
|
; Otherwise scans even-indexed state entries beginning at $B8. Entries whose
|
|
; state value is $04 undergo two proximity tests using the four-byte
|
|
; structures beginning at $001E.
|
|
;
|
|
; $02 is shifted once for each scanned entry and acts as a candidate bitmask.
|
|
; When a qualifying entry is found, the routine selects one of several state
|
|
; transition paths based on X and ($02 & $88).
|
|
;
|
|
; Global:
|
|
; Called during normal gameplay processing from GameModeState04. This
|
|
; routine appears to detect proximity/collision conditions and initiate
|
|
; corresponding gameplay-state transitions.
|
|
;
|
|
; Notes:
|
|
; $00/$01 form a temporary pointer, initially $001E.
|
|
; $02 is a shifting bitmask.
|
|
; $03 is temporary storage for distance/index calculations.
|
|
;
|
|
; Lookup tables begin at ProximityCandidateValues and will be decoded separately.
|
|
;==============================================================================
|
|
CheckGameplayProximity:
|
|
lda $6A
|
|
bne @Start
|
|
|
|
rts
|
|
|
|
@Start:
|
|
lda #$1E
|
|
sta $00
|
|
|
|
lda #$00
|
|
sta $01
|
|
|
|
lda #$01
|
|
sta $02
|
|
|
|
ldx #$00
|
|
|
|
@ScanEntries:
|
|
lda $B8,x
|
|
cmp #$04
|
|
bne @NextEntry
|
|
|
|
ldy #$00
|
|
|
|
lda $1A
|
|
cmp ($00),y
|
|
bcs @FirstAxisReverse
|
|
|
|
lda ($00),y
|
|
sec
|
|
sbc $1A
|
|
bcs @CheckFirstAxisDistance
|
|
|
|
@FirstAxisReverse:
|
|
sbc ($00),y
|
|
|
|
@CheckFirstAxisDistance:
|
|
cmp #$0A
|
|
bcs @NextEntry
|
|
|
|
sta $03
|
|
|
|
ldy #$02
|
|
|
|
lda $1C
|
|
cmp ($00),y
|
|
bcs @SecondAxisReverse
|
|
|
|
lda ($00),y
|
|
sec
|
|
sbc $1C
|
|
bcs @CheckSecondAxisDistance
|
|
|
|
@SecondAxisReverse:
|
|
sbc ($00),y
|
|
|
|
@CheckSecondAxisDistance:
|
|
cmp #$0A
|
|
bcs @NextEntry
|
|
|
|
adc $03
|
|
cmp #$05
|
|
bcc @CandidateFound
|
|
|
|
|
|
@NextEntry:
|
|
inx
|
|
inx
|
|
|
|
lda $00
|
|
clc
|
|
adc #$04
|
|
sta $00
|
|
|
|
asl $02
|
|
|
|
cpx #$0A
|
|
bne @ScanEntries
|
|
|
|
rts
|
|
|
|
|
|
@CandidateFound:
|
|
cpx #$08
|
|
beq @ProcessSecondaryState
|
|
|
|
lda $02
|
|
and $88
|
|
beq @SpecialCandidate
|
|
|
|
txa
|
|
lsr
|
|
sta $03
|
|
|
|
ldy $D9
|
|
|
|
lda ProximityCandidateValues,y
|
|
|
|
ldy $03
|
|
sta $0033,y
|
|
|
|
lda #$00
|
|
sta $32
|
|
|
|
ldy $D9
|
|
|
|
lda ProximityDDValues,y
|
|
sta $DD
|
|
|
|
lda ProximityDEValues,y
|
|
sta $DE
|
|
|
|
inc $D9
|
|
|
|
lda #$08
|
|
sta $B8,x
|
|
sta $0607
|
|
|
|
lda #$06
|
|
sta $3F
|
|
|
|
jmp $E0E6
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D337
|
|
; Candidate path selected when ($02 & $88) == 0.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@SpecialCandidate:
|
|
lda #$08
|
|
sta $3F
|
|
|
|
lda #$12
|
|
sta $32
|
|
|
|
lda #$80
|
|
sta $DB
|
|
|
|
lda #$00
|
|
sta $87
|
|
|
|
rts
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D348
|
|
; Special path selected when X == $08.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@ProcessSecondaryState:
|
|
lda $8B
|
|
beq @InitializeSecondaryState
|
|
|
|
rts
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D34D
|
|
; Initialize secondary state.
|
|
;------------------------------------------------------------------------------
|
|
@InitializeSecondaryState:
|
|
sta $D7
|
|
|
|
lda #$80
|
|
sta $D8
|
|
sta $8B
|
|
sta $0606
|
|
|
|
ldy $93
|
|
|
|
lda SecondaryStateDDValues,y
|
|
sta $DD
|
|
|
|
lda SecondaryStateDEValues,y
|
|
sta $DE
|
|
|
|
lda SecondaryState37Values,y
|
|
sta $37
|
|
|
|
jmp $E0E6
|
|
|
|
;==============================================================================
|
|
; $D36C-$D38F: Gameplay Proximity / Transition Lookup Data
|
|
;
|
|
; Local:
|
|
; Lookup data used by CheckGameplayProximity when a qualifying proximity
|
|
; condition triggers a gameplay-state transition.
|
|
;
|
|
; Global:
|
|
; Supplies values written to $33+, $37, $DD and $DE during the different
|
|
; transition paths handled by CheckGameplayProximity.
|
|
;
|
|
; Notes:
|
|
; $D370 is intentionally a label inside the table beginning at $D36C.
|
|
; No bytes are duplicated.
|
|
;==============================================================================
|
|
ProximityCandidateValues:
|
|
; $D36C-$D36F
|
|
.byte $2D,$2F,$32,$34
|
|
|
|
SecondaryState37Values:
|
|
; $D370-$D373
|
|
; Also forms bytes 4-7 of ProximityCandidateValues.
|
|
.byte $2C,$2E,$30,$31
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D374-$D377
|
|
; Consumer not yet established.
|
|
;------------------------------------------------------------------------------
|
|
ProximityUnknownTableD374:
|
|
.byte $33,$35,$36,$37
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D378-$D37B
|
|
; Indexed by $D9 and loaded into $DE.
|
|
;------------------------------------------------------------------------------
|
|
ProximityDEValues:
|
|
.byte $00,$00,$00,$01
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D37C-$D37F
|
|
; Indexed by $D9 and loaded into $DD.
|
|
;------------------------------------------------------------------------------
|
|
ProximityDDValues:
|
|
.byte $02,$04,$08,$06
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D380-$D387
|
|
; Indexed by $93 and loaded into $DD.
|
|
;------------------------------------------------------------------------------
|
|
SecondaryStateDDValues:
|
|
.byte $01,$03,$05,$07
|
|
.byte $00,$00,$00,$00
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D388-$D38F
|
|
; Indexed by $93 and loaded into $DE.
|
|
;------------------------------------------------------------------------------
|
|
SecondaryStateDEValues:
|
|
.byte $00,$00,$00,$00
|
|
.byte $01,$02,$03,$05
|
|
|
|
;==============================================================================
|
|
; $D390-...: Gameplay Direction / Movement Processing
|
|
;
|
|
; Local:
|
|
; Processes directional controller input, validates a requested direction
|
|
; against the current map/tile state, and selects movement parameters.
|
|
;
|
|
; Global:
|
|
; Called during normal gameplay processing from GameModeState04.
|
|
;
|
|
; Notes:
|
|
; Address-derived labels are retained during this pass to make branch
|
|
; targets explicit while maintaining byte identity.
|
|
;==============================================================================
|
|
|
|
UpdatePlayerMovement:
|
|
lda $48
|
|
beq @D397
|
|
|
|
jmp $D506
|
|
|
|
@D397:
|
|
lda $4F
|
|
and #$F0
|
|
beq @D3D2
|
|
|
|
ldx #$FF
|
|
|
|
@D39F:
|
|
inx
|
|
asl
|
|
bcc @D39F
|
|
|
|
lda InputDirectionTable,x
|
|
sta $50
|
|
|
|
clc
|
|
adc #$02
|
|
and #$03
|
|
cmp $51
|
|
bne @D3C9
|
|
|
|
lda $1A
|
|
ora $1C
|
|
and #$07
|
|
bne @D3C2
|
|
|
|
ldy $50
|
|
|
|
lda $022B,y
|
|
and #$F0
|
|
bne @D3C9
|
|
|
|
|
|
@D3C2:
|
|
lda $50
|
|
sta $51
|
|
|
|
jmp @D3D6
|
|
|
|
|
|
@D3C9:
|
|
ldx $50
|
|
|
|
lda $022B,x
|
|
and #$F0
|
|
beq @D3D6
|
|
|
|
|
|
@D3D2:
|
|
lda $51
|
|
sta $50
|
|
|
|
|
|
@D3D6:
|
|
ldx #$04
|
|
|
|
lda $88
|
|
bne @D3DE
|
|
|
|
ldx #$0A
|
|
|
|
@D3DE:
|
|
lda $022A
|
|
cmp #$01
|
|
beq @D3F4
|
|
|
|
cmp #$02
|
|
beq @D3F4
|
|
|
|
dex
|
|
dex
|
|
|
|
cmp #$03
|
|
beq @D3F4
|
|
|
|
cmp #$09
|
|
beq @D3F4
|
|
|
|
dex
|
|
dex
|
|
|
|
|
|
@D3F4:
|
|
lda $9F,x
|
|
sta $B5
|
|
|
|
lda $A0,x
|
|
sta $B6
|
|
|
|
lda $51
|
|
asl
|
|
tay
|
|
|
|
lda MovementArithmeticTable,y
|
|
sta $10
|
|
|
|
lda MovementArithmeticTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
;==============================================================================
|
|
; $D40E-$D415: Movement Arithmetic Dispatch Table
|
|
;
|
|
; Local:
|
|
; Four 16-bit handlers selected using the internal direction value in $51.
|
|
;
|
|
; Global:
|
|
; Dispatches into direction-specific coordinate arithmetic used by
|
|
; UpdatePlayerMovement.
|
|
;
|
|
; Notes:
|
|
; Direction semantics remain unnamed during this pass.
|
|
;==============================================================================
|
|
MovementArithmeticTable:
|
|
.word $D416
|
|
.word $D41A
|
|
.word $D435
|
|
.word $D431
|
|
;==============================================================================
|
|
; $D416-$D443: Direction-Specific Movement Arithmetic
|
|
;
|
|
; Local:
|
|
; Four entry points selected by MovementArithmeticTable converge into two
|
|
; shared arithmetic paths.
|
|
;
|
|
; $D416/$D41A select the coordinate component and enter subtraction.
|
|
; $D431/$D435 select the coordinate component and enter addition.
|
|
;
|
|
; Global:
|
|
; Computes the fixed-point movement result used by the second direction
|
|
; dispatch beginning at MovementApplyResult.
|
|
;
|
|
; Notes:
|
|
; Shared labels are deliberately non-local because multiple entry-point
|
|
; labels must branch into the same code.
|
|
;==============================================================================
|
|
|
|
MovementArithmeticD416:
|
|
ldx #$02
|
|
bne MovementSubtract
|
|
|
|
MovementArithmeticD41A:
|
|
ldx #$00
|
|
|
|
MovementSubtract:
|
|
lda $1B,x
|
|
sec
|
|
sbc $B5
|
|
sta $1B,x
|
|
|
|
lda #$00
|
|
bcs MovementSubtractNoBorrow
|
|
|
|
lda #$01
|
|
|
|
MovementSubtractNoBorrow:
|
|
clc
|
|
adc $B6
|
|
sta $CC
|
|
|
|
jmp MovementApplyResult
|
|
|
|
|
|
MovementArithmeticD431:
|
|
ldx #$00
|
|
beq MovementAdd
|
|
|
|
|
|
MovementArithmeticD435:
|
|
ldx #$02
|
|
|
|
|
|
MovementAdd:
|
|
lda $1B,x
|
|
clc
|
|
adc $B5
|
|
sta $1B,x
|
|
|
|
lda #$00
|
|
adc $B6
|
|
sta $CC
|
|
|
|
;==============================================================================
|
|
; $D444-$D459: Apply Movement Result and Dispatch Direction Handler
|
|
;
|
|
; Local:
|
|
; Decrements the movement accumulator $CC. If it becomes negative, returns
|
|
; immediately.
|
|
;
|
|
; Otherwise uses the current direction value at $51 as a byte offset into a
|
|
; four-entry handler table beginning at $D45A.
|
|
;
|
|
; Global:
|
|
; Second stage of UpdatePlayerMovement. After the fixed-point arithmetic
|
|
; performed by the $D416-$D443 handlers, this dispatches to the actual
|
|
; direction-specific coordinate/tile movement code.
|
|
;
|
|
; Notes:
|
|
; $51 is multiplied by two before indexing the pointer table.
|
|
;==============================================================================
|
|
|
|
MovementApplyResult:
|
|
dec $CC
|
|
bpl @D449
|
|
|
|
rts
|
|
|
|
|
|
@D449:
|
|
lda $51
|
|
asl
|
|
tay
|
|
|
|
lda MovementDirectionTable,y
|
|
sta $10
|
|
|
|
lda MovementDirectionTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
;==============================================================================
|
|
; $D45A-$D461: Direction-Specific Movement Dispatch Table
|
|
;
|
|
; Local:
|
|
; Four handlers selected according to the internal direction value in $51.
|
|
;
|
|
; Notes:
|
|
; Handler names remain address-based until coordinate effects are fully
|
|
; mapped to semantic direction names.
|
|
;==============================================================================
|
|
|
|
MovementDirectionTable:
|
|
.word MovementDirectionD49A
|
|
.word MovementDirectionD490
|
|
.word MovementDirectionD46C
|
|
.word MovementDirectionD462
|
|
|
|
;==============================================================================
|
|
; $D462-$D501: Direction-Specific Movement Handlers
|
|
;
|
|
; Local:
|
|
; Four entry points selected by MovementDirectionTable.
|
|
;
|
|
; $D462 and $D46C enter the increment path.
|
|
; $D490 and $D49A enter the decrement path.
|
|
;
|
|
; X selects which coordinate component at $1A/$1C is modified. $00 and $01
|
|
; preserve working indexes used for collision/tile checks against $022B.
|
|
;
|
|
; After movement, the shared tail handles coordinate wrapping/state flags
|
|
; and, when aligned to an 8-unit boundary, commits a requested direction
|
|
; change from $50 to $51.
|
|
;
|
|
; Global:
|
|
; Final stage of UpdatePlayerMovement. Applies movement to the player's
|
|
; coordinate state and reconciles requested direction changes.
|
|
;
|
|
; Notes:
|
|
; Entry points intentionally share code. Use non-local labels for shared
|
|
; targets so ca65 scope rules do not change the branch structure.
|
|
;==============================================================================
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D462
|
|
; Increment coordinate component X=0.
|
|
;------------------------------------------------------------------------------
|
|
|
|
MovementDirectionD462:
|
|
ldx #$00
|
|
stx $00
|
|
|
|
lda #$03
|
|
sta $01
|
|
|
|
bne MovementIncrement
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D46C
|
|
; Increment coordinate component X=2.
|
|
;------------------------------------------------------------------------------
|
|
|
|
MovementDirectionD46C:
|
|
ldx #$02
|
|
stx $00
|
|
stx $01
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D472: Shared increment path.
|
|
;------------------------------------------------------------------------------
|
|
|
|
MovementIncrement:
|
|
lda $1A,x
|
|
clc
|
|
adc #$01
|
|
sta $1A,x
|
|
|
|
and #$04
|
|
bne MovementSharedTail
|
|
|
|
ldx $01
|
|
|
|
lda $022B,x
|
|
and #$F0
|
|
beq MovementSharedTail
|
|
|
|
ldx $00
|
|
|
|
lda $1A,x
|
|
and #$FC
|
|
sta $1A,x
|
|
|
|
bne MovementSharedTail
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D490
|
|
; Decrement coordinate component X=0.
|
|
;------------------------------------------------------------------------------
|
|
|
|
MovementDirectionD490:
|
|
ldx #$00
|
|
stx $00
|
|
|
|
lda #$01
|
|
sta $01
|
|
|
|
bne MovementDecrement
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D49A
|
|
; Decrement coordinate component X=2.
|
|
;------------------------------------------------------------------------------
|
|
|
|
MovementDirectionD49A:
|
|
ldx #$02
|
|
stx $00
|
|
|
|
lda #$00
|
|
sta $01
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D4A2: Shared decrement path.
|
|
;------------------------------------------------------------------------------
|
|
|
|
MovementDecrement:
|
|
lda $1A,x
|
|
sec
|
|
sbc #$01
|
|
sta $1A,x
|
|
|
|
and #$04
|
|
beq MovementSharedTail
|
|
|
|
ldx $01
|
|
|
|
lda $022B,x
|
|
and #$F0
|
|
beq MovementSharedTail
|
|
|
|
ldx $00
|
|
|
|
lda $1A,x
|
|
clc
|
|
adc #$04
|
|
and #$FC
|
|
sta $1A,x
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D4C1: Shared movement/wrap tail.
|
|
;------------------------------------------------------------------------------
|
|
|
|
MovementSharedTail:
|
|
lda $1A
|
|
|
|
cmp #$18
|
|
bcc MovementCheckLeftWrap
|
|
|
|
cmp #$A9
|
|
bcs MovementCheckLeftWrap
|
|
|
|
lda $38
|
|
and #$DF
|
|
bcc MovementStoreWrapState
|
|
|
|
MovementCheckLeftWrap:
|
|
lda #$20
|
|
ora $38
|
|
|
|
MovementStoreWrapState:
|
|
sta $38
|
|
|
|
lda $1A
|
|
cmp #$0B
|
|
bcs MovementCheckRightWrap
|
|
|
|
lda #$BF
|
|
sta $1A
|
|
bne MovementCheckAlignment
|
|
|
|
MovementCheckRightWrap:
|
|
cmp #$C0
|
|
bcc MovementCheckAlignment
|
|
|
|
lda #$0B
|
|
sta $1A
|
|
|
|
|
|
MovementCheckAlignment:
|
|
lda $1A
|
|
ora $1C
|
|
and #$07
|
|
bne MovementReturnToArithmetic
|
|
|
|
lda $50
|
|
cmp $51
|
|
beq MovementReturnToArithmetic
|
|
|
|
sta $51
|
|
|
|
inc $CC
|
|
inc $CC
|
|
|
|
|
|
MovementReturnToArithmetic:
|
|
jmp MovementApplyResult
|
|
|
|
;==============================================================================
|
|
; $D502-$D505: Controller Direction Mapping
|
|
;==============================================================================
|
|
|
|
InputDirectionTable:
|
|
.byte $03,$01,$02,$00
|
|
|
|
;==============================================================================
|
|
; $D506-$D51E: Scripted Direction/Input Update
|
|
;
|
|
; Local:
|
|
; Uses $E3 as a countdown and $E4 as an offset into the table beginning at
|
|
; $D51F.
|
|
;
|
|
; Each time $E3 reaches zero:
|
|
; - Advances $E4 by two.
|
|
; - Loads a new duration from $D51F+$E4 into $E3.
|
|
;
|
|
; It then takes the following table byte, masks it to two bits, and
|
|
; tail-jumps into UpdatePlayerMovement at $D3A6 with that value in A.
|
|
;
|
|
; Global:
|
|
; Entered from UpdatePlayerMovement when $48 is nonzero. This provides a
|
|
; scripted/autonomous direction source in place of normal controller input.
|
|
;
|
|
; Notes:
|
|
; $E4 indexes two-byte table records:
|
|
;
|
|
; byte 0 = duration/count
|
|
; byte 1 = direction/control value
|
|
;
|
|
; The second byte is masked with #$03 before entering movement processing.
|
|
;==============================================================================
|
|
|
|
UpdateScriptedDirection:
|
|
ldy $E4
|
|
|
|
dec $E3
|
|
bne @UseCurrentEntry
|
|
|
|
inc $E4
|
|
inc $E4
|
|
|
|
ldy $E4
|
|
|
|
lda ScriptedDirectionTable,y
|
|
sta $E3
|
|
|
|
@UseCurrentEntry:
|
|
lda ScriptedDirectionTable+1,y
|
|
and #$03
|
|
|
|
jmp $D3A6
|
|
|
|
;==============================================================================
|
|
; $D51F-...: Scripted Direction Table
|
|
;
|
|
; Local:
|
|
; Two-byte records used by UpdateScriptedDirection:
|
|
;
|
|
; byte 0 = duration
|
|
; byte 1 = direction/control number
|
|
;
|
|
; Global:
|
|
; Drives autonomous/scripted movement when $48 selects this path instead of
|
|
; normal player controller processing.
|
|
;==============================================================================
|
|
ScriptedDirectionTable:
|
|
.byte $00,$01
|
|
.byte $D0,$00
|
|
.byte $28,$01
|
|
.byte $28,$02
|
|
.byte $90,$03
|
|
.byte $38,$00
|
|
.byte $20,$03
|
|
.byte $18,$01
|
|
.byte $60,$02
|
|
.byte $30,$01
|
|
.byte $10,$02
|
|
.byte $48,$01
|
|
.byte $18,$02
|
|
.byte $40,$01
|
|
.byte $20,$02
|
|
.byte $18,$00
|
|
.byte $20,$03
|
|
.byte $40,$02
|
|
.byte $38,$01
|
|
.byte $18,$02
|
|
.byte $E0,$03
|
|
.byte $30,$00
|
|
.byte $28,$01
|
|
.byte $28,$02
|
|
.byte $20,$02
|
|
.byte $80,$03
|
|
.byte $40,$00
|
|
.byte $40,$01
|
|
|
|
;==============================================================================
|
|
; $D557-$D586: Update Four Gameplay Entities
|
|
;
|
|
; Local:
|
|
; Iterates four gameplay entries using X offsets:
|
|
;
|
|
; $00, $02, $04, $06
|
|
;
|
|
; Initializes several temporary values before the loop:
|
|
;
|
|
; $00 = $2F
|
|
; $01 = $02
|
|
; $02 = $1E
|
|
; $03 = $00
|
|
; $04 = $01
|
|
;
|
|
; For each entry, calls the dispatcher at $D587. After each call:
|
|
;
|
|
; $00 += 4
|
|
; $02 += 4
|
|
; $04 <<= 1
|
|
; X += 2
|
|
;
|
|
; Processing ends after X reaches $08.
|
|
;
|
|
; Global:
|
|
; Called every active gameplay frame from GameModeState04. Coordinates
|
|
; per-entry updates for four gameplay entities/state slots.
|
|
;
|
|
; Notes:
|
|
; $00 and $02 appear to advance through parallel four-byte-strided RAM
|
|
; structures.
|
|
;
|
|
; $04 becomes a per-entry bitmask:
|
|
;
|
|
; $01,$02,$04,$08
|
|
;
|
|
; The exact roles of the temporary values will become clearer as the
|
|
; dispatcher at $D587 and its handlers are decoded.
|
|
;==============================================================================
|
|
|
|
UpdateGameplayEntities:
|
|
ldx #$00
|
|
|
|
lda #$2F
|
|
sta $00
|
|
|
|
lda #$02
|
|
sta $01
|
|
|
|
lda #$1E
|
|
sta $02
|
|
|
|
lda #$00
|
|
sta $03
|
|
|
|
lda #$01
|
|
sta $04
|
|
|
|
@UpdateNextEntity:
|
|
jsr $D587
|
|
|
|
lda $00
|
|
clc
|
|
adc #$04
|
|
sta $00
|
|
|
|
lda $02
|
|
clc
|
|
adc #$04
|
|
sta $02
|
|
|
|
asl $04
|
|
|
|
inx
|
|
inx
|
|
|
|
cpx #$08
|
|
bne @UpdateNextEntity
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $D587-$D595: Gameplay Entity State Dispatcher
|
|
;
|
|
; Local:
|
|
; Reads the state value for the current entity from $B8,X and uses that
|
|
; value directly as a byte offset into EntityStateTable.
|
|
;
|
|
; The selected 16-bit handler address is copied to $10/$11 and execution
|
|
; transfers to it with an indirect JMP.
|
|
;
|
|
; Global:
|
|
; Called by UpdateGameplayEntities once for each of four gameplay entity
|
|
; slots. This provides the per-entity state machine used by those entries.
|
|
;
|
|
; Notes:
|
|
; X identifies the current entry using even offsets:
|
|
;
|
|
; $00,$02,$04,$06
|
|
;
|
|
; $B8,X is a byte offset into the pointer table, so valid state values are
|
|
; even:
|
|
;
|
|
; $00,$02,$04,$06,$08
|
|
;==============================================================================
|
|
|
|
DispatchGameplayEntityState:
|
|
ldy $B8,x
|
|
|
|
lda EntityStateTable,y
|
|
sta $10
|
|
|
|
lda EntityStateTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
;==============================================================================
|
|
; $D596-$D59F: Gameplay Entity State Table
|
|
;
|
|
; Local:
|
|
; Five 16-bit handlers indexed directly by the even state value stored in
|
|
; $B8,X.
|
|
;
|
|
; Global:
|
|
; Defines the per-entity state machine used by
|
|
; DispatchGameplayEntityState.
|
|
;
|
|
; Notes:
|
|
; States $04 and $06 deliberately share the same handler at $D5A1.
|
|
; State $08 targets $D5A0, one byte before that shared handler, suggesting
|
|
; another intentional overlapping entry point.
|
|
;==============================================================================
|
|
|
|
EntityStateTable:
|
|
.word $D8D5 ; state $00
|
|
.word $D885 ; state $02
|
|
.word $D5A1 ; state $04
|
|
.word $D5A1 ; state $06
|
|
.word EntityState08 ; state $08
|
|
|
|
;==============================================================================
|
|
; $D5A0: Entity State $08 Handler
|
|
;
|
|
; Local:
|
|
; Returns immediately.
|
|
;
|
|
; Global:
|
|
; The entity-state table uses this as the handler for state $08, effectively
|
|
; disabling further processing for that entity state.
|
|
;==============================================================================
|
|
|
|
EntityState08:
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $D5A1-$D5B4: Entity State $04/$06 Secondary Dispatcher
|
|
;
|
|
; Local:
|
|
; Called for entity states $04 and $06 from EntityStateTable.
|
|
;
|
|
; First invokes the common entity helper at $D821. It then reads the
|
|
; secondary state value at $B9,X, doubles it, and uses the result as a byte
|
|
; offset into a four-entry pointer table at $D5B5.
|
|
;
|
|
; The selected address is stored in $10/$11 and execution transfers through
|
|
; an indirect JMP.
|
|
;
|
|
; Global:
|
|
; Provides a second-level state machine for gameplay entities whose primary
|
|
; state at $B8,X is $04 or $06.
|
|
;
|
|
; Notes:
|
|
; $B9,X behaves as an ordinal secondary state here. Unlike several earlier
|
|
; state tables, the value is explicitly multiplied by two before indexing
|
|
; the pointer table.
|
|
;==============================================================================
|
|
|
|
DispatchEntitySecondaryState:
|
|
jsr $D821
|
|
|
|
lda $B9,x
|
|
asl
|
|
tay
|
|
|
|
lda EntitySecondaryStateTable,y
|
|
sta $10
|
|
|
|
lda EntitySecondaryStateTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
;==============================================================================
|
|
; $D5B5-$D5BC: Entity Secondary-State Dispatch Table
|
|
;
|
|
; Local:
|
|
; Four handler addresses selected using ($B9,X * 2).
|
|
;
|
|
; Global:
|
|
; Defines the second-level state machine used by primary entity states
|
|
; $04 and $06.
|
|
;==============================================================================
|
|
|
|
EntitySecondaryStateTable:
|
|
.word EntitySecondaryState0 ; secondary state 0
|
|
.word EntitySecondaryState1 ; secondary state 1
|
|
.word EntitySecondaryState2 ; secondary state 2
|
|
.word EntitySecondaryState3 ; secondary state 3
|
|
|
|
;==============================================================================
|
|
; $D5BD-$D5D2: Secondary-State Coordinate Adjustment
|
|
;
|
|
; Local:
|
|
; Secondary state 2 enters at $D5BD and selects Y=$03.
|
|
; Secondary state 3 enters at $D5C1 and selects Y=$01.
|
|
;
|
|
; Both then read through the indirect pointer at $02/$03, add the
|
|
; entity-specific values at $C2,X/$C3,X, write the low-byte result back
|
|
; through the pointer, and store the high-byte result in $CC.
|
|
;
|
|
; Control then tail-jumps to $D5EB.
|
|
;
|
|
; Global:
|
|
; Shared movement/update arithmetic for two secondary entity states.
|
|
;
|
|
; Notes:
|
|
; $02/$03 were initialized by UpdateGameplayEntities and advance by four
|
|
; bytes per entity, so they identify the current entity's four-byte state
|
|
; structure.
|
|
;==============================================================================
|
|
|
|
EntitySecondaryState2:
|
|
ldy #$03
|
|
bne EntitySecondaryAdjust
|
|
|
|
EntitySecondaryState3:
|
|
ldy #$01
|
|
|
|
EntitySecondaryAdjust:
|
|
lda ($02),y
|
|
clc
|
|
adc $C2,x
|
|
sta ($02),y
|
|
|
|
lda #$00
|
|
adc $C3,x
|
|
sta $CC
|
|
|
|
jmp $D5EB
|
|
|
|
;==============================================================================
|
|
; $D5D3-$D5EE: Entity Secondary States $00/$01 Movement Arithmetic
|
|
;
|
|
; Local:
|
|
; Secondary state 0 enters at $D5D3 and selects Y=$03.
|
|
; Secondary state 1 enters at $D5D7 and selects Y=$01.
|
|
;
|
|
; Both subtract the entity-specific movement value at $C2,X from the
|
|
; structure addressed by $02/$03. Borrow is converted into a high-byte
|
|
; adjustment using $C3,X and stored in $CC.
|
|
;
|
|
; Afterward, $CC is decremented. A negative result returns immediately;
|
|
; otherwise execution continues into another secondary dispatcher at $D5EF.
|
|
;
|
|
; Global:
|
|
; Complements the addition paths at $D5BD/$D5C1. Together, the four
|
|
; secondary states provide signed movement along two coordinate components.
|
|
;
|
|
; Notes:
|
|
; The shared labels are non-local because multiple handler entry points
|
|
; converge into them.
|
|
;==============================================================================
|
|
|
|
EntitySecondaryState0:
|
|
ldy #$03
|
|
bne EntitySecondarySubtract
|
|
|
|
|
|
EntitySecondaryState1:
|
|
ldy #$01
|
|
|
|
|
|
EntitySecondarySubtract:
|
|
lda ($02),y
|
|
sec
|
|
sbc $C2,x
|
|
sta ($02),y
|
|
|
|
lda #$00
|
|
bcs EntitySecondarySubtractNoBorrow
|
|
|
|
lda #$01
|
|
|
|
|
|
EntitySecondarySubtractNoBorrow:
|
|
clc
|
|
adc $C3,x
|
|
sta $CC
|
|
|
|
|
|
;==============================================================================
|
|
; $D5EB-$D600: Apply Entity Movement and Dispatch Direction Substate
|
|
;
|
|
; Local:
|
|
; Shared continuation reached by both the addition and subtraction
|
|
; secondary-state handlers.
|
|
;
|
|
; Decrements $CC. If it becomes negative, returns. Otherwise reads the
|
|
; current entity secondary state from $B9,X, doubles it, and selects a
|
|
; handler from the table at $D601.
|
|
;
|
|
; Global:
|
|
; Final arithmetic stage for entity movement before dispatching into the
|
|
; direction/substate-specific update handlers.
|
|
;==============================================================================
|
|
|
|
EntitySecondaryApplyResult:
|
|
dec $CC
|
|
bpl EntityDirectionDispatch
|
|
|
|
rts
|
|
|
|
|
|
EntityDirectionDispatch:
|
|
lda $B9,x
|
|
asl
|
|
tay
|
|
|
|
lda EntityDirectionStateTable,y
|
|
sta $10
|
|
|
|
lda EntityDirectionStateTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
;==============================================================================
|
|
; $D601-$D608: Entity Direction-State Dispatch Table
|
|
;
|
|
; Local:
|
|
; Four handlers selected from the entity's secondary state at $B9,X.
|
|
;
|
|
; Notes:
|
|
; The pointer order deliberately differs from the physical order of the
|
|
; handlers in ROM.
|
|
;==============================================================================
|
|
|
|
EntityDirectionStateTable:
|
|
.word $D609
|
|
.word $D61D
|
|
.word $D60F
|
|
.word $D617
|
|
|
|
;==============================================================================
|
|
; $D609-$D622: Entity Direction-State Handlers
|
|
;
|
|
; Local:
|
|
; Four handlers selected by EntityDirectionStateTable.
|
|
;
|
|
; Each handler configures:
|
|
;
|
|
; $05 = +1 or -1
|
|
; Y = $00 or $02
|
|
;
|
|
; before entering the shared coordinate-update code at $D623.
|
|
;
|
|
; Global:
|
|
; Provides the four direction-specific movement modes for the per-entity
|
|
; state machine.
|
|
;
|
|
; Notes:
|
|
; The four states form two coordinate axes and two signed directions:
|
|
;
|
|
; $D609 -> $05=$FF, Y=$02
|
|
; $D60F -> $05=$01, Y=$02
|
|
; $D617 -> $05=$01, Y=$00
|
|
; $D61D -> $05=$FF, Y=$00
|
|
;
|
|
; Concrete direction names remain deferred until the coordinate axes are
|
|
; mapped to screen X/Y.
|
|
;==============================================================================
|
|
|
|
EntityDirectionD609:
|
|
lda #$FF
|
|
sta $05
|
|
bne EntityDirectionAxis2
|
|
|
|
|
|
EntityDirectionD60F:
|
|
lda #$01
|
|
sta $05
|
|
|
|
|
|
EntityDirectionAxis2:
|
|
ldy #$02
|
|
bne EntityDirectionMove
|
|
|
|
|
|
EntityDirectionD617:
|
|
lda #$01
|
|
sta $05
|
|
bne EntityDirectionAxis0
|
|
|
|
|
|
EntityDirectionD61D:
|
|
lda #$FF
|
|
sta $05
|
|
|
|
|
|
EntityDirectionAxis0:
|
|
ldy #$00
|
|
|
|
;==============================================================================
|
|
; $D623-$D69A: Shared Entity Direction Movement
|
|
;
|
|
; Local:
|
|
; Applies the signed step in $05 to either byte $00 or $02 of the entity
|
|
; structure referenced by $02/$03.
|
|
;
|
|
; Performs coordinate wrapping/bounds handling, updates a per-entity flag
|
|
; stored in $39+, checks tile/grid alignment, and when the entity reaches a
|
|
; specific location ($60,$70) changes the entity primary state to $02.
|
|
;
|
|
; Global:
|
|
; Shared movement implementation for the four handlers above.
|
|
;
|
|
; Notes:
|
|
; This section eventually rejoins the earlier movement arithmetic at $D5EB
|
|
; when the entity is not aligned to the grid.
|
|
;==============================================================================
|
|
|
|
EntityDirectionMove:
|
|
lda ($02),y
|
|
clc
|
|
adc $05
|
|
sta ($02),y
|
|
|
|
ldy #$00
|
|
|
|
lda ($02),y
|
|
cmp #$0A
|
|
bne @D637
|
|
|
|
lda #$BF
|
|
sta ($02),y
|
|
bne @D64B
|
|
|
|
|
|
@D637:
|
|
cmp #$C0
|
|
bne @D641
|
|
|
|
lda #$0B
|
|
sta ($02),y
|
|
bne @D64B
|
|
|
|
|
|
@D641:
|
|
cmp #$18
|
|
bcc @D64B
|
|
|
|
cmp #$A9
|
|
bcc @D64F
|
|
|
|
|
|
@D64B:
|
|
lda #$20
|
|
bne @D651
|
|
|
|
|
|
@D64F:
|
|
lda #$00
|
|
|
|
|
|
@D651:
|
|
sta $05
|
|
|
|
txa
|
|
lsr
|
|
tay
|
|
|
|
lda $39,y
|
|
and #$DF
|
|
ora $05
|
|
sta $39,y
|
|
|
|
ldy #$00
|
|
lda ($02),y
|
|
|
|
ldy #$02
|
|
ora ($02),y
|
|
and #$07
|
|
beq @D66E
|
|
|
|
jmp EntitySecondaryApplyResult
|
|
|
|
@D66E:
|
|
ldy #$00
|
|
|
|
lda ($02),y
|
|
cmp #$60
|
|
bne $D69B
|
|
|
|
ldy #$02
|
|
|
|
lda ($02),y
|
|
cmp #$70
|
|
bne $D69B
|
|
|
|
lda #$02
|
|
sta $B8,x
|
|
|
|
lda #$00
|
|
clc
|
|
sbc $04
|
|
and $88
|
|
sta $88
|
|
|
|
txa
|
|
lsr
|
|
tay
|
|
sta $05
|
|
|
|
lda $39,y
|
|
and #$FC
|
|
ora $05
|
|
sta $39,y
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $D69B-$D6C6: Entity Movement Continuation / Target Selection
|
|
;
|
|
; Local:
|
|
; Continues entity processing after direction movement.
|
|
;
|
|
; Primary entity state $06 selects the fixed value $6F60 in $CD/$CE.
|
|
; Otherwise entity bitmasks in $04 are tested against $88 and $87.
|
|
;
|
|
; ($04 & $88) != 0 transfers to $D70A.
|
|
; ($04 & $87) != 0 transfers to $D6CF.
|
|
;
|
|
; If neither mask matches, the current entity index X selects a 16-bit value
|
|
; from EntityTargetTable and processing continues at $D778.
|
|
;
|
|
; Global:
|
|
; Chooses the next entity target/path-processing mode based on entity state
|
|
; and per-entity bitmasks.
|
|
;
|
|
; Notes:
|
|
; Cross-region branch targets remain raw until the destination blocks are
|
|
; decoded.
|
|
;==============================================================================
|
|
|
|
EntityMovementContinuation:
|
|
lda $B8,x
|
|
cmp #$06
|
|
bne @CheckEntityMasks
|
|
|
|
lda #$60
|
|
sta $CD
|
|
|
|
lda #$6F
|
|
sta $CE
|
|
|
|
jmp $D778
|
|
|
|
|
|
@CheckEntityMasks:
|
|
lda $04
|
|
and $88
|
|
bne $D70A
|
|
|
|
lda $04
|
|
and $87
|
|
bne $D6CF
|
|
|
|
txa
|
|
tay
|
|
|
|
lda EntityTargetTable,y
|
|
sta $CD
|
|
|
|
lda EntityTargetTable+1,y
|
|
sta $CE
|
|
|
|
jmp $D778
|
|
|
|
;==============================================================================
|
|
; $D6C7-$D6CE: Entity Target Table
|
|
;
|
|
; Local:
|
|
; Four 16-bit values indexed directly by the even entity offset X.
|
|
;
|
|
; Global:
|
|
; Supplies the $CD/$CE working target used by EntityMovementContinuation.
|
|
;
|
|
; Notes:
|
|
; Values are retained numerically until the consumer at $D778 is decoded.
|
|
;==============================================================================
|
|
|
|
EntityTargetTable:
|
|
.word $08A8
|
|
.word $0818
|
|
.word $D0A8
|
|
.word $D018
|
|
|
|
;==============================================================================
|
|
; $D6CF-$D6DD: Entity Target-Selection Dispatcher
|
|
;
|
|
; Local:
|
|
; Uses the current even entity index X directly as a byte offset into the
|
|
; four-entry pointer table at $D6DE.
|
|
;
|
|
; The selected handler address is stored in $10/$11 and execution transfers
|
|
; through an indirect JMP.
|
|
;
|
|
; Global:
|
|
; Entered from EntityMovementContinuation when the current entity's bit in
|
|
; $87 is set. Selects entity-specific target/path behavior.
|
|
;
|
|
; Notes:
|
|
; X is already constrained by the calling code to the even entity offsets:
|
|
;
|
|
; $00,$02,$04,$06
|
|
;
|
|
; Therefore no multiply-by-two is required here.
|
|
;==============================================================================
|
|
|
|
DispatchEntityTargetBehavior:
|
|
txa
|
|
tay
|
|
|
|
lda EntityTargetBehaviorTable,y
|
|
sta $10
|
|
|
|
lda EntityTargetBehaviorTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
;==============================================================================
|
|
; $D6DE-$D6E5: Entity Target-Behavior Dispatch Table
|
|
;
|
|
; Local:
|
|
; Four 16-bit handlers indexed directly by the even entity index X.
|
|
;
|
|
; Global:
|
|
; Selects different target/path calculations for each of the four gameplay
|
|
; entities.
|
|
;
|
|
; Notes:
|
|
; The fourth entry deliberately points backward to $D6E6, immediately after
|
|
; this table.
|
|
;==============================================================================
|
|
|
|
EntityTargetBehaviorTable:
|
|
.word EntityTargetBehaviorD73B ; X = $00
|
|
.word EntityTargetBehaviorD745 ; X = $02
|
|
.word EntityTargetBehaviorD764 ; X = $04
|
|
.word EntityTargetBehaviorD6E6 ; X = $06
|
|
|
|
;==============================================================================
|
|
; $D6E6-$D73A: Entity Target Behavior - Proximity/Direction Selection
|
|
;
|
|
; Local:
|
|
; Computes absolute differences between $1A/$2A and $1C/$2C.
|
|
; If either difference is at least $20, transfers to EntityTargetBehaviorD73B.
|
|
;
|
|
; Otherwise attempts up to five candidate directions. Each candidate is
|
|
; checked against the data addressed by $00/$01 and against the current
|
|
; entity direction/state at $B9,X.
|
|
;
|
|
; The selected value is stored into $B9,X before returning to the common
|
|
; entity movement result handler at $D5EB.
|
|
;
|
|
; Global:
|
|
; Fourth entry in EntityTargetBehaviorTable, selected for entity X=$06.
|
|
;
|
|
; Notes:
|
|
; Cross-block target $D73B remains raw until that handler is decoded.
|
|
;==============================================================================
|
|
|
|
EntityTargetBehaviorD6E6:
|
|
lda $1A
|
|
sec
|
|
sbc $2A
|
|
bcs @D6F4
|
|
|
|
sta $05
|
|
|
|
lda #$00
|
|
sec
|
|
sbc $05
|
|
|
|
@D6F4:
|
|
cmp #$20
|
|
bcs $D73B
|
|
|
|
lda $1C
|
|
sec
|
|
sbc $2C
|
|
bcs @D703
|
|
|
|
sta $05
|
|
|
|
lda #$00
|
|
sec
|
|
sbc $05
|
|
|
|
@D703:
|
|
cmp #$20
|
|
bcs $D73B
|
|
|
|
lda $4B
|
|
sta $05
|
|
|
|
lda #$05
|
|
sta $06
|
|
|
|
|
|
@D712:
|
|
dec $06
|
|
bne @D71A
|
|
|
|
lda #$02
|
|
bne @D736
|
|
|
|
|
|
@D71A:
|
|
inc $05
|
|
|
|
lda $05
|
|
and #$03
|
|
tay
|
|
|
|
lda ($00),y
|
|
and #$F8
|
|
bne @D712
|
|
|
|
lda $05
|
|
clc
|
|
adc #$02
|
|
and #$03
|
|
cmp $B9,x
|
|
beq @D712
|
|
|
|
lda $05
|
|
and #$03
|
|
|
|
|
|
@D736:
|
|
sta $B9,x
|
|
|
|
jmp EntitySecondaryApplyResult
|
|
|
|
;==============================================================================
|
|
; $D73B-$D777: Entity Target Calculation Handlers
|
|
;
|
|
; Local:
|
|
; Three handlers selected by EntityTargetBehaviorTable.
|
|
;
|
|
; $D73B:
|
|
; Uses the current $1A/$1C coordinate pair directly as the target.
|
|
;
|
|
; $D745:
|
|
; Uses $51 to select a signed coordinate offset from the table at $D75C,
|
|
; then adds that offset to $1A/$1C.
|
|
;
|
|
; $D764:
|
|
; Reflects/extrapolates the current coordinate pair relative to
|
|
; $1E/$20.
|
|
;
|
|
; All three produce the target coordinate in $CD/$CE and converge on the
|
|
; still-undecoded common processing at $D778.
|
|
;
|
|
; Global:
|
|
; Three of the four target strategies selected by
|
|
; EntityTargetBehaviorTable.
|
|
;
|
|
; Notes:
|
|
; Cross-block destination $D778 remains raw until the common handler is
|
|
; decoded separately.
|
|
;==============================================================================
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D73B: direct target
|
|
;------------------------------------------------------------------------------
|
|
|
|
EntityTargetBehaviorD73B:
|
|
lda $1A
|
|
sta $CD
|
|
|
|
lda $1C
|
|
sta $CE
|
|
|
|
bne $D778
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D745: direction-offset target
|
|
;------------------------------------------------------------------------------
|
|
|
|
EntityTargetBehaviorD745:
|
|
lda $51
|
|
asl
|
|
tay
|
|
|
|
lda EntityDirectionTargetOffsets,y
|
|
clc
|
|
adc $1A
|
|
sta $CD
|
|
|
|
lda EntityDirectionTargetOffsets+1,y
|
|
clc
|
|
adc $1C
|
|
sta $CE
|
|
|
|
jmp $D778
|
|
|
|
;==============================================================================
|
|
; $D75C-$D763: Direction Target Offset Table
|
|
;
|
|
; Local:
|
|
; Four signed coordinate offset pairs selected by ($51 * 2).
|
|
;
|
|
; As signed 8-bit values:
|
|
;
|
|
; 0 -> ( 0, -24 )
|
|
; 1 -> (-24, 0 )
|
|
; 2 -> ( 0, +24 )
|
|
; 3 -> (+24, 0 )
|
|
;
|
|
; Global:
|
|
; Used by EntityTargetBehaviorD745 to project a target position in the
|
|
; entity's current direction.
|
|
;==============================================================================
|
|
|
|
EntityDirectionTargetOffsets:
|
|
.byte $00,$E8
|
|
.byte $E8,$00
|
|
.byte $00,$18
|
|
.byte $18,$00
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D764: relative/reflected target
|
|
;
|
|
; Computes:
|
|
;
|
|
; $CD = $1A + ($1A - $1E)
|
|
; $CE = $1C + ($1C - $20)
|
|
;
|
|
; which algebraically corresponds to:
|
|
;
|
|
; $CD = 2*$1A - $1E
|
|
; $CE = 2*$1C - $20
|
|
;
|
|
; using 8-bit arithmetic.
|
|
;------------------------------------------------------------------------------
|
|
|
|
EntityTargetBehaviorD764:
|
|
lda $1A
|
|
sec
|
|
sbc $1E
|
|
|
|
clc
|
|
adc $1A
|
|
sta $CD
|
|
|
|
lda $1C
|
|
sec
|
|
sbc $20
|
|
|
|
clc
|
|
adc $1C
|
|
sta $CE
|
|
|
|
;==============================================================================
|
|
; $D778-$D79F: Common Entity Target Processing
|
|
;
|
|
; Local:
|
|
; Shared continuation used after an entity target coordinate has been
|
|
; calculated in $CD/$CE.
|
|
;
|
|
; Uses the entity primary state at $B8,X, minus $04, as a byte offset into
|
|
; a packed pointer table beginning at $D881. The selected pointer is stored
|
|
; in $0A/$0B and passed to BuildLegalDirectionList.
|
|
;
|
|
; The results returned in $0C/$0D determine the entity's next secondary
|
|
; state at $B9,X:
|
|
;
|
|
; $0C == $FF
|
|
; -> force state $02
|
|
;
|
|
; $0C != $FF and $0D == $FF
|
|
; -> store $0C into $B9,X and return
|
|
;
|
|
; $0C != $FF and $0D != $FF
|
|
; -> continue at $D7A0 for additional selection logic
|
|
;
|
|
; Global:
|
|
; Common target-evaluation stage reached by the entity target strategies
|
|
; at $D73B, $D745 and $D764, as well as fixed-target paths from earlier
|
|
; entity processing.
|
|
;
|
|
; Notes:
|
|
; $D881 remains undecoded and is therefore referenced by address.
|
|
;
|
|
; The branch to $D7A0 is intentionally kept raw because $D7A0 belongs to
|
|
; the next block and is an explicit continuation rather than an RTS.
|
|
;==============================================================================
|
|
|
|
EntityTargetCommon:
|
|
lda $B8,x
|
|
sec
|
|
sbc #$04
|
|
tay
|
|
|
|
lda $D881,y
|
|
sta $0A
|
|
|
|
lda $D882,y
|
|
sta $0B
|
|
|
|
jsr BuildLegalDirectionList
|
|
|
|
lda $0C
|
|
cmp #$FF
|
|
bne @D795
|
|
|
|
lda #$02
|
|
bne @D79D
|
|
|
|
|
|
@D795:
|
|
lda $0D
|
|
cmp #$FF
|
|
bne $D7A0
|
|
|
|
lda $0C
|
|
|
|
|
|
@D79D:
|
|
sta $B9,x
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $D7A0-$D820: Select Entity Direction Toward Target
|
|
;
|
|
; Local:
|
|
; Entered from EntityTargetCommon when both $0C and $0D returned by
|
|
; BuildLegalDirectionList are valid.
|
|
;
|
|
; Computes absolute coordinate distances between target $CD/$CE and the
|
|
; current entity coordinates addressed through $02/$03.
|
|
;
|
|
; $05 accumulates direction-order information according to:
|
|
; - sign of the horizontal/vertical difference
|
|
; - which axis has the larger absolute distance
|
|
;
|
|
; The result is used to index a direction-priority table at $D871.
|
|
; Candidate directions are compared against the four values at $0C-$0F.
|
|
; When a candidate matches, execution branches back to the common direction
|
|
; store at $D79D.
|
|
;
|
|
; If the preferred candidates fail, the routine tests directions adjacent
|
|
; to the current secondary state $B9,X before eventually returning.
|
|
;
|
|
; Global:
|
|
; Alternate continuation of EntityTargetCommon. Selects the next movement
|
|
; direction for an entity based on its current position and target.
|
|
;
|
|
; Notes:
|
|
; $05 is a temporary direction-priority index.
|
|
; $06/$07 hold absolute coordinate differences.
|
|
; $08 is temporary storage during absolute-value calculations.
|
|
;
|
|
; $D871 is not decoded yet and remains a raw table reference.
|
|
;==============================================================================
|
|
|
|
SelectEntityDirectionTowardTarget:
|
|
ldy #$00
|
|
sty $05
|
|
|
|
lda $CD
|
|
sec
|
|
sbc ($02),y
|
|
bcs @D7B9
|
|
|
|
sta $08
|
|
|
|
lda #$00
|
|
sec
|
|
sbc $08
|
|
|
|
inc $05
|
|
inc $05
|
|
inc $05
|
|
inc $05
|
|
|
|
@D7B9:
|
|
sta $06
|
|
|
|
lda $CE
|
|
|
|
ldy #$02
|
|
|
|
sec
|
|
sbc ($02),y
|
|
bcs @D7D2
|
|
|
|
sta $08
|
|
|
|
lda #$00
|
|
sec
|
|
sbc $08
|
|
|
|
inc $05
|
|
inc $05
|
|
|
|
@D7D2:
|
|
sta $07
|
|
|
|
lda $06
|
|
cmp $07
|
|
bcs @D7DB
|
|
|
|
inc $05
|
|
|
|
@D7DB:
|
|
lda $05
|
|
asl
|
|
sta $05
|
|
|
|
lda #$02
|
|
sta $06
|
|
|
|
|
|
@D7E3:
|
|
ldy $05
|
|
|
|
lda $D871,y
|
|
|
|
ldy #$00
|
|
|
|
@D7EA:
|
|
cmp $000C,y
|
|
beq $D79D
|
|
|
|
iny
|
|
cpy #$04
|
|
bne @D7EA
|
|
|
|
inc $05
|
|
|
|
dec $06
|
|
bne @D7E3
|
|
|
|
lda $B9,x
|
|
sec
|
|
sbc #$01
|
|
and #$03
|
|
|
|
ldy #$00
|
|
|
|
@D802:
|
|
cmp $000C,y
|
|
beq $D79D
|
|
|
|
iny
|
|
cpy #$04
|
|
bne @D802
|
|
|
|
lda $B9,x
|
|
clc
|
|
adc #$01
|
|
and #$03
|
|
|
|
ldy #$00
|
|
|
|
@D814:
|
|
cmp $000C,y
|
|
beq $D79D
|
|
|
|
iny
|
|
cpy #$04
|
|
bne @D814
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $D821-$D870: Select Entity Movement Parameters
|
|
;
|
|
; Local:
|
|
; Chooses the two-byte movement/step value stored at:
|
|
;
|
|
; $C2,X
|
|
; $C3,X
|
|
;
|
|
; for the current gameplay entity.
|
|
;
|
|
; Selection depends on:
|
|
;
|
|
; - primary entity state $B8,X
|
|
; - current entity coordinates through ($02)
|
|
; - entity bitmask $04 against $88
|
|
; - whether X is zero or identifies another entity
|
|
;
|
|
; Parameter pairs are copied from several global values:
|
|
;
|
|
; $B3/$B4
|
|
; $CA/$CB
|
|
; $AF/$B0
|
|
; $B1/$B2
|
|
;
|
|
; Primary state $06 instead installs the fixed pair:
|
|
;
|
|
; $00,$02
|
|
;
|
|
; Global:
|
|
; Called before the $B9,X secondary-state dispatcher at $D5A1. This chooses
|
|
; the movement increment used by the entity movement arithmetic.
|
|
;
|
|
; Notes:
|
|
; The coordinate pointer $02/$03 identifies the current entity's structure.
|
|
; X is the even entity slot index.
|
|
;==============================================================================
|
|
|
|
SelectEntityMovementSpeed:
|
|
lda $B8,x
|
|
cmp #$06
|
|
beq @D864
|
|
|
|
ldy #$02
|
|
|
|
lda ($02),y
|
|
cmp #$70
|
|
bne @D843
|
|
|
|
ldy #$00
|
|
|
|
lda ($02),y
|
|
cmp #$90
|
|
bcs @D83D
|
|
|
|
cmp #$30
|
|
bcs @D843
|
|
|
|
@D83D:
|
|
lda $B3
|
|
sta $C2,x
|
|
|
|
lda $B4
|
|
sta $C3,x
|
|
|
|
rts
|
|
|
|
|
|
@D843:
|
|
lda $04
|
|
and $88
|
|
bne @D85A
|
|
|
|
txa
|
|
bne @D854
|
|
|
|
lda $CA
|
|
sta $C2
|
|
|
|
lda $CB
|
|
sta $C3
|
|
|
|
rts
|
|
|
|
|
|
@D854:
|
|
lda $AF
|
|
sta $C2,x
|
|
|
|
lda $B0
|
|
sta $C3,x
|
|
|
|
rts
|
|
|
|
|
|
@D85A:
|
|
lda $B1
|
|
sta $C2,x
|
|
|
|
lda $B2
|
|
sta $C3,x
|
|
|
|
rts
|
|
|
|
|
|
@D864:
|
|
lda #$00
|
|
sta $C2,x
|
|
|
|
lda #$02
|
|
sta $C3,x
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $D871-$D880: Entity Direction Priority Table
|
|
;
|
|
; Local:
|
|
; Sixteen direction values used by SelectEntityDirectionTowardTarget.
|
|
;
|
|
; $05 is derived from:
|
|
; - the sign of each target-coordinate difference,
|
|
; - which axis has the greater absolute distance.
|
|
;
|
|
; $05 is doubled before indexing this table, and the routine may examine
|
|
; the following entry as its second preferred candidate.
|
|
;
|
|
; Global:
|
|
; Defines the preferred entity movement directions for the different
|
|
; relative target-position quadrants/axis priorities.
|
|
;
|
|
; Notes:
|
|
; Values are internal direction numbers 0-3. Concrete direction names remain
|
|
; deferred until the internal direction numbering is fully mapped.
|
|
;
|
|
; The natural layout is eight pairs of preferred directions.
|
|
;==============================================================================
|
|
|
|
EntityDirectionPriorityTable:
|
|
.byte $03,$02
|
|
.byte $02,$03
|
|
.byte $03,$00
|
|
.byte $00,$03
|
|
.byte $01,$02
|
|
.byte $02,$01
|
|
.byte $01,$00
|
|
.byte $00,$01
|
|
|
|
;==============================================================================
|
|
; $D881-$D884: Entity Path/Map Pointer Table
|
|
;
|
|
; Local:
|
|
; Two 16-bit values selected according to entity primary state:
|
|
;
|
|
; state $04 -> $0000
|
|
; state $06 -> $082C
|
|
;
|
|
; The selected value is placed in $0A/$0B and passed to the helper at
|
|
; BuildLegalDirectionList.
|
|
;
|
|
; Global:
|
|
; Supplies state-dependent path/map parameters used by EntityTargetCommon.
|
|
;
|
|
; Notes:
|
|
; Keep the entries as literal 16-bit values until BuildLegalDirectionList
|
|
; is decoded and the semantic meaning of $0A/$0B is established.
|
|
;==============================================================================
|
|
|
|
EntityPathParameterTable:
|
|
.word $0000
|
|
.word $082C
|
|
|
|
;==============================================================================
|
|
; $D885-$D8D4: Entity Primary State $02 Handler
|
|
;==============================================================================
|
|
|
|
UpdateEntityState02:
|
|
lda #$00
|
|
tay
|
|
sta $05
|
|
|
|
lda #$80
|
|
sta $06
|
|
|
|
lda ($02),y
|
|
cmp #$60
|
|
beq UpdateEntityState02SecondaryPhase
|
|
|
|
bcc @D89C
|
|
|
|
dec $05
|
|
|
|
lda #$01
|
|
bne @D89E
|
|
|
|
@D89C:
|
|
lda #$03
|
|
|
|
@D89E:
|
|
sta $B9,x
|
|
|
|
ldy #$01
|
|
|
|
lda ($02),y
|
|
clc
|
|
adc $06
|
|
sta ($02),y
|
|
|
|
ldy #$00
|
|
|
|
lda ($02),y
|
|
adc $05
|
|
sta ($02),y
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $D8B2-$D8D4: Entity State $02 Secondary Movement Phase
|
|
;==============================================================================
|
|
|
|
UpdateEntityState02SecondaryPhase:
|
|
lda #$00
|
|
sta $B9,x
|
|
|
|
ldy #$03
|
|
|
|
lda ($02),y
|
|
sec
|
|
sbc #$80
|
|
sta ($02),y
|
|
|
|
ldy #$02
|
|
|
|
lda ($02),y
|
|
sbc #$00
|
|
sta ($02),y
|
|
|
|
cmp #$58
|
|
beq @D8CC
|
|
|
|
rts
|
|
|
|
@D8CC:
|
|
lda #$01
|
|
sta $B9,x
|
|
|
|
lda #$04
|
|
sta $B8,x
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $D8D5-$D913: Entity Primary State $00 Handler
|
|
;
|
|
; Local:
|
|
; Initializes working movement values:
|
|
;
|
|
; $05 = $00
|
|
; $06 = $80
|
|
;
|
|
; Then uses the entity secondary state at $B9,X as a byte offset into a
|
|
; two-entry table at $D8EC.
|
|
;
|
|
; The selected subhandler adjusts bytes 3/2 of the current entity structure
|
|
; through $02/$03. When the resulting high byte crosses defined thresholds,
|
|
; $B9,X advances to secondary state $02 or resets to $00.
|
|
;
|
|
; Global:
|
|
; Handler selected by EntityStateTable for primary entity state $00.
|
|
;
|
|
; Notes:
|
|
; Unlike the $D5A1 secondary dispatcher, $B9,X is already treated as a byte
|
|
; offset here. Valid values are $00 and $02.
|
|
;==============================================================================
|
|
|
|
EntityState00:
|
|
lda #$00
|
|
sta $05
|
|
|
|
lda #$80
|
|
sta $06
|
|
|
|
ldy $B9,x
|
|
|
|
lda EntityState00SubstateTable,y
|
|
sta $10
|
|
|
|
lda EntityState00SubstateTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
|
|
;==============================================================================
|
|
; $D8EC-$D8EF: Entity State $00 Secondary Table
|
|
;==============================================================================
|
|
|
|
EntityState00SubstateTable:
|
|
.word UpdateEntityState00MovingNegative
|
|
.word UpdateEntityState00MovingPositive
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D8F0: secondary state $00
|
|
;------------------------------------------------------------------------------
|
|
|
|
UpdateEntityState00MovingNegative:
|
|
dec $05
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $D8F2: secondary state $02
|
|
;------------------------------------------------------------------------------
|
|
|
|
UpdateEntityState00MovingPositive:
|
|
ldy #$03
|
|
|
|
lda ($02),y
|
|
clc
|
|
adc $06
|
|
sta ($02),y
|
|
|
|
ldy #$02
|
|
|
|
lda ($02),y
|
|
adc $05
|
|
sta ($02),y
|
|
|
|
cmp #$69
|
|
bcs @D90B
|
|
|
|
lda #$02
|
|
bne @D911
|
|
|
|
|
|
@D90B:
|
|
cmp #$70
|
|
bcc @D913
|
|
|
|
lda #$00
|
|
|
|
@D911:
|
|
sta $B9,x
|
|
|
|
@D913:
|
|
rts
|
|
;==============================================================================
|
|
; $D914-$D943: Update Four Gameplay Entity States
|
|
;
|
|
; Local:
|
|
; Iterates the four gameplay entity slots using even X offsets:
|
|
;
|
|
; $00,$02,$04,$06
|
|
;
|
|
; Initializes the same per-entity working values used by the other entity
|
|
; update coordinator:
|
|
;
|
|
; $00 = $2F
|
|
; $01 = $02
|
|
; $02 = $1E
|
|
; $03 = $00
|
|
; $04 = $01
|
|
;
|
|
; Calls the entity dispatcher at $D944 for each slot.
|
|
;
|
|
; After each call:
|
|
;
|
|
; $00 += 4
|
|
; $02 += 4
|
|
; $04 <<= 1
|
|
; X += 2
|
|
;
|
|
; Global:
|
|
; Called from GameModeState06 during its per-frame update sequence.
|
|
; Processes a second entity-state machine for all four gameplay entities.
|
|
;
|
|
; Notes:
|
|
; The layout closely parallels UpdateGameplayEntities at $D557, but uses
|
|
; a different dispatcher and therefore a different behavior set.
|
|
;==============================================================================
|
|
|
|
UpdateEntityMovementStates:
|
|
ldx #$00
|
|
|
|
lda #$2F
|
|
sta $00
|
|
|
|
lda #$02
|
|
sta $01
|
|
|
|
lda #$1E
|
|
sta $02
|
|
|
|
lda #$00
|
|
sta $03
|
|
|
|
lda #$01
|
|
sta $04
|
|
|
|
@D92A:
|
|
jsr $D944
|
|
|
|
lda $00
|
|
clc
|
|
adc #$04
|
|
sta $00
|
|
|
|
lda $02
|
|
clc
|
|
adc #$04
|
|
sta $02
|
|
|
|
asl $04
|
|
|
|
inx
|
|
inx
|
|
|
|
cpx #$08
|
|
bne @D92A
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $D944-$D952: Gameplay Entity Transition-State Dispatcher
|
|
;
|
|
; Local:
|
|
; Reads the current entity primary state from $B8,X and uses it directly as
|
|
; a byte offset into the packed pointer table at $D953.
|
|
;
|
|
; The selected 16-bit address is stored in $10/$11 and execution transfers
|
|
; to it through an indirect JMP.
|
|
;
|
|
; Global:
|
|
; Called by UpdateEntityMovementStates once for each of the four
|
|
; gameplay entity slots.
|
|
;
|
|
; Notes:
|
|
; X identifies the entity using even offsets:
|
|
;
|
|
; $00,$02,$04,$06
|
|
;
|
|
; $B8,X is itself an even byte offset into the pointer table:
|
|
;
|
|
; $00,$02,$04,$06,$08
|
|
;==============================================================================
|
|
|
|
DispatchEntityMovementState:
|
|
ldy $B8,x
|
|
|
|
lda EntityMovementStateHandlerTable,y
|
|
sta $10
|
|
|
|
lda EntityMovementStateHandlerTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
|
|
;==============================================================================
|
|
; $D953-$D95C: Gameplay Entity Transition-State Table
|
|
;
|
|
; Local:
|
|
; Five 16-bit handlers indexed directly by the entity primary state stored
|
|
; in $B8,X.
|
|
;
|
|
; Global:
|
|
; Defines the per-entity behavior used by
|
|
; DispatchEntityMovementState.
|
|
;
|
|
; Notes:
|
|
; States $00, $02, $04 and $08 all use the same handler at $D95D.
|
|
;
|
|
; State $06 reuses DispatchEntitySecondaryState at $D5A1.
|
|
;==============================================================================
|
|
|
|
EntityMovementStateHandlerTable:
|
|
.word EntityMovementStateNoOp ; state $00
|
|
.word EntityMovementStateNoOp ; state $02
|
|
.word EntityMovementStateNoOp ; state $04
|
|
.word DispatchEntitySecondaryState ; state $06
|
|
.word EntityMovementStateNoOp ; state $08
|
|
|
|
;==============================================================================
|
|
; $D95D: No-Op Entity Transition Handler
|
|
;
|
|
; Local:
|
|
; Returns immediately.
|
|
;
|
|
; Global:
|
|
; Used by EntityMovementStateHandlerTable for primary entity states
|
|
; $00, $02, $04 and $08.
|
|
;==============================================================================
|
|
EntityMovementStateNoOp:
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $D95E-$D979: Check Entity Transition State
|
|
;
|
|
; Local:
|
|
; Scans the four primary entity-state entries at:
|
|
;
|
|
; $B8,$BA,$BC,$BE
|
|
;
|
|
; If any entity is in primary state $06, stores the current A value
|
|
; ($06 from the CMP) into $0608 and returns.
|
|
;
|
|
; If no entity is in state $06, tests $88. When $88 is nonzero, stores that
|
|
; value into $0609 before returning.
|
|
;
|
|
; Global:
|
|
; Called during normal gameplay processing. Exports entity/state conditions
|
|
; to RAM $0608/$0609 for use by other gameplay systems.
|
|
;
|
|
; Notes:
|
|
; $00 is initialized but not subsequently used inside this routine in the
|
|
; decoded path. Preserve the write because another overlapping entry or
|
|
; external expectation may depend on it.
|
|
;==============================================================================
|
|
|
|
UpdateEntityStatusFlags:
|
|
ldx #$00
|
|
stx $00
|
|
|
|
@D962:
|
|
lda $B8,x
|
|
cmp #$06
|
|
bne @D96C
|
|
|
|
sta $0608
|
|
rts
|
|
|
|
@D96C:
|
|
inx
|
|
inx
|
|
|
|
cpx #$08
|
|
bne @D962
|
|
|
|
lda $88
|
|
beq UpdatePlayerVerticalRegionFlag
|
|
|
|
sta $0609
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $D97A-$D98D: Update Gameplay Range Flag
|
|
;==============================================================================
|
|
UpdatePlayerVerticalRegionFlag:
|
|
ldy #$00
|
|
|
|
lda $6A
|
|
cmp #$88
|
|
bcs @D988
|
|
|
|
iny
|
|
|
|
cmp #$42
|
|
bcs @D988
|
|
|
|
iny
|
|
|
|
@D988:
|
|
lda #$01
|
|
sta $060A,y
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $D98E-$D9C5: Update Direction-Dependent Gameplay Value
|
|
;
|
|
; Local:
|
|
; Builds a base value from the current direction $51, then selects an
|
|
; additional offset based on coordinate alignment, tile state, and $B7.
|
|
;
|
|
; The resulting value is stored in $32.
|
|
;
|
|
; Notes:
|
|
; Address-derived labels preserve the original compact control flow.
|
|
;==============================================================================
|
|
|
|
UpdatePlayerDirectionAnimation:
|
|
lda $51
|
|
asl
|
|
clc
|
|
adc #$02
|
|
sta $00
|
|
|
|
lda $1A
|
|
ora $1C
|
|
and #$07
|
|
bne @D9AE
|
|
|
|
ldy $51
|
|
|
|
lda $022B,y
|
|
and #$F0
|
|
beq @D9AE
|
|
|
|
lda $B7
|
|
and #$03
|
|
jmp @D9B2
|
|
|
|
|
|
@D9AE:
|
|
inc $B7
|
|
|
|
lda $B7
|
|
|
|
@D9B2:
|
|
and #$07
|
|
cmp #$06
|
|
bcc @D9BC
|
|
|
|
lda #$01
|
|
bne @D9C3
|
|
|
|
|
|
@D9BC:
|
|
tay
|
|
|
|
lda PlayerDirectionAnimationOffsets,y
|
|
clc
|
|
adc $00
|
|
|
|
|
|
@D9C3:
|
|
sta $32
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $D9C6-$D9CB: Direction-Value Offset Table
|
|
;
|
|
; Local:
|
|
; Six values indexed by $B7 & $07 when that result is less than six.
|
|
;
|
|
; Global:
|
|
; Provides the small offset added to the direction-derived base before the
|
|
; result is stored in $32.
|
|
;==============================================================================
|
|
|
|
PlayerDirectionAnimationOffsets:
|
|
.byte $00,$00,$00,$01,$01,$00
|
|
|
|
;==============================================================================
|
|
; $D9CC-$D9EA: Update Four Entity Display/State Values
|
|
;
|
|
; Local:
|
|
; Initializes:
|
|
;
|
|
; X = $00
|
|
; $00 = $00 or $01 depending on frame-counter bit 3
|
|
; $01 = $01
|
|
;
|
|
; Then iterates the four entity slots:
|
|
;
|
|
; X = $00,$02,$04,$06
|
|
;
|
|
; For each entity:
|
|
; - Calls the dispatcher at $D9EB.
|
|
; - Shifts $01 left once, producing per-entity masks:
|
|
;
|
|
; $01,$02,$04,$08
|
|
;
|
|
; - Advances X by two.
|
|
;
|
|
; Global:
|
|
; Called from several game-mode states and during normal gameplay. Provides
|
|
; per-frame updates for all four gameplay entities, with an alternating
|
|
; phase selected from frame-counter bit 3.
|
|
;
|
|
; Notes:
|
|
; $4B is the NMI-driven frame counter.
|
|
; $00 is a two-phase animation/control value.
|
|
; $01 is the current entity bitmask.
|
|
;==============================================================================
|
|
|
|
UpdateEntitySpriteStates:
|
|
lda #$00
|
|
tax
|
|
sta $00
|
|
|
|
lda $4B
|
|
and #$08
|
|
beq @D9DC
|
|
|
|
lda #$01
|
|
sta $00
|
|
|
|
|
|
@D9DC:
|
|
lda #$01
|
|
sta $01
|
|
|
|
|
|
@D9E0:
|
|
jsr $D9EB
|
|
|
|
asl $01
|
|
|
|
inx
|
|
inx
|
|
|
|
cpx #$08
|
|
bne @D9E0
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $D9EB-$D9F9: Per-Entity Display/State Dispatcher
|
|
;==============================================================================
|
|
|
|
DispatchEntitySpriteState:
|
|
ldy $B8,x
|
|
|
|
lda EntitySpriteStateHandlerTable,y
|
|
sta $10
|
|
|
|
lda EntitySpriteStateHandlerTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
|
|
;==============================================================================
|
|
; $D9FA-$DA03: Entity Display/State Table
|
|
;==============================================================================
|
|
EntitySpriteStateHandlerTable:
|
|
.word UpdateNormalEntitySprite ; state $00
|
|
.word UpdateNormalEntitySprite ; state $02
|
|
.word UpdateNormalEntitySprite ; state $04
|
|
.word UpdateSpecialEntitySprite ; state $06
|
|
.word $D9EA ; state $08 -> shared RTS
|
|
|
|
;==============================================================================
|
|
; $DA04-$DA3F: Entity Display/State Value Handlers
|
|
;
|
|
; Local:
|
|
; Three entry points used by EntitySpriteStateHandlerTable:
|
|
;
|
|
; $DA21 primary states $00/$02/$04
|
|
; $DA2D primary state $06
|
|
;
|
|
; $DA04 is shared calculation code entered by those handlers.
|
|
;
|
|
; Each path computes a value from the entity secondary state $B9,X, combines
|
|
; it with a base value, and stores the final result into one of $33-$36
|
|
; according to the current entity index X.
|
|
;
|
|
; Global:
|
|
; Produces per-entity display/state values during UpdateEntitySpriteStates.
|
|
;
|
|
; Notes:
|
|
; X is an even entity index ($00,$02,$04,$06). TXA/LSR converts this into
|
|
; the ordinal entity index 0-3 for the final store at $33,Y.
|
|
;==============================================================================
|
|
|
|
;==============================================================================
|
|
; $DA04-$DA3F: Entity Display/State Value Handlers
|
|
;
|
|
; Local:
|
|
; Shared calculations used by the per-entity display/state dispatcher.
|
|
;
|
|
; Global:
|
|
; UpdateNormalEntitySprite handles primary states $00/$02/$04.
|
|
; UpdateSpecialEntitySprite handles primary state $06.
|
|
;
|
|
; Notes:
|
|
; Non-local labels are intentional because multiple handler entry points
|
|
; branch backward into shared code.
|
|
;==============================================================================
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DA04
|
|
;------------------------------------------------------------------------------
|
|
|
|
CalculateEntitySpriteValue:
|
|
lda $B9,x
|
|
sta $03
|
|
|
|
lda #$0A
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DA0A
|
|
;------------------------------------------------------------------------------
|
|
|
|
CalculateEntitySpriteValueLoop:
|
|
dec $03
|
|
bmi AddEntitySpriteBase
|
|
|
|
clc
|
|
adc #$02
|
|
bne CalculateEntitySpriteValueLoop
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DA13
|
|
;------------------------------------------------------------------------------
|
|
|
|
AddEntitySpriteBase:
|
|
clc
|
|
adc $00
|
|
sta $02
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DA18
|
|
;------------------------------------------------------------------------------
|
|
|
|
StoreEntitySpriteValue:
|
|
txa
|
|
lsr
|
|
tay
|
|
|
|
lda $02
|
|
sta $0033,y
|
|
|
|
rts
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DA21
|
|
; Primary entity states $00/$02/$04.
|
|
;------------------------------------------------------------------------------
|
|
|
|
UpdateNormalEntitySprite:
|
|
lda $01
|
|
and $88
|
|
beq CalculateEntitySpriteValue
|
|
|
|
lda #$1E
|
|
sta $02
|
|
|
|
bne AddEntitySpriteBase
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DA2D
|
|
; Primary entity state $06.
|
|
;------------------------------------------------------------------------------
|
|
|
|
UpdateSpecialEntitySprite:
|
|
lda $B9,x
|
|
sta $03
|
|
|
|
lda #$20
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DA33
|
|
;------------------------------------------------------------------------------
|
|
|
|
UpdateSpecialEntitySpriteLoop:
|
|
dec $03
|
|
bmi UpdateSpecialEntitySpriteDone
|
|
|
|
clc
|
|
adc #$01
|
|
bne UpdateSpecialEntitySpriteLoop
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DA3C
|
|
;------------------------------------------------------------------------------
|
|
|
|
UpdateSpecialEntitySpriteDone:
|
|
sta $02
|
|
|
|
bmi StoreEntitySpriteValue
|
|
|
|
;==============================================================================
|
|
; $DA40-$DAF0: Gameplay Entity Collision / Slot Exchange
|
|
;
|
|
; Local:
|
|
; Copies $24 bytes from zero-page $1A-$3D to RAM $0274-$0297.
|
|
;
|
|
; Then initializes an indirect pointer to $0284 and scans entity structures
|
|
; while testing them against the primary coordinate pair at $0274/$0276.
|
|
;
|
|
; For each enabled entity, computes absolute coordinate differences. If both
|
|
; axes are within $19 and their combined distance is below $10, exchanges
|
|
; coordinate and associated state fields between the primary slot and the
|
|
; selected entity slot.
|
|
;
|
|
; If no qualifying overlap is found, advances the structure pointer backward
|
|
; by four bytes, shifts the per-entity mask, and continues.
|
|
;
|
|
; Global:
|
|
; Called in several game-mode states and during normal gameplay. Maintains
|
|
; the mirrored gameplay/object state in $0274+ and handles close-overlap
|
|
; exchanges between entity slots.
|
|
;
|
|
; Notes:
|
|
; $00/$01 form a temporary pointer, initially $0284.
|
|
; $02 counts entity slots.
|
|
; $03 is a bitmask, initially $08.
|
|
; $04-$06 are temporary coordinate/state values during a swap.
|
|
;
|
|
; $DAF1 is a separate routine and is not included in this block.
|
|
;==============================================================================
|
|
|
|
CheckEntityCollisions:
|
|
ldx #$23
|
|
|
|
@CopyWorkingState:
|
|
lda $1A,x
|
|
sta $0274,x
|
|
|
|
dex
|
|
bpl @CopyWorkingState
|
|
|
|
lda #$84
|
|
sta $00
|
|
|
|
lda #$02
|
|
sta $01
|
|
|
|
lda #$08
|
|
sta $03
|
|
|
|
lda #$03
|
|
sta $02
|
|
|
|
|
|
@CheckNextEntity:
|
|
lda $03
|
|
and $88
|
|
bne @AdvanceEntity
|
|
|
|
ldy #$00
|
|
|
|
lda $0274
|
|
cmp ($00),y
|
|
bcs @FirstAxisReverse
|
|
|
|
lda ($00),y
|
|
sec
|
|
sbc $0274
|
|
bcs @CheckFirstAxis
|
|
|
|
@FirstAxisReverse:
|
|
sbc ($00),y
|
|
|
|
@CheckFirstAxis:
|
|
cmp #$19
|
|
bcs @AdvanceEntity
|
|
|
|
sta $04
|
|
|
|
ldy #$02
|
|
|
|
lda $0276
|
|
cmp ($00),y
|
|
bcs @SecondAxisReverse
|
|
|
|
lda ($00),y
|
|
sec
|
|
sbc $0276
|
|
bcs @CheckSecondAxis
|
|
|
|
@SecondAxisReverse:
|
|
sbc ($00),y
|
|
|
|
@CheckSecondAxis:
|
|
cmp #$19
|
|
bcs @AdvanceEntity
|
|
|
|
adc $04
|
|
cmp #$10
|
|
bcs @AdvanceEntity
|
|
|
|
; Save the primary slot coordinates/state.
|
|
lda $0274
|
|
sta $03
|
|
|
|
lda $0276
|
|
sta $04
|
|
|
|
lda $028C
|
|
sta $05
|
|
|
|
lda $0292
|
|
sta $06
|
|
|
|
; Copy selected entity coordinates into the primary slot.
|
|
ldy #$00
|
|
lda ($00),y
|
|
sta $0274
|
|
|
|
lda $03
|
|
sta ($00),y
|
|
|
|
ldy #$02
|
|
lda ($00),y
|
|
sta $0276
|
|
|
|
lda $04
|
|
sta ($00),y
|
|
|
|
; Exchange the parallel status values.
|
|
ldx $02
|
|
|
|
lda $028D,x
|
|
sta $028C
|
|
|
|
lda $05
|
|
sta $028D,x
|
|
|
|
lda $0293,x
|
|
sta $0292
|
|
|
|
lda $06
|
|
sta $0293,x
|
|
|
|
jmp $DAEB
|
|
|
|
|
|
@AdvanceEntity:
|
|
lda $00
|
|
sec
|
|
sbc #$04
|
|
sta $00
|
|
|
|
lsr $03
|
|
|
|
dec $02
|
|
bmi @NoCollision
|
|
|
|
jmp @CheckNextEntity
|
|
|
|
|
|
@NoCollision:
|
|
jsr $E1DA
|
|
|
|
jmp $DAF1
|
|
|
|
;==============================================================================
|
|
; $DAF1-$DBEE: Rebuild Gameplay Entity Render Data
|
|
;
|
|
; Local:
|
|
; Builds four-byte render/object records in page $07 from mirrored gameplay
|
|
; state beginning at $0274.
|
|
;
|
|
; Working variables:
|
|
;
|
|
; $00/$01 = source pointer, initially $0274
|
|
; $02/$03 = destination pointer, initially $0700
|
|
; $04 = source-group index
|
|
; $05 = record/lookup index
|
|
; $06 = temporary lookup index
|
|
;
|
|
; X advances through even entity offsets $00,$02,$04,$06.
|
|
;
|
|
; Encoded state values at $028C+ determine which lookup-table path is used
|
|
; to construct bytes 1 and 2 of each four-byte output record.
|
|
;
|
|
; Global:
|
|
; Called by several gameplay paths to rebuild the page-$07 representation
|
|
; used by the rendering/object pipeline.
|
|
;
|
|
; Notes:
|
|
; Several ROM tables referenced here remain undecoded:
|
|
;
|
|
; $DBEE
|
|
; $DCEE
|
|
; $DD22
|
|
; EntitySpriteAttributeTable0
|
|
; EntitySpriteCoordinateOffsets
|
|
; $DE57
|
|
;
|
|
; $DBEE is particularly interesting because it is also the RTS terminating
|
|
; this routine. The ROM intentionally uses that address as both executable
|
|
; code and the base of a later indexed lookup.
|
|
;==============================================================================
|
|
BuildEntitySpriteBuffer:
|
|
lda #$74
|
|
sta $00
|
|
|
|
lda #$02
|
|
sta $01
|
|
|
|
lda #$00
|
|
sta $02
|
|
|
|
lda #$07
|
|
sta $03
|
|
|
|
lda #$00
|
|
sta $04
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DB05
|
|
; Start/restart one source group.
|
|
;------------------------------------------------------------------------------
|
|
|
|
BuildSpriteBufferNextGroup:
|
|
lda #$00
|
|
sta $05
|
|
|
|
tax
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DB0A
|
|
; Build one four-byte render record.
|
|
;------------------------------------------------------------------------------
|
|
|
|
BuildSpriteBufferNextSprite:
|
|
ldy #$02
|
|
|
|
lda ($00),y
|
|
bne AdjustSpriteY
|
|
|
|
lda #$FF
|
|
bne StoreSpriteY
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DB14
|
|
;------------------------------------------------------------------------------
|
|
|
|
AdjustSpriteY:
|
|
clc
|
|
adc EntitySpriteCoordinateOffsets,x
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DB18
|
|
;------------------------------------------------------------------------------
|
|
|
|
StoreSpriteY:
|
|
ldy #$00
|
|
sta ($02),y
|
|
|
|
ldy $04
|
|
|
|
lda $028C,y
|
|
asl
|
|
rol
|
|
rol
|
|
and #$03
|
|
|
|
beq BuildSpriteClass0
|
|
|
|
cmp #$02
|
|
beq BuildSpriteClass2
|
|
|
|
bcc BuildSpriteClass1
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DB2E
|
|
; Status-class path.
|
|
;------------------------------------------------------------------------------
|
|
|
|
lda $028C,y
|
|
asl
|
|
asl
|
|
clc
|
|
adc $05
|
|
tay
|
|
|
|
sta $06
|
|
|
|
lda $DD22,y
|
|
|
|
ldy #$01
|
|
sta ($02),y
|
|
|
|
ldy $04
|
|
lda $0292,y
|
|
|
|
ldy $06
|
|
ora EntitySpriteCoordinateOffsets,y
|
|
|
|
ldy #$02
|
|
sta ($02),y
|
|
|
|
jmp BuildSpriteX
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DB51
|
|
;------------------------------------------------------------------------------
|
|
|
|
BuildSpriteClass0:
|
|
lda $028C,y
|
|
asl
|
|
asl
|
|
clc
|
|
adc $05
|
|
tay
|
|
|
|
sta $06
|
|
|
|
lda $DBEE,y
|
|
|
|
ldy #$01
|
|
sta ($02),y
|
|
|
|
ldy $04
|
|
lda $0292,y
|
|
|
|
ldy $06
|
|
ora $DD22,y
|
|
|
|
ldy #$02
|
|
sta ($02),y
|
|
|
|
jmp BuildSpriteX
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DB74
|
|
;------------------------------------------------------------------------------
|
|
|
|
BuildSpriteClass1:
|
|
lda $028C,y
|
|
asl
|
|
asl
|
|
clc
|
|
adc $05
|
|
tay
|
|
|
|
sta $06
|
|
|
|
lda $DCEE,y
|
|
|
|
ldy #$01
|
|
sta ($02),y
|
|
|
|
ldy $04
|
|
lda $0292,y
|
|
|
|
ldy $06
|
|
ora $DE22,y
|
|
|
|
ldy #$02
|
|
sta ($02),y
|
|
|
|
jmp BuildSpriteX
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DB97
|
|
;------------------------------------------------------------------------------
|
|
|
|
BuildSpriteClass2:
|
|
lda $028C,y
|
|
asl
|
|
asl
|
|
clc
|
|
adc $05
|
|
tay
|
|
|
|
sta $06
|
|
|
|
lda $DD22,y
|
|
|
|
ldy #$01
|
|
sta ($02),y
|
|
|
|
ldy $04
|
|
lda $0292,y
|
|
|
|
ldy $06
|
|
ora EntitySpriteCoordinateOffsets,y
|
|
|
|
ldy #$02
|
|
sta ($02),y
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DBB7
|
|
; Construct byte 3 of the render record.
|
|
;------------------------------------------------------------------------------
|
|
|
|
BuildSpriteX:
|
|
ldy #$00
|
|
|
|
lda ($00),y
|
|
bne AdjustSpriteX
|
|
|
|
lda #$FF
|
|
bne StoreSpriteX
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DBC0
|
|
;------------------------------------------------------------------------------
|
|
|
|
AdjustSpriteX:
|
|
clc
|
|
adc EntitySpriteCoordinateOffsets+1,x
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DBC4
|
|
;------------------------------------------------------------------------------
|
|
|
|
StoreSpriteX:
|
|
ldy #$03
|
|
sta ($02),y
|
|
|
|
; Advance destination by one 4-byte record.
|
|
lda $02
|
|
clc
|
|
adc #$04
|
|
sta $02
|
|
|
|
inc $05
|
|
|
|
inx
|
|
inx
|
|
|
|
cpx #$08
|
|
beq BuildSpriteBufferNextSource
|
|
|
|
jmp BuildSpriteBufferNextSprite
|
|
|
|
|
|
BuildSpriteBufferNextSource:
|
|
lda $00
|
|
clc
|
|
adc #$04
|
|
sta $00
|
|
|
|
inc $04
|
|
|
|
lda $04
|
|
cmp #$06
|
|
beq BuildSpriteBufferDone
|
|
|
|
jmp BuildSpriteBufferNextGroup
|
|
|
|
BuildSpriteBufferDone:
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $DBEE-$DC3F: Gameplay Entity Render Lookup Data
|
|
;
|
|
; Local:
|
|
; Lookup data used by BuildEntitySpriteBuffer.
|
|
;
|
|
; The routine constructs an index from:
|
|
;
|
|
; ($028C,Y * 4) + $05
|
|
;
|
|
; and uses that value to index this region for render-facing object data.
|
|
;
|
|
; Global:
|
|
; Supplies tile/state values used when rebuilding the four-byte page-$07
|
|
; entity records.
|
|
;
|
|
; Notes:
|
|
; The region contains strongly patterned groups of repeated values, but the
|
|
; complete set of consumers has not yet been decoded. Keep this as one
|
|
; contiguous table during the first pass rather than assigning speculative
|
|
; semantic subdivisions.
|
|
;==============================================================================
|
|
|
|
EntitySpriteTileTable0:
|
|
|
|
; $DBEE-$DBFD
|
|
.byte $4C,$4C,$4C,$4C
|
|
.byte $00,$00,$00,$00
|
|
.byte $04,$04,$03,$03
|
|
.byte $08,$08,$07,$07
|
|
|
|
; $DBFE-$DC0D
|
|
.byte $02,$01,$02,$01
|
|
.byte $06,$05,$06,$05
|
|
.byte $03,$03,$04,$04
|
|
.byte $07,$07,$08,$08
|
|
|
|
; $DC0E-$DC1D
|
|
.byte $01,$02,$01,$02
|
|
.byte $05,$06,$05,$06
|
|
.byte $18,$18,$19,$19
|
|
.byte $18,$18,$1A,$1A
|
|
|
|
; $DC1E-$DC2D
|
|
.byte $1B,$1C,$1D,$1F
|
|
.byte $1B,$1C,$1E,$20
|
|
.byte $21,$21,$22,$22
|
|
.byte $21,$21,$23,$23
|
|
|
|
; $DC2E-$DC3D
|
|
.byte $1C,$1B,$1F,$1D
|
|
.byte $1C,$1B,$20,$1E
|
|
.byte $00,$00,$00,$00
|
|
.byte $09,$09,$0A,$0A
|
|
|
|
; $DC3E-$DC3F
|
|
.byte $0B,$0B
|
|
|
|
;==============================================================================
|
|
; $DC40-$DCED: Gameplay Entity Render Lookup Data, Continued
|
|
;
|
|
; Local:
|
|
; Additional render/tile lookup values associated with the table beginning
|
|
; at $DBEE.
|
|
;
|
|
; The data is strongly grouped into repeated pairs and four-byte patterns,
|
|
; consistent with direction/animation variants used by the four-byte entity
|
|
; render records.
|
|
;
|
|
; Global:
|
|
; Part of the graphics-facing lookup data used when gameplay state is
|
|
; converted into page-$07 render records.
|
|
;
|
|
; Notes:
|
|
; Keep these bytes as a contiguous data block for now. $DCEE is separately
|
|
; referenced by BuildEntitySpriteBuffer and therefore marks the next
|
|
; known lookup-table boundary.
|
|
;==============================================================================
|
|
EntityRenderLookupDC40:
|
|
; $DC40-$DC4F
|
|
.byte $0C,$0C,$4C,$4C
|
|
.byte $0D,$0D,$4C,$4C
|
|
.byte $0E,$0E,$4C,$4C
|
|
.byte $0F,$0F,$4C,$4C
|
|
|
|
; $DC50-$DC5F
|
|
.byte $10,$10,$4C,$4C
|
|
.byte $11,$11,$4C,$4C
|
|
.byte $12,$12,$4C,$4C
|
|
.byte $13,$13,$14,$15
|
|
|
|
; $DC60-$DC6F
|
|
.byte $16,$17,$4C,$4C
|
|
.byte $4C,$4C,$24,$24
|
|
.byte $25,$25,$24,$24
|
|
.byte $26,$26,$27,$27
|
|
|
|
; $DC70-$DC7F
|
|
.byte $4C,$4C,$28,$29
|
|
.byte $2A,$2B,$2C,$2C
|
|
.byte $2D,$2D,$29,$28
|
|
.byte $2B,$2A,$90,$91
|
|
|
|
; $DC80-$DC8F
|
|
.byte $92,$93,$94,$95
|
|
.byte $96,$97,$98,$99
|
|
.byte $9A,$9B,$9C,$9D
|
|
.byte $9E,$9F,$A0,$A1
|
|
|
|
; $DC90-$DC9F
|
|
.byte $A2,$A3,$A4,$A5
|
|
.byte $A6,$A7,$A8,$A9
|
|
.byte $AA,$AB,$AC,$AD
|
|
.byte $AE,$AF,$2E,$2F
|
|
|
|
; $DCA0-$DCAF
|
|
.byte $30,$31,$32,$2F
|
|
.byte $33,$31,$34,$2F
|
|
.byte $35,$31,$36,$2F
|
|
.byte $37,$31,$38,$2F
|
|
|
|
; $DCB0-$DCBF
|
|
.byte $39,$31,$3A,$2F
|
|
.byte $3B,$31,$3C,$2F
|
|
.byte $3D,$31,$3E,$3F
|
|
.byte $40,$41,$42,$3F
|
|
|
|
; $DCC0-$DCCF
|
|
.byte $43,$41,$44,$45
|
|
.byte $46,$47,$48,$45
|
|
.byte $49,$47,$4A,$45
|
|
.byte $4B,$47,$4D,$4E
|
|
|
|
; $DCD0-$DCDF
|
|
.byte $4F,$50,$4E,$4D
|
|
.byte $50,$4F,$4F,$50
|
|
.byte $4D,$4E,$50,$4F
|
|
.byte $4E,$4D,$4D,$4E
|
|
|
|
; $DCE0-$DCED
|
|
.byte $4F,$51,$4E,$52
|
|
.byte $53,$54,$4F,$51
|
|
.byte $4D,$4E,$53,$54
|
|
.byte $4E,$52
|
|
|
|
;==============================================================================
|
|
; $DCEE-$DD21: Gameplay Entity Render Lookup Table
|
|
;
|
|
; Local:
|
|
; Lookup values used by BuildEntitySpriteBuffer in the status-class
|
|
; path beginning at $DB74.
|
|
;
|
|
; The index is constructed from:
|
|
;
|
|
; ($028C,Y * 4) + $05
|
|
;
|
|
; and the selected byte is written as byte 1 of the generated page-$07
|
|
; render record.
|
|
;
|
|
; Global:
|
|
; Supplies graphics/tile values for one class of gameplay entity render
|
|
; states.
|
|
;
|
|
; Notes:
|
|
; The repeated $4C values and four-byte groupings strongly suggest
|
|
; animation/direction variants. Keep the table as raw values during this
|
|
; first pass.
|
|
;
|
|
; $DD22 is separately referenced by the render-data builder and therefore
|
|
; marks the next lookup-table boundary.
|
|
;==============================================================================
|
|
|
|
EntitySpriteTileTable2:
|
|
|
|
; $DCEE-$DCFD
|
|
.byte $55,$4C,$56,$4C
|
|
.byte $56,$4C,$55,$4C
|
|
.byte $4C,$57,$4C,$58
|
|
.byte $4C,$59,$4C,$5A
|
|
|
|
; $DCFE-$DD0D
|
|
.byte $4C,$5B,$4C,$5C
|
|
.byte $4C,$4C,$4C,$5D
|
|
.byte $18,$18,$19,$5E
|
|
.byte $60,$61,$19,$5E
|
|
|
|
; $DD0E-$DD1D
|
|
.byte $1B,$1C,$1D,$62
|
|
.byte $1B,$1C,$1E,$63
|
|
.byte $64,$65,$66,$67
|
|
.byte $64,$65,$68,$69
|
|
|
|
; $DD1E-$DD21
|
|
.byte $6A,$6B,$4C,$4C
|
|
|
|
|
|
|
|
;==============================================================================
|
|
; $DD22-$DE21: Gameplay Entity Render Attribute Lookup
|
|
;
|
|
; Local:
|
|
; 256-byte lookup table used by BuildEntitySpriteBuffer.
|
|
;
|
|
; Entries are predominantly:
|
|
;
|
|
; $00
|
|
; $40
|
|
; $80
|
|
; $C0
|
|
;
|
|
; These values occupy bits 6-7 and are ORed with the corresponding value
|
|
; from $0292+ before being written as byte 2 of a page-$07 four-byte render
|
|
; record.
|
|
;
|
|
; Global:
|
|
; Supplies upper-bit render attributes for gameplay entities across their
|
|
; various states, animation phases and directional variants.
|
|
;
|
|
; Notes:
|
|
; The table is exactly $100 bytes long:
|
|
;
|
|
; $DD22-$DE21
|
|
;
|
|
; $DE22 is independently referenced by another render-data path and therefore
|
|
; marks the next table boundary.
|
|
;==============================================================================
|
|
|
|
EntitySpriteAttributeTable0:
|
|
|
|
; $DD22-$DD31
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$40,$80,$C0
|
|
.byte $80,$C0,$80,$C0
|
|
.byte $80,$C0,$80,$C0
|
|
|
|
; $DD32-$DD41
|
|
.byte $00,$00,$80,$80
|
|
.byte $00,$00,$80,$80
|
|
.byte $00,$40,$00,$40
|
|
.byte $00,$40,$00,$40
|
|
|
|
; $DD42-$DD51
|
|
.byte $40,$40,$C0,$C0
|
|
.byte $40,$40,$C0,$C0
|
|
.byte $00,$40,$00,$40
|
|
.byte $00,$40,$00,$40
|
|
|
|
; $DD52-$DD61
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$40,$00,$40
|
|
.byte $00,$40,$00,$40
|
|
|
|
; $DD62-$DD71
|
|
.byte $40,$40,$40,$40
|
|
.byte $40,$40,$40,$40
|
|
.byte $00,$40,$80,$C0
|
|
.byte $00,$40,$00,$40
|
|
|
|
; $DD72-$DD81
|
|
.byte $00,$40,$00,$40
|
|
.byte $00,$00,$00,$40
|
|
.byte $00,$00,$00,$40
|
|
.byte $00,$00,$00,$40
|
|
|
|
; $DD82-$DD91
|
|
.byte $00,$00,$00,$40
|
|
.byte $00,$00,$00,$40
|
|
.byte $00,$00,$00,$40
|
|
.byte $00,$00,$00,$40
|
|
|
|
; $DD92-$DDA1
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$40,$00,$40
|
|
.byte $00,$40,$00,$40
|
|
|
|
; $DDA2-$DDB1
|
|
.byte $00,$40,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$40,$00,$40
|
|
.byte $40,$40,$40,$40
|
|
|
|
; $DDB2-$DDC1
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
|
|
; $DDC2-$DDD1
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
|
|
; $DDD2-$DDE1
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
|
|
; $DDE2-$DDF1
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
|
|
; $DDF2-$DE01
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
|
|
; $DE02-$DE11
|
|
.byte $00,$00,$00,$00
|
|
.byte $40,$40,$00,$40
|
|
.byte $80,$00,$80,$80
|
|
.byte $00,$C0,$C0,$C0
|
|
|
|
; $DE12-$DE21
|
|
.byte $00,$00,$00,$00
|
|
.byte $40,$00,$00,$00
|
|
.byte $80,$80,$80,$80
|
|
.byte $80,$80,$C0,$80
|
|
|
|
;==============================================================================
|
|
; $DE22-$DE55: Secondary Gameplay Entity Render Attribute Lookup
|
|
;
|
|
; Local:
|
|
; Lookup data used by BuildEntitySpriteBuffer in the path beginning
|
|
; at $DB74.
|
|
;
|
|
; Values from this table are ORed with the corresponding state value from
|
|
; $0292+ and written as byte 2 of a four-byte page-$07 render record.
|
|
;
|
|
; Global:
|
|
; Supplies upper-bit render attributes for one class of gameplay entity
|
|
; render states.
|
|
;
|
|
; Notes:
|
|
; As with the larger table at $DD22, the significant nonzero values occupy
|
|
; the upper bits, primarily $40 and $80.
|
|
;
|
|
; EntitySpriteCoordinateOffsets is separately referenced as another
|
|
; lookup-table base and therefore marks the next known boundary.
|
|
;==============================================================================
|
|
|
|
EntitySpriteAttributeTable1:
|
|
|
|
; $DE22-$DE31
|
|
.byte $00,$00,$00,$00
|
|
.byte $80,$00,$80,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
|
|
; $DE32-$DE41
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$40,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
|
|
; $DE42-$DE51
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
.byte $00,$00,$00,$00
|
|
|
|
; $DE52-$DE55
|
|
.byte $00,$00,$00,$00
|
|
|
|
;==============================================================================
|
|
; $DE56-$DE5D: Entity Render Coordinate Adjustment Table
|
|
;
|
|
; Local:
|
|
; Eight coordinate-adjustment bytes used by
|
|
; BuildEntitySpriteBuffer.
|
|
;
|
|
; X takes even values $00,$02,$04,$06, and the routine reads:
|
|
;
|
|
; EntitySpriteCoordinateOffsets,X
|
|
; EntitySpriteCoordinateOffsets+1,X
|
|
;
|
|
; giving four byte pairs.
|
|
;
|
|
; Global:
|
|
; Adjusts source coordinates when building page-$07 four-byte render
|
|
; records.
|
|
;==============================================================================
|
|
|
|
EntitySpriteCoordinateOffsets:
|
|
.byte $03,$F4
|
|
.byte $03,$FC
|
|
.byte $0B,$F4
|
|
.byte $0B,$FC
|
|
|
|
;==============================================================================
|
|
; $DE5E-$DE7D: Periodic Four-Entry State Update
|
|
;
|
|
; Local:
|
|
; Once every 16 frames, updates the four entries at $6C-$6F:
|
|
;
|
|
; $07 -> remains $07
|
|
; $01 -> becomes $02
|
|
; anything else -> becomes $01
|
|
;==============================================================================
|
|
|
|
UpdatePeriodicFourEntryState:
|
|
lda $4B
|
|
and #$0F
|
|
beq @DE65
|
|
|
|
rts
|
|
|
|
|
|
@DE65:
|
|
tax
|
|
|
|
|
|
@DE66:
|
|
lda $6C,x
|
|
cmp #$07
|
|
beq @DE76
|
|
|
|
cmp #$01
|
|
bne @DE74
|
|
|
|
lda #$02
|
|
bne @DE76
|
|
|
|
|
|
@DE74:
|
|
lda #$01
|
|
|
|
|
|
@DE76:
|
|
sta $6C,x
|
|
|
|
inx
|
|
cpx #$04
|
|
bne @DE66
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $DE7E-$DF6B: Gameplay PPU / Display Update Processor
|
|
;
|
|
; Local:
|
|
; Processes several gameplay display-update buffers and writes their data
|
|
; directly to the PPU.
|
|
;
|
|
; Handles:
|
|
; - Six-byte update block at $023F using destination $026B/$026C.
|
|
; - Six-byte update block at $0245 using destination $0272/$0273.
|
|
; - Three-byte periodic update at $026F-$0271.
|
|
; - Four state values at $6C-$6F written to PPU addresses in the table
|
|
; beginning at GameplayStatusPpuAddressTable.
|
|
; - Generic PPU command stream beginning at $024B.
|
|
;
|
|
; Global:
|
|
; Central gameplay display-update routine.
|
|
;
|
|
; Notes:
|
|
; UpdateAnimatedGameplayPpuFields at $DF15 is a shared entry point reached from
|
|
; several earlier control-flow paths and is therefore a global label rather
|
|
; than a ca65 cheap-local label.
|
|
;==============================================================================
|
|
|
|
FlushGameplayPpuUpdates:
|
|
lda $48
|
|
beq @DE85
|
|
|
|
jmp UpdateAnimatedGameplayPpuFields
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DE85
|
|
; Process the update block beginning at $023F.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@DE85:
|
|
lda $023F
|
|
cmp #$FF
|
|
beq @DEB5
|
|
|
|
lda PPUSTATUS
|
|
|
|
lda $026B
|
|
sta PPUADDR
|
|
|
|
lda $026C
|
|
sta PPUADDR
|
|
|
|
ldy #$00
|
|
|
|
|
|
@DE9B:
|
|
lda $023F,y
|
|
sta PPUDATA
|
|
|
|
iny
|
|
cpy #$06
|
|
bne @DE9B
|
|
|
|
lda #$30
|
|
sta PPUDATA
|
|
|
|
lda #$FF
|
|
sta $023F
|
|
|
|
bne @DEE2
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DEB5
|
|
; Process the update block beginning at $0245.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@DEB5:
|
|
lda $0245
|
|
cmp #$FF
|
|
beq @DEE2
|
|
|
|
lda PPUSTATUS
|
|
|
|
lda $0272
|
|
sta PPUADDR
|
|
|
|
lda $0273
|
|
sta PPUADDR
|
|
|
|
ldy #$00
|
|
|
|
|
|
@DECB:
|
|
lda $0245,y
|
|
sta PPUDATA
|
|
|
|
iny
|
|
cpy #$06
|
|
bne @DECB
|
|
|
|
lda #$30
|
|
sta PPUDATA
|
|
|
|
lda #$FF
|
|
sta $0245
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DEE2
|
|
; Periodic three-byte display update.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@DEE2:
|
|
lda $4B
|
|
and #$07
|
|
bne UpdateAnimatedGameplayPpuFields
|
|
|
|
lda PPUSTATUS
|
|
|
|
lda $026D
|
|
sta PPUADDR
|
|
|
|
lda $026E
|
|
sta PPUADDR
|
|
|
|
ldx #$00
|
|
|
|
lda $4B
|
|
and #$18
|
|
beq @DF05
|
|
|
|
|
|
@DEFB:
|
|
lda $026F,x
|
|
sta PPUDATA
|
|
|
|
inx
|
|
cpx #$03
|
|
bne @DEFB
|
|
|
|
beq UpdateAnimatedGameplayPpuFields
|
|
|
|
|
|
@DF05:
|
|
lda #$20
|
|
|
|
|
|
@DF07:
|
|
sta PPUDATA
|
|
|
|
inx
|
|
cpx #$03
|
|
bne @DF07
|
|
|
|
|
|
;==============================================================================
|
|
; $DF15: Shared frame-dependent display update entry
|
|
;==============================================================================
|
|
UpdateAnimatedGameplayPpuFields:
|
|
lda $4B
|
|
and #$01
|
|
beq @DF42
|
|
|
|
ldy #$00
|
|
ldx #$00
|
|
|
|
lda $46
|
|
and $47
|
|
beq @DF27
|
|
|
|
ldy #$08
|
|
|
|
|
|
@DF27:
|
|
lda PPUSTATUS
|
|
|
|
lda GameplayStatusPpuAddressTable,y
|
|
sta PPUADDR
|
|
|
|
lda GameplayStatusPpuAddressTable+1,y
|
|
sta PPUADDR
|
|
|
|
lda $6C,x
|
|
sta PPUDATA
|
|
|
|
iny
|
|
iny
|
|
|
|
inx
|
|
cpx #$04
|
|
bne @DF27
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $DF42
|
|
; Process the $024B command stream.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@DF42:
|
|
lda PPUSTATUS
|
|
|
|
ldy #$FF
|
|
|
|
|
|
@DF46:
|
|
iny
|
|
|
|
lda $024B,y
|
|
cmp #$FF
|
|
beq @DF66
|
|
|
|
sta PPUADDR
|
|
|
|
iny
|
|
|
|
lda $024B,y
|
|
sta PPUADDR
|
|
|
|
|
|
@DF55:
|
|
iny
|
|
|
|
lda $024B,y
|
|
beq @DF46
|
|
|
|
cmp #$FF
|
|
beq @DF66
|
|
|
|
sta PPUDATA
|
|
|
|
bne @DF55
|
|
|
|
|
|
@DF66:
|
|
sta $024B
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $DF6C-$DF7B: Gameplay PPU Address Table
|
|
;
|
|
; Local:
|
|
; Eight PPU addresses stored in high-byte/low-byte order.
|
|
;
|
|
; When ($46 & $47) == 0, the first four addresses are used.
|
|
; Otherwise the second four addresses are used.
|
|
;
|
|
; Values from $6C-$6F are written to the selected addresses.
|
|
;
|
|
; Notes:
|
|
; These must remain .byte pairs. Using .word would reverse each address
|
|
; because ca65 emits words little-endian.
|
|
;==============================================================================
|
|
|
|
GameplayStatusPpuAddressTable:
|
|
.byte $20,$B4
|
|
.byte $20,$A2
|
|
.byte $22,$D4
|
|
.byte $22,$C2
|
|
|
|
.byte $28,$B4
|
|
.byte $28,$A2
|
|
.byte $2A,$D4
|
|
.byte $2A,$C2
|
|
|
|
;==============================================================================
|
|
; $DF7C-$E042: Gameplay Tile / State Update
|
|
;
|
|
; Local:
|
|
; Processes selected values of $022A, updates $6C-$6F, emits a command into
|
|
; the $024B display-command buffer, updates $6A and related gameplay state,
|
|
; and may transfer control to $E0E6.
|
|
;
|
|
; Global:
|
|
; Called during the normal gameplay frame-update chain.
|
|
;
|
|
; Notes:
|
|
; $E043 and $E044 are lookup-table bases used near the end of this routine.
|
|
; Those bytes are data and begin immediately after the final JMP at $E040.
|
|
;==============================================================================
|
|
|
|
UpdateGameplayTileState:
|
|
ldx #$00
|
|
|
|
lda $022A
|
|
cmp #$09
|
|
beq $DFBB
|
|
|
|
inx
|
|
inx
|
|
|
|
cmp #$03
|
|
beq $DFBB
|
|
|
|
cmp #$01
|
|
beq @DF94
|
|
|
|
cmp #$02
|
|
beq @DF94
|
|
|
|
rts
|
|
|
|
|
|
@DF94:
|
|
jsr $E063
|
|
|
|
lda $1A
|
|
sta $02
|
|
|
|
lda $1C
|
|
sta $03
|
|
|
|
jsr $E263
|
|
|
|
ldx #$00
|
|
|
|
lda $03
|
|
and #$07
|
|
beq @DFAD
|
|
|
|
inx
|
|
inx
|
|
|
|
|
|
@DFAD:
|
|
lda $02
|
|
and #$0F
|
|
cmp #$04
|
|
beq @DFB6
|
|
|
|
inx
|
|
|
|
@DFB6:
|
|
lda #$07
|
|
sta $6C,x
|
|
|
|
@DFBB:
|
|
ldx #$04
|
|
lda #$00
|
|
sta $D5
|
|
sta $D6
|
|
|
|
lda $1A
|
|
sta $02
|
|
|
|
lda $1C
|
|
sta $03
|
|
|
|
jsr $E263
|
|
|
|
ldy #$FF
|
|
|
|
@DFCE:
|
|
iny
|
|
|
|
lda $024B,y
|
|
cmp #$FF
|
|
bne @DFCE
|
|
|
|
tya
|
|
beq @DFDC
|
|
|
|
lda #$00
|
|
sta $024B,y
|
|
|
|
iny
|
|
|
|
|
|
@DFDC:
|
|
lda $03
|
|
sta $024B,y
|
|
|
|
iny
|
|
|
|
lda $02
|
|
sta $024B,y
|
|
|
|
iny
|
|
|
|
lda $E043,x
|
|
sta $024B,y
|
|
|
|
iny
|
|
|
|
lda #$FF
|
|
sta $024B,y
|
|
|
|
lda #$07
|
|
sta $022A
|
|
|
|
lda $E044,x
|
|
sta $DC
|
|
|
|
dec $6A
|
|
bne @E012
|
|
|
|
lda #$0C
|
|
sta $3F
|
|
|
|
lda #$00
|
|
sta $87
|
|
|
|
lda #$48
|
|
sta $4C
|
|
|
|
|
|
@E012:
|
|
lda $6A
|
|
|
|
cmp #$37
|
|
beq @E01C
|
|
|
|
cmp #$86
|
|
bne $E036
|
|
|
|
@E01C:
|
|
lda #$0A
|
|
sta $D7
|
|
|
|
lda #$3C
|
|
sta $D8
|
|
|
|
ldy $93
|
|
|
|
lda GameplayStateValueLookup,y
|
|
sta $37
|
|
|
|
lda #$03
|
|
sta $3D
|
|
|
|
lda #$60
|
|
sta $2E
|
|
|
|
lda #$80
|
|
sta $30
|
|
|
|
lda $6A
|
|
and #$01
|
|
tay
|
|
|
|
lda #$01
|
|
sta $0604,y
|
|
|
|
jmp $E0E6
|
|
|
|
;==============================================================================
|
|
; $E043-$E048: Gameplay Tile-State Lookup
|
|
;
|
|
; Local:
|
|
; Used by UpdateGameplayTileState through overlapping indexed reads at
|
|
; $E043,X and $E044,X.
|
|
;==============================================================================
|
|
|
|
TileEventDisplayLookup:
|
|
.byte $08,$01,$07,$01,$07,$05
|
|
|
|
;==============================================================================
|
|
; $E049-$E05A: Activate First Available State Slot
|
|
;
|
|
; Local:
|
|
; Scans the three even-indexed entries:
|
|
;
|
|
; $BA,$BC,$BE
|
|
;
|
|
; for the first zero value. If one is found, changes it to $02 and returns.
|
|
; If all three are already active/nonzero, returns without modification.
|
|
;==============================================================================
|
|
|
|
ActivateNextStateSlotE049:
|
|
ldx #$00
|
|
|
|
@E04B:
|
|
lda $BA,x
|
|
bne @E054
|
|
|
|
lda #$02
|
|
sta $BA,x
|
|
|
|
rts
|
|
|
|
|
|
@E054:
|
|
inx
|
|
inx
|
|
|
|
cpx #$06
|
|
bne @E04B
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $E05B-$E062: Gameplay State Value Lookup
|
|
;
|
|
; Local:
|
|
; Eight sequential values indexed by $93 and copied into $37 during
|
|
; gameplay-state transitions.
|
|
;==============================================================================
|
|
|
|
GameplayStateValueLookup:
|
|
.byte $24,$25,$26,$27,$28,$29,$2A,$2B
|
|
|
|
;==============================================================================
|
|
; $E063-$E0E5: Initialize / Adjust Entity Direction State
|
|
;
|
|
; Local:
|
|
; Initializes several gameplay variables and scans all four entity slots.
|
|
;
|
|
; Initialization:
|
|
;
|
|
; if $8C == 0:
|
|
; $8A = $1E
|
|
;
|
|
; $89 = $00
|
|
; $88 = $0F
|
|
; $D9 = $00
|
|
;
|
|
; The low two bits of $39-$3C are normalized to $01, preserving the upper
|
|
; six bits.
|
|
;
|
|
; Palette/update values are installed at:
|
|
;
|
|
; $02AE = $11
|
|
; $02A9 = $0F
|
|
;
|
|
; Then the four entity structures are examined. For eligible entities in
|
|
; primary state $04, a candidate secondary direction is calculated from
|
|
; $B9,X and accepted when coordinate alignment and path-map checks permit it.
|
|
;
|
|
; Global:
|
|
; Called from UpdateGameplayTileState before that routine derives its
|
|
; direction/tile update.
|
|
;
|
|
; Notes:
|
|
; $00/$01 and $02/$03 are parallel indirect pointers.
|
|
; X advances through entity offsets $00,$02,$04,$06.
|
|
; $04 temporarily holds a candidate direction value.
|
|
;==============================================================================
|
|
InitializeEntityDirectionState:
|
|
lda $8C
|
|
bne @E06D
|
|
|
|
lda #$1E
|
|
sta $8A
|
|
|
|
lda #$00
|
|
|
|
|
|
@E06D:
|
|
sta $89
|
|
|
|
lda #$0F
|
|
sta $88
|
|
|
|
ldx #$03
|
|
|
|
@E075:
|
|
lda $39,x
|
|
and #$FC
|
|
ora #$01
|
|
sta $39,x
|
|
|
|
dex
|
|
bpl @E075
|
|
|
|
lda #$11
|
|
sta $02AE
|
|
|
|
lda #$0F
|
|
sta $02A9
|
|
|
|
lda #$00
|
|
sta $D9
|
|
|
|
ldx #$00
|
|
|
|
lda #$2F
|
|
sta $00
|
|
|
|
lda #$02
|
|
sta $01
|
|
|
|
lda #$1E
|
|
sta $02
|
|
|
|
lda #$00
|
|
sta $03
|
|
|
|
@E09E:
|
|
lda #$0F
|
|
cmp $88
|
|
beq @E0AA
|
|
|
|
lda $D2
|
|
bne @E0D1
|
|
|
|
@E0AA:
|
|
lda $B8,x
|
|
cmp #$04
|
|
bne @E0D1
|
|
|
|
lda $B9,x
|
|
clc
|
|
adc #$02
|
|
and #$03
|
|
sta $04
|
|
|
|
ldy #$00
|
|
|
|
lda ($02),y
|
|
|
|
ldy #$02
|
|
|
|
ora ($02),y
|
|
and #$07
|
|
bne @E0CD
|
|
|
|
ldy $04
|
|
|
|
lda ($00),y
|
|
and #$F8
|
|
bne @E0D1
|
|
|
|
|
|
@E0CD:
|
|
lda $04
|
|
sta $B9,x
|
|
|
|
|
|
@E0D1:
|
|
lda $00
|
|
clc
|
|
adc #$04
|
|
sta $00
|
|
|
|
lda $02
|
|
clc
|
|
adc #$04
|
|
sta $02
|
|
|
|
inx
|
|
inx
|
|
|
|
cpx #$08
|
|
bne @E0AA
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $E0E6-$E1BF: Score / State Display Update
|
|
;
|
|
; Updates the six decimal-like values at $70-$75 using increments at $DC-$E1,
|
|
; converts the result into display characters at $023F, handles progression
|
|
; state associated with $6B/$73/$67, appends display commands to $024B, then
|
|
; compares and updates the saved values at $61-$66.
|
|
;==============================================================================
|
|
|
|
UpdateScoreDisplay:
|
|
lda $48
|
|
beq @E0EB
|
|
|
|
rts
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E0EB
|
|
; Add $DC-$E1 into the six values at $70-$75 using decimal carry handling.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E0EB:
|
|
ldy #$00
|
|
|
|
lda #$06
|
|
sta $00
|
|
|
|
clc
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E0F2
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E0F2:
|
|
lda $70,y
|
|
adc $DC,y
|
|
sta $70,y
|
|
|
|
cmp #$0A
|
|
bcc @E105
|
|
|
|
sbc #$0A
|
|
sta $70,y
|
|
|
|
sec
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E105
|
|
; Clear the consumed increment and continue through all six entries.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E105:
|
|
lda #$00
|
|
sta $DC,y
|
|
|
|
iny
|
|
|
|
dec $00
|
|
bne @E0F2
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E10F
|
|
; Convert the six numeric values into display/tile values.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ldx #$00
|
|
|
|
dey
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E112
|
|
; Suppress leading zero-style values by replacing $30 with $20.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E112:
|
|
lda $70,y
|
|
jsr $E1CE
|
|
|
|
cmp #$30
|
|
bne @E12B
|
|
|
|
lda #$20
|
|
sta $023F,x
|
|
|
|
inx
|
|
|
|
dey
|
|
bne @E112
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E125
|
|
; Convert remaining digits without leading-space suppression.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E125:
|
|
lda $70,y
|
|
jsr $E1CE
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E12B
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E12B:
|
|
sta $023F,x
|
|
|
|
inx
|
|
|
|
dey
|
|
bpl @E125
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E132
|
|
; Progression check.
|
|
;------------------------------------------------------------------------------
|
|
|
|
lda $6B
|
|
bne @E196
|
|
|
|
lda #$01
|
|
cmp $73
|
|
bne @E196
|
|
|
|
lda #$01
|
|
sta $6B
|
|
sta $0602
|
|
|
|
inc $67
|
|
|
|
lda $67
|
|
sec
|
|
sbc #$02
|
|
asl
|
|
sta $00
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Locate the $FF terminator of the $024B display-command stream.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ldy #$FF
|
|
|
|
|
|
@E14D:
|
|
iny
|
|
|
|
lda $024B,y
|
|
cmp #$FF
|
|
bne @E14D
|
|
|
|
tya
|
|
beq @E15D
|
|
|
|
lda #$00
|
|
sta $024B,y
|
|
|
|
iny
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E15D
|
|
; Select a display offset according to $46 & $47.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E15D:
|
|
lda $46
|
|
and $47
|
|
beq @E165
|
|
|
|
lda #$08
|
|
|
|
|
|
@E165:
|
|
sta $01
|
|
|
|
ldx #$00
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E169
|
|
; Append two five-byte command templates from $E1C0.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E169:
|
|
lda ScorePpuCommandTemplates,x
|
|
clc
|
|
adc $01
|
|
sta $024B,y
|
|
|
|
iny
|
|
inx
|
|
|
|
lda ScorePpuCommandTemplates,x
|
|
clc
|
|
adc $00
|
|
sta $024B,y
|
|
|
|
lda #$03
|
|
sta $02
|
|
|
|
|
|
@E182:
|
|
iny
|
|
inx
|
|
|
|
lda ScorePpuCommandTemplates,x
|
|
sta $024B,y
|
|
|
|
dec $02
|
|
bne @E182
|
|
|
|
iny
|
|
inx
|
|
|
|
cpx #$0A
|
|
bne @E169
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E196
|
|
; Compare saved values $61-$66 with current values $70-$75.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E196:
|
|
ldy #$05
|
|
|
|
|
|
@E198:
|
|
lda $61,y
|
|
cmp $70,y
|
|
beq @E1A3
|
|
|
|
bcc @E1A7
|
|
|
|
rts
|
|
|
|
|
|
@E1A3:
|
|
dey
|
|
bpl @E198
|
|
|
|
rts
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E1A7
|
|
; Copy display buffer $023F-$0244 to $0245-$024A.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E1A7:
|
|
ldx #$00
|
|
|
|
|
|
@E1A9:
|
|
lda $023F,x
|
|
sta $0245,x
|
|
|
|
inx
|
|
cpx #$06
|
|
bne @E1A9
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Copy current values $70-$75 into saved values $61-$66.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ldx #$00
|
|
|
|
|
|
@E1B4:
|
|
lda $70,x
|
|
sta $61,x
|
|
|
|
inx
|
|
cpx #$06
|
|
bne @E1B4
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $E1C0-$E1C9: Score Display Command Table
|
|
;==============================================================================
|
|
|
|
ScorePpuCommandTemplates:
|
|
.byte $23,$17,$3C,$3D,$00
|
|
.byte $23,$37,$3E,$3F,$FF
|
|
|
|
;==============================================================================
|
|
; $E1CA-$E1D9: Convert High Nibble to Display Character
|
|
;
|
|
; Input:
|
|
; A = packed numeric value
|
|
;
|
|
; Output:
|
|
; A = display character code
|
|
;
|
|
; Behavior:
|
|
; Uses the original high nibble:
|
|
;
|
|
; $0-$9 -> $30-$39
|
|
; $A-$F -> $40-$45
|
|
;
|
|
; Global:
|
|
; Called by UpdateScoreDisplay while building the display buffer at
|
|
; $023F.
|
|
;==============================================================================
|
|
|
|
ConvertNibbleToDigitTile:
|
|
lsr
|
|
lsr
|
|
lsr
|
|
lsr
|
|
|
|
and #$0F
|
|
|
|
cmp #$0A
|
|
bcs @HexDigit
|
|
|
|
adc #$30
|
|
rts
|
|
|
|
@HexDigit:
|
|
adc #$36
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $E1DA-$E262: Rebuild Gameplay Coordinate/Map Buffer
|
|
;
|
|
; Local:
|
|
; Converts the primary coordinate pair $1A/$1C through the helper at $E263
|
|
; and stores the result at $0200/$0201.
|
|
;
|
|
; Then iterates through gameplay coordinate structures beginning at $1A,
|
|
; advancing X by four each iteration.
|
|
;
|
|
; For each iteration:
|
|
; - Converts the current $1A+X/$1C+X pair through $E263.
|
|
; - Initializes working 16-bit values in $12-$15.
|
|
; - Calls helpers at $E2D4 and $E2C6.
|
|
; - Emits two groups of four bytes into the buffer at $0202+.
|
|
;
|
|
; The output loop terminates when Y reaches $28.
|
|
;
|
|
; Global:
|
|
; Called after gameplay collision/entity-state changes to rebuild a
|
|
; 40-byte coordinate/map-facing buffer in page $02.
|
|
;
|
|
; Notes:
|
|
; $E263 is the next known helper and is already called elsewhere.
|
|
;==============================================================================
|
|
|
|
BuildNearbyTileAddressBuffer:
|
|
lda $1A
|
|
sta $02
|
|
|
|
lda $1C
|
|
sta $03
|
|
|
|
jsr $E263
|
|
|
|
lda $03
|
|
sta $0200
|
|
|
|
lda $02
|
|
sta $0201
|
|
|
|
ldx #$00
|
|
ldy #$00
|
|
|
|
|
|
@E1F2:
|
|
lda $1A,x
|
|
sta $02
|
|
|
|
lda $1C,x
|
|
sta $03
|
|
|
|
jsr $E263
|
|
|
|
lda #$20
|
|
sta $14
|
|
|
|
lda #$00
|
|
sta $15
|
|
|
|
lda $02
|
|
sta $12
|
|
|
|
lda $03
|
|
sta $13
|
|
|
|
jsr $E2D4
|
|
|
|
lda $13
|
|
sta $0202,y
|
|
|
|
lda $12
|
|
iny
|
|
sta $0202,y
|
|
|
|
lda $03
|
|
iny
|
|
sta $0202,y
|
|
|
|
lda $02
|
|
sec
|
|
sbc #$01
|
|
iny
|
|
sta $0202,y
|
|
|
|
lda #$20
|
|
sta $14
|
|
|
|
lda #$00
|
|
sta $15
|
|
|
|
lda $02
|
|
sta $12
|
|
|
|
lda $03
|
|
sta $13
|
|
|
|
jsr $E2C6
|
|
|
|
lda $13
|
|
iny
|
|
sta $0202,y
|
|
|
|
lda $12
|
|
iny
|
|
sta $0202,y
|
|
|
|
lda $03
|
|
iny
|
|
sta $0202,y
|
|
|
|
lda $02
|
|
clc
|
|
adc #$01
|
|
iny
|
|
sta $0202,y
|
|
|
|
inx
|
|
inx
|
|
inx
|
|
inx
|
|
|
|
iny
|
|
|
|
cpy #$28
|
|
bne @E1F2
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $E263-$E2A1: Convert Gameplay Coordinates to Map/PPU Address
|
|
;
|
|
; Input:
|
|
; $02 = first gameplay coordinate
|
|
; $03 = second gameplay coordinate
|
|
;
|
|
; Output:
|
|
; $02/$03 = converted 16-bit map/PPU-style address
|
|
;
|
|
; Local:
|
|
; Derives a nametable-style address from the coordinate pair.
|
|
;
|
|
; The second coordinate is adjusted by -4, aligned to an 8-unit boundary,
|
|
; then multiplied/shifted while carries are accumulated in $05.
|
|
;
|
|
; The first coordinate is adjusted by -4 and divided by eight before being
|
|
; added to the low address byte.
|
|
;
|
|
; The resulting address receives a base of $20xx.
|
|
;
|
|
; When ($46 & $47) is nonzero, $08 is added to the high/result byte at $03,
|
|
; selecting the corresponding alternate nametable region.
|
|
;
|
|
; Global:
|
|
; Called from several gameplay routines whenever object coordinates need to
|
|
; be converted into map/PPU addresses.
|
|
;
|
|
; Notes:
|
|
; $04/$05 are temporary low/high address components.
|
|
;==============================================================================
|
|
|
|
ConvertPixelToNametableAddress:
|
|
lda #$00
|
|
sta $05
|
|
|
|
lda $03
|
|
sec
|
|
sbc #$04
|
|
and #$F8
|
|
|
|
asl
|
|
rol $05
|
|
|
|
asl
|
|
rol $05
|
|
|
|
clc
|
|
adc #$40
|
|
sta $04
|
|
|
|
lda #$00
|
|
adc $05
|
|
sta $05
|
|
|
|
lda $02
|
|
sec
|
|
sbc #$04
|
|
|
|
lsr
|
|
lsr
|
|
lsr
|
|
|
|
clc
|
|
adc $04
|
|
sta $02
|
|
|
|
lda $05
|
|
clc
|
|
adc #$20
|
|
sta $03
|
|
|
|
lda $46
|
|
and $47
|
|
bne @E299
|
|
|
|
rts
|
|
|
|
@E299:
|
|
lda $03
|
|
clc
|
|
adc #$08
|
|
sta $03
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $E2A2-$E2C5: Read PPU Values for Coordinate Address Buffer
|
|
;
|
|
; Reads 21 PPU addresses stored at $0200-$0229 and stores the corresponding
|
|
; PPU data bytes at $022A-$023E.
|
|
;
|
|
; PPUSTATUS is read once before processing the address list.
|
|
;==============================================================================
|
|
|
|
ReadNearbyNametableTiles:
|
|
ldx #$00
|
|
ldy #$00
|
|
|
|
lda PPUSTATUS
|
|
|
|
|
|
@E2A9:
|
|
lda $0200,x
|
|
sta PPUADDR
|
|
|
|
inx
|
|
|
|
lda $0200,x
|
|
sta PPUADDR
|
|
|
|
; Buffered PPU read.
|
|
lda PPUDATA
|
|
|
|
; Actual requested value.
|
|
lda PPUDATA
|
|
sta $022A,y
|
|
|
|
inx
|
|
iny
|
|
|
|
cpx #$2A
|
|
bne @E2A9
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $E2C6-$E2D3: Add 16-Bit Working Values
|
|
;
|
|
; Input:
|
|
; $12/$13 = low/high first operand
|
|
; $14/$15 = low/high second operand
|
|
;
|
|
; Output:
|
|
; $12/$13 = 16-bit sum
|
|
;==============================================================================
|
|
|
|
Add16BitWorkingValue:
|
|
clc
|
|
|
|
lda $12
|
|
adc $14
|
|
sta $12
|
|
|
|
lda $13
|
|
adc $15
|
|
sta $13
|
|
|
|
rts
|
|
;==============================================================================
|
|
; $E2D4-$E2E1: Subtract 16-Bit Working Values
|
|
;
|
|
; Input:
|
|
; $12/$13 = low/high first operand
|
|
; $14/$15 = low/high second operand
|
|
;
|
|
; Output:
|
|
; $12/$13 = first operand - second operand
|
|
;==============================================================================
|
|
Subtract16BitWorkingValue:
|
|
sec
|
|
|
|
lda $12
|
|
sbc $14
|
|
sta $12
|
|
|
|
lda $13
|
|
sbc $15
|
|
sta $13
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $E2E2-$E381: Draw Gameplay Nametable
|
|
;
|
|
; Local:
|
|
; Expands compressed gameplay map data directly into VRAM.
|
|
;
|
|
; The primary destination begins at:
|
|
;
|
|
; $2040 when ($47 & $46) == 0
|
|
; $2840 when ($47 & $46) != 0
|
|
;
|
|
; The compressed source pointer is loaded from $FFF6/$FFF7.
|
|
;
|
|
; After the primary map is written, a small decoration pattern from
|
|
; MazeNametableDecorationTiles is written to additional PPU locations.
|
|
;
|
|
; Global:
|
|
; Called from GameModeState00 while initializing gameplay.
|
|
;
|
|
; Notes:
|
|
; $00/$01 = compressed source pointer during the first phase
|
|
; $02/$03 = PPU destination during the first phase
|
|
; $04 = number of PPU bytes remaining in current row
|
|
; $05 = repeat count extracted from the source byte
|
|
; X = row counter
|
|
; Y = compressed source index
|
|
;==============================================================================
|
|
|
|
DrawMazeNametable:
|
|
lda #$20
|
|
sta $02
|
|
|
|
lda #$40
|
|
sta $03
|
|
|
|
lda $47
|
|
and $46
|
|
beq @E2F4
|
|
|
|
lda #$28
|
|
sta $02
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E2F4
|
|
; Load compressed-map source pointer.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E2F4:
|
|
lda MazeDataPointerBytes+1
|
|
sta $01
|
|
|
|
lda MazeDataPointerBytes
|
|
sta $00
|
|
|
|
ldx #$1B
|
|
ldy #$00
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E302
|
|
; Set PPU destination for the next row.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E302:
|
|
lda PPUSTATUS
|
|
|
|
lda $02
|
|
sta PPUADDR
|
|
|
|
lda $03
|
|
sta PPUADDR
|
|
|
|
lda #$16
|
|
sta $04
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E313
|
|
; Start decoding the next compressed source byte.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E313:
|
|
lda #$00
|
|
sta $05
|
|
|
|
lda ($00),y
|
|
|
|
asl
|
|
rol $05
|
|
|
|
asl
|
|
rol $05
|
|
|
|
lda ($00),y
|
|
and #$3F
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E321
|
|
; Repeat the decoded value according to the repeat count in $05.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E321:
|
|
sta PPUDATA
|
|
|
|
dec $04
|
|
dec $05
|
|
bpl @E321
|
|
|
|
iny
|
|
bne @E32F
|
|
|
|
inc $01
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E32F
|
|
; Continue until the current row contains $16 output bytes.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E32F:
|
|
lda $04
|
|
bne @E313
|
|
|
|
lda $03
|
|
clc
|
|
adc #$20
|
|
sta $03
|
|
|
|
lda $02
|
|
adc #$00
|
|
sta $02
|
|
|
|
dex
|
|
bne @E302
|
|
|
|
|
|
;==============================================================================
|
|
; $E345-$E381: Draw additional nametable decoration strips.
|
|
;==============================================================================
|
|
|
|
ldy #$02
|
|
|
|
lda #$21
|
|
sta $00
|
|
|
|
lda #$D6
|
|
sta $01
|
|
|
|
lda $47
|
|
and $46
|
|
beq @E359
|
|
|
|
lda #$29
|
|
sta $00
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E359
|
|
; Start one decoration strip.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E359:
|
|
ldx #$07
|
|
|
|
lda PPUSTATUS
|
|
|
|
lda $00
|
|
sta PPUADDR
|
|
|
|
lda $01
|
|
sta PPUADDR
|
|
|
|
lda MazeNametableDecorationTiles,y
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E36B
|
|
; Write the selected table value eight times.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E36B:
|
|
sta PPUDATA
|
|
|
|
dex
|
|
bpl @E36B
|
|
|
|
lda $01
|
|
clc
|
|
adc #$20
|
|
sta $01
|
|
|
|
lda #$00
|
|
adc $00
|
|
sta $00
|
|
|
|
dey
|
|
bpl @E359
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $E382-$E385: Gameplay Nametable Decoration Table
|
|
;==============================================================================
|
|
|
|
MazeNametableDecorationTiles:
|
|
.byte $2D,$04,$2D
|
|
;==============================================================================
|
|
; $E385-$E3FE: Initialize Gameplay Nametable Regions
|
|
;
|
|
; Fills gameplay nametable regions with tile $2D, then clears the corresponding
|
|
; attribute-table regions.
|
|
;
|
|
; Address-based global labels are used for shared entry points to avoid ca65
|
|
; cheap-local scope issues and collisions with previously defined symbols.
|
|
;==============================================================================
|
|
|
|
ClearGameplayNametables:
|
|
lda PPUSTATUS
|
|
|
|
lda #$20
|
|
sta PPUADDR
|
|
|
|
lda #$00
|
|
sta PPUADDR
|
|
|
|
lda #$01
|
|
sta $02
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E396
|
|
; Shared entry used for another nametable pass.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ClearGameplayNametablesSecondPass:
|
|
lda #$01
|
|
sta $03
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E39A
|
|
; Initialize fill counters.
|
|
;------------------------------------------------------------------------------
|
|
|
|
InitializeNametableFillCounters:
|
|
lda #$03
|
|
sta $00
|
|
|
|
lda #$C0
|
|
sta $01
|
|
|
|
lda #$2D
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E3A4
|
|
; Shared fill loop.
|
|
;------------------------------------------------------------------------------
|
|
|
|
FillNametableByte:
|
|
sta PPUDATA
|
|
|
|
dec $01
|
|
bne FillNametableByte
|
|
|
|
dec $00
|
|
bpl FillNametableByte
|
|
|
|
dec $03
|
|
bne AdvanceNametableFillPass
|
|
|
|
lda #$40
|
|
sta $01
|
|
|
|
lda #$00
|
|
beq FillNametableByte
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E3BB
|
|
; Advance to alternate nametable / next phase.
|
|
;------------------------------------------------------------------------------
|
|
|
|
AdvanceNametableFillPass:
|
|
dec $02
|
|
bne ClearGameplayAttributeTables
|
|
|
|
lda PPUSTATUS
|
|
|
|
lda #$28
|
|
sta PPUADDR
|
|
|
|
lda #$00
|
|
sta PPUADDR
|
|
|
|
jmp ClearGameplayNametablesSecondPass
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E3CF
|
|
; Begin clearing attribute-table regions.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ClearGameplayAttributeTables:
|
|
lda #$01
|
|
sta $00
|
|
|
|
lda PPUSTATUS
|
|
|
|
lda #$23
|
|
sta PPUADDR
|
|
|
|
lda #$C0
|
|
sta PPUADDR
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E3E0
|
|
; Shared attribute-clear setup.
|
|
;------------------------------------------------------------------------------
|
|
|
|
BeginAttributeTableClear:
|
|
lda #$00
|
|
tay
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E3E3
|
|
; Write $20 zero bytes to PPUDATA.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ClearAttributeTableLoop:
|
|
sta PPUDATA
|
|
|
|
iny
|
|
cpy #$20
|
|
bne ClearAttributeTableLoop
|
|
|
|
dec $00
|
|
bne ClearSecondAttributeTable
|
|
|
|
rts
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E3F0
|
|
; Set destination to the second attribute table, $2BC0.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ClearSecondAttributeTable:
|
|
lda PPUSTATUS
|
|
|
|
lda #$2B
|
|
sta PPUADDR
|
|
|
|
lda #$C0
|
|
sta PPUADDR
|
|
|
|
bne BeginAttributeTableClear
|
|
|
|
;==============================================================================
|
|
; $E3FF-$E473: Draw Gameplay Numeric / Status Fields
|
|
;
|
|
; Local:
|
|
; Configures a PPU destination and repeatedly draws numeric fields through
|
|
; the helper at DrawSixDigitScore.
|
|
;
|
|
; Initial destination/configuration:
|
|
;
|
|
; $00/$01 = PPU destination
|
|
; $04 = destination stride
|
|
; X = index into a pointer table at ScoreFieldSourcePointerTable
|
|
;
|
|
; The destination and table index vary depending on $47 & $46.
|
|
;
|
|
; Three fields are drawn per pass. The routine may perform another pass
|
|
; according to $47 and the current field counter.
|
|
;
|
|
; Global:
|
|
; Called by GameModeState00 as part of gameplay initialization.
|
|
;
|
|
; Notes:
|
|
; DrawSixDigitScore renders one numeric field using the source pointer
|
|
; loaded from the table at ScoreFieldSourcePointerTable.
|
|
;==============================================================================
|
|
|
|
DrawGameplayScoreFields:
|
|
lda #$20
|
|
sta $00
|
|
|
|
lda #$B6
|
|
sta $01
|
|
|
|
lda #$80
|
|
sta $04
|
|
|
|
ldx #$00
|
|
|
|
lda $47
|
|
and $46
|
|
beq @E429
|
|
|
|
lda #$28
|
|
sta $00
|
|
|
|
bne @E429
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Alternate setup path.
|
|
;------------------------------------------------------------------------------
|
|
|
|
lda #$20
|
|
sta $00
|
|
|
|
lda #$83
|
|
sta $01
|
|
|
|
lda #$09
|
|
sta $04
|
|
|
|
lda #$01
|
|
sta $47
|
|
|
|
ldx #$0C
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E429
|
|
; Adjust lookup-table index for alternate player/mode state.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E429:
|
|
lda $47
|
|
and $46
|
|
beq @E436
|
|
|
|
txa
|
|
clc
|
|
adc #$06
|
|
tax
|
|
|
|
|
|
@E436:
|
|
lda #$03
|
|
sta $05
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E43A: render one status field.
|
|
;------------------------------------------------------------------------------
|
|
|
|
@E43A:
|
|
lda PPUSTATUS
|
|
|
|
lda $00
|
|
sta PPUADDR
|
|
|
|
lda $01
|
|
sta PPUADDR
|
|
|
|
lda ScoreFieldSourcePointerTable,x
|
|
sta $02
|
|
|
|
lda ScoreFieldSourcePointerTable+1,x
|
|
sta $03
|
|
|
|
jsr DrawSixDigitScore
|
|
|
|
inx
|
|
inx
|
|
|
|
lda $01
|
|
clc
|
|
adc $04
|
|
sta $01
|
|
|
|
lda #$00
|
|
adc $00
|
|
sta $00
|
|
|
|
dec $05
|
|
|
|
lda $05
|
|
cmp #$01
|
|
bne @E46D
|
|
|
|
lda $47
|
|
beq @E473
|
|
|
|
|
|
@E46D:
|
|
lda $05
|
|
bne @E43A
|
|
|
|
|
|
@E473:
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $E474-$E49E: Draw Six-Digit Numeric Field
|
|
;
|
|
; Input:
|
|
; $02/$03 = pointer to packed numeric values
|
|
;
|
|
; Local:
|
|
; Processes six source values from index 5 down to 0.
|
|
;
|
|
; Leading values whose low nibble is zero are rendered as spaces ($20).
|
|
; Once a nonzero low nibble is encountered, remaining values are converted
|
|
; through the shared conversion entry at $E1CE and written to PPUDATA.
|
|
;
|
|
; The final value at Y=0 is always converted, after which a trailing $30
|
|
; character is written.
|
|
;
|
|
; Notes:
|
|
; The conversion calls MUST target $E1CE, not $E1CA. $E1CE is the shared
|
|
; entry that begins with AND #$0F, while $E1CA additionally shifts A right
|
|
; four times.
|
|
;==============================================================================
|
|
DrawSixDigitScore:
|
|
ldy #$05
|
|
|
|
|
|
SkipLeadingZeroDigits:
|
|
lda ($02),y
|
|
and #$0F
|
|
bne ConvertCurrentScoreDigit
|
|
|
|
lda #$20
|
|
sta PPUDATA
|
|
|
|
dey
|
|
bne SkipLeadingZeroDigits
|
|
|
|
beq DrawFinalScoreDigit
|
|
|
|
|
|
LoadNextScoreDigit:
|
|
lda ($02),y
|
|
|
|
|
|
ConvertCurrentScoreDigit:
|
|
jsr $E1CE
|
|
|
|
sta PPUDATA
|
|
|
|
dey
|
|
bne LoadNextScoreDigit
|
|
|
|
|
|
DrawFinalScoreDigit:
|
|
lda ($02),y
|
|
|
|
jsr $E1CE
|
|
|
|
sta PPUDATA
|
|
|
|
lda #$30
|
|
sta PPUDATA
|
|
|
|
rts
|
|
;==============================================================================
|
|
; $E49F-$E4B0: Gameplay Status Field Source Pointer Table
|
|
;
|
|
; Local:
|
|
; Nine little-endian zero-page/RAM pointers used by the gameplay status-field
|
|
; drawing routine beginning at $E3FF.
|
|
;
|
|
; X indexes this table in steps of two. Each selected address is loaded into
|
|
; $02/$03 and passed to DrawSixDigitScore.
|
|
;
|
|
; Global:
|
|
; Selects the numeric/state arrays rendered into the different gameplay
|
|
; status display fields.
|
|
;==============================================================================
|
|
|
|
ScoreFieldSourcePointerTable:
|
|
.word $0061
|
|
.word $0070
|
|
.word $0080
|
|
|
|
.word $0061
|
|
.word $0080
|
|
.word $0070
|
|
|
|
.word $0070
|
|
.word $0061
|
|
.word $0080
|
|
|
|
;==============================================================================
|
|
; $E4B1-$E501: Build Entity Direction Candidate List
|
|
;
|
|
; Input:
|
|
; $00/$01 = pointer to direction/path data
|
|
; $0A/$0B = comparison values prepared by the caller
|
|
; X = current entity slot index
|
|
;
|
|
; Output:
|
|
; $0C-$0F = candidate direction values, with invalid entries marked $FF
|
|
;
|
|
; Local:
|
|
; First clears all four candidate entries to $FF.
|
|
;
|
|
; Then examines four values through ($00),Y. A candidate is accepted when
|
|
; either:
|
|
;
|
|
; value == $0A
|
|
;
|
|
; or:
|
|
;
|
|
; (value & $F8) != 0
|
|
; and value == $0B
|
|
;
|
|
; Accepted entries store their Y index into $0C-$0F.
|
|
;
|
|
; The entity's reverse/current-excluded direction is then calculated from
|
|
; $B9,X and explicitly removed from the candidate list.
|
|
;
|
|
; Finally performs up to three passes compacting $FF holes by shifting the
|
|
; following entry left.
|
|
;
|
|
; Global:
|
|
; Called by EntityTargetCommon at $D778 before entity direction selection.
|
|
;
|
|
; Notes:
|
|
; $0C-$0F therefore form a filtered list of legal direction indices.
|
|
;==============================================================================
|
|
|
|
BuildLegalDirectionList:
|
|
ldy #$FF
|
|
|
|
sty $0C
|
|
sty $0D
|
|
sty $0E
|
|
sty $0F
|
|
|
|
iny
|
|
|
|
|
|
ScanDirectionCandidate:
|
|
lda ($00),y
|
|
cmp $0A
|
|
beq AcceptDirectionCandidate
|
|
|
|
and #$F8
|
|
beq AcceptDirectionCandidate
|
|
|
|
cmp $0B
|
|
bne NextDirectionCandidate
|
|
|
|
|
|
AcceptDirectionCandidate:
|
|
tya
|
|
sta $000C,y
|
|
|
|
|
|
NextDirectionCandidate:
|
|
iny
|
|
cpy #$04
|
|
bne ScanDirectionCandidate
|
|
|
|
lda $B9,x
|
|
clc
|
|
adc #$02
|
|
and #$03
|
|
tay
|
|
|
|
lda #$FF
|
|
sta $000C,y
|
|
|
|
lda #$03
|
|
sta $0B
|
|
|
|
|
|
CompactDirectionListPass:
|
|
ldy #$00
|
|
|
|
|
|
CompactDirectionListEntry:
|
|
lda $000C,y
|
|
cmp #$FF
|
|
bne NextDirectionListEntry
|
|
|
|
lda $000D,y
|
|
sta $000C,y
|
|
|
|
lda #$FF
|
|
sta $000D,y
|
|
|
|
|
|
NextDirectionListEntry:
|
|
iny
|
|
cpy #$03
|
|
bne CompactDirectionListEntry
|
|
|
|
dec $0B
|
|
bne CompactDirectionListPass
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $E502-$E53B: Draw Gameplay Initialization Data
|
|
;
|
|
; Local:
|
|
; Reads compact PPU command data beginning at $E53C and writes the payloads
|
|
; directly to PPUDATA.
|
|
;
|
|
; X selects between two passes/variants.
|
|
; Y indexes the command stream.
|
|
; $00 holds the number of bytes remaining in the current payload.
|
|
;
|
|
; Global:
|
|
; Called from GameModeState00 during gameplay initialization.
|
|
;==============================================================================
|
|
|
|
DrawGameplayHudLabels:
|
|
ldx #$01
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E504
|
|
; Reset command-stream index for a pass.
|
|
;------------------------------------------------------------------------------
|
|
|
|
InitData_E504:
|
|
ldy #$00
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E506
|
|
; Start one command record.
|
|
;------------------------------------------------------------------------------
|
|
|
|
InitData_E506:
|
|
lda $E53C,y
|
|
|
|
cpx #$00
|
|
bne InitData_E50F
|
|
|
|
adc #$07
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E50F
|
|
; Write PPU destination address.
|
|
;------------------------------------------------------------------------------
|
|
|
|
InitData_E50F:
|
|
sta PPUADDR
|
|
|
|
iny
|
|
|
|
lda $E53C,y
|
|
sta PPUADDR
|
|
|
|
iny
|
|
|
|
lda $E53C,y
|
|
sta $00
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E51F
|
|
; Write record payload.
|
|
;------------------------------------------------------------------------------
|
|
|
|
InitData_E51F:
|
|
iny
|
|
|
|
lda $E53C,y
|
|
sta PPUDATA
|
|
|
|
dec $00
|
|
bne InitData_E51F
|
|
|
|
iny
|
|
|
|
cpy #$11
|
|
bne InitData_E534
|
|
|
|
lda $47
|
|
bne InitData_E534
|
|
|
|
rts
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E534
|
|
; Continue through the first/second stream section.
|
|
;------------------------------------------------------------------------------
|
|
|
|
InitData_E534:
|
|
cpy #$17
|
|
bne InitData_E506
|
|
|
|
dex
|
|
beq InitData_E504
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $E53C-$E552: Gameplay Initialization PPU Command Data
|
|
;
|
|
; Record format:
|
|
; byte 0 = PPU address high
|
|
; byte 1 = PPU address low
|
|
; byte 2 = payload length
|
|
; remaining bytes = payload written to PPUDATA
|
|
;==============================================================================
|
|
|
|
GameplayHudInitializationData:
|
|
|
|
; $E53C: PPU $2076, 8-byte payload
|
|
.byte $20,$76,$08
|
|
.byte $B4,$B5,$B6,$B7,$B8,$B9,$BA,$BB
|
|
|
|
; $E547: PPU $20F7, 3-byte payload
|
|
.byte $20,$F7,$03
|
|
.byte $B0,$B3,$B2
|
|
|
|
; $E54D: PPU $2177, 3-byte payload
|
|
.byte $21,$77,$03
|
|
.byte $B1,$B3,$B2
|
|
|
|
;==============================================================================
|
|
; $E553-$E5C0: Draw Progression / Status Markers
|
|
;
|
|
; Local:
|
|
; Returns immediately when $67 is zero.
|
|
;
|
|
; Otherwise computes:
|
|
;
|
|
; count = min($67 + 1, $07)
|
|
;
|
|
; and stores that in $02.
|
|
;
|
|
; Initializes:
|
|
;
|
|
; $03 = $04
|
|
; $00/$01 = $2317
|
|
;
|
|
; If ($46 & $47) != 0, the high destination byte is adjusted by $08.
|
|
;
|
|
; The routine then performs nested loops, calling the helper at $E59A with
|
|
; Y=$3C. The helper writes a 2x2-style pattern at the current PPU position.
|
|
;
|
|
; Global:
|
|
; Called during gameplay initialization to draw a progression/status display.
|
|
;
|
|
; Notes:
|
|
; $E59A is a valid internal helper entry point within this routine.
|
|
;==============================================================================
|
|
|
|
DrawLevelProgressMarkers:
|
|
lda $67
|
|
bne Progression_E558
|
|
|
|
rts
|
|
|
|
|
|
Progression_E558:
|
|
clc
|
|
adc #$01
|
|
|
|
cmp #$07
|
|
bcc Progression_E55F
|
|
|
|
lda #$07
|
|
|
|
|
|
Progression_E55F:
|
|
sta $02
|
|
|
|
lda #$04
|
|
sta $03
|
|
|
|
lda #$23
|
|
sta $00
|
|
|
|
lda #$17
|
|
sta $01
|
|
|
|
lda $46
|
|
and $47
|
|
beq Progression_E57C
|
|
|
|
lda $00
|
|
clc
|
|
adc #$08
|
|
sta $00
|
|
|
|
|
|
Progression_E57C:
|
|
dec $02
|
|
bne Progression_E581
|
|
|
|
rts
|
|
|
|
|
|
Progression_E581:
|
|
dec $03
|
|
bne Progression_E58A
|
|
|
|
lda $01
|
|
clc
|
|
adc #$3A
|
|
sta $01
|
|
|
|
|
|
Progression_E58A:
|
|
ldy #$3C
|
|
|
|
jsr Draw2x2Marker
|
|
|
|
lda $01
|
|
clc
|
|
adc #$02
|
|
sta $01
|
|
|
|
bne Progression_E57C
|
|
|
|
;==============================================================================
|
|
; $E59A-$E5C0: Draw 2x2 Progression Marker
|
|
;
|
|
; Input:
|
|
; $00/$01 = first PPU destination
|
|
; Y = first tile value
|
|
;
|
|
; Effect:
|
|
; Writes Y and Y+1 horizontally, then Y+2 and Y+3 one row ($20 bytes)
|
|
; below the initial destination.
|
|
;==============================================================================
|
|
|
|
Draw2x2Marker:
|
|
lda $00
|
|
sta PPUADDR
|
|
|
|
lda $01
|
|
sta PPUADDR
|
|
|
|
sty PPUDATA
|
|
|
|
iny
|
|
sty PPUDATA
|
|
|
|
lda $00
|
|
sta PPUADDR
|
|
|
|
lda $01
|
|
clc
|
|
adc #$20
|
|
sta PPUADDR
|
|
|
|
iny
|
|
sty PPUDATA
|
|
|
|
iny
|
|
sty PPUDATA
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $-$E699: Initialize Gameplay State / Markers
|
|
;
|
|
; Local:
|
|
; Builds several gameplay marker/display values using the current value at
|
|
; $68 and a collection of lookup tables beginning at LevelProgressMarkerIndexTable
|
|
;
|
|
; The routine:
|
|
; - Initializes working values at $0A-$0F.
|
|
; - Derives an index/count from $68.
|
|
; - Selects PPU coordinates according to $46/$47.
|
|
; - Draws repeated 2x2 marker blocks using Draw2x2Marker.
|
|
; - Combines several lookup-table values into $0A+ working state.
|
|
; - Writes the resulting values directly into PPU attribute/display areas.
|
|
; - Selects final values for $02B6 and $02A9.
|
|
;
|
|
; Global:
|
|
; Called from GameModeState00 during initial gameplay setup.
|
|
;
|
|
; Notes:
|
|
; Address-oriented labels are used for the larger loops to preserve the
|
|
; original compact branch structure.
|
|
;==============================================================================
|
|
|
|
InitializeLevelProgressDisplay:
|
|
lda #$00
|
|
sta $03
|
|
sta $0E
|
|
sta $0F
|
|
|
|
lda #$15
|
|
sta $0A
|
|
|
|
lda #$11
|
|
sta $0D
|
|
|
|
lda #$05
|
|
sta $0B
|
|
sta $0C
|
|
|
|
lda $68
|
|
sta $02
|
|
|
|
sec
|
|
sbc #$07
|
|
bcc UseFirstLevelProgressIndex
|
|
|
|
cmp #$0C
|
|
bcc ClampLevelProgressIndex
|
|
|
|
lda #$0C
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E5E9
|
|
;------------------------------------------------------------------------------
|
|
|
|
ClampLevelProgressIndex:
|
|
tax
|
|
|
|
lda #$07
|
|
sta $02
|
|
|
|
bne InitializeLevelProgressPosition
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E5F0
|
|
;------------------------------------------------------------------------------
|
|
|
|
UseFirstLevelProgressIndex:
|
|
ldx #$00
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E5F2
|
|
; Initial PPU destination.
|
|
;------------------------------------------------------------------------------
|
|
|
|
InitializeLevelProgressPosition:
|
|
lda #$22
|
|
sta $00
|
|
|
|
lda #$56
|
|
sta $01
|
|
|
|
lda $46
|
|
and $47
|
|
beq InitializeLevelProgressRowCounter
|
|
|
|
lda $00
|
|
clc
|
|
adc #$08
|
|
sta $00
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E605
|
|
;------------------------------------------------------------------------------
|
|
|
|
InitializeLevelProgressRowCounter:
|
|
lda #$05
|
|
sta $04
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E609
|
|
; Main marker loop.
|
|
;------------------------------------------------------------------------------
|
|
|
|
DrawNextLevelProgressMarker:
|
|
dec $04
|
|
bne SelectLevelProgressMarker
|
|
|
|
lda $01
|
|
clc
|
|
adc #$38
|
|
sta $01
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E612
|
|
; Select marker information.
|
|
;------------------------------------------------------------------------------
|
|
|
|
SelectLevelProgressMarker:
|
|
lda LevelProgressMarkerIndexTable,x
|
|
sta $05
|
|
|
|
asl
|
|
asl
|
|
adc #$60
|
|
tay
|
|
|
|
jsr Draw2x2Marker
|
|
|
|
ldy $03
|
|
|
|
lda LevelProgressAttributeIndexTable,y
|
|
sta $06
|
|
|
|
lda LevelProgressAttributeIndexTable+1,y
|
|
sta $07
|
|
|
|
ldy $05
|
|
|
|
lda LevelProgressAttributeBits,y
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E633
|
|
; Shift selected marker bits.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ShiftLevelProgressAttributeBits:
|
|
dec $07
|
|
bmi StoreLevelProgressAttributeBits
|
|
|
|
asl
|
|
asl
|
|
bcc ShiftLevelProgressAttributeBits
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E63B
|
|
; Combine marker bits into working values.
|
|
;------------------------------------------------------------------------------
|
|
|
|
StoreLevelProgressAttributeBits:
|
|
ldy $06
|
|
|
|
ora $0A,y
|
|
sta $0A,y
|
|
|
|
lda $01
|
|
clc
|
|
adc #$02
|
|
sta $01
|
|
|
|
inc $03
|
|
inc $03
|
|
|
|
inx
|
|
|
|
dec $02
|
|
bpl DrawNextLevelProgressMarker
|
|
|
|
|
|
;==============================================================================
|
|
; Write generated marker-state values into PPU memory.
|
|
;==============================================================================
|
|
|
|
ldx #$23
|
|
|
|
lda $47
|
|
and $46
|
|
beq SetLevelProgressAttributeAddress
|
|
|
|
ldx #$2B
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E65D
|
|
; Set first PPU destination.
|
|
;------------------------------------------------------------------------------
|
|
|
|
SetLevelProgressAttributeAddress:
|
|
stx PPUADDR
|
|
stx $00
|
|
|
|
lda #$E5
|
|
sta PPUADDR
|
|
|
|
ldx #$00
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E667
|
|
; Reset count for one three-byte PPU group.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ResetAttributeWriteCount:
|
|
lda #$03
|
|
sta $01
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E66B
|
|
; Write three values from $0A+.
|
|
;------------------------------------------------------------------------------
|
|
|
|
WriteLevelProgressAttribute:
|
|
lda $0A,x
|
|
sta PPUDATA
|
|
|
|
inx
|
|
|
|
dec $01
|
|
bne WriteLevelProgressAttribute
|
|
|
|
inc $02
|
|
bne SelectLevelProgressPalette
|
|
|
|
lda $00
|
|
sta PPUADDR
|
|
|
|
lda #$ED
|
|
sta PPUADDR
|
|
|
|
bne ResetAttributeWriteCount
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E685
|
|
; Select final marker/display value.
|
|
;------------------------------------------------------------------------------
|
|
|
|
SelectLevelProgressPalette:
|
|
lda $68
|
|
|
|
cmp #$10
|
|
bcc StoreLevelProgressPalette
|
|
|
|
lda #$0F
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E68D
|
|
;------------------------------------------------------------------------------
|
|
|
|
StoreLevelProgressPalette:
|
|
tay
|
|
|
|
lda LevelProgressPaletteTable,y
|
|
sta $02B6
|
|
|
|
lda #$0F
|
|
sta $02A9
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $E69A-$E6AD: Gameplay Marker Level Index Table
|
|
;==============================================================================
|
|
|
|
LevelProgressMarkerIndexTable:
|
|
.byte $00,$01,$02,$02
|
|
.byte $03,$03,$04,$04
|
|
.byte $05,$05,$06,$06
|
|
.byte $07,$07,$07,$07
|
|
.byte $07,$07,$07,$07
|
|
|
|
;==============================================================================
|
|
; $E6AE-$E6BD: Gameplay Marker Working-Value Table
|
|
;
|
|
; Used as byte pairs through $03.
|
|
;==============================================================================
|
|
|
|
LevelProgressAttributeIndexTable:
|
|
.byte $00,$03
|
|
.byte $01,$02
|
|
.byte $01,$03
|
|
.byte $02,$02
|
|
.byte $03,$01
|
|
.byte $04,$00
|
|
.byte $04,$01
|
|
.byte $05,$00
|
|
|
|
;==============================================================================
|
|
; $E6BE-$E6C5: Gameplay Marker Bit/Pattern Table
|
|
;==============================================================================
|
|
|
|
LevelProgressAttributeBits:
|
|
.byte $02,$02,$02,$02
|
|
.byte $03,$03,$03,$03
|
|
|
|
;==============================================================================
|
|
; $E6C6-$E6D5: Gameplay Marker Final Value Table
|
|
;
|
|
; Indexed by min($68,$0F). Selected value is stored at $02B6.
|
|
;==============================================================================
|
|
|
|
LevelProgressPaletteTable:
|
|
.byte $16,$16,$26,$26
|
|
.byte $06,$06,$19,$19
|
|
.byte $17,$17,$17,$17
|
|
.byte $12,$12,$12,$12
|
|
|
|
|
|
;==============================================================================
|
|
; $E6D6-$E737: Initialize Gameplay Transition State
|
|
;==============================================================================
|
|
|
|
InitializeGameplayTransitionState:
|
|
lda #$08
|
|
sta $43
|
|
sta PPUCTRL
|
|
|
|
|
|
TransitionInit_E6DD:
|
|
lda PPUSTATUS
|
|
bpl TransitionInit_E6DD
|
|
|
|
lda #$01
|
|
sta $060D
|
|
sta $060E
|
|
|
|
lda #$00
|
|
sta PPUMASK
|
|
|
|
jsr ClearPlayfieldNametable
|
|
|
|
lda #$01
|
|
sta $028D
|
|
|
|
lda #$01
|
|
sta $0293
|
|
|
|
lda #$F7
|
|
sta $0278
|
|
|
|
lda #$7C
|
|
sta $027A
|
|
|
|
lda #$FF
|
|
sta $1E
|
|
|
|
lda #$00
|
|
sta $1F
|
|
|
|
lda #$00
|
|
sta $88
|
|
|
|
ldy #$00
|
|
|
|
|
|
TransitionInit_CopyPalette:
|
|
lda GameplayTransitionPalette,y
|
|
sta $02A9,y
|
|
|
|
iny
|
|
cpy #$10
|
|
bne TransitionInit_CopyPalette
|
|
|
|
lda #$20
|
|
sta $026F
|
|
sta $0270
|
|
sta $0271
|
|
|
|
lda #$10
|
|
sta $3F
|
|
|
|
lda #$88
|
|
sta PPUCTRL
|
|
sta $43
|
|
|
|
jmp $CAA7
|
|
|
|
|
|
;==============================================================================
|
|
; $E738-$E7AE: Initialize Gameplay PPU Region
|
|
;
|
|
; Selects $2000/$2800 according to $47 & $46, performs a patterned fill,
|
|
; clears $40 PPU bytes, and conditionally writes tile $5E at $2230/$2A30.
|
|
;
|
|
; Several branches deliberately re-enter the counter setup at $E751.
|
|
;==============================================================================
|
|
|
|
ClearPlayfieldNametable:
|
|
ldx #$20
|
|
|
|
lda $47
|
|
and $46
|
|
beq SetPlayfieldPpuAddress
|
|
|
|
ldx #$28
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E742
|
|
; Initialize selected nametable address.
|
|
;------------------------------------------------------------------------------
|
|
|
|
SetPlayfieldPpuAddress:
|
|
lda PPUSTATUS
|
|
|
|
stx PPUADDR
|
|
|
|
lda #$00
|
|
sta PPUADDR
|
|
|
|
lda #$1C
|
|
sta $00
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E751
|
|
; Shared counter-setup entry.
|
|
;
|
|
; The outer $00 loop deliberately jumps back here rather than rebuilding $00.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ResetPlayfieldFillCounters:
|
|
lda #$02
|
|
sta $01
|
|
|
|
lda #$1C
|
|
sta $02
|
|
|
|
lda #$02
|
|
sta $03
|
|
|
|
lda #$2D
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E75F
|
|
; Shared PPUDATA write point.
|
|
;------------------------------------------------------------------------------
|
|
|
|
WritePlayfieldFillByte:
|
|
sta PPUDATA
|
|
|
|
ldx $01
|
|
beq AdvancePlayfieldInnerRun
|
|
|
|
dec $01
|
|
bne WritePlayfieldFillByte
|
|
|
|
lda #$20
|
|
bne WritePlayfieldFillByte
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E76E
|
|
; Process the second run counter.
|
|
;------------------------------------------------------------------------------
|
|
|
|
AdvancePlayfieldInnerRun:
|
|
ldx $02
|
|
beq AdvancePlayfieldOuterRun
|
|
|
|
dec $02
|
|
bne WritePlayfieldFillByte
|
|
|
|
lda #$2D
|
|
bne WritePlayfieldFillByte
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E77A
|
|
; Process outer fill counters.
|
|
;------------------------------------------------------------------------------
|
|
|
|
AdvancePlayfieldOuterRun:
|
|
dec $03
|
|
bne WritePlayfieldFillByte
|
|
|
|
dec $00
|
|
bne ResetPlayfieldFillCounters
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E782
|
|
; Clear $40 PPU bytes.
|
|
;------------------------------------------------------------------------------
|
|
|
|
lda #$00
|
|
tax
|
|
|
|
|
|
ClearPlayfieldTail:
|
|
sta PPUDATA
|
|
|
|
inx
|
|
cpx #$40
|
|
bne ClearPlayfieldTail
|
|
|
|
lda $87
|
|
cmp #$02
|
|
beq DrawPlayfieldSpecialTile
|
|
|
|
rts
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $E794
|
|
; Optional special tile at PPU $2230 or $2A30.
|
|
;------------------------------------------------------------------------------
|
|
|
|
DrawPlayfieldSpecialTile:
|
|
ldx #$22
|
|
|
|
lda $47
|
|
and $46
|
|
beq SetSpecialTilePpuAddress
|
|
|
|
ldx #$2A
|
|
|
|
|
|
SetSpecialTilePpuAddress:
|
|
lda PPUSTATUS
|
|
|
|
stx PPUADDR
|
|
|
|
lda #$30
|
|
sta PPUADDR
|
|
|
|
lda #$5E
|
|
sta PPUDATA
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $E7AF-$E7BE: Gameplay Transition Palette
|
|
;==============================================================================
|
|
|
|
GameplayTransitionPalette:
|
|
.byte $0F,$36,$20,$06
|
|
.byte $0F,$27,$20,$06
|
|
.byte $0F,$11,$20,$33
|
|
.byte $0F,$36,$20,$11
|
|
|
|
;==============================================================================
|
|
; $E7BF-$E7CD: Gameplay Transition Update Coordinator
|
|
;
|
|
; Runs several already-known gameplay/render helpers, then dispatches through
|
|
; the state machine at $E7CE before returning to the main game-mode dispatcher.
|
|
;==============================================================================
|
|
|
|
UpdateIntermissionTransition:
|
|
jsr $EA19
|
|
jsr $EA94
|
|
jsr BuildEntitySpriteBuffer
|
|
jsr DispatchIntermissionState
|
|
|
|
jmp $CAA7
|
|
|
|
|
|
;==============================================================================
|
|
; $E7CE-$E7DC: Transition state dispatcher
|
|
;
|
|
; $87 is an even state value used directly as a byte offset into the table.
|
|
;==============================================================================
|
|
|
|
DispatchIntermissionState:
|
|
ldy $87
|
|
|
|
lda IntermissionStateHandlerTable,y
|
|
sta $10
|
|
|
|
lda IntermissionStateHandlerTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
|
|
;==============================================================================
|
|
; $E7DD-$E7E2: Transition state pointer table
|
|
;==============================================================================
|
|
|
|
IntermissionStateHandlerTable:
|
|
.word DispatchIntermissionPhase
|
|
.word DispatchIntermissionState2Phase
|
|
.word DispatchIntermissionState4Phase
|
|
|
|
|
|
;==============================================================================
|
|
; $E7E3-$E7F1: Secondary transition-state dispatcher
|
|
;
|
|
; $88 is used directly as a byte offset into another pointer table.
|
|
;==============================================================================
|
|
|
|
DispatchIntermissionPhase:
|
|
ldy $88
|
|
|
|
lda IntermissionPhaseHandlerTable,y
|
|
sta $10
|
|
|
|
lda IntermissionPhaseHandlerTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
|
|
;==============================================================================
|
|
; $E7F2-$E7F9: Transition substate pointer table
|
|
;==============================================================================
|
|
|
|
IntermissionPhaseHandlerTable:
|
|
.word UpdateIntermissionPhase0
|
|
.word UpdateIntermissionPhase1
|
|
.word UpdateIntermissionPhase2
|
|
.word UpdateIntermissionPhase3
|
|
|
|
|
|
;==============================================================================
|
|
; $E7FA-$E822: Transition substate 0
|
|
;
|
|
; Waits until $0278 reaches at least $D0, then advances $88 by two and
|
|
; initializes several mirrored object/state values.
|
|
;==============================================================================
|
|
|
|
UpdateIntermissionPhase0:
|
|
lda $0278
|
|
cmp #$D0
|
|
bcc TransitionSubstate_E802
|
|
|
|
rts
|
|
|
|
|
|
TransitionSubstate_E802:
|
|
inc $88
|
|
inc $88
|
|
|
|
lda #$0C
|
|
sta $028C
|
|
|
|
lda #$20
|
|
sta $0292
|
|
|
|
lda #$F7
|
|
sta $0274
|
|
|
|
lda #$7C
|
|
sta $0276
|
|
|
|
lda #$FE
|
|
sta $1A
|
|
|
|
lda #$E0
|
|
sta $1B
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $E823-$E84D: Transition substate 1
|
|
;
|
|
; Waits for $0274 to become zero, then advances $88 and initializes a
|
|
; different object/state configuration.
|
|
;==============================================================================
|
|
|
|
UpdateIntermissionPhase1:
|
|
lda $0274
|
|
beq TransitionSubstate_E829
|
|
|
|
rts
|
|
|
|
|
|
TransitionSubstate_E829:
|
|
inc $88
|
|
inc $88
|
|
|
|
lda #$40
|
|
sta $4C
|
|
|
|
lda #$1E
|
|
sta $028C
|
|
|
|
lda #$22
|
|
sta $0292
|
|
|
|
lda #$09
|
|
sta $0274
|
|
|
|
lda #$7C
|
|
sta $0276
|
|
|
|
lda #$01
|
|
sta $1A
|
|
|
|
lda #$00
|
|
sta $1B
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $E84E-$E8B9: Transition substate 2
|
|
;
|
|
; Waits until $0274 reaches at least $80, then advances $88 and initializes
|
|
; four related coordinate/state structures and their mirrored render values.
|
|
;==============================================================================
|
|
|
|
UpdateIntermissionPhase2:
|
|
lda #$01
|
|
sta $060D
|
|
sta $060E
|
|
|
|
lda $0274
|
|
cmp #$80
|
|
bcs TransitionSubstate_E85D
|
|
|
|
rts
|
|
|
|
|
|
TransitionSubstate_E85D:
|
|
inc $88
|
|
inc $88
|
|
|
|
lda #$01
|
|
sta $1E
|
|
sta $22
|
|
sta $26
|
|
sta $2A
|
|
|
|
lda #$C0
|
|
sta $1F
|
|
sta $23
|
|
sta $27
|
|
sta $2B
|
|
|
|
clc
|
|
|
|
lda #$38
|
|
sta $028D
|
|
|
|
adc #$01
|
|
sta $028E
|
|
|
|
adc #$01
|
|
sta $028F
|
|
|
|
adc #$01
|
|
sta $0290
|
|
|
|
lda #$21
|
|
sta $0293
|
|
sta $0294
|
|
sta $0295
|
|
sta $0296
|
|
|
|
lda #$09
|
|
sta $0278
|
|
sta $0280
|
|
|
|
lda #$19
|
|
sta $027C
|
|
sta $0284
|
|
|
|
lda #$6C
|
|
sta $027A
|
|
sta $027E
|
|
|
|
lda #$7C
|
|
sta $0282
|
|
sta $0286
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $E8BA-$E8C6: Transition substate 3
|
|
;
|
|
; Waits for $0278 to become zero, then primes delay $4C and transfers to the
|
|
; routine at $EA14.
|
|
;==============================================================================
|
|
|
|
UpdateIntermissionPhase3:
|
|
lda $0278
|
|
beq TransitionSubstate_E8C0
|
|
|
|
rts
|
|
|
|
|
|
TransitionSubstate_E8C0:
|
|
lda #$40
|
|
sta $4C
|
|
|
|
jmp $EA14
|
|
|
|
|
|
;==============================================================================
|
|
; $E8C7-$E8D5: Transition State $02 Substate Dispatcher
|
|
;
|
|
; Local:
|
|
; Uses $88 as an even byte offset into IntermissionState2PhaseTable.
|
|
;==============================================================================
|
|
|
|
DispatchIntermissionState2Phase:
|
|
ldy $88
|
|
|
|
lda IntermissionState2PhaseTable,y
|
|
sta $10
|
|
|
|
lda IntermissionState2PhaseTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
|
|
;==============================================================================
|
|
; $E8D6-$E8DB: Transition phase table
|
|
;==============================================================================
|
|
|
|
IntermissionState2PhaseTable:
|
|
.word UpdateIntermissionState2Phase0
|
|
.word UpdateIntermissionState2Phase1
|
|
.word UpdateIntermissionState2Phase2
|
|
|
|
|
|
;==============================================================================
|
|
; $E8DC-$E904: Transition phase 0
|
|
;
|
|
; Waits until $0278 reaches $A0, then advances the $88 state and initializes
|
|
; the primary mirrored object/state values.
|
|
;==============================================================================
|
|
|
|
UpdateIntermissionState2Phase0:
|
|
lda $0278
|
|
cmp #$A0
|
|
bcc TransitionPhase_E8E4
|
|
|
|
rts
|
|
|
|
|
|
TransitionPhase_E8E4:
|
|
inc $88
|
|
inc $88
|
|
|
|
lda #$0C
|
|
sta $028C
|
|
|
|
lda #$20
|
|
sta $0292
|
|
|
|
lda #$F7
|
|
sta $0274
|
|
|
|
lda #$7C
|
|
sta $0276
|
|
|
|
lda #$FF
|
|
sta $1A
|
|
|
|
lda #$00
|
|
sta $1B
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $E905-$E93E: Transition phase 1
|
|
;
|
|
; Watches $0274. At $80 it installs one object configuration. At $78 it
|
|
; clears the position pair and advances to the next phase.
|
|
;==============================================================================
|
|
|
|
UpdateIntermissionState2Phase1:
|
|
lda $0274
|
|
|
|
cmp #$80
|
|
bne TransitionPhase_E92D
|
|
|
|
lda #$FF
|
|
sta $1A
|
|
|
|
lda #$C0
|
|
sta $1B
|
|
|
|
lda #$42
|
|
sta $028E
|
|
|
|
lda #$00
|
|
sta $0294
|
|
|
|
lda #$80
|
|
sta $027C
|
|
|
|
lda #$7C
|
|
sta $027E
|
|
|
|
lda #$00
|
|
sta $22
|
|
sta $23
|
|
|
|
rts
|
|
|
|
|
|
TransitionPhase_E92D:
|
|
cmp #$78
|
|
beq TransitionPhase_E933
|
|
|
|
rts
|
|
|
|
|
|
TransitionPhase_E933:
|
|
lda #$00
|
|
sta $1A
|
|
sta $1B
|
|
|
|
inc $88
|
|
inc $88
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $E93F-$E96D: Transition phase 2
|
|
;
|
|
; Uses bit $40 of $028C and timer/state value $89 to alternate the object
|
|
; state between values $46 and $47. Eventually transfers to $EA14.
|
|
;==============================================================================
|
|
|
|
UpdateIntermissionState2Phase2:
|
|
lda $028C
|
|
and #$40
|
|
bne TransitionPhase_E953
|
|
|
|
lda #$46
|
|
sta $028C
|
|
|
|
lda #$45
|
|
sta $028E
|
|
|
|
lda #$40
|
|
sta $89
|
|
|
|
rts
|
|
|
|
|
|
TransitionPhase_E953:
|
|
dec $89
|
|
beq TransitionPhase_E958
|
|
|
|
rts
|
|
|
|
|
|
TransitionPhase_E958:
|
|
lda $028C
|
|
cmp #$47
|
|
bne TransitionPhase_E963
|
|
|
|
jmp $EA14
|
|
|
|
|
|
TransitionPhase_E963:
|
|
lda #$47
|
|
sta $028C
|
|
|
|
lda #$40
|
|
sta $89
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $E96E-$E97C: Transition State $04 Dispatcher
|
|
;
|
|
; $88 is an even byte offset into the four-entry phase table.
|
|
;==============================================================================
|
|
DispatchIntermissionState4Phase:
|
|
ldy $88
|
|
|
|
lda IntermissionState4PhaseTable,y
|
|
sta $10
|
|
|
|
lda IntermissionState4PhaseTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
;==============================================================================
|
|
; $E97D-$E984: Transition State $04 Phase Table
|
|
;==============================================================================
|
|
IntermissionState4PhaseTable:
|
|
.word UpdateIntermissionState4Phase0
|
|
.word UpdateIntermissionState4Phase1
|
|
.word UpdateIntermissionState4Phase2
|
|
.word UpdateIntermissionState4Phase3
|
|
|
|
;==============================================================================
|
|
; $E985-$E9AD: Phase 0
|
|
;
|
|
; Waits until $0278 reaches $D8, advances $88, then installs the initial
|
|
; mirrored object/state configuration.
|
|
;==============================================================================
|
|
|
|
UpdateIntermissionState4Phase0:
|
|
lda $0278
|
|
cmp #$D8
|
|
bcc TransitionPhase_E98D
|
|
|
|
rts
|
|
|
|
TransitionPhase_E98D:
|
|
inc $88
|
|
inc $88
|
|
|
|
lda #$4C
|
|
sta $028C
|
|
|
|
lda #$20
|
|
sta $0292
|
|
|
|
lda #$F7
|
|
sta $0274
|
|
|
|
lda #$7C
|
|
sta $0276
|
|
|
|
lda #$FF
|
|
sta $1A
|
|
|
|
lda #$00
|
|
sta $1B
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $E9AE-$E9D8: Phase 1
|
|
;
|
|
; Waits for $0274 to reach zero, advances $88 and installs the next object
|
|
; configuration.
|
|
;==============================================================================
|
|
|
|
UpdateIntermissionState4Phase1:
|
|
lda $0274
|
|
beq TransitionPhase_E9B4
|
|
|
|
rts
|
|
|
|
TransitionPhase_E9B4:
|
|
inc $88
|
|
inc $88
|
|
|
|
lda #$28
|
|
sta $4C
|
|
|
|
lda #$4A
|
|
sta $028C
|
|
|
|
lda #$23
|
|
sta $0292
|
|
|
|
lda #$09
|
|
sta $0274
|
|
|
|
lda #$7C
|
|
sta $0276
|
|
|
|
lda #$01
|
|
sta $1A
|
|
|
|
lda #$00
|
|
sta $1B
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $E9D9-$EA09: Phase 2
|
|
;
|
|
; Enables transition flags, waits until $0274 reaches $19, then advances $88
|
|
; and sets the next mirrored-state values.
|
|
;==============================================================================
|
|
UpdateIntermissionState4Phase2:
|
|
lda #$01
|
|
sta $060D
|
|
sta $060E
|
|
|
|
lda $0274
|
|
cmp #$19
|
|
bcs TransitionPhase_E9E8
|
|
|
|
rts
|
|
|
|
TransitionPhase_E9E8:
|
|
inc $88
|
|
inc $88
|
|
|
|
lda #$4C
|
|
sta $028D
|
|
|
|
lda #$21
|
|
sta $0293
|
|
|
|
lda #$11
|
|
sta $0278
|
|
|
|
lda #$84
|
|
sta $027A
|
|
|
|
lda #$01
|
|
sta $1E
|
|
|
|
lda #$00
|
|
sta $1F
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $EA0A-$EA18: Phase 3
|
|
;
|
|
; Waits for $0278 to reach zero, then primes the next game-mode/state
|
|
; transition.
|
|
;==============================================================================
|
|
UpdateIntermissionState4Phase3:
|
|
lda $0278
|
|
beq TransitionPhase_EA10
|
|
|
|
rts
|
|
|
|
TransitionPhase_EA10:
|
|
lda #$40
|
|
sta $4C
|
|
|
|
lda #$00
|
|
sta $3F
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $EA19-$EA93: Update Mirrored Gameplay Object Positions
|
|
;
|
|
; Local:
|
|
; Walks five four-byte structures in parallel:
|
|
;
|
|
; $00/$01 -> source gameplay structures beginning at $001A
|
|
; $02/$03 -> mirrored structures beginning at $0274
|
|
;
|
|
; Movement increments from the source structures are added into mirrored
|
|
; coordinates. Attribute bit $20 in $0292+ is adjusted according to the
|
|
; resulting coordinate, and coordinate reset/wrap handling is performed.
|
|
;
|
|
; Global:
|
|
; Called from gameplay transition processing before render data is rebuilt.
|
|
;
|
|
; Notes:
|
|
; Several branches deliberately re-enter shared code, so global address-style
|
|
; labels are used throughout.
|
|
;==============================================================================
|
|
UpdateTransitionObjectPositions:
|
|
lda #$1A
|
|
sta $00
|
|
|
|
lda #$00
|
|
sta $01
|
|
|
|
lda #$74
|
|
sta $02
|
|
|
|
lda #$02
|
|
sta $03
|
|
|
|
ldx #$00
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EA2B
|
|
; Process one structure.
|
|
;------------------------------------------------------------------------------
|
|
UpdateNextTransitionObject:
|
|
ldy #$00
|
|
|
|
lda ($02),y
|
|
beq AdvanceTransitionObjectPointers
|
|
|
|
iny
|
|
|
|
lda ($00),y
|
|
clc
|
|
adc ($02),y
|
|
sta ($02),y
|
|
|
|
dey
|
|
|
|
lda ($00),y
|
|
adc ($02),y
|
|
sta ($02),y
|
|
|
|
cmp #$C0
|
|
bcc UpdateTransitionObjectAttribute
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EA44
|
|
; Set attribute bit $20.
|
|
;------------------------------------------------------------------------------
|
|
SetTransitionObjectAttributeBit:
|
|
lda #$20
|
|
ora $0292,x
|
|
sta $0292,x
|
|
|
|
bne CheckTransitionObjectWrap
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EA4E
|
|
; Clear/set attribute according to coordinate range.
|
|
;
|
|
; If value < $40, branch backward to $EA44 and set bit $20.
|
|
; Otherwise clear bit $20 with mask $DF.
|
|
;------------------------------------------------------------------------------
|
|
|
|
UpdateTransitionObjectAttribute:
|
|
cmp #$40
|
|
bcc SetTransitionObjectAttributeBit
|
|
|
|
lda #$DF
|
|
and $0292,x
|
|
sta $0292,x
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EA5A
|
|
; Coordinate wrap/reset test.
|
|
;------------------------------------------------------------------------------
|
|
|
|
CheckTransitionObjectWrap:
|
|
ldy #$00
|
|
|
|
lda ($02),y
|
|
cmp #$FC
|
|
bcc CheckTransitionObjectLowBoundary
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EA62
|
|
; Reset coordinate/movement state.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ResetTransitionObjectPosition:
|
|
lda #$00
|
|
sta ($02),y
|
|
sta ($00),y
|
|
|
|
iny
|
|
sta ($00),y
|
|
|
|
iny
|
|
sta ($02),y
|
|
|
|
bne AdvanceTransitionObjectPointers
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EA70
|
|
; Values below $04 also take the reset path.
|
|
;------------------------------------------------------------------------------
|
|
|
|
CheckTransitionObjectLowBoundary:
|
|
cmp #$04
|
|
bcc ResetTransitionObjectPosition
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EA74
|
|
; Advance both source and mirrored pointers.
|
|
;------------------------------------------------------------------------------
|
|
|
|
AdvanceTransitionObjectPointers:
|
|
lda $00
|
|
clc
|
|
adc #$04
|
|
sta $00
|
|
|
|
lda $01
|
|
adc #$00
|
|
sta $01
|
|
|
|
lda $02
|
|
clc
|
|
adc #$04
|
|
sta $02
|
|
|
|
lda $03
|
|
adc #$00
|
|
sta $03
|
|
|
|
inx
|
|
|
|
cpx #$05
|
|
bne UpdateNextTransitionObject
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $EA94-$EAA2: Gameplay Animation State Dispatcher
|
|
;
|
|
; $87 is an even state value used directly as an offset into the pointer table
|
|
; at $EAA3.
|
|
;==============================================================================
|
|
|
|
DispatchTransitionAnimation:
|
|
ldy $87
|
|
|
|
lda TransitionAnimationHandlerTable,y
|
|
sta $10
|
|
|
|
lda TransitionAnimationHandlerTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
;==============================================================================
|
|
; $EAA3-$EAA8: Gameplay Animation State Table
|
|
;==============================================================================
|
|
|
|
TransitionAnimationHandlerTable:
|
|
.word DispatchTransitionAnimationPhase
|
|
.word DispatchTransitionAnimationState2
|
|
.word DispatchTransitionAnimationState4
|
|
|
|
;==============================================================================
|
|
; $EAA9-$EAB7: Animation Substate Dispatcher
|
|
;
|
|
; $88 is an even state value used directly as an offset into this table.
|
|
;==============================================================================
|
|
|
|
DispatchTransitionAnimationPhase:
|
|
ldy $88
|
|
|
|
lda TransitionAnimationPhaseTable,y
|
|
sta $10
|
|
|
|
lda TransitionAnimationPhaseTable+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
|
|
;==============================================================================
|
|
; $EAB8-$EABF: Animation Substate Table
|
|
;==============================================================================
|
|
|
|
TransitionAnimationPhaseTable:
|
|
.word UpdateTransitionAnimationFrame
|
|
.word UpdateTransitionAnimationType1
|
|
.word UpdateTransitionAnimationType2
|
|
.word UpdateTransitionAnimationPattern
|
|
|
|
|
|
;==============================================================================
|
|
; $EAC0-$EACD: Animation Substate 0
|
|
;
|
|
; Advances $B7 modulo eight and uses it to select a value for $028D.
|
|
;==============================================================================
|
|
|
|
UpdateTransitionAnimationFrame:
|
|
inc $B7
|
|
|
|
lda $B7
|
|
and #$07
|
|
tay
|
|
|
|
lda TransitionAnimationFrameTable,y
|
|
sta $028D
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $EACE-$EAD5: Animation frame table
|
|
;==============================================================================
|
|
|
|
TransitionAnimationFrameTable:
|
|
.byte $04,$04,$04,$05
|
|
.byte $05,$04,$01,$01
|
|
|
|
|
|
;==============================================================================
|
|
; $EAD6-$EAEC: Animation Substate 1
|
|
;
|
|
; Runs only when ($4B & 7) == 0. Alternates $028C between $0C and $0D
|
|
; according to frame-counter bit 3, then falls back into the common animation
|
|
; update path beginning at $EAC0.
|
|
;==============================================================================
|
|
|
|
UpdateTransitionAnimationType1:
|
|
lda $4B
|
|
and #$07
|
|
bne UpdateTransitionAnimationFrame
|
|
|
|
lda $4B
|
|
and #$08
|
|
bne AnimationSubstate_EAE7
|
|
|
|
lda #$0C
|
|
bne AnimationSubstate_EAE9
|
|
|
|
|
|
AnimationSubstate_EAE7:
|
|
lda #$0D
|
|
|
|
|
|
AnimationSubstate_EAE9:
|
|
sta $028C
|
|
|
|
bne UpdateTransitionAnimationFrame
|
|
|
|
|
|
;==============================================================================
|
|
; $EAED-$EB03: Animation Substate 2
|
|
;
|
|
; Updates only once every eight frames and alternates $028C between $1E/$1F
|
|
; according to frame-counter bit 3.
|
|
;==============================================================================
|
|
|
|
UpdateTransitionAnimationType2:
|
|
lda $4B
|
|
and #$07
|
|
beq AnimationSubstate_EAF5
|
|
|
|
rts
|
|
|
|
|
|
AnimationSubstate_EAF5:
|
|
lda $4B
|
|
and #$08
|
|
bne AnimationSubstate_EB00
|
|
|
|
lda #$1E
|
|
bne AnimationSubstate_EB02
|
|
|
|
|
|
AnimationSubstate_EB00:
|
|
lda #$1F
|
|
|
|
|
|
AnimationSubstate_EB02:
|
|
sta $028C
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $EB04-$EB28: Animation Substate 3
|
|
;
|
|
; Advances $B7 modulo eight, maps the result through a small index table, and
|
|
; uses the selected entry to load four consecutive animation values into
|
|
; $028D-$0290.
|
|
;
|
|
; The final BNE intentionally branches backward into the common update path.
|
|
;==============================================================================
|
|
|
|
UpdateTransitionAnimationPattern:
|
|
inc $B7
|
|
|
|
lda $B7
|
|
and #$07
|
|
tay
|
|
|
|
lda TransitionAnimationPatternIndex,y
|
|
tay
|
|
|
|
lda TransitionAnimationPatternTiles,y
|
|
sta $028D
|
|
|
|
lda TransitionAnimationPatternTiles+1,y
|
|
sta $028E
|
|
|
|
lda TransitionAnimationPatternTiles+2,y
|
|
sta $028F
|
|
|
|
lda TransitionAnimationPatternTiles+3,y
|
|
sta $0290
|
|
|
|
bne UpdateTransitionAnimationType2
|
|
|
|
|
|
;==============================================================================
|
|
; $EB29-$EB30: Animation pattern index table
|
|
;==============================================================================
|
|
|
|
TransitionAnimationPatternIndex:
|
|
.byte $00,$00,$00,$04
|
|
.byte $04,$00,$08,$08
|
|
|
|
|
|
;==============================================================================
|
|
; $EB31-$EB3C: Animation pattern data
|
|
;
|
|
; Indexed using offsets 0, 4 and 8. The final logical group continues beyond
|
|
; this initial range, so preserve the next code/data boundary carefully.
|
|
;==============================================================================
|
|
TransitionAnimationPatternTiles:
|
|
.byte $3C,$3D,$3E,$3F
|
|
.byte $3C,$40,$3E,$41
|
|
.byte $38,$39,$3A,$3B
|
|
|
|
;==============================================================================
|
|
; $EB3D-$EB4B: Gameplay Animation State $02 Dispatcher
|
|
;==============================================================================
|
|
|
|
DispatchTransitionAnimationState2:
|
|
ldy $88
|
|
|
|
lda TransitionAnimationState2Table,y
|
|
sta $10
|
|
|
|
lda TransitionAnimationState2Table+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
|
|
;==============================================================================
|
|
; $EB4C-$EB51: Gameplay Animation State $02 Pointer Table
|
|
;==============================================================================
|
|
|
|
TransitionAnimationState2Table:
|
|
.word UpdateTransitionAnimationFrame
|
|
.word UpdateTransitionAnimationState2
|
|
.word UpdateTransitionAnimationFrame
|
|
|
|
|
|
;==============================================================================
|
|
; $EB52-$EB6C: Animation State $02 Handler
|
|
;==============================================================================
|
|
|
|
UpdateTransitionAnimationState2:
|
|
jsr UpdateTransitionAnimationType1
|
|
|
|
lda $0274
|
|
cmp #$7D
|
|
bne AnimationState2_EB62
|
|
|
|
lda #$43
|
|
sta $028E
|
|
|
|
rts
|
|
|
|
|
|
AnimationState2_EB62:
|
|
cmp #$7B
|
|
beq AnimationState2_EB68
|
|
|
|
rts
|
|
|
|
|
|
AnimationState2_EB68:
|
|
lda #$44
|
|
sta $028E
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $EB6D-$EB7B: Gameplay Animation State $04 Dispatcher
|
|
;==============================================================================
|
|
DispatchTransitionAnimationState4:
|
|
ldy $88
|
|
|
|
lda TransitionAnimationState4Table,y
|
|
sta $10
|
|
|
|
lda TransitionAnimationState4Table+1,y
|
|
sta $11
|
|
|
|
jmp ($0010)
|
|
|
|
;==============================================================================
|
|
; $EB7C-$EB83: Gameplay Animation State $04 Pointer Table
|
|
;==============================================================================
|
|
|
|
TransitionAnimationState4Table:
|
|
.word UpdateTransitionAnimationFrame
|
|
.word UpdateTransitionAnimationState4Type1
|
|
.word UpdateTransitionAnimationState4Type2
|
|
.word UpdateTransitionAnimationState4Type2
|
|
|
|
;==============================================================================
|
|
; $EB84-$EB9E: Animation State $04 Handler 1
|
|
;
|
|
; Alternates $028C between $48/$49 every eight frames, while non-update
|
|
; frames tail-jump into the common $EAC0 animation updater.
|
|
;==============================================================================
|
|
UpdateTransitionAnimationState4Type1:
|
|
lda $4B
|
|
and #$07
|
|
beq AnimationState4_EB8E
|
|
|
|
jmp UpdateTransitionAnimationFrame
|
|
|
|
AnimationState4_EB8E:
|
|
lda $4B
|
|
and #$08
|
|
bne AnimationState4_EB97
|
|
|
|
lda #$48
|
|
bne AnimationState4_EB99
|
|
|
|
AnimationState4_EB97:
|
|
lda #$49
|
|
|
|
AnimationState4_EB99:
|
|
sta $028C
|
|
|
|
jmp UpdateTransitionAnimationFrame
|
|
|
|
;==============================================================================
|
|
; $EB9F-$EBB5: Animation State $04 Handler 2/3
|
|
;
|
|
; Alternates $028C between $4A and $4B every eight frames.
|
|
;==============================================================================
|
|
|
|
UpdateTransitionAnimationState4Type2:
|
|
lda $4B
|
|
and #$07
|
|
beq AnimationState4_EBA6
|
|
|
|
rts
|
|
|
|
AnimationState4_EBA6:
|
|
lda $4B
|
|
and #$08
|
|
bne AnimationState4_EBB0
|
|
|
|
lda #$4A
|
|
bne AnimationState4_EBB2
|
|
|
|
AnimationState4_EBB0:
|
|
lda #$4B
|
|
|
|
AnimationState4_EBB2:
|
|
sta $028C
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $EBB6-$EC3F: Gameplay Lookup Data
|
|
;
|
|
; Raw lookup data preserved byte-for-byte.
|
|
; Semantic subdivision is deferred until the consuming routines are decoded.
|
|
;==============================================================================
|
|
|
|
MazeGameplayData_EBB6:
|
|
|
|
; $EBB6-$EBC5
|
|
.byte $00,$07,$00,$00,$00,$04,$01,$06
|
|
.byte $01,$01,$01,$04,$01,$04,$02,$02
|
|
|
|
; $EBC6-$EBD5
|
|
.byte $02,$03,$02,$03,$02,$02,$02,$03
|
|
.byte $02,$02,$02,$02,$03,$03,$03,$05
|
|
|
|
; $EBD6-$EBE5
|
|
.byte $03,$02,$03,$03,$03,$02,$03,$02
|
|
.byte $04,$03,$03,$02,$03,$02,$04,$03
|
|
|
|
; $EBE6-$EBF5
|
|
.byte $03,$01,$04,$02,$05,$03,$03,$05
|
|
.byte $04,$02,$05,$03,$03,$02,$04,$02
|
|
|
|
; $EBF6-$EC05
|
|
.byte $06,$03,$03,$01,$05,$02,$06,$03
|
|
.byte $03,$01,$05,$02,$07,$03,$03,$03
|
|
|
|
; $EC06-$EC15
|
|
.byte $05,$02,$07,$03,$03,$01,$06,$02
|
|
.byte $07,$03,$03,$01,$06,$02,$07,$03
|
|
|
|
; $EC16-$EC25
|
|
.byte $03,$00,$06,$02,$07,$03,$03,$01
|
|
.byte $06,$02,$07,$03,$03,$00,$06,$02
|
|
|
|
; $EC26-$EC35
|
|
.byte $07,$03,$03,$00,$06,$02,$07,$03
|
|
.byte $03,$00,$06,$02,$07,$03,$04,$00
|
|
|
|
; $EC36-$EC3F
|
|
.byte $06,$02,$07,$03,$04,$00,$06,$02
|
|
.byte $07,$03
|
|
|
|
|
|
;==============================================================================
|
|
; $EC40-$ECAB: Gameplay Parameter Lookup Data
|
|
;
|
|
; Raw lookup data preserved byte-for-byte.
|
|
;
|
|
; The byte pattern strongly resembles little-endian 16-bit quantities, but
|
|
; semantic grouping is intentionally deferred until the consuming routines
|
|
; have been identified.
|
|
;==============================================================================
|
|
MazeGameplayData_EC40:
|
|
; $EC40-$EC4F
|
|
.byte $D0,$00,$C0,$00,$A0,$00,$B0,$00
|
|
.byte $A0,$00,$80,$00,$A0,$00,$B0,$00
|
|
|
|
; $EC50-$EC5F
|
|
.byte $90,$00,$50,$00,$50,$00,$D0,$00
|
|
.byte $C0,$00,$A0,$00,$B0,$00,$A0,$00
|
|
|
|
; $EC60-$EC6F
|
|
.byte $80,$00,$B0,$00,$C0,$00,$A0,$00
|
|
.byte $50,$00,$50,$00,$F0,$00,$E0,$00
|
|
|
|
; $EC70-$EC7F
|
|
.byte $C0,$00,$E0,$00,$D0,$00,$B0,$00
|
|
.byte $E0,$00,$F0,$00,$D0,$00,$70,$00
|
|
|
|
; $EC80-$EC8F
|
|
.byte $70,$00,$00,$01,$F0,$00,$D0,$00
|
|
.byte $00,$01,$F0,$00,$D0,$00,$00,$01
|
|
|
|
; $EC90-$EC9F
|
|
.byte $10,$01,$F0,$00,$80,$00,$80,$00
|
|
.byte $00,$01,$F0,$00,$D0,$00,$00,$01
|
|
|
|
; $ECA0-$ECAB
|
|
.byte $F0,$00,$D0,$00,$20,$01,$30,$01
|
|
.byte $10,$01,$80,$00
|
|
|
|
|
|
|
|
;==============================================================================
|
|
; $ECAC-$ECFF: Gameplay Lookup / Parameter Data
|
|
;
|
|
; Raw data preserved byte-for-byte. Semantic subdivision is intentionally
|
|
; deferred until the consuming routines are decoded.
|
|
;==============================================================================
|
|
|
|
MazeGameplayData_ECAC:
|
|
|
|
; $ECAC-$ECBB
|
|
.byte $80,$00,$07,$14,$07,$14,$05,$14
|
|
.byte $05,$FF,$07,$14,$07,$14,$05,$FF
|
|
|
|
; $ECBC-$ECCB
|
|
.byte $00,$00,$05,$14,$05,$14,$05,$FF
|
|
.byte $00,$00,$05,$14,$05,$14,$05,$FF
|
|
|
|
; $ECCC-$ECDB
|
|
.byte $00,$00,$14,$0A,$1E,$0F,$28,$14
|
|
.byte $32,$19,$3C,$1E,$50,$28,$64,$32
|
|
|
|
; $ECDC-$ECEB
|
|
.byte $02,$1E,$5A,$00,$03,$32,$00,$00
|
|
.byte $04,$00,$00,$00,$01,$07,$11,$20
|
|
|
|
; $ECEC-$ECFB
|
|
.byte $2D,$1F,$D0,$D0,$10,$13,$D0,$D0
|
|
.byte $10,$1D,$2D,$11,$C3,$C3,$03,$11
|
|
|
|
; $ECFC-$ECFF
|
|
.byte $C3,$C3,$03,$11
|
|
|
|
;==============================================================================
|
|
; $ED00-$EDFF: Gameplay Lookup / Pattern Data
|
|
;
|
|
; Raw data preserved byte-for-byte. This region contains highly structured
|
|
; repeated values and bit-pattern-like fields, but semantic subdivisions are
|
|
; deferred until the routines that consume this region are identified.
|
|
;==============================================================================
|
|
|
|
MazeLayoutData_ED00:
|
|
|
|
; $ED00-$ED0F
|
|
.byte $2D,$11,$03,$1F,$10,$1D,$03,$1F
|
|
.byte $10,$1D,$03,$11,$03,$1F,$10,$1D
|
|
|
|
; $ED10-$ED1F
|
|
.byte $03,$1F,$10,$1D,$03,$11,$2D,$11
|
|
.byte $01,$11,$20,$11,$03,$11,$20,$11
|
|
|
|
; $ED20-$ED2F
|
|
.byte $03,$11,$03,$11,$20,$11,$03,$11
|
|
.byte $20,$11,$01,$11,$2D,$11,$03,$1E
|
|
|
|
; $ED30-$ED3F
|
|
.byte $10,$1C,$03,$1E,$10,$1C,$03,$1A
|
|
.byte $03,$1E,$10,$1C,$03,$1E,$10,$1C
|
|
|
|
; $ED40-$ED4F
|
|
.byte $03,$11,$2D,$11,$C3,$C3,$C3,$C3
|
|
.byte $83,$11,$2D,$11,$03,$1F,$10,$1D
|
|
|
|
; $ED50-$ED5F
|
|
.byte $03,$1B,$03,$1F,$10,$10,$10,$1D
|
|
.byte $03,$1B,$03,$1F,$10,$1D,$03,$11
|
|
|
|
; $ED60-$ED6F
|
|
.byte $2D,$11,$03,$1E,$10,$1C,$03,$11
|
|
.byte $03,$1E,$10,$13,$10,$1C,$03,$11
|
|
|
|
; $ED70-$ED7F
|
|
.byte $03,$1E,$10,$1C,$03,$11,$2D,$11
|
|
.byte $C3,$03,$11,$83,$11,$83,$11,$C3
|
|
|
|
; $ED80-$ED8F
|
|
.byte $03,$11,$2D,$1E,$90,$1D,$03,$15
|
|
.byte $10,$18,$08,$1A,$08,$19,$10,$14
|
|
|
|
; $ED90-$ED9F
|
|
.byte $03,$1F,$90,$1C,$2D,$E0,$11,$03
|
|
.byte $11,$C0,$80,$11,$03,$11,$E0,$2D
|
|
|
|
; $EDA0-$EDAF
|
|
.byte $E0,$11,$03,$11,$00,$1F,$17,$2C
|
|
.byte $16,$1D,$00,$11,$03,$11,$E0,$2D
|
|
|
|
; $EDB0-$EDBF
|
|
.byte $22,$90,$1C,$03,$1A,$00,$11,$80
|
|
.byte $11,$00,$1A,$03,$1E,$90,$21,$04
|
|
|
|
; $EDC0-$EDCF
|
|
.byte $06,$C0,$03,$40,$11,$80,$11,$40
|
|
.byte $03,$C0,$05,$2D,$22,$90,$1D,$03
|
|
|
|
; $EDD0-$EDDF
|
|
.byte $1B,$00,$1E,$90,$1C,$00,$1B,$03
|
|
.byte $1F,$90,$21,$2D,$E0,$11,$03,$11
|
|
|
|
; $EDE0-$EDEF
|
|
.byte $C0,$80,$11,$03,$11,$E0,$2D,$E0
|
|
.byte $11,$03,$11,$00,$1F,$90,$1D,$00
|
|
|
|
; $EDF0-$EDFF
|
|
.byte $11,$03,$11,$E0,$2D,$1F,$90,$1C
|
|
.byte $03,$1A,$00,$1E,$10,$13,$10,$1C
|
|
|
|
;==============================================================================
|
|
; $EE00-$EE8B: Gameplay Lookup / Pattern Data
|
|
;
|
|
; Raw data preserved byte-for-byte.
|
|
;==============================================================================
|
|
|
|
MazeLayoutData_EE00:
|
|
|
|
; $EE00-$EE0F
|
|
.byte $00,$1A,$03,$1E,$90,$1D,$2D,$11
|
|
.byte $C3,$C3,$03,$11,$C3,$C3,$03,$11
|
|
|
|
; $EE10-$EE1F
|
|
.byte $2D,$11,$03,$19,$10,$1D,$03,$19
|
|
.byte $10,$18,$09,$1A,$09,$19,$10,$18
|
|
|
|
; $EE20-$EE2F
|
|
.byte $03,$1F,$10,$18,$03,$11,$2D,$11
|
|
.byte $01,$43,$11,$C3,$03,$00,$C3,$03
|
|
|
|
; $EE30-$EE3F
|
|
.byte $11,$43,$01,$11,$2D,$15,$10,$1D
|
|
.byte $03,$11,$03,$1B,$03,$1F,$90,$1D
|
|
|
|
; $EE40-$EE4F
|
|
.byte $03,$1B,$03,$11,$03,$1F,$10,$14
|
|
.byte $2D,$15,$10,$1C,$03,$1A,$03,$11
|
|
|
|
; $EE50-$EE5F
|
|
.byte $03,$1E,$10,$13,$10,$1C,$03,$11
|
|
.byte $03,$1A,$03,$1E,$10,$14,$2D,$11
|
|
|
|
; $EE60-$EE6F
|
|
.byte $C3,$03,$11,$83,$11,$83,$11,$C3
|
|
.byte $03,$11,$2D,$11,$03,$19,$90,$12
|
|
|
|
; $EE70-$EE7F
|
|
.byte $10,$18,$03,$1A,$03,$19,$10,$12
|
|
.byte $90,$18,$03,$11,$2D,$11,$C3,$C3
|
|
|
|
; $EE80-$EE8B
|
|
.byte $C3,$C3,$83,$11,$2D,$1E,$D0,$D0
|
|
.byte $D0,$D0,$90,$1C
|
|
|
|
|
|
;==============================================================================
|
|
; $EE8C-$EECF: Initialize Runtime Work Buffers
|
|
;
|
|
; Initializes zero-page runtime pointers and hardware state, clears $0600-$060F,
|
|
; then clears sixteen locations at eight-byte intervals beginning at $0620.
|
|
;==============================================================================
|
|
|
|
InitializeAudioEngine:
|
|
lda #$00
|
|
sta audioRequestPtr
|
|
|
|
lda #$06
|
|
sta audioRequestPtr+1
|
|
|
|
lda #$20
|
|
sta audioChannelTablePtr
|
|
|
|
lda #$06
|
|
sta audioChannelTablePtr+1
|
|
|
|
lda $F100
|
|
sta audioSequenceTablePtr
|
|
|
|
lda $F101
|
|
sta audioSequenceTablePtr+1
|
|
|
|
lda #$40
|
|
sta audioWorkValue
|
|
|
|
lda #$1F
|
|
sta APUSTATUS
|
|
|
|
lda #$C0
|
|
sta APUFRAMECNT
|
|
|
|
ldy #$00
|
|
|
|
lda #$00
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EEB8
|
|
; Clear sixteen contiguous bytes through ($F0).
|
|
;------------------------------------------------------------------------------
|
|
|
|
RuntimeInit_Clear0600:
|
|
sta (audioRequestPtr),y
|
|
|
|
iny
|
|
cpy #$10
|
|
bne RuntimeInit_Clear0600
|
|
|
|
ldy #$00
|
|
ldx #$10
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EEC3
|
|
; Clear sixteen entries at an eight-byte stride.
|
|
;
|
|
; LDA #$00 is intentionally executed on every iteration.
|
|
;------------------------------------------------------------------------------
|
|
RuntimeInit_Clear0620Stride:
|
|
lda #$00
|
|
sta (audioChannelTablePtr),y
|
|
|
|
tya
|
|
clc
|
|
adc #$08
|
|
tay
|
|
|
|
dex
|
|
bne RuntimeInit_Clear0620Stride
|
|
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $EED0-$EF2C: Initialize and Scan Runtime Command Slots
|
|
;
|
|
; Clears runtime work values, then scans sixteen 8-byte entries addressed
|
|
; through $F2/$F3. Occupied entries update flags through $FE/$FF, while newly
|
|
; activated entries copy four bytes through the pointer selected in $F6.
|
|
;
|
|
; Execution falls through at $EF2D into the next processing phase.
|
|
;==============================================================================
|
|
|
|
InitializeAudioChannels:
|
|
lda #$00
|
|
sta audioChannelFlags
|
|
sta $F9
|
|
sta $FA
|
|
sta $FB
|
|
sta audioChannelOffset
|
|
sta $FF
|
|
|
|
lda #$F8
|
|
sta audioIndirectPtr
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EEE2
|
|
; Examine one eight-byte slot.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ScanAudioChannelSlot:
|
|
ldy $FD
|
|
|
|
lda (audioChannelTablePtr),y
|
|
beq AdvanceAudioChannelSlot
|
|
|
|
cmp #$05
|
|
bcc ActivateAudioChannelSlot
|
|
|
|
sec
|
|
sbc #$05
|
|
tay
|
|
|
|
lda #$01
|
|
sta ($FE),y
|
|
|
|
jmp AdvanceAudioChannelSlot
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EEF5
|
|
; Process slot values $01-$04.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ActivateAudioChannelSlot:
|
|
sec
|
|
sbc #$01
|
|
tay
|
|
|
|
lda ($FE),y
|
|
bne AdvanceAudioChannelSlot
|
|
|
|
lda #$01
|
|
sta ($FE),y
|
|
|
|
tya
|
|
tax
|
|
|
|
adc #$04
|
|
|
|
ldy $FD
|
|
sta ($F2),y
|
|
|
|
txa
|
|
asl
|
|
asl
|
|
sta $F6
|
|
|
|
ldx #$00
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EF12
|
|
; Set initial four-byte copy count.
|
|
;------------------------------------------------------------------------------
|
|
|
|
BeginAudioChannelParameterCopy:
|
|
lda #$04
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EF14
|
|
; Push the current copy count.
|
|
;
|
|
; The loop at $EF20 deliberately returns here, so PHA is repeated on every
|
|
; iteration.
|
|
;------------------------------------------------------------------------------
|
|
|
|
CopyAudioChannelParameter:
|
|
pha
|
|
|
|
iny
|
|
|
|
lda ($F2),y
|
|
sta ($F6,x)
|
|
|
|
inc $F6
|
|
|
|
pla
|
|
|
|
sec
|
|
sbc #$01
|
|
bne CopyAudioChannelParameter
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EF22
|
|
; Advance to the next eight-byte slot.
|
|
;------------------------------------------------------------------------------
|
|
|
|
AdvanceAudioChannelSlot:
|
|
lda $FD
|
|
clc
|
|
adc #$08
|
|
sta $FD
|
|
|
|
cmp #$80
|
|
bcc ScanAudioChannelSlot
|
|
|
|
; Fall through to $EF2D.
|
|
|
|
|
|
;==============================================================================
|
|
; $EF2D-$F006: Process Runtime Command Entries
|
|
;
|
|
; Continuation of the runtime command-slot scan.
|
|
;
|
|
; $FC indexes source commands through ($F0).
|
|
; $FD indexes eight-byte runtime records through ($F2).
|
|
;
|
|
; Empty runtime records are initialized from tables through $F4/$F5 and
|
|
; command bytes fetched through the helper at $F0C3. Active records update
|
|
; countdowns and command parameters before both indices advance.
|
|
;==============================================================================
|
|
|
|
UpdateAudioChannels:
|
|
ldy #$00
|
|
sty $FC
|
|
sty $FD
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EF33
|
|
; Process one source entry.
|
|
;------------------------------------------------------------------------------
|
|
|
|
UpdateNextAudioSequence:
|
|
ldy $FC
|
|
|
|
lda ($F0),y
|
|
bne CheckAudioChannelActive
|
|
|
|
jmp AdvanceAudioSequence
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EF3B
|
|
; Check the corresponding runtime record.
|
|
;------------------------------------------------------------------------------
|
|
|
|
CheckAudioChannelActive:
|
|
ldy $FD
|
|
|
|
lda ($F2),y
|
|
bne TickAudioChannelDelay
|
|
|
|
lda $FC
|
|
asl
|
|
tay
|
|
|
|
lda ($F4),y
|
|
pha
|
|
|
|
lda $FD
|
|
adc #$05
|
|
tay
|
|
|
|
pla
|
|
sta ($F2),y
|
|
|
|
lda $FC
|
|
asl
|
|
adc #$01
|
|
tay
|
|
|
|
lda ($F4),y
|
|
pha
|
|
|
|
lda $FD
|
|
adc #$06
|
|
tay
|
|
|
|
pla
|
|
sta ($F2),y
|
|
|
|
jsr $F0C3
|
|
|
|
ldy $FD
|
|
sta ($F2),y
|
|
|
|
jsr $F0C3
|
|
tax
|
|
|
|
lda $FD
|
|
clc
|
|
adc #$01
|
|
tay
|
|
|
|
txa
|
|
sta ($F2),y
|
|
|
|
jsr $F0C3
|
|
tax
|
|
|
|
lda $FD
|
|
clc
|
|
adc #$02
|
|
tay
|
|
|
|
txa
|
|
sta ($F2),y
|
|
|
|
jsr $F0C3
|
|
tax
|
|
|
|
lda $FD
|
|
clc
|
|
adc #$04
|
|
tay
|
|
|
|
txa
|
|
sta ($F2),y
|
|
|
|
jmp DecodeAudioCommand
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EF94
|
|
; Decrement the active record countdown at offset 7.
|
|
;------------------------------------------------------------------------------
|
|
|
|
TickAudioChannelDelay:
|
|
lda $FD
|
|
clc
|
|
adc #$07
|
|
tay
|
|
|
|
lda ($F2),y
|
|
sec
|
|
sbc #$01
|
|
sta ($F2),y
|
|
|
|
bne AdvanceAudioSequence
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EFA2
|
|
; Fetch and decode the next runtime command byte.
|
|
;------------------------------------------------------------------------------
|
|
|
|
DecodeAudioCommand:
|
|
jsr $F0C3
|
|
|
|
cmp #$F0
|
|
bcs $F00D
|
|
|
|
cmp #$C0
|
|
bcs LoadAudioCommandDelay
|
|
|
|
pha
|
|
|
|
and #$F0
|
|
lsr
|
|
lsr
|
|
lsr
|
|
tax
|
|
|
|
lda AudioFrequencyLookupTable,x
|
|
sta $FE
|
|
|
|
lda AudioFrequencyLookupTable+1,x
|
|
sta $FF
|
|
|
|
pla
|
|
|
|
and #$0F
|
|
beq ApplyAudioFrequencyMask
|
|
|
|
tax
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EFC4
|
|
; Shift the selected mask by the command low nibble.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ShiftAudioFrequencyMask:
|
|
lsr $FE
|
|
ror $FF
|
|
|
|
dex
|
|
bne ShiftAudioFrequencyMask
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EFCB
|
|
; Merge the generated mask into the runtime record.
|
|
;------------------------------------------------------------------------------
|
|
|
|
ApplyAudioFrequencyMask:
|
|
lda $FD
|
|
clc
|
|
adc #$04
|
|
tay
|
|
|
|
lda ($F2),y
|
|
and #$F8
|
|
ora $FE
|
|
sta ($F2),y
|
|
|
|
lda $FF
|
|
dey
|
|
sta ($F2),y
|
|
|
|
ldy $FD
|
|
|
|
lda ($F2),y
|
|
cmp #$05
|
|
bcc LoadAudioCommandDelay
|
|
|
|
sec
|
|
sbc #$04
|
|
sta ($F2),y
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EFEB
|
|
; Load the new runtime countdown.
|
|
;------------------------------------------------------------------------------
|
|
|
|
LoadAudioCommandDelay:
|
|
jsr $F0C3
|
|
pha
|
|
|
|
lda $FD
|
|
clc
|
|
adc #$07
|
|
tay
|
|
|
|
pla
|
|
sta ($F2),y
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; $EFF8
|
|
; Advance to the next runtime/source entry.
|
|
;------------------------------------------------------------------------------
|
|
|
|
AdvanceAudioSequence:
|
|
lda $FD
|
|
clc
|
|
adc #$08
|
|
sta $FD
|
|
|
|
lda $FC
|
|
adc #$01
|
|
sta $FC
|
|
|
|
cmp #$10
|
|
|
|
; Fall through at $F007 to the next control-flow block.
|
|
|
|
;==============================================================================
|
|
; $F007-$F00C: Runtime command-loop termination / continuation
|
|
;
|
|
; Entry is the fall-through from the CMP #$10 at $F005.
|
|
;==============================================================================
|
|
|
|
FinishAudioSequenceScan:
|
|
bcs AudioSequenceUpdateDone
|
|
|
|
jmp UpdateNextAudioSequence
|
|
|
|
|
|
AudioSequenceUpdateDone:
|
|
rts
|
|
|
|
|
|
;==============================================================================
|
|
; $F00D-$F01D: Runtime Command Dispatcher
|
|
;
|
|
; Input:
|
|
; A = command byte >= $F0
|
|
;
|
|
; Uses the low nibble to select a handler through the pointer table at $F01E.
|
|
;==============================================================================
|
|
|
|
DispatchAudioCommand:
|
|
and #$0F
|
|
asl
|
|
tax
|
|
|
|
lda AudioCommandHandlerTable,x
|
|
sta $FE
|
|
|
|
lda AudioCommandHandlerTable+1,x
|
|
sta $FF
|
|
|
|
jmp ($00FE)
|
|
|
|
|
|
;==============================================================================
|
|
; $F01E-$F03D: Runtime Command Handler Table
|
|
;
|
|
; Sixteen 16-bit handlers. Unsupported command values use the no-op handler
|
|
; at $F03E.
|
|
;==============================================================================
|
|
|
|
AudioCommandHandlerTable:
|
|
.word StopAudioSequence ; $F0
|
|
.word AudioCommandF1 ; $F1
|
|
.word AudioCommandF2 ; $F2
|
|
.word AudioCommandF3 ; $F3
|
|
.word AudioCommandF4 ; $F4
|
|
.word AudioCommandF5 ; $F5
|
|
.word AudioCommandF6 ; $F6
|
|
.word StopAudioSequence ; $F7
|
|
.word StopAudioSequence ; $F8
|
|
.word StopAudioSequence ; $F9
|
|
.word StopAudioSequence ; $FA
|
|
.word StopAudioSequence ; $FB
|
|
.word StopAudioSequence ; $FC
|
|
.word StopAudioSequence ; $FD
|
|
.word StopAudioSequence ; $FE
|
|
.word StopAudioSequence ; $FF
|
|
|
|
|
|
;==============================================================================
|
|
; $F03E-$F04A: Runtime command no-op/terminate handler
|
|
;
|
|
; Clears the current source entry and current runtime record, then advances
|
|
; through the common continuation at $EFF8.
|
|
;==============================================================================
|
|
|
|
StopAudioSequence:
|
|
ldy $FC
|
|
|
|
lda #$00
|
|
sta ($F0),y
|
|
|
|
ldy $FD
|
|
sta ($F2),y
|
|
|
|
jmp AdvanceAudioSequence
|
|
|
|
|
|
;==============================================================================
|
|
; $F04B-$F062: Runtime command $F1
|
|
;
|
|
; Fetches one command byte and merges its bits into runtime-record byte 0/1.
|
|
;==============================================================================
|
|
|
|
AudioCommandF1:
|
|
jsr FetchAudioSequenceByte
|
|
pha
|
|
|
|
lda $FD
|
|
clc
|
|
adc #$01
|
|
tay
|
|
|
|
lda ($F2),y
|
|
and #$3F
|
|
sta ($F2),y
|
|
|
|
pla
|
|
ora ($F2),y
|
|
sta ($F2),y
|
|
|
|
jmp DecodeAudioCommand
|
|
|
|
;==============================================================================
|
|
; $F063-$F07A: Runtime command $F2
|
|
;==============================================================================
|
|
|
|
AudioCommandF2:
|
|
jsr FetchAudioSequenceByte
|
|
pha
|
|
|
|
lda $FD
|
|
clc
|
|
adc #$01
|
|
tay
|
|
|
|
lda ($F2),y
|
|
and #$CF
|
|
sta ($F2),y
|
|
|
|
pla
|
|
ora ($F2),y
|
|
sta ($F2),y
|
|
|
|
jmp DecodeAudioCommand
|
|
|
|
;==============================================================================
|
|
; $F07B-$F092: Runtime command $F3
|
|
;==============================================================================
|
|
|
|
AudioCommandF3:
|
|
jsr FetchAudioSequenceByte
|
|
pha
|
|
|
|
lda $FD
|
|
clc
|
|
adc #$01
|
|
tay
|
|
|
|
lda ($F2),y
|
|
and #$F0
|
|
sta ($F2),y
|
|
|
|
pla
|
|
ora ($F2),y
|
|
sta ($F2),y
|
|
|
|
jmp DecodeAudioCommand
|
|
|
|
;==============================================================================
|
|
; $F093-$F0A2: Runtime command $F4
|
|
;==============================================================================
|
|
|
|
AudioCommandF4:
|
|
jsr FetchAudioSequenceByte
|
|
pha
|
|
|
|
lda $FD
|
|
clc
|
|
adc #$02
|
|
tay
|
|
|
|
pla
|
|
sta ($F2),y
|
|
|
|
jmp DecodeAudioCommand
|
|
|
|
;==============================================================================
|
|
; $F0A3-$F0B2: Runtime command $F5
|
|
;==============================================================================
|
|
|
|
AudioCommandF5:
|
|
jsr FetchAudioSequenceByte
|
|
pha
|
|
|
|
lda $FD
|
|
clc
|
|
adc #$04
|
|
tay
|
|
|
|
pla
|
|
sta ($F2),y
|
|
|
|
jmp DecodeAudioCommand
|
|
|
|
;==============================================================================
|
|
; $F0B3-$F0C2: Runtime command $F6
|
|
;==============================================================================
|
|
|
|
AudioCommandF6:
|
|
jsr FetchAudioSequenceByte
|
|
pha
|
|
|
|
lda $FD
|
|
clc
|
|
adc #$01
|
|
tay
|
|
|
|
pla
|
|
sta ($F2),y
|
|
|
|
jmp DecodeAudioCommand
|
|
|
|
;==============================================================================
|
|
; $F0C3-$F0E7: Fetch Runtime Command Byte
|
|
;
|
|
; Uses the 16-bit source pointer stored in runtime-record bytes +5/+6.
|
|
;
|
|
; Output:
|
|
; A = byte read from the command stream
|
|
;
|
|
; Side effect:
|
|
; Advances the source pointer by one and writes it back into bytes +5/+6.
|
|
;==============================================================================
|
|
|
|
FetchAudioSequenceByte:
|
|
lda $FD
|
|
clc
|
|
adc #$05
|
|
tay
|
|
|
|
lda ($F2),y
|
|
sta $FE
|
|
|
|
iny
|
|
|
|
lda ($F2),y
|
|
sta $FF
|
|
|
|
ldx #$00
|
|
|
|
lda ($FE,x)
|
|
pha
|
|
|
|
lda $FE
|
|
|
|
dey
|
|
clc
|
|
adc #$01
|
|
sta ($F2),y
|
|
|
|
lda $FF
|
|
adc #$00
|
|
|
|
iny
|
|
sta ($F2),y
|
|
|
|
pla
|
|
|
|
rts
|
|
|
|
;==============================================================================
|
|
; $F0E8-$F14F: Runtime / Audio Lookup Data
|
|
;
|
|
; Raw data preserved byte-for-byte.
|
|
;
|
|
; The first portion is referenced by UpdateAudioChannels through
|
|
; $F0E8,X / $F0E9,X as paired mask values. Later portions appear to contain
|
|
; additional pointers and command/parameter data.
|
|
;
|
|
; Semantic subdivision is deferred until all consumers are decoded.
|
|
;==============================================================================
|
|
AudioFrequencyLookupTable:
|
|
; $F0E8-$F0F7
|
|
.byte $03,$F9,$03,$C0,$03,$8A,$03,$57
|
|
.byte $03,$27,$02,$FA,$02,$CF,$02,$A7
|
|
|
|
; $F0F8-$F107
|
|
.byte $02,$81,$02,$5D,$02,$3B,$02,$1B
|
|
.byte $02,$F1,$CB,$F3,$14,$F4,$22,$F1
|
|
|
|
; $F108-$F117
|
|
.byte $3C,$F3,$3F,$F4,$50,$F4,$37,$F1
|
|
.byte $E4,$F1,$1D,$F3,$CF,$F1,$62,$F1
|
|
|
|
; $F118-$F127
|
|
.byte $8D,$F1,$B0,$F1,$07,$F2,$7A,$F2
|
|
.byte $61,$F4,$01,$03,$7F,$08,$A2,$0C
|
|
|
|
; $F128-$F137
|
|
.byte $A2,$0C,$A2,$0C,$A2,$0C,$A2,$0C
|
|
.byte $A2,$0C,$A2,$0C,$A2,$0C,$F0,$03
|
|
|
|
; $F138-$F147
|
|
.byte $04,$7F,$08,$33,$01,$23,$01,$03
|
|
.byte $01,$A2,$01,$92,$01,$72,$01,$52
|
|
|
|
; $F148-$F14F
|
|
.byte $01,$32,$01,$22,$01,$02,$01,$A1
|
|
|
|
|
|
|
|
;==============================================================================
|
|
; $F150-$F24F: Runtime / Audio Command Data
|
|
;
|
|
; Raw data preserved byte-for-byte.
|
|
;
|
|
; The region contains strongly patterned pairs and command-like values used
|
|
; by the late-PRG runtime/audio interpreter. Semantic subdivision is deferred
|
|
; until its individual consumers are mapped.
|
|
;==============================================================================
|
|
AudioSequenceData_F150:
|
|
; $F150-$F15F
|
|
.byte $01,$91,$01,$C0,$08,$91,$01,$A1
|
|
.byte $01,$02,$01,$22,$01,$32,$01,$52
|
|
|
|
; $F160-$F16F
|
|
.byte $01,$F0,$01,$96,$7F,$28,$82,$01
|
|
.byte $92,$01,$A2,$01,$B2,$01,$03,$01
|
|
|
|
; $F170-$F17F
|
|
.byte $13,$01,$23,$01,$33,$01,$43,$01
|
|
.byte $53,$01,$33,$01,$23,$01,$13,$01
|
|
|
|
; $F180-$F18F
|
|
.byte $03,$01,$B2,$01,$A2,$01,$92,$01
|
|
.byte $82,$01,$72,$01,$F0,$01,$96,$7F
|
|
|
|
; $F190-$F19F
|
|
.byte $28,$A2,$01,$B2,$01,$03,$01,$13
|
|
.byte $01,$23,$01,$33,$01,$43,$01,$53
|
|
|
|
; $F1A0-$F1AF
|
|
.byte $01,$33,$01,$23,$01,$13,$01,$03
|
|
.byte $01,$B2,$01,$A2,$01,$92,$01,$F0
|
|
|
|
; $F1B0-$F1BF
|
|
.byte $01,$96,$7F,$28,$B2,$01,$03,$01
|
|
.byte $13,$01,$23,$01,$33,$01,$43,$01
|
|
|
|
; $F1C0-$F1CF
|
|
.byte $53,$01,$33,$01,$23,$01,$13,$01
|
|
.byte $03,$01,$B2,$01,$A2,$01,$F0,$02
|
|
|
|
; $F1D0-$F1DF
|
|
.byte $9C,$7F,$28,$31,$01,$71,$01,$A1
|
|
.byte $01,$12,$01,$32,$01,$72,$01,$A2
|
|
|
|
; $F1E0-$F1EF
|
|
.byte $01,$13,$01,$F0,$02,$00,$7F,$10
|
|
.byte $20,$03,$50,$03,$80,$02,$A0,$02
|
|
|
|
; $F1F0-$F1FF
|
|
.byte $21,$02,$51,$02,$81,$01,$A1,$01
|
|
.byte $02,$01,$22,$01,$32,$01,$52,$01
|
|
|
|
; $F200-$F20F
|
|
.byte $F5,$18,$73,$01,$C0,$08,$F0,$01
|
|
.byte $03,$7F,$08,$72,$02,$82,$08,$72
|
|
|
|
; $F210-$F21F
|
|
.byte $02,$82,$08,$72,$02,$82,$08,$42
|
|
.byte $02,$52,$04,$32,$04,$82,$06,$82
|
|
|
|
; $F220-$F22F
|
|
.byte $08,$B2,$02,$03,$10,$C0,$08,$72
|
|
.byte $02,$82,$08,$72,$02,$82,$08,$72
|
|
|
|
; $F230-$F23F
|
|
.byte $02,$82,$08,$42,$02,$52,$04,$32
|
|
.byte $04,$82,$06,$82,$08,$42,$02,$52
|
|
|
|
; $F240-$F24F
|
|
.byte $10,$C0,$08,$72,$02,$82,$08,$72
|
|
.byte $02,$82,$08,$72,$02,$82,$08,$42
|
|
|
|
;==============================================================================
|
|
; $F250-$F34F: Runtime / Audio Command Data
|
|
;
|
|
; Raw data preserved byte-for-byte.
|
|
; Semantic subdivision is deferred until the individual stream consumers are
|
|
; fully mapped.
|
|
;==============================================================================
|
|
|
|
AudioSequenceData_F250:
|
|
|
|
; $F250-$F25F
|
|
.byte $02,$52,$04,$32,$04,$82,$06,$82
|
|
.byte $08,$A2,$02,$B2,$08,$03,$02,$13
|
|
|
|
; $F260-$F26F
|
|
.byte $0A,$13,$02,$23,$0C,$03,$02,$13
|
|
.byte $08,$A2,$02,$B2,$08,$82,$0A,$A2
|
|
|
|
; $F270-$F27F
|
|
.byte $02,$B2,$0A,$72,$02,$82,$10,$C0
|
|
.byte $08,$F0,$02,$81,$7F,$40,$80,$08
|
|
|
|
; $F280-$F28F
|
|
.byte $C0,$06,$80,$04,$C0,$02,$80,$08
|
|
.byte $C0,$06,$80,$04,$C0,$02,$80,$08
|
|
|
|
; $F290-$F29F
|
|
.byte $C0,$06,$80,$04,$C0,$02,$01,$04
|
|
.byte $C0,$01,$11,$04,$C0,$01,$21,$04
|
|
|
|
; $F2A0-$F2AF
|
|
.byte $C0,$01,$31,$04,$C0,$01,$80,$08
|
|
.byte $C0,$06,$80,$04,$C0,$02,$80,$08
|
|
|
|
; $F2B0-$F2BF
|
|
.byte $C0,$06,$80,$04,$C0,$02,$80,$08
|
|
.byte $C0,$06,$80,$04,$C0,$02,$01,$04
|
|
|
|
; $F2C0-$F2CF
|
|
.byte $C0,$01,$11,$04,$C0,$01,$21,$04
|
|
.byte $C0,$01,$31,$04,$C0,$01,$80,$08
|
|
|
|
; $F2D0-$F2DF
|
|
.byte $C0,$06,$80,$04,$C0,$02,$80,$08
|
|
.byte $C0,$06,$80,$04,$C0,$02,$80,$08
|
|
|
|
; $F2E0-$F2EF
|
|
.byte $C0,$06,$80,$04,$C0,$02,$01,$04
|
|
.byte $C0,$01,$11,$04,$C0,$01,$21,$04
|
|
|
|
; $F2F0-$F2FF
|
|
.byte $C0,$01,$31,$04,$C0,$01,$81,$0A
|
|
.byte $31,$04,$C0,$01,$21,$04,$C0,$01
|
|
|
|
; $F300-$F30F
|
|
.byte $11,$04,$C0,$01,$B0,$04,$C0,$01
|
|
.byte $80,$04,$C0,$01,$70,$04,$C0,$01
|
|
|
|
; $F310-$F31F
|
|
.byte $60,$08,$C0,$02,$70,$08,$C0,$02
|
|
.byte $80,$0C,$C0,$06,$F0,$02,$98,$7F
|
|
|
|
; $F320-$F32F
|
|
.byte $28,$33,$01,$23,$01,$13,$01,$03
|
|
.byte $01,$A2,$01,$82,$01,$72,$01,$52
|
|
|
|
; $F330-$F33F
|
|
.byte $01,$32,$01,$12,$01,$A1,$01,$71
|
|
.byte $01,$31,$01,$F0,$01,$42,$7F,$38
|
|
|
|
; $F340-$F34F
|
|
.byte $23,$02,$33,$02,$43,$02,$53,$02
|
|
.byte $43,$02,$33,$02,$23,$02,$13,$02
|
|
|
|
;==============================================================================
|
|
; $F350-$F44F: Runtime / Audio Command Data
|
|
;
|
|
; Raw command/parameter stream preserved byte-for-byte.
|
|
; Semantic subdivision is deferred until all stream consumers are mapped.
|
|
;==============================================================================
|
|
|
|
AudioSequenceData_F350:
|
|
|
|
; $F350-$F35F
|
|
.byte $23,$02,$33,$02,$43,$02,$33,$02
|
|
.byte $23,$02,$13,$02,$03,$02,$13,$02
|
|
|
|
; $F360-$F36F
|
|
.byte $23,$02,$33,$02,$23,$02,$13,$02
|
|
.byte $03,$02,$B2,$02,$03,$02,$13,$02
|
|
|
|
; $F370-$F37F
|
|
.byte $23,$02,$13,$02,$03,$02,$B2,$02
|
|
.byte $A2,$02,$B2,$02,$03,$02,$23,$02
|
|
|
|
; $F380-$F38F
|
|
.byte $03,$02,$B2,$02,$A2,$02,$92,$02
|
|
.byte $A2,$02,$B2,$02,$03,$02,$B2,$02
|
|
|
|
; $F390-$F39F
|
|
.byte $A2,$02,$92,$02,$82,$02,$92,$02
|
|
.byte $A2,$02,$03,$02,$A2,$02,$92,$02
|
|
|
|
; $F3A0-$F3AF
|
|
.byte $82,$02,$F2,$00,$F3,$00,$F5,$18
|
|
.byte $31,$01,$71,$01,$B1,$01,$32,$01
|
|
|
|
; $F3B0-$F3BF
|
|
.byte $72,$01,$B2,$01,$33,$01,$73,$01
|
|
.byte $C0,$02,$31,$01,$71,$01,$B1,$01
|
|
|
|
; $F3C0-$F3CF
|
|
.byte $32,$01,$72,$01,$B2,$01,$33,$01
|
|
.byte $73,$01,$F0,$01,$81,$7F,$40,$31
|
|
|
|
; $F3D0-$F3DF
|
|
.byte $08,$32,$08,$A1,$08,$71,$08,$32
|
|
.byte $07,$A1,$07,$71,$0C,$C0,$06,$41
|
|
|
|
; $F3E0-$F3EF
|
|
.byte $08,$42,$08,$B1,$08,$81,$08,$42
|
|
.byte $07,$B1,$07,$81,$0C,$C0,$06,$31
|
|
|
|
; $F3F0-$F3FF
|
|
.byte $08,$32,$08,$A1,$08,$71,$08,$32
|
|
.byte $07,$A1,$07,$71,$0C,$C0,$06,$61
|
|
|
|
; $F400-$F40F
|
|
.byte $05,$71,$05,$81,$05,$81,$05,$91
|
|
.byte $05,$A1,$05,$A1,$05,$B1,$05,$02
|
|
|
|
; $F410-$F41F
|
|
.byte $05,$32,$0C,$F0,$02,$82,$7F,$40
|
|
.byte $30,$18,$A0,$08,$30,$0E,$A0,$0C
|
|
|
|
; $F420-$F42F
|
|
.byte $C0,$06,$40,$18,$B0,$08,$40,$0E
|
|
.byte $B0,$0C,$C0,$06,$30,$18,$A0,$08
|
|
|
|
; $F430-$F43F
|
|
.byte $30,$0E,$A0,$0C,$C0,$06,$A0,$0F
|
|
.byte $01,$0F,$21,$0F,$31,$0C,$F0,$01
|
|
|
|
; $F440-$F44F
|
|
.byte $9F,$7F,$28,$01,$01,$41,$01,$71
|
|
.byte $01,$A1,$01,$02,$01,$F5,$18,$F0
|
|
|
|
|
|
;==============================================================================
|
|
; $F450-$F49A: Runtime / Audio Command Data
|
|
;
|
|
; Raw command data preserved byte-for-byte.
|
|
;==============================================================================
|
|
|
|
AudioSequenceData_F450:
|
|
|
|
; $F450-$F45F
|
|
.byte $01,$9F,$7F,$28,$02,$01,$A1,$01
|
|
.byte $71,$01,$41,$01,$F5,$18,$01,$01
|
|
|
|
; $F460-$F46F
|
|
.byte $F0,$01,$9F,$7F,$28,$52,$01,$92
|
|
.byte $01,$03,$01,$33,$01,$F5,$18,$53
|
|
|
|
; $F470-$F47F
|
|
.byte $03,$F5,$28,$53,$01,$33,$01,$03
|
|
.byte $01,$92,$01,$F5,$18,$52,$03,$92
|
|
|
|
; $F480-$F48F
|
|
.byte $01,$13,$01,$43,$01,$73,$01,$F5
|
|
.byte $18,$93,$0A,$F5,$28,$93,$01,$73
|
|
|
|
; $F490-$F49A
|
|
.byte $01,$43,$01,$13,$01,$F5,$18,$92
|
|
.byte $03,$F0,$FF
|
|
|
|
;==============================================================================
|
|
; $F49B-$F64F: PRG Padding
|
|
;==============================================================================
|
|
.res $0B5B, $FF
|
|
|
|
|
|
;==============================================================================
|
|
; $FFF6-$FFF9: Final ROM Data
|
|
;
|
|
; Notes:
|
|
; $FFF6/$FFF7 are read directly by DrawMazeNametable:
|
|
;
|
|
; lda $FFF7
|
|
; sta $01
|
|
; lda $FFF6
|
|
; sta $00
|
|
;
|
|
; Therefore the first two bytes form the little-endian value $ECEC.
|
|
;
|
|
; $FFF8/$FFF9 form the little-endian value $C10E.
|
|
;==============================================================================
|
|
|
|
MazeDataPointerBytes:
|
|
.byte $EC,$EC
|
|
.byte $0E,$C1
|
|
|
|
;==============================================================================
|
|
; $FFFA-$FFFF: Interrupt Vectors
|
|
;==============================================================================
|
|
.org $FFFA
|
|
CpuInterruptVectors:
|
|
.word NmiHandler ; NMI
|
|
.word Reset ; Reset
|
|
.word IrqHandler ; IRQ/BRK
|