Files
disasm/NROM/Baseball (UE)/listing.txt
T
tmerrittandClaude Opus 4.8 49e117bfcc Fix Pass 3 symbol application and add promotion criteria to PROMPTS.md
- 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>
2026-10-20 16:44:06 -04:00

22402 lines
1.4 MiB
Plaintext

ca65 V2.18 - Debian 2.19-2
Main file : prg.s
Current file: prg.s
000000r 1 ; Balloon Fight - ca65 PRG disassembly
000000r 1 ; 16 KiB NROM PRG mapped at CPU $C000-$FFFF
000000r 1 ; Hardware register and controller symbols are provided by symbols.inc.
000000r 1 .setcpu "6502"
000000r 1 .include "symbols.inc"
000000r 2 ; PPU registers
000000r 2 PPUCTRL = $2000
000000r 2 PPUMASK = $2001
000000r 2 PPUSTATUS = $2002
000000r 2 OAMADDR = $2003
000000r 2 OAMDATA = $2004
000000r 2 PPUSCROLL = $2005
000000r 2 PPUADDR = $2006
000000r 2 PPUDATA = $2007
000000r 2 OAMDMA = $4014
000000r 2 JOY1 = $4016
000000r 2 JOY2 = $4017
000000r 2
000000r 2 APUPC1BASE = $4000
000000r 2 APUPC1SWEEP = $4001
000000r 2 APUPC1TLOW = $4002
000000r 2 APUPC1THIGH = $4003
000000r 2
000000r 2 APUPC2BASE = $4004
000000r 2 APUPC2SWEEP = $4005
000000r 2 APUPC2LOW = $4006
000000r 2 APUPC2HIGH = $4007
000000r 2
000000r 2 APUTRIBASE = $4008
000000r 2 APUTRILOW = $400A
000000r 2 APUTRIHIGH = $400B
000000r 2
000000r 2 APUNOISEBASE = $400C
000000r 2 APUNOISELOOP = $400E
000000r 2 APUNOISELENGTH = $400F
000000r 2
000000r 2 APUDMABASE = $4010
000000r 2 APUDMALOAD = $4011
000000r 2 APUDMAADDR = $4012
000000r 2 APUDMALEN = $4013
000000r 2
000000r 2 APUCTRL = $4015
000000r 2 APUSTATUS = $4015
000000r 2 APUFRAMECNT = $4017
000000r 2
000000r 2 ; Controller Masks
000000r 2 PAD_RIGHT=$01
000000r 2 PAD_LEFT=$02
000000r 2 PAD_DOWN=$04
000000r 2 PAD_UP=$08
000000r 2 PAD_START=$10
000000r 2 PAD_SELECT=$20
000000r 2 PAD_B=$40
000000r 2 PAD_A=$80
000000r 2 PAD_HORIZONTAL=PAD_LEFT|PAD_RIGHT
000000r 2 PAD_VERTICAL=PAD_UP|PAD_DOWN
000000r 2 PAD_DPAD=PAD_HORIZONTAL|PAD_VERTICAL
000000r 2
000000r 1 .include "locals.inc"
000000r 2 ; ============================================================================
000000r 2 ; Confirmed and high-confidence zero-page symbols
000000r 2 ; ============================================================================
000000r 2
000000r 2 IndirectPtrLo = $00
000000r 2 IndirectPtrHi = $01
000000r 2 RecordPtrLo = $02
000000r 2 RecordPtrHi = $03
000000r 2
000000r 2 MathTemp05 = $05
000000r 2 NmiSavedX = $0D
000000r 2 NmiSavedY = $0E
000000r 2 DerivedControl0 = $0F
000000r 2
000000r 2 ControllerHeld1 = $11
000000r 2 ControllerHeld2 = $12
000000r 2 InputState1 = $13
000000r 2 InputState2 = $14
000000r 2 ControllerPressed1 = $15
000000r 2 ControllerPressed2 = $16
000000r 2 InputAux1 = $17
000000r 2 InputAux2 = $18
000000r 2
000000r 2 RandomStateLo = $19
000000r 2 RandomStateHi = $1A
000000r 2 TransitionCounter = $1B
000000r 2 TransitionActive = $1D
000000r 2 SessionActive = $1E
000000r 2 NmiStateFlag = $1F
000000r 2 FrameState20 = $20
000000r 2 SelectedPitchAction = $21
000000r 2
000000r 2 SavedIndex = $22
000000r 2 InlineReturnLo = $26
000000r 2 InlineReturnHi = $27
000000r 2
000000r 2 SelectionValue0 = $32
000000r 2 RoundStateIndex = $33
000000r 2 PlayerOneSelection = $34
000000r 2 PlayerTwoSelection = $35
000000r 2
000000r 2 ObjectScreenX = $36
000000r 2 ObjectScreenXHi = $37
000000r 2 ObjectScreenY = $38
000000r 2 ObjectScreenYHi = $39
000000r 2
000000r 2 PpuQueueOffset = $3E
000000r 2 OamWriteOffset = $3F
000000r 2
000000r 2 ModeFlags = $40
000000r 2 CurrentObjectArrayOffset= $42
000000r 2 SelectionState = $43
000000r 2 PlayerSelectionActive = $44
000000r 2 MatchCompleteFlag = $45
000000r 2 StateSequenceActive = $46
000000r 2
000000r 2 DelayCounter = $48
000000r 2 LoopCounter49 = $49
000000r 2 QueueDestination = $4A
000000r 2 ActivePlayerSide = $4B
000000r 2 HorizontalDirectionMask = $4C
000000r 2
000000r 2 RandomState0 = $4D
000000r 2 RandomState1 = $4E
000000r 2 RandomBits0 = $4F
000000r 2 RandomBits1 = $50
000000r 2 Counter51 = $51
000000r 2 Counter52 = $52
000000r 2
000000r 2 SavedBaseXLo = $53
000000r 2 SavedBaseXHi = $54
000000r 2 SavedBaseYLo = $55
000000r 2 SavedBaseYHi = $56
000000r 2
000000r 2 BaseMotionActive = $5C
000000r 2 BaseMotionPhase = $5D
000000r 2 BaseMotionEventCount = $5E
000000r 2 TrajectoryResult = $5F
000000r 2
000000r 2 PendingStateTransition = $60
000000r 2 UpdateCounter = $61
000000r 2 PrimarySequenceState = $62
000000r 2 TransitionSequenceState = $63
000000r 2 SecondarySequenceState = $64
000000r 2 PendingScoreIncrement = $65
000000r 2 InningOrSharedScore = $66
000000r 2 PlayerOneScore = $67
000000r 2 PlayerTwoScore = $68
000000r 2 EventWriteIndex = $69
000000r 2 EventReadIndex = $6A
000000r 2 TextCopyCount = $6B
000000r 2 SpecialSequenceState = $6D
000000r 2 ObjectTransitionState = $6E
000000r 2 PendingEvent = $6F
000000r 2
000000r 2 TableCopyIndex = $70
000000r 2 DisplayCounterValue = $71
000000r 2 StateSelector = $72
000000r 2 WindupLoopCounter = $73
000000r 2 MotionSettledCountdown = $76
000000r 2 StateTimer78 = $78
000000r 2
000000r 2 ActionSequenceCounter = $7E
000000r 2 SelectedStateCount = $7F
000000r 2 RandomValue81 = $81
000000r 2 ActorActionComplete = $82
000000r 2 ObjectApproachCount = $83
000000r 2 ObjectApproachDirectionFlag = $84
000000r 2 TrajectoryEvaluationEnabled = $86
000000r 2 ObjectProximityState = $87
000000r 2 MotionDirectionState = $88
000000r 2
000000r 2 FielderAnimationCountdown = $8C
000000r 2 FielderInputBalance = $8D
000000r 2 RandomHorizontalMotion = $8E
000000r 2 CalculatedVerticalMotion= $8F
000000r 2 RandomVerticalMotion = $90
000000r 2 PitchDirectionDecision = $91
000000r 2 ActionDelayCounter = $92
000000r 2 PitchUpdateDelay = $94
000000r 2
000000r 2 CurrentActionState = $9D
000000r 2 SecondaryActorState0 = $9F
000000r 2 SecondaryActorState1 = $A0
000000r 2 SecondaryActorState2 = $A1
000000r 2 ObjectSequenceState = $A2
000000r 2 ObjectSelectionLowerBound= $A5
000000r 2
000000r 2 CalculatedCoordinateLow = $AE
000000r 2 CalculatedCoordinateHigh= $AF
000000r 2
000000r 2 PositionSignState = $B7
000000r 2 ObjectListFlag = $C7
000000r 2 SpriteSortBaseIndex = $C9
000000r 2 SpriteArrayEnd = $CA
000000r 2
000000r 2 MathShiftCount = $DB
000000r 2
000000r 2 PpuCtrlShadow = $DD
000000r 2 PpuMaskShadow = $DE
000000r 2 ScrollX = $DF
000000r 2 ScrollY = $E0
000000r 2
000000r 2 CurrentObjectIndex = $E1
000000r 2 ScriptDepth = $E2
000000r 2 FrameCounter = $E3
000000r 2
000000r 2 GameplaySuspended = $EF
000000r 2 SoundPtrLo = $F6
000000r 2 SoundPtrHi = $F7
000000r 2
000000r 2 PendingAudioFlags = $FE
000000r 2 RenderStateFlags = $FF
000000r 2
000000r 1
000000r 1 ; ============================================================================
000000r 1 ; Zero-page scratch policy
000000r 1 ;
000000r 1 ; $00-$0C are intentionally left numeric. Their meanings vary between pointer
000000r 1 ; decoding, arithmetic, OAM construction, geometry, PPU streaming, and audio.
000000r 1 ; Routine contracts describe the local role when it can be inferred safely.
000000r 1 ; ============================================================================
000000r 1 .segment "PRG"
000000r 1 .org $C000
00C000 1
00C000 1 ; ============================================================================
00C000 1 ; $C000-$C023
00C000 1 ; Title-screen copyright PPU stream.
00C000 1 ; ============================================================================
00C000 1
00C000 1 TitleCopyrightPpuStream: ; $C000
00C000 1 23 45 05 .byte $23,$45,$05
00C003 1 AF 01 09 08 .byte $AF,$01,$09,$08,$04
00C007 1 04
00C008 1
00C008 1 23 65 18 .byte $23,$65,$18
00C00B 1 17 12 17 1D .byte $17,$12,$17,$1D,$0E,$17,$0D,$18
00C00F 1 0E 17 0D 18
00C013 1 25 18 0F 25 .byte $25,$18,$0F,$25,$0A,$16,$0E,$1B
00C017 1 0A 16 0E 1B
00C01B 1 12 0C 0A 25 .byte $12,$0C,$0A,$25,$12,$17,$0C,$AC
00C01F 1 12 17 0C AC
00C023 1
00C023 1 00 .byte $00
00C024 1
00C024 1 ; ============================================================================
00C024 1 ; $C024-$C029
00C024 1 ; Tile values for the six selectable team initials: A, C, D, P, R, Y.
00C024 1 ; ============================================================================
00C024 1
00C024 1 TeamInitialTileTable: ; $C024
00C024 1 0A 0C 0D 19 .byte $0A,$0C,$0D,$19,$1B,$22
00C028 1 1B 22
00C02A 1
00C02A 1 ; ============================================================================
00C02A 1 ; $C02A-$C02F
00C02A 1 ; Sprite tile selected for each team-selection marker.
00C02A 1 ; ============================================================================
00C02A 1
00C02A 1 TeamSelectionSpriteTileTable: ; $C02A
00C02A 1 0C 16 12 16 .byte $0C,$16,$12,$16,$03,$0F
00C02E 1 03 0F
00C030 1
00C030 1 ; ============================================================================
00C030 1 ; $C030-$C035
00C030 1 ; X coordinate used for each team-selection marker sprite.
00C030 1 ; ============================================================================
00C030 1
00C030 1 TeamSelectionSpriteXTable: ; $C030
00C030 1 30 21 10 30 .byte $30,$21,$10,$30,$21,$10
00C034 1 21 10
00C036 1
00C036 1 ; ============================================================================
00C036 1 ; $C036-$C045
00C036 1 ; Calculate randomized signed pitch motion.
00C036 1 ; ============================================================================
00C036 1
00C036 1 CalculateRandomizedPitchMotion: ; $C036
00C036 1 A9 E2 lda #$E2 ; $C036: A9 E2
00C038 1 ED 39 05 sbc $0539 ; $C038: ED 39 05
00C03B 1
00C03B 1 C9 80 cmp #$80 ; $C03B: C9 80
00C03D 1 6A ror ; $C03D: 6A
00C03E 1
00C03E 1 C9 80 cmp #$80 ; $C03E: C9 80
00C040 1 6A ror ; $C040: 6A
00C041 1
00C041 1 38 sec ; $C041: 38
00C042 1 ED 39 05 sbc $0539 ; $C042: ED 39 05
00C045 1
00C045 1 60 rts ; $C045: 60
00C046 1
00C046 1 ; ============================================================================
00C046 1 ; $C046-$C122
00C046 1 ; NMI handler
00C046 1 ; ============================================================================
00C046 1
00C046 1 NMI: ; $C046
00C046 1 48 pha ; $C046: 48
00C047 1 86 0D stx NmiSavedX ; $C047: 86 0D
00C049 1 84 0E sty NmiSavedY ; $C049: 84 0E
00C04B 1
00C04B 1 AD 02 20 lda PPUSTATUS ; $C04B: AD 02 20
00C04E 1
00C04E 1 A9 02 lda #$02 ; $C04E: A9 02
00C050 1 8D 14 40 sta OAMDMA ; $C050: 8D 14 40
00C053 1
00C053 1 A0 00 ldy #$00 ; $C053: A0 00
00C055 1
00C055 1 NMI_PacketLoop: ; $C055
00C055 1 BE 00 03 ldx $0300,y ; $C055: BE 00 03
00C058 1 F0 33 beq NMI_QueueDone ; $C058: F0 33
00C05A 1
00C05A 1 C8 iny ; $C05A: C8
00C05B 1
00C05B 1 B9 00 03 lda $0300,y ; $C05B: B9 00 03
00C05E 1 8D 06 20 sta PPUADDR ; $C05E: 8D 06 20
00C061 1
00C061 1 C8 iny ; $C061: C8
00C062 1
00C062 1 B9 00 03 lda $0300,y ; $C062: B9 00 03
00C065 1 8D 06 20 sta PPUADDR ; $C065: 8D 06 20
00C068 1
00C068 1 C8 iny ; $C068: C8
00C069 1 C8 iny ; $C069: C8
00C06A 1
00C06A 1 B9 FF 02 lda $02FF,y ; $C06A: B9 FF 02
00C06D 1 8D 00 20 sta PPUCTRL ; $C06D: 8D 00 20
00C070 1
00C070 1 30 0C bmi NMI_ReadPacket ; $C070: 30 0C
00C072 1
00C072 1 NMI_WritePacket: ; $C072
00C072 1 B9 00 03 lda $0300,y ; $C072: B9 00 03
00C075 1 8D 07 20 sta PPUDATA ; $C075: 8D 07 20
00C078 1
00C078 1 C8 iny ; $C078: C8
00C079 1 CA dex ; $C079: CA
00C07A 1
00C07A 1 D0 F6 bne NMI_WritePacket ; $C07A: D0 F6
00C07C 1 F0 D7 beq NMI_PacketLoop ; $C07C: F0 D7
00C07E 1
00C07E 1 NMI_ReadPacket: ; $C07E
00C07E 1 AD 07 20 lda PPUDATA ; $C07E: AD 07 20
00C081 1 ; Discard buffered PPU read.
00C081 1
00C081 1 NMI_ReadPacketLoop: ; $C081
00C081 1 AD 07 20 lda PPUDATA ; $C081: AD 07 20
00C084 1 99 00 03 sta $0300,y ; $C084: 99 00 03
00C087 1
00C087 1 C8 iny ; $C087: C8
00C088 1 CA dex ; $C088: CA
00C089 1
00C089 1 D0 F6 bne NMI_ReadPacketLoop ; $C089: D0 F6
00C08B 1 F0 C8 beq NMI_PacketLoop ; $C08B: F0 C8
00C08D 1
00C08D 1 NMI_QueueDone: ; $C08D
00C08D 1 8E 00 03 stx $0300 ; $C08D: 8E 00 03
00C090 1
00C090 1 A5 DF lda ScrollX ; $C090: A5 DF
00C092 1 8D 05 20 sta PPUSCROLL ; $C092: 8D 05 20
00C095 1
00C095 1 A5 E0 lda ScrollY ; $C095: A5 E0
00C097 1 8D 05 20 sta PPUSCROLL ; $C097: 8D 05 20
00C09A 1
00C09A 1 A5 DE lda PpuMaskShadow ; $C09A: A5 DE
00C09C 1 8D 01 20 sta PPUMASK ; $C09C: 8D 01 20
00C09F 1
00C09F 1 A5 DD lda PpuCtrlShadow ; $C09F: A5 DD
00C0A1 1 8D 00 20 sta PPUCTRL ; $C0A1: 8D 00 20
00C0A4 1
00C0A4 1 20 D0 F9 jsr InitializeAudioEngine ; $C0A4: 20 D0 F9
00C0A7 1
00C0A7 1 A9 01 lda #$01 ; $C0A7: A9 01
00C0A9 1 8D 16 40 sta JOY1 ; $C0A9: 8D 16 40
00C0AC 1
00C0AC 1 A9 00 lda #$00 ; $C0AC: A9 00
00C0AE 1 8D 16 40 sta JOY1 ; $C0AE: 8D 16 40
00C0B1 1
00C0B1 1 A2 08 ldx #$08 ; $C0B1: A2 08
00C0B3 1
00C0B3 1 NMI_ReadControllers: ; $C0B3
00C0B3 1 AD 16 40 lda JOY1 ; $C0B3: AD 16 40
00C0B6 1 29 03 and #$03 ; $C0B6: 29 03
00C0B8 1 C9 01 cmp #$01 ; $C0B8: C9 01
00C0BA 1 26 15 rol ControllerPressed1 ; $C0BA: 26 15
00C0BC 1
00C0BC 1 AD 17 40 lda JOY2 ; $C0BC: AD 17 40
00C0BF 1 29 03 and #$03 ; $C0BF: 29 03
00C0C1 1 C9 01 cmp #$01 ; $C0C1: C9 01
00C0C3 1 26 16 rol ControllerPressed2 ; $C0C3: 26 16
00C0C5 1
00C0C5 1 CA dex ; $C0C5: CA
00C0C6 1 D0 EB bne NMI_ReadControllers ; $C0C6: D0 EB
00C0C8 1
00C0C8 1 A2 01 ldx #$01 ; $C0C8: A2 01
00C0CA 1
00C0CA 1 NMI_UpdateControllerState: ; $C0CA
00C0CA 1 B5 15 lda ControllerPressed1,x ; $C0CA: B5 15
00C0CC 1 A8 tay ; $C0CC: A8
00C0CD 1
00C0CD 1 55 11 eor ControllerHeld1,x ; $C0CD: 55 11
00C0CF 1 35 15 and ControllerPressed1,x ; $C0CF: 35 15
00C0D1 1
00C0D1 1 95 15 sta ControllerPressed1,x ; $C0D1: 95 15
00C0D3 1 94 11 sty ControllerHeld1,x ; $C0D3: 94 11
00C0D5 1
00C0D5 1 CA dex ; $C0D5: CA
00C0D6 1 10 F2 bpl NMI_UpdateControllerState
00C0D8 1 ; $C0D6: 10 F2
00C0D8 1
00C0D8 1 29 10 and #$10 ; $C0D8: 29 10
00C0DA 1 F0 10 beq NMI_CheckState ; $C0DA: F0 10
00C0DC 1
00C0DC 1 A5 1E lda SessionActive ; $C0DC: A5 1E
00C0DE 1 D0 07 bne NMI_RunCommand0B ; $C0DE: D0 07
00C0E0 1
00C0E0 1 85 1D sta TransitionActive ; $C0E0: 85 1D
00C0E2 1 85 EF sta GameplaySuspended ; $C0E2: 85 EF
00C0E4 1
00C0E4 1 4C 9C C4 jmp InitializeNewSession ; $C0E4: 4C 9C C4
00C0E7 1
00C0E7 1 NMI_RunCommand0B: ; $C0E7
00C0E7 1 A2 0B ldx #$0B ; $C0E7: A2 0B
00C0E9 1 20 2A EB jsr ProcessQueuedObjectEvent; $C0E9: 20 2A EB
00C0EC 1
00C0EC 1 NMI_CheckState: ; $C0EC
00C0EC 1 A5 1F lda NmiStateFlag ; $C0EC: A5 1F
00C0EE 1 D0 2C bne NMI_RestoreRegisters ; $C0EE: D0 2C
00C0F0 1
00C0F0 1 20 0A EB jsr QueueInlineObjectEvent ; $C0F0: 20 0A EB
00C0F3 1
00C0F3 1 ; Inline command data consumed by the routine at QueueInlineObjectEvent.
00C0F3 1 ; These bytes must not be assembled as 6502 instructions.
00C0F3 1 05 21 C1 .byte $05,$21,$C1 ; $C0F3-$C0F5
00C0F6 1
00C0F6 1 A2 00 ldx #$00 ; $C0F6: A2 00
00C0F8 1 20 2A EB jsr ProcessQueuedObjectEvent ; $C0F8: 20 2A EB
00C0FB 1
00C0FB 1 E6 E3 inc FrameCounter ; $C0FB: E6 E3
00C0FD 1 20 7E C8 jsr CalculateControllerAssignments ; $C0FD: 20 7E C8
00C100 1
00C100 1 A6 0F ldx DerivedControl0 ; $C100: A6 0F
00C102 1 8A txa ; $C102: 8A
00C103 1 A8 tay ; $C103: A8
00C104 1
00C104 1 F0 04 beq NMI_StoreFirstObject ; $C104: F0 04
00C106 1
00C106 1 B5 10 lda $10,x ; $C106: B5 10
00C108 1 B4 14 ldy InputState2,x ; $C108: B4 14
00C10A 1
00C10A 1 NMI_StoreFirstObject: ; $C10A
00C10A 1 85 13 sta InputState1 ; $C10A: 85 13
00C10C 1 84 17 sty InputAux1 ; $C10C: 84 17
00C10E 1
00C10E 1 A6 10 ldx $10 ; $C10E: A6 10
00C110 1 8A txa ; $C110: 8A
00C111 1 A8 tay ; $C111: A8
00C112 1
00C112 1 F0 04 beq NMI_StoreSecondObject ; $C112: F0 04
00C114 1
00C114 1 B5 10 lda $10,x ; $C114: B5 10
00C116 1 B4 14 ldy InputState2,x ; $C116: B4 14
00C118 1
00C118 1 NMI_StoreSecondObject: ; $C118
00C118 1 85 14 sta InputState2 ; $C118: 85 14
00C11A 1 84 18 sty InputAux2 ; $C11A: 84 18
00C11C 1
00C11C 1 NMI_RestoreRegisters: ; $C11C
00C11C 1 A4 0E ldy NmiSavedY ; $C11C: A4 0E
00C11E 1 A6 0D ldx NmiSavedX ; $C11E: A6 0D
00C120 1
00C120 1 68 pla ; $C120: 68
00C121 1 40 rti ; $C121: 40
00C122 1
00C122 1 ; ============================================================================
00C122 1 ; $C122-$C18C
00C122 1 ; Main-frame initialization, timer updates, and 16-bit position updates
00C122 1 ; ============================================================================
00C122 1
00C122 1 UpdateFrameObjectsAndTimers: ; $C122
00C122 1 A2 00 ldx #$00 ; $C122: A2 00
00C124 1
00C124 1 86 3E stx PpuQueueOffset ; $C124: 86 3E
00C126 1 86 3F stx OamWriteOffset ; $C126: 86 3F
00C128 1 86 20 stx FrameState20 ; $C128: 86 20
00C12A 1
00C12A 1 20 0A EB jsr QueueInlineObjectEvent ; $C12A: 20 0A EB
00C12D 1
00C12D 1 ; Inline command data consumed by the routine at QueueInlineObjectEvent.
00C12D 1 07 64 C2 .byte $07,$64,$C2 ; $C12D-$C12F
00C130 1
00C130 1 A2 01 ldx #$01 ; $C130: A2 01
00C132 1 20 2A EB jsr ProcessQueuedObjectEvent ; $C132: 20 2A EB
00C135 1
00C135 1 A2 30 ldx #$30 ; $C135: A2 30
00C137 1
00C137 1 UpdateObjectTimerLoop: ; $C137
00C137 1 BD 3F 06 lda $063F,x ; $C137: BD 3F 06
00C13A 1 F0 08 beq UpdateNextObjectTimer ; $C13A: F0 08
00C13C 1
00C13C 1 DE 3F 06 dec $063F,x ; $C13C: DE 3F 06
00C13F 1 D0 03 bne UpdateNextObjectTimer ; $C13F: D0 03
00C141 1
00C141 1 20 15 EB jsr QueueDecodedObjectEventSelectIndex ; $C141: 20 15 EB
00C144 1
00C144 1 UpdateNextObjectTimer: ; $C144
00C144 1 CA dex ; $C144: CA
00C145 1 D0 F0 bne UpdateObjectTimerLoop ; $C145: D0 F0
00C147 1
00C147 1 A2 03 ldx #$03 ; $C147: A2 03
00C149 1
00C149 1 UpdateShortCountdowns: ; $C149
00C149 1 DE AD 05 dec $05AD,x ; $C149: DE AD 05
00C14C 1 10 03 bpl UpdateNextShortCountdown
00C14E 1 ; $C14C: 10 03
00C14E 1
00C14E 1 FE AD 05 inc $05AD,x ; $C14E: FE AD 05
00C151 1
00C151 1 UpdateNextShortCountdown: ; $C151
00C151 1 CA dex ; $C151: CA
00C152 1 10 F5 bpl UpdateShortCountdowns
00C154 1 ; $C152: 10 F5
00C154 1
00C154 1 A5 1D lda TransitionActive ; $C154: A5 1D
00C156 1 F0 03 beq IntegrateAllObjectPositions
00C158 1 ; $C156: F0 03
00C158 1
00C158 1 4C 6A EB jmp CommonEngineExit ; $C158: 4C 6A EB
00C15B 1
00C15B 1 IntegrateAllObjectPositions: ; $C15B
00C15B 1 A2 24 ldx #$24 ; $C15B: A2 24
00C15D 1
00C15D 1 ; Each logical object occupies two adjacent indices.
00C15D 1 ; X advances by two after both coordinate pairs are updated.
00C15D 1
00C15D 1 IntegrateObjectPositionLoop: ; $C15D
00C15D 1 A0 00 ldy #$00 ; $C15D: A0 00
00C15F 1
00C15F 1 BD 6F 05 lda $056F,x ; $C15F: BD 6F 05
00C162 1 10 01 bpl AddObjectHorizontalDelta ; $C162: 10 01
00C164 1
00C164 1 88 dey ; $C164: 88
00C165 1 ; Sign-extend the low-byte delta.
00C165 1
00C165 1 AddObjectHorizontalDelta: ; $C165
00C165 1 18 clc ; $C165: 18
00C166 1
00C166 1 7D 0B 05 adc $050B,x ; $C166: 7D 0B 05
00C169 1 9D 0B 05 sta $050B,x ; $C169: 9D 0B 05
00C16C 1
00C16C 1 98 tya ; $C16C: 98
00C16D 1 7D 0C 05 adc $050C,x ; $C16D: 7D 0C 05
00C170 1 9D 0C 05 sta $050C,x ; $C170: 9D 0C 05
00C173 1
00C173 1 A0 00 ldy #$00 ; $C173: A0 00
00C175 1
00C175 1 BD 70 05 lda $0570,x ; $C175: BD 70 05
00C178 1 10 01 bpl AddObjectVerticalDelta ; $C178: 10 01
00C17A 1
00C17A 1 88 dey ; $C17A: 88
00C17B 1 ; Sign-extend the second delta.
00C17B 1
00C17B 1 AddObjectVerticalDelta: ; $C17B
00C17B 1 18 clc ; $C17B: 18
00C17C 1
00C17C 1 7D 3C 05 adc $053C,x ; $C17C: 7D 3C 05
00C17F 1 9D 3C 05 sta $053C,x ; $C17F: 9D 3C 05
00C182 1
00C182 1 98 tya ; $C182: 98
00C183 1 7D 3D 05 adc $053D,x ; $C183: 7D 3D 05
00C186 1 9D 3D 05 sta $053D,x ; $C186: 9D 3D 05
00C189 1
00C189 1 CA dex ; $C189: CA
00C18A 1 CA dex ; $C18A: CA
00C18B 1
00C18B 1 10 D0 bpl IntegrateObjectPositionLoop
00C18D 1 ; $C18B: 10 D0
00C18D 1
00C18D 1 ; ============================================================================
00C18D 1 ; $C18D-$C264
00C18D 1 ; Object processing, signed coordinate adjustment, and state handling
00C18D 1 ; ============================================================================
00C18D 1
00C18D 1 UpdateBaseMotionSequence: ; $C18D
00C18D 1 A2 00 ldx #$00 ; $C18D: A2 00
00C18F 1 20 CA C3 jsr IntegrateObjectVelocityAndPosition ; $C18F: 20 CA C3
00C192 1
00C192 1 A2 31 ldx #$31 ; $C192: A2 31
00C194 1 20 CA C3 jsr IntegrateObjectVelocityAndPosition ; $C194: 20 CA C3
00C197 1
00C197 1 A2 62 ldx #$62 ; $C197: A2 62
00C199 1 20 CA C3 jsr IntegrateObjectVelocityAndPosition ; $C199: 20 CA C3
00C19C 1
00C19C 1 AD 6C 05 lda $056C ; $C19C: AD 6C 05
00C19F 1 30 03 bmi ReflectBaseMotionValues
00C1A1 1 ; $C19F: 30 03
00C1A1 1
00C1A1 1 4C 28 C2 jmp UpdatePositionSignState ; $C1A1: 4C 28 C2
00C1A4 1
00C1A4 1 ; ----------------------------------------------------------------------------
00C1A4 1 ; Negate the signed values at $056B/$056C and $0569/$056A.
00C1A4 1 ; The second result is divided by two using LSR/ROR.
00C1A4 1 ; ----------------------------------------------------------------------------
00C1A4 1
00C1A4 1 ReflectBaseMotionValues: ; $C1A4
00C1A4 1 A0 00 ldy #$00 ; $C1A4: A0 00
00C1A6 1 38 sec ; $C1A6: 38
00C1A7 1
00C1A7 1 98 tya ; $C1A7: 98
00C1A8 1 ED 6B 05 sbc $056B ; $C1A8: ED 6B 05
00C1AB 1 8D 6B 05 sta $056B ; $C1AB: 8D 6B 05
00C1AE 1
00C1AE 1 98 tya ; $C1AE: 98
00C1AF 1 ED 6C 05 sbc $056C ; $C1AF: ED 6C 05
00C1B2 1 8D 6C 05 sta $056C ; $C1B2: 8D 6C 05
00C1B5 1
00C1B5 1 38 sec ; $C1B5: 38
00C1B6 1
00C1B6 1 98 tya ; $C1B6: 98
00C1B7 1 ED 69 05 sbc $0569 ; $C1B7: ED 69 05
00C1BA 1 8D 69 05 sta $0569 ; $C1BA: 8D 69 05
00C1BD 1
00C1BD 1 98 tya ; $C1BD: 98
00C1BE 1 ED 6A 05 sbc $056A ; $C1BE: ED 6A 05
00C1C1 1
00C1C1 1 4A lsr ; $C1C1: 4A
00C1C2 1 8D 6A 05 sta $056A ; $C1C2: 8D 6A 05
00C1C5 1 6E 69 05 ror $0569 ; $C1C5: 6E 69 05
00C1C8 1
00C1C8 1 ; ----------------------------------------------------------------------------
00C1C8 1 ; Subtract twice the signed value in $0508 from $0507/$0508.
00C1C8 1 ; ----------------------------------------------------------------------------
00C1C8 1
00C1C8 1 A0 00 ldy #$00 ; $C1C8: A0 00
00C1CA 1
00C1CA 1 AD 08 05 lda $0508 ; $C1CA: AD 08 05
00C1CD 1 10 01 bpl DoubleHorizontalVelocity
00C1CF 1 ; $C1CD: 10 01
00C1CF 1
00C1CF 1 88 dey ; $C1CF: 88
00C1D0 1
00C1D0 1 DoubleHorizontalVelocity: ; $C1D0
00C1D0 1 0A asl ; $C1D0: 0A
00C1D1 1 85 07 sta $07 ; $C1D1: 85 07
00C1D3 1
00C1D3 1 98 tya ; $C1D3: 98
00C1D4 1 2A rol ; $C1D4: 2A
00C1D5 1 85 08 sta $08 ; $C1D5: 85 08
00C1D7 1
00C1D7 1 38 sec ; $C1D7: 38
00C1D8 1
00C1D8 1 AD 07 05 lda $0507 ; $C1D8: AD 07 05
00C1DB 1 E5 07 sbc $07 ; $C1DB: E5 07
00C1DD 1 8D 07 05 sta $0507 ; $C1DD: 8D 07 05
00C1E0 1
00C1E0 1 AD 08 05 lda $0508 ; $C1E0: AD 08 05
00C1E3 1 E5 08 sbc $08 ; $C1E3: E5 08
00C1E5 1 8D 08 05 sta $0508 ; $C1E5: 8D 08 05
00C1E8 1
00C1E8 1 ; ----------------------------------------------------------------------------
00C1E8 1 ; Repeat the signed adjustment for $0538/$0539.
00C1E8 1 ; ----------------------------------------------------------------------------
00C1E8 1
00C1E8 1 A0 00 ldy #$00 ; $C1E8: A0 00
00C1EA 1
00C1EA 1 AD 39 05 lda $0539 ; $C1EA: AD 39 05
00C1ED 1 10 01 bpl DoubleVerticalVelocity
00C1EF 1 ; $C1ED: 10 01
00C1EF 1
00C1EF 1 88 dey ; $C1EF: 88
00C1F0 1
00C1F0 1 DoubleVerticalVelocity: ; $C1F0
00C1F0 1 0A asl ; $C1F0: 0A
00C1F1 1 85 07 sta $07 ; $C1F1: 85 07
00C1F3 1
00C1F3 1 98 tya ; $C1F3: 98
00C1F4 1 2A rol ; $C1F4: 2A
00C1F5 1 85 08 sta $08 ; $C1F5: 85 08
00C1F7 1
00C1F7 1 38 sec ; $C1F7: 38
00C1F8 1
00C1F8 1 AD 38 05 lda $0538 ; $C1F8: AD 38 05
00C1FB 1 E5 07 sbc $07 ; $C1FB: E5 07
00C1FD 1 8D 38 05 sta $0538 ; $C1FD: 8D 38 05
00C200 1
00C200 1 AD 39 05 lda $0539 ; $C200: AD 39 05
00C203 1 E5 08 sbc $08 ; $C203: E5 08
00C205 1 8D 39 05 sta $0539 ; $C205: 8D 39 05
00C208 1
00C208 1 20 D2 CA jsr EvaluateTrajectoryResult ; $C208: 20 D2 CA
00C20B 1
00C20B 1 ; ----------------------------------------------------------------------------
00C20B 1 ; Advance state and refresh coordinate-related values.
00C20B 1 ; ----------------------------------------------------------------------------
00C20B 1
00C20B 1 A5 5D lda BaseMotionPhase ; $C20B: A5 5D
00C20D 1 C9 03 cmp #$03 ; $C20D: C9 03
00C20F 1 B0 04 bcs AdvanceBaseMotionPhase
00C211 1 ; $C20F: B0 04
00C211 1
00C211 1 A9 10 lda #$10 ; $C211: A9 10
00C213 1 85 FF sta RenderStateFlags ; $C213: 85 FF
00C215 1
00C215 1 AdvanceBaseMotionPhase: ; $C215
00C215 1 E6 5D inc BaseMotionPhase ; $C215: E6 5D
00C217 1
00C217 1 AD 08 05 lda $0508 ; $C217: AD 08 05
00C21A 1 0D 39 05 ora $0539 ; $C21A: 0D 39 05
00C21D 1 0D 6A 05 ora $056A ; $C21D: 0D 6A 05
00C220 1 D0 06 bne UpdatePositionSignState ; $C220: D0 06
00C222 1
00C222 1 20 43 C9 jsr ClearBaseAccelerationFields ; $C222: 20 43 C9
00C225 1 20 4F C9 jsr ClearBasePositionFields ; $C225: 20 4F C9
00C228 1
00C228 1 ; ----------------------------------------------------------------------------
00C228 1 ; Calculate a signed magnitude from the current position.
00C228 1 ; ----------------------------------------------------------------------------
00C228 1
00C228 1 UpdatePositionSignState: ; $C228
00C228 1 38 sec ; $C228: 38
00C229 1
00C229 1 AD 3B 05 lda $053B ; $C229: AD 3B 05
00C22C 1 E9 0A sbc #$0A ; $C22C: E9 0A
00C22E 1 10 0A bpl SaveSignedPositionDelta ; $C22E: 10 0A
00C230 1
00C230 1 AD 0A 05 lda $050A ; $C230: AD 0A 05
00C233 1 10 02 bpl SubtractPositionThreshold ; $C233: 10 02
00C235 1
00C235 1 49 FF eor #$FF ; $C235: 49 FF
00C237 1
00C237 1 SubtractPositionThreshold: ; $C237
00C237 1 38 sec ; $C237: 38
00C238 1 E9 0A sbc #$0A ; $C238: E9 0A
00C23A 1
00C23A 1 SaveSignedPositionDelta: ; $C23A
00C23A 1 48 pha ; $C23A: 48
00C23B 1
00C23B 1 45 B7 eor PositionSignState ; $C23B: 45 B7
00C23D 1 10 0A bpl CommitSignedPositionDelta
00C23F 1 ; $C23D: 10 0A
00C23F 1
00C23F 1 A5 42 lda CurrentObjectArrayOffset ; $C23F: A5 42
00C241 1 D0 06 bne CommitSignedPositionDelta
00C243 1 ; $C241: D0 06
00C243 1
00C243 1 20 0A EB jsr QueueInlineObjectEvent ; $C243: 20 0A EB
00C246 1
00C246 1 ; Inline command data consumed by the routine at QueueInlineObjectEvent.
00C246 1 23 52 C2 .byte $23,$52,$C2 ; $C246-$C248
00C249 1
00C249 1 CommitSignedPositionDelta: ; $C249
00C249 1 68 pla ; $C249: 68
00C24A 1 85 B7 sta PositionSignState ; $C24A: 85 B7
00C24C 1
00C24C 1 0A asl ; $C24C: 0A
00C24D 1 20 46 E7 jsr InitializeRenderingStateFromCarry ; $C24D: 20 46 E7
00C250 1
00C250 1 4C 6A EB jmp CommonEngineExit ; $C250: 4C 6A EB
00C253 1
00C253 1 ; ----------------------------------------------------------------------------
00C253 1 ; Alternate object/state path.
00C253 1 ; ----------------------------------------------------------------------------
00C253 1
00C253 1 UpdateAllGameplayObjects: ; $C253
00C253 1 A2 26 ldx #$26 ; $C253: A2 26
00C255 1
00C255 1 UpdateNextGameplayObject: ; $C255
00C255 1 86 42 stx CurrentObjectArrayOffset ; $C255: 86 42
00C257 1 20 B7 E6 jsr ClearMovementTransforms ; $C257: 20 B7 E6
00C25A 1
00C25A 1 A6 42 ldx CurrentObjectArrayOffset ; $C25A: A6 42
00C25C 1 CA dex ; $C25C: CA
00C25D 1 CA dex ; $C25D: CA
00C25E 1 D0 F5 bne UpdateNextGameplayObject ; $C25E: D0 F5
00C260 1
00C260 1 86 42 stx CurrentObjectArrayOffset ; $C260: 86 42
00C262 1 4C 6A EB jmp CommonEngineExit ; $C262: 4C 6A EB
00C265 1
00C265 1 ; ============================================================================
00C265 1 ; $C265-$C2DD
00C265 1 ; Select object sprite attributes and animation tiles.
00C265 1 ; ============================================================================
00C265 1
00C265 1 UpdateBaseObjectSprites: ; $C265
00C265 1 A5 5C lda BaseMotionActive ; $C265: A5 5C
00C267 1 F0 67 beq SetDefaultBaseObjectTile
00C269 1 ; $C267: F0 67
00C269 1
00C269 1 A5 FF lda RenderStateFlags ; $C269: A5 FF
00C26B 1 AE 6C 05 ldx $056C ; $C26B: AE 6C 05
00C26E 1
00C26E 1 E0 03 cpx #$03 ; $C26E: E0 03
00C270 1 90 09 bcc SaveBaseObjectRenderFlags ; $C270: 90 09
00C272 1
00C272 1 09 20 ora #$20 ; $C272: 09 20
00C274 1
00C274 1 AE 6A 05 ldx $056A ; $C274: AE 6A 05
00C277 1 10 02 bpl SaveBaseObjectRenderFlags ; $C277: 10 02
00C279 1
00C279 1 09 40 ora #$40 ; $C279: 09 40
00C27B 1
00C27B 1 SaveBaseObjectRenderFlags: ; $C27B
00C27B 1 85 FF sta RenderStateFlags ; $C27B: 85 FF
00C27D 1
00C27D 1 20 73 E6 jsr BuildCurrentMovementTransforms ; $C27D: 20 73 E6
00C280 1 B0 21 bcs SelectSecondaryAnimationTile
00C282 1 ; $C280: B0 21
00C282 1
00C282 1 9D DD 03 sta $03DD,x ; $C282: 9D DD 03
00C285 1
00C285 1 A5 36 lda ObjectScreenX ; $C285: A5 36
00C287 1 9D BB 03 sta $03BB,x ; $C287: 9D BB 03
00C28A 1
00C28A 1 ; ----------------------------------------------------------------------------
00C28A 1 ; Select the first animation tile according to the value in $2E.
00C28A 1 ; ----------------------------------------------------------------------------
00C28A 1
00C28A 1 A4 2E ldy $2E ; $C28A: A4 2E
00C28C 1
00C28C 1 A9 76 lda #$76 ; $C28C: A9 76
00C28E 1 C0 20 cpy #$20 ; $C28E: C0 20
00C290 1 B0 0E bcs StorePrimaryAnimationTile
00C292 1 ; $C290: B0 0E
00C292 1
00C292 1 A9 77 lda #$77 ; $C292: A9 77
00C294 1 C0 12 cpy #$12 ; $C294: C0 12
00C296 1 B0 08 bcs StorePrimaryAnimationTile
00C298 1 ; $C296: B0 08
00C298 1
00C298 1 A9 78 lda #$78 ; $C298: A9 78
00C29A 1 C0 08 cpy #$08 ; $C29A: C0 08
00C29C 1 B0 02 bcs StorePrimaryAnimationTile
00C29E 1 ; $C29C: B0 02
00C29E 1
00C29E 1 A9 79 lda #$79 ; $C29E: A9 79
00C2A0 1
00C2A0 1 StorePrimaryAnimationTile: ; $C2A0
00C2A0 1 9D 99 03 sta $0399,x ; $C2A0: 9D 99 03
00C2A3 1
00C2A3 1 ; ----------------------------------------------------------------------------
00C2A3 1 ; Select the second animation tile.
00C2A3 1 ; ----------------------------------------------------------------------------
00C2A3 1
00C2A3 1 SelectSecondaryAnimationTile: ; $C2A3
00C2A3 1 20 95 E6 jsr BuildBaseMovementTransforms ; $C2A3: 20 95 E6
00C2A6 1 B0 2F bcs SetFinalBaseObjectTile
00C2A8 1 ; $C2A6: B0 2F
00C2A8 1
00C2A8 1 A4 2E ldy $2E ; $C2A8: A4 2E
00C2AA 1
00C2AA 1 A9 7A lda #$7A ; $C2AA: A9 7A
00C2AC 1 C0 20 cpy #$20 ; $C2AC: C0 20
00C2AE 1 B0 1A bcs StoreSecondaryAnimationTile
00C2B0 1 ; $C2AE: B0 1A
00C2B0 1
00C2B0 1 A9 71 lda #$71 ; $C2B0: A9 71
00C2B2 1 C0 12 cpy #$12 ; $C2B2: C0 12
00C2B4 1 B0 14 bcs StoreSecondaryAnimationTile
00C2B6 1 ; $C2B4: B0 14
00C2B6 1
00C2B6 1 A9 72 lda #$72 ; $C2B6: A9 72
00C2B8 1 C0 08 cpy #$08 ; $C2B8: C0 08
00C2BA 1 B0 0E bcs StoreSecondaryAnimationTile
00C2BC 1 ; $C2BA: B0 0E
00C2BC 1
00C2BC 1 A9 73 lda #$73 ; $C2BC: A9 73
00C2BE 1 C0 05 cpy #$05 ; $C2BE: C0 05
00C2C0 1 B0 08 bcs StoreSecondaryAnimationTile
00C2C2 1 ; $C2C0: B0 08
00C2C2 1
00C2C2 1 A9 74 lda #$74 ; $C2C2: A9 74
00C2C4 1 C0 03 cpy #$03 ; $C2C4: C0 03
00C2C6 1 B0 02 bcs StoreSecondaryAnimationTile
00C2C8 1 ; $C2C6: B0 02
00C2C8 1
00C2C8 1 A9 75 lda #$75 ; $C2C8: A9 75
00C2CA 1
00C2CA 1 StoreSecondaryAnimationTile: ; $C2CA
00C2CA 1 9D 9A 03 sta $039A,x ; $C2CA: 9D 9A 03
00C2CD 1
00C2CD 1 4C DE C2 jmp BuildFrameOam ; $C2CD: 4C DE C2
00C2D0 1
00C2D0 1 ; ----------------------------------------------------------------------------
00C2D0 1 ; Default tile path when $5C is zero.
00C2D0 1 ; ----------------------------------------------------------------------------
00C2D0 1
00C2D0 1 SetDefaultBaseObjectTile: ; $C2D0
00C2D0 1 A6 C9 ldx SpriteSortBaseIndex ; $C2D0: A6 C9
00C2D2 1
00C2D2 1 A9 7A lda #$7A ; $C2D2: A9 7A
00C2D4 1 9D 9A 03 sta $039A,x ; $C2D4: 9D 9A 03
00C2D7 1
00C2D7 1 SetFinalBaseObjectTile: ; $C2D7
00C2D7 1 A6 C9 ldx SpriteSortBaseIndex ; $C2D7: A6 C9
00C2D9 1
00C2D9 1 A9 7A lda #$7A ; $C2D9: A9 7A
00C2DB 1 9D 9B 03 sta $039B,x ; $C2DB: 9D 9B 03
00C2DE 1
00C2DE 1 ; ============================================================================
00C2DE 1 ; $C2DE-$C330
00C2DE 1 ; Initialize OAM entries for the current game state.
00C2DE 1 ; ============================================================================
00C2DE 1
00C2DE 1 BuildFrameOam: ; $C2DE
00C2DE 1 A5 1D lda TransitionActive ; $C2DE: A5 1D
00C2E0 1 F0 13 beq CheckOamBuildMode ; $C2E0: F0 13
00C2E2 1
00C2E2 1 ; ----------------------------------------------------------------------------
00C2E2 1 ; Copy a 88-byte sprite/OAM template from $F94D into shadow OAM at $0200.
00C2E2 1 ; ----------------------------------------------------------------------------
00C2E2 1
00C2E2 1 A2 00 ldx #$00 ; $C2E2: A2 00
00C2E4 1 A0 58 ldy #$58 ; $C2E4: A0 58
00C2E6 1
00C2E6 1 CopyTransitionOamTemplate: ; $C2E6
00C2E6 1 BD 4D F9 lda FrameOamTemplate_F94D,x ; $C2E6: BD 4D F9
00C2E9 1 9D 00 02 sta $0200,x ; $C2E9: 9D 00 02
00C2EC 1
00C2EC 1 E8 inx ; $C2EC: E8
00C2ED 1 88 dey ; $C2ED: 88
00C2EE 1 D0 F6 bne CopyTransitionOamTemplate
00C2F0 1 ; $C2EE: D0 F6
00C2F0 1
00C2F0 1 86 3F stx OamWriteOffset ; $C2F0: 86 3F
00C2F2 1 4C AA C3 jmp TerminatePpuUpdateQueue
00C2F5 1 ; $C2F2: 4C AA C3
00C2F5 1
00C2F5 1 ; ----------------------------------------------------------------------------
00C2F5 1 ; Alternate path used when $1D is zero.
00C2F5 1 ; ----------------------------------------------------------------------------
00C2F5 1
00C2F5 1 CheckOamBuildMode: ; $C2F5
00C2F5 1 A5 44 lda PlayerSelectionActive ; $C2F5: A5 44
00C2F7 1 F0 40 beq SortObjectsByY ; $C2F7: F0 40
00C2F9 1
00C2F9 1 ; ----------------------------------------------------------------------------
00C2F9 1 ; Copy an eight-byte OAM template from $C331 into $0200-$0207.
00C2F9 1 ; The table itself remains in the following .incbin region for now.
00C2F9 1 ; ----------------------------------------------------------------------------
00C2F9 1
00C2F9 1 A2 07 ldx #$07 ; $C2F9: A2 07
00C2FB 1
00C2FB 1 CopySelectionOamTemplate: ; $C2FB
00C2FB 1 BD 31 C3 lda $C331,x ; $C2FB: BD 31 C3
00C2FE 1 9D 00 02 sta $0200,x ; $C2FE: 9D 00 02
00C301 1
00C301 1 CA dex ; $C301: CA
00C302 1 10 F7 bpl CopySelectionOamTemplate
00C304 1 ; $C302: 10 F7
00C304 1
00C304 1 ; ----------------------------------------------------------------------------
00C304 1 ; Position the first sprite using the selected player's coordinate.
00C304 1 ; Each value is multiplied by 16 and offset by $50.
00C304 1 ; ----------------------------------------------------------------------------
00C304 1
00C304 1 A6 4B ldx ActivePlayerSide ; $C304: A6 4B
00C306 1
00C306 1 B5 34 lda PlayerOneSelection,x ; $C306: B5 34
00C308 1 0A asl ; $C308: 0A
00C309 1 0A asl ; $C309: 0A
00C30A 1 0A asl ; $C30A: 0A
00C30B 1 0A asl ; $C30B: 0A
00C30C 1
00C30C 1 69 50 adc #$50 ; $C30C: 69 50
00C30E 1 8D 03 02 sta $0203 ; $C30E: 8D 03 02
00C311 1
00C311 1 ; ----------------------------------------------------------------------------
00C311 1 ; Position the second sprite using the opposite player's coordinate.
00C311 1 ; ----------------------------------------------------------------------------
00C311 1
00C311 1 8A txa ; $C311: 8A
00C312 1 49 01 eor #$01 ; $C312: 49 01
00C314 1 AA tax ; $C314: AA
00C315 1
00C315 1 B5 34 lda PlayerOneSelection,x ; $C315: B5 34
00C317 1 0A asl ; $C317: 0A
00C318 1 0A asl ; $C318: 0A
00C319 1 0A asl ; $C319: 0A
00C31A 1 0A asl ; $C31A: 0A
00C31B 1
00C31B 1 69 50 adc #$50 ; $C31B: 69 50
00C31D 1 8D 07 02 sta $0207 ; $C31D: 8D 07 02
00C320 1
00C320 1 ; ----------------------------------------------------------------------------
00C320 1 ; Choose the tile used by the second sprite.
00C320 1 ; ----------------------------------------------------------------------------
00C320 1
00C320 1 A5 40 lda ModeFlags ; $C320: A5 40
00C322 1 4A lsr ; $C322: 4A
00C323 1 B0 05 bcs FinishSelectionOam ; $C323: B0 05
00C325 1
00C325 1 A9 AC lda #$AC ; $C325: A9 AC
00C327 1 8D 05 02 sta $0205 ; $C327: 8D 05 02
00C32A 1
00C32A 1 FinishSelectionOam: ; $C32A
00C32A 1 A2 08 ldx #$08 ; $C32A: A2 08
00C32C 1 86 3F stx OamWriteOffset ; $C32C: 86 3F
00C32E 1
00C32E 1 4C 86 C3 jmp FinalizeOamAndPpuQueue ; $C32E: 4C 86 C3
00C331 1
00C331 1 ; ============================================================================
00C331 1 ; $C331-$C338
00C331 1 ; Eight-byte OAM template referenced by the code at $C2FB.
00C331 1 ; ============================================================================
00C331 1
00C331 1 OAMTemplate_C331: ; $C331
00C331 1 77 A2 03 00 .byte $77,$A2,$03,$00 ; $C331-$C334
00C335 1 77 A4 03 00 .byte $77,$A4,$03,$00 ; $C335-$C338
00C339 1
00C339 1 ; ============================================================================
00C339 1 ; $C339-$C385
00C339 1 ; Sort object indices by their signed 16-bit coordinates, then emit sprite
00C339 1 ; information in the resulting order.
00C339 1 ; ============================================================================
00C339 1
00C339 1 SortObjectsByY: ; $C339
00C339 1 A4 C9 ldy SpriteSortBaseIndex ; $C339: A4 C9
00C33B 1
00C33B 1 C8 iny ; $C33B: C8
00C33C 1
00C33C 1 SortNextObjectPair: ; $C33C
00C33C 1 84 22 sty $22 ; $C33C: 84 22
00C33E 1
00C33E 1 BE 78 03 ldx $0378,y ; $C33E: BE 78 03
00C341 1 B9 77 03 lda $0377,y ; $C341: B9 77 03
00C344 1 A8 tay ; $C344: A8
00C345 1
00C345 1 ; ----------------------------------------------------------------------------
00C345 1 ; Compare the signed 16-bit values at:
00C345 1 ;
00C345 1 ; $0538,X / $0539,X
00C345 1 ; $0538,Y / $0539,Y
00C345 1 ;
00C345 1 ; The subtraction is used only for ordering. If the X entry sorts before the
00C345 1 ; Y entry, their indices in $0377/$0378 are exchanged.
00C345 1 ; ----------------------------------------------------------------------------
00C345 1
00C345 1 BD 38 05 lda $0538,x ; $C345: BD 38 05
00C348 1 D9 38 05 cmp $0538,y ; $C348: D9 38 05
00C34B 1
00C34B 1 BD 39 05 lda $0539,x ; $C34B: BD 39 05
00C34E 1 F9 39 05 sbc $0539,y ; $C34E: F9 39 05
00C351 1
00C351 1 10 0A bpl ContinueObjectDepthSort
00C353 1 ; $C351: 10 0A
00C353 1
00C353 1 98 tya ; $C353: 98
00C354 1
00C354 1 A4 22 ldy $22 ; $C354: A4 22
00C356 1 99 78 03 sta $0378,y ; $C356: 99 78 03
00C359 1
00C359 1 8A txa ; $C359: 8A
00C35A 1 99 77 03 sta $0377,y ; $C35A: 99 77 03
00C35D 1
00C35D 1 ContinueObjectDepthSort: ; $C35D
00C35D 1 A4 22 ldy $22 ; $C35D: A4 22
00C35F 1 C8 iny ; $C35F: C8
00C360 1
00C360 1 C4 CA cpy $CA ; $C360: C4 CA
00C362 1 90 D8 bcc SortNextObjectPair ; $C362: 90 D8
00C364 1
00C364 1 A4 C9 ldy SpriteSortBaseIndex ; $C364: A4 C9
00C366 1
00C366 1 RenderNextSortedObject: ; $C366
00C366 1 B9 78 03 lda $0378,y ; $C366: B9 78 03
00C369 1 4A lsr ; $C369: 4A
00C36A 1 65 C9 adc SpriteSortBaseIndex ; $C36A: 65 C9
00C36C 1 AA tax ; $C36C: AA
00C36D 1
00C36D 1 BD BC 03 lda $03BC,x ; $C36D: BD BC 03
00C370 1 85 36 sta ObjectScreenX ; $C370: 85 36
00C372 1
00C372 1 BD DE 03 lda $03DE,x ; $C372: BD DE 03
00C375 1 85 38 sta ObjectScreenY ; $C375: 85 38
00C377 1
00C377 1 BD 9A 03 lda $039A,x ; $C377: BD 9A 03
00C37A 1
00C37A 1 84 22 sty $22 ; $C37A: 84 22
00C37C 1 20 7B E7 jsr RenderSpriteRecordList ; $C37C: 20 7B E7
00C37F 1 A4 22 ldy $22 ; $C37F: A4 22
00C381 1
00C381 1 C4 CA cpy $CA ; $C381: C4 CA
00C383 1 C8 iny ; $C383: C8
00C384 1 90 E0 bcc RenderNextSortedObject
00C386 1 ; $C384: 90 E0
00C386 1
00C386 1 ; ============================================================================
00C386 1 ; $C386-$C3C9
00C386 1 ; Copy additional OAM entries, terminate the PPU command queue, hide unused
00C386 1 ; sprites, and finish the frame.
00C386 1 ; ============================================================================
00C386 1
00C386 1 FinalizeOamAndPpuQueue: ; $C386
00C386 1 A5 C7 lda ObjectListFlag ; $C386: A5 C7
00C388 1 D0 20 bne TerminatePpuUpdateQueue
00C38A 1 ; $C388: D0 20
00C38A 1
00C38A 1 ; ----------------------------------------------------------------------------
00C38A 1 ; Copy twenty bytes from $EBC2 into available shadow OAM space.
00C38A 1 ; ----------------------------------------------------------------------------
00C38A 1
00C38A 1 A6 3F ldx OamWriteOffset ; $C38A: A6 3F
00C38C 1 A0 13 ldy #$13 ; $C38C: A0 13
00C38E 1
00C38E 1 CopyStatusOamData: ; $C38E
00C38E 1 B9 C2 EB lda $EBC2,y ; $C38E: B9 C2 EB
00C391 1 9D 00 02 sta $0200,x ; $C391: 9D 00 02
00C394 1
00C394 1 E8 inx ; $C394: E8
00C395 1 88 dey ; $C395: 88
00C396 1 10 F6 bpl CopyStatusOamData
00C398 1 ; $C396: 10 F6
00C398 1
00C398 1 ; ----------------------------------------------------------------------------
00C398 1 ; Select two additional bytes from a table beginning at $EBBC.
00C398 1 ; ----------------------------------------------------------------------------
00C398 1
00C398 1 A4 34 ldy PlayerOneSelection ; $C398: A4 34
00C39A 1 B9 BC EB lda $EBBC,y ; $C39A: B9 BC EB
00C39D 1 9D F9 01 sta $01F9,x ; $C39D: 9D F9 01
00C3A0 1
00C3A0 1 A4 35 ldy PlayerTwoSelection ; $C3A0: A4 35
00C3A2 1 B9 BC EB lda $EBBC,y ; $C3A2: B9 BC EB
00C3A5 1 9D FD 01 sta $01FD,x ; $C3A5: 9D FD 01
00C3A8 1
00C3A8 1 86 3F stx OamWriteOffset ; $C3A8: 86 3F
00C3AA 1
00C3AA 1 ; ----------------------------------------------------------------------------
00C3AA 1 ; Terminate the PPU command queue.
00C3AA 1 ; ----------------------------------------------------------------------------
00C3AA 1
00C3AA 1 TerminatePpuUpdateQueue: ; $C3AA
00C3AA 1 A9 00 lda #$00 ; $C3AA: A9 00
00C3AC 1 A4 3E ldy PpuQueueOffset ; $C3AC: A4 3E
00C3AE 1 99 00 03 sta $0300,y ; $C3AE: 99 00 03
00C3B1 1
00C3B1 1 ; ----------------------------------------------------------------------------
00C3B1 1 ; Hide all unused sprites by writing $F0 to each remaining OAM Y coordinate.
00C3B1 1 ; ----------------------------------------------------------------------------
00C3B1 1
00C3B1 1 A6 3F ldx OamWriteOffset ; $C3B1: A6 3F
00C3B3 1 D0 04 bne HideUnusedOamSprites
00C3B5 1 ; $C3B3: D0 04
00C3B5 1
00C3B5 1 A5 20 lda FrameState20 ; $C3B5: A5 20
00C3B7 1 D0 0E bne FinishFrameRendering ; $C3B7: D0 0E
00C3B9 1
00C3B9 1 HideUnusedOamSprites: ; $C3B9
00C3B9 1 A9 F0 lda #$F0 ; $C3B9: A9 F0
00C3BB 1
00C3BB 1 HideUnusedOamSpriteLoop: ; $C3BB
00C3BB 1 9D 00 02 sta $0200,x ; $C3BB: 9D 00 02
00C3BE 1
00C3BE 1 E8 inx ; $C3BE: E8
00C3BF 1 E8 inx ; $C3BF: E8
00C3C0 1 E8 inx ; $C3C0: E8
00C3C1 1 E8 inx ; $C3C1: E8
00C3C2 1
00C3C2 1 D0 F7 bne HideUnusedOamSpriteLoop
00C3C4 1 ; $C3C2: D0 F7
00C3C4 1
00C3C4 1 20 F5 E5 jsr AdvanceRandomState ; $C3C4: 20 F5 E5
00C3C7 1
00C3C7 1 FinishFrameRendering: ; $C3C7
00C3C7 1 4C 6A EB jmp CommonEngineExit ; $C3C7: 4C 6A EB
00C3CA 1
00C3CA 1 ; ============================================================================
00C3CA 1 ; $C3CA-$C40A
00C3CA 1 ; Update one object's signed fixed-point position.
00C3CA 1 ;
00C3CA 1 ; Entry:
00C3CA 1 ; X = object-array offset
00C3CA 1 ;
00C3CA 1 ; Fields used relative to X:
00C3CA 1 ; $0506,X = fractional movement component
00C3CA 1 ; $0507,X = position low byte
00C3CA 1 ; $0508,X = position high byte / signed movement component
00C3CA 1 ; $0509,X = second position low byte
00C3CA 1 ; $050A,X = second position high byte
00C3CA 1 ;
00C3CA 1 ; Called earlier with X = $00, $31, and $62.
00C3CA 1 ; ============================================================================
00C3CA 1
00C3CA 1 ; ----------------------------------------------------------------------------
00C3CA 1 ; Contract:
00C3CA 1 ; Description: Implements Integrate Object Velocity And Position.
00C3CA 1 ; Entry: Registers: A, Y; Memory: $0506, $0508, mathtemp05, $0507, $0509, $050a
00C3CA 1 ; Returns/products: Registers/clobbers: A, Y
00C3CA 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00C3CA 1 ; Memory effects: mathtemp05, $0507, $0508, $0509, $050a
00C3CA 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00C3CA 1 ; comparison, load, or store path and are not a stable API product.
00C3CA 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 3.
00C3CA 1 ; ----------------------------------------------------------------------------
00C3CA 1 IntegrateObjectVelocityAndPosition: ; $C3CA
00C3CA 1 BC 06 05 ldy $0506,x ; $C3CA: BC 06 05
00C3CD 1
00C3CD 1 BD 08 05 lda $0508,x ; $C3CD: BD 08 05
00C3D0 1 10 01 bpl CalculateSignedVelocityDelta ; $C3D0: 10 01
00C3D2 1
00C3D2 1 C8 iny ; $C3D2: C8
00C3D3 1 ; Adjust the high-byte sign value.
00C3D3 1
00C3D3 1 CalculateSignedVelocityDelta: ; $C3D3
00C3D3 1 38 sec ; $C3D3: 38
00C3D4 1
00C3D4 1 A9 00 lda #$00 ; $C3D4: A9 00
00C3D6 1 FD 08 05 sbc $0508,x ; $C3D6: FD 08 05
00C3D9 1 B0 01 bcs SaveVelocitySignExtension ; $C3D9: B0 01
00C3DB 1
00C3DB 1 88 dey ; $C3DB: 88
00C3DC 1
00C3DC 1 SaveVelocitySignExtension: ; $C3DC
00C3DC 1 84 05 sty MathTemp05 ; $C3DC: 84 05
00C3DE 1
00C3DE 1 ; ----------------------------------------------------------------------------
00C3DE 1 ; Arithmetic shift the signed 16-bit value in $05:A right twice.
00C3DE 1 ;
00C3DE 1 ; CMP #$80 places bit 7 of Y into carry:
00C3DE 1 ; Y >= $80 sets carry
00C3DE 1 ; Y < $80 clears carry
00C3DE 1 ;
00C3DE 1 ; ROR $05 followed by ROR A therefore performs a sign-preserving shift.
00C3DE 1 ; ----------------------------------------------------------------------------
00C3DE 1
00C3DE 1 C0 80 cpy #$80 ; $C3DE: C0 80
00C3E0 1 66 05 ror MathTemp05 ; $C3E0: 66 05
00C3E2 1 6A ror ; $C3E2: 6A
00C3E3 1
00C3E3 1 C0 80 cpy #$80 ; $C3E3: C0 80
00C3E5 1 66 05 ror MathTemp05 ; $C3E5: 66 05
00C3E7 1 6A ror ; $C3E7: 6A
00C3E8 1
00C3E8 1 ; ----------------------------------------------------------------------------
00C3E8 1 ; Add the shifted signed value to $0507,X/$0508,X.
00C3E8 1 ; ----------------------------------------------------------------------------
00C3E8 1
00C3E8 1 A4 05 ldy MathTemp05 ; $C3E8: A4 05
00C3EA 1
00C3EA 1 7D 07 05 adc $0507,x ; $C3EA: 7D 07 05
00C3ED 1 9D 07 05 sta $0507,x ; $C3ED: 9D 07 05
00C3F0 1
00C3F0 1 98 tya ; $C3F0: 98
00C3F1 1
00C3F1 1 A0 00 ldy #$00 ; $C3F1: A0 00
00C3F3 1
00C3F3 1 7D 08 05 adc $0508,x ; $C3F3: 7D 08 05
00C3F6 1 9D 08 05 sta $0508,x ; $C3F6: 9D 08 05
00C3F9 1
00C3F9 1 10 01 bpl AddIntegratedPosition
00C3FB 1 ; $C3F9: 10 01
00C3FB 1
00C3FB 1 88 dey ; $C3FB: 88
00C3FC 1 ; Sign-extend the high result.
00C3FC 1
00C3FC 1 ; ----------------------------------------------------------------------------
00C3FC 1 ; Add the resulting signed value to $0509,X/$050A,X.
00C3FC 1 ; ----------------------------------------------------------------------------
00C3FC 1
00C3FC 1 AddIntegratedPosition: ; $C3FC
00C3FC 1 18 clc ; $C3FC: 18
00C3FD 1
00C3FD 1 7D 09 05 adc $0509,x ; $C3FD: 7D 09 05
00C400 1 9D 09 05 sta $0509,x ; $C400: 9D 09 05
00C403 1
00C403 1 98 tya ; $C403: 98
00C404 1
00C404 1 7D 0A 05 adc $050A,x ; $C404: 7D 0A 05
00C407 1 9D 0A 05 sta $050A,x ; $C407: 9D 0A 05
00C40A 1
00C40A 1 60 rts ; $C40A: 60
00C40B 1
00C40B 1 ; ============================================================================
00C40B 1 ; $C40B-$C43D
00C40B 1 ; RESET handler
00C40B 1 ;
00C40B 1 ; Initializes the CPU, clears RAM and PPU state, initializes engine systems,
00C40B 1 ; disables APU channels/frame IRQs, and transfers control to $C74A.
00C40B 1 ; ============================================================================
00C40B 1
00C40B 1 Reset: ; $C40B
00C40B 1 78 sei ; $C40B: 78
00C40C 1 ; Disable maskable interrupts.
00C40C 1
00C40C 1 D8 cld ; $C40C: D8
00C40D 1 ; Clear decimal mode.
00C40D 1
00C40D 1 ; ----------------------------------------------------------------------------
00C40D 1 ; Clear CPU RAM at $0000-$07FF.
00C40D 1 ;
00C40D 1 ; $01 is used as the high byte of the indirect pointer $00/$01.
00C40D 1 ; Each pass clears one 256-byte page. The loop also repeatedly writes zero to
00C40D 1 ; PPUCTRL at $2000.
00C40D 1 ; ----------------------------------------------------------------------------
00C40D 1
00C40D 1 A9 07 lda #$07 ; $C40D: A9 07
00C40F 1 85 01 sta IndirectPtrHi ; $C40F: 85 01
00C411 1
00C411 1 A0 00 ldy #$00 ; $C411: A0 00
00C413 1 84 00 sty IndirectPtrLo ; $C413: 84 00
00C415 1
00C415 1 98 tya ; $C415: 98
00C416 1 ; A = $00
00C416 1
00C416 1 Reset_ClearPageLoop: ; $C416
00C416 1 91 00 sta (IndirectPtrLo),y ; $C416: 91 00
00C418 1 8D 00 20 sta PPUCTRL ; $C418: 8D 00 20
00C41B 1
00C41B 1 88 dey ; $C41B: 88
00C41C 1 D0 F8 bne Reset_ClearPageLoop ; $C41C: D0 F8
00C41E 1
00C41E 1 C6 01 dec IndirectPtrHi ; $C41E: C6 01
00C420 1 10 F4 bpl Reset_ClearPageLoop ; $C420: 10 F4
00C422 1
00C422 1 ; ----------------------------------------------------------------------------
00C422 1 ; Initialize game and PPU-related systems.
00C422 1 ; ----------------------------------------------------------------------------
00C422 1
00C422 1 20 B1 C7 jsr InitializeSpriteSortTables ; $C422: 20 B1 C7
00C425 1 20 6C E9 jsr DisablePpuRendering ; $C425: 20 6C E9
00C428 1
00C428 1 ; ----------------------------------------------------------------------------
00C428 1 ; Disable APU channels and inhibit frame-counter IRQ generation.
00C428 1 ; ----------------------------------------------------------------------------
00C428 1
00C428 1 A2 00 ldx #$00 ; $C428: A2 00
00C42A 1 8E 15 40 stx APUSTATUS ; $C42A: 8E 15 40
00C42D 1 ; Disable all APU sound channels.
00C42D 1
00C42D 1 CA dex ; $C42D: CA
00C42E 1 ; X = $FF
00C42E 1
00C42E 1 8E 17 40 stx JOY2 ; $C42E: 8E 17 40
00C431 1 ; Select five-step frame-counter mode and
00C431 1 ; inhibit frame IRQ generation.
00C431 1
00C431 1 ; ----------------------------------------------------------------------------
00C431 1 ; Invoke the routine at $C8BB.
00C431 1 ;; The three bytes immediately following the JSR are inline data interpreted by
00C431 1 ; that routine. They must not be assembled as 6502 instructions.
00C431 1 ; ----------------------------------------------------------------------------
00C431 1
00C431 1 20 BB C8 jsr ExpandRecordPointerList ; $C431: 20 BB C8
00C434 1
00C434 1 22 9C EE .byte $22,$9C,$EE ; $C434-$C436
00C437 1 ; Inline command/parameter data.
00C437 1
00C437 1 ; ----------------------------------------------------------------------------
00C437 1 ; Set the initial PPU mask shadow value, then enter the main initialization
00C437 1 ; path. This JMP does not return to RESET.
00C437 1 ; ----------------------------------------------------------------------------
00C437 1
00C437 1 A9 1A lda #$1A ; $C437: A9 1A
00C439 1 85 DE sta PpuMaskShadow ; $C439: 85 DE
00C43B 1
00C43B 1 4C 4A C7 jmp InitializeTitleScreen ; $C43B: 4C 4A C7
00C43E 1
00C43E 1 ; ============================================================================
00C43E 1 ; $C43E
00C43E 1 ; IRQ/BRK handler
00C43E 1 ; ============================================================================
00C43E 1
00C43E 1 IRQ: ; $C43E
00C43E 1 40 rti ; $C43E: 40
00C43F 1
00C43F 1 ; ============================================================================
00C43F 1 ; $C43F-$C488
00C43F 1 ; Display/update loop
00C43F 1 ; ============================================================================
00C43F 1
00C43F 1 RunAttractMessageLoop: ; $C43F
00C43F 1 A9 00 lda #$00 ; $C43F: A9 00
00C441 1 85 1F sta NmiStateFlag ; $C441: 85 1F
00C443 1
00C443 1 20 48 EB jsr SelectObjectEventBank1 ; $C443: 20 48 EB
00C446 1
00C446 1 ; ----------------------------------------------------------------------------
00C446 1 ; Draw six blank characters.
00C446 1 ; The routine at $EA17 consumes the inline bytes following the JSR.
00C446 1 ; ----------------------------------------------------------------------------
00C446 1
00C446 1 A5 C7 lda ObjectListFlag ; $C446: A5 C7
00C448 1 18 clc ; $C448: 18
00C449 1 09 23 ora #$23 ; $C449: 09 23
00C44B 1
00C44B 1 A2 37 ldx #$37 ; $C44B: A2 37
00C44D 1 A0 06 ldy #$06 ; $C44D: A0 06
00C44F 1
00C44F 1 20 17 EA jsr CopyInlineDisplayRecord ; $C44F: 20 17 EA
00C452 1
00C452 1 06 .byte $06 ; $C452
00C453 1 25 25 25 .byte $25,$25,$25 ; $C453-$C455
00C456 1 25 25 25 .byte $25,$25,$25 ; $C456-$C458
00C459 1
00C459 1 ; ----------------------------------------------------------------------------
00C459 1 ; Wait or process an engine command.
00C459 1 ; ----------------------------------------------------------------------------
00C459 1
00C459 1 A2 0B ldx #$0B ; $C459: A2 0B
00C45B 1 20 4E EB jsr UpdateObjectEventBank_Exchange ; $C45B: 20 4E EB
00C45E 1
00C45E 1 20 48 EB jsr SelectObjectEventBank1 ; $C45E: 20 48 EB
00C461 1
00C461 1 A9 10 lda #$10 ; $C461: A9 10
00C463 1 85 FD sta $FD ; $C463: 85 FD
00C465 1
00C465 1 ; ----------------------------------------------------------------------------
00C465 1 ; Draw the second six-character encoded message.
00C465 1 ; ----------------------------------------------------------------------------
00C465 1
00C465 1 A5 C7 lda ObjectListFlag ; $C465: A5 C7
00C467 1 18 clc ; $C467: 18
00C468 1 09 23 ora #$23 ; $C468: 09 23
00C46A 1
00C46A 1 A2 37 ldx #$37 ; $C46A: A2 37
00C46C 1 A0 06 ldy #$06 ; $C46C: A0 06
00C46E 1
00C46E 1 20 17 EA jsr CopyInlineDisplayRecord ; $C46E: 20 17 EA
00C471 1
00C471 1 06 .byte $06 ; $C471
00C472 1 19 0A 1E .byte $19,$0A,$1E ; $C472-$C474
00C475 1 1C 0E 25 .byte $1C,$0E,$25 ; $C475-$C477
00C478 1
00C478 1 ; ----------------------------------------------------------------------------
00C478 1 ; Complete the update, increment $1F, and repeat.
00C478 1 ; ----------------------------------------------------------------------------
00C478 1
00C478 1 20 48 EB jsr SelectObjectEventBank1 ; $C478: 20 48 EB
00C47B 1
00C47B 1 E6 1F inc NmiStateFlag ; $C47B: E6 1F
00C47D 1
00C47D 1 A2 0B ldx #$0B ; $C47D: A2 0B
00C47F 1 20 4E EB jsr UpdateObjectEventBank_Exchange ; $C47F: 20 4E EB
00C482 1
00C482 1 A9 10 lda #$10 ; $C482: A9 10
00C484 1 85 FD sta $FD ; $C484: 85 FD
00C486 1
00C486 1 4C 3F C4 jmp RunAttractMessageLoop ; $C486: 4C 3F C4
00C489 1
00C489 1 ; ============================================================================
00C489 1 ; $C489-$C4B8
00C489 1 ; Wait for controller input, initialize game state, and configure the PPU.
00C489 1 ; ============================================================================
00C489 1
00C489 1 WaitForStartInput: ; $C489
00C489 1 20 4C EB jsr SelectObjectEventBank0 ; $C489: 20 4C EB
00C48C 1
00C48C 1 A5 15 lda ControllerPressed1 ; $C48C: A5 15
00C48E 1 0A asl ; $C48E: 0A
00C48F 1 0A asl ; $C48F: 0A
00C490 1 0A asl ; $C490: 0A
00C491 1
00C491 1 90 03 bcc CheckStartInputSign ; $C491: 90 03
00C493 1
00C493 1 4C 4A C7 jmp InitializeTitleScreen ; $C493: 4C 4A C7
00C496 1
00C496 1 CheckStartInputSign: ; $C496
00C496 1 10 F1 bpl WaitForStartInput ; $C496: 10 F1
00C498 1
00C498 1 ; ----------------------------------------------------------------------------
00C498 1 ; Initialize state variables.
00C498 1 ; ----------------------------------------------------------------------------
00C498 1
00C498 1 A9 00 lda #$00 ; $C498: A9 00
00C49A 1 85 EF sta GameplaySuspended ; $C49A: 85 EF
00C49C 1
00C49C 1 InitializeNewSession: ; $C49C
00C49C 1 A9 00 lda #$00 ; $C49C: A9 00
00C49E 1 85 60 sta PendingStateTransition ; $C49E: 85 60
00C4A0 1 8D 96 05 sta $0596 ; $C4A0: 8D 96 05
00C4A3 1 85 33 sta RoundStateIndex ; $C4A3: 85 33
00C4A5 1
00C4A5 1 E6 1E inc SessionActive ; $C4A5: E6 1E
00C4A7 1
00C4A7 1 20 9D EB jsr InitializeQueuedEventSystem ; $C4A7: 20 9D EB
00C4AA 1
00C4AA 1 ; ----------------------------------------------------------------------------
00C4AA 1 ; Set the PPUCTRL shadow value and initialize PPU-related state.
00C4AA 1 ; ----------------------------------------------------------------------------
00C4AA 1 InitializeSessionDisplay:
00C4AA 1 A9 88 lda #$88 ; $C4AA: A9 88
00C4AC 1 85 DD sta PpuCtrlShadow ; $C4AC: 85 DD
00C4AE 1
00C4AE 1 20 6C E9 jsr DisablePpuRendering ; $C4AE: 20 6C E9
00C4B1 1 20 83 E9 jsr FillPpuMemoryWith26 ; $C4B1: 20 83 E9
00C4B4 1
00C4B4 1 ; ----------------------------------------------------------------------------
00C4B4 1 ; The routine at $EA63 consumes the two inline bytes following the JSR.
00C4B4 1 ; They must remain raw data rather than being decoded as 6502 opcodes.
00C4B4 1 ; ----------------------------------------------------------------------------
00C4B4 1
00C4B4 1 20 63 EA jsr ProcessInlinePpuStream ; $C4B4: 20 63 EA
00C4B7 1
00C4B7 1 F2 F4 .byte $F2,$F4 ; $C4B7-$C4B8
00C4B9 1 ; Inline command/pointer data.
00C4B9 1
00C4B9 1 ; ============================================================================
00C4B9 1 ; $C4B9-$C51D
00C4B9 1 ; Initialize play state, choose player values, and invoke setup routines.
00C4B9 1 ; ============================================================================
00C4B9 1
00C4B9 1 InitializeMatchState: ; $C4B9
00C4B9 1 20 4F C9 jsr ClearBasePositionFields ; $C4B9: 20 4F C9
00C4BC 1 20 43 C9 jsr ClearBaseAccelerationFields ; $C4BC: 20 43 C9
00C4BF 1
00C4BF 1 ; ----------------------------------------------------------------------------
00C4BF 1 ; Initialize signed position/state values.
00C4BF 1 ; ----------------------------------------------------------------------------
00C4BF 1
00C4BF 1 A9 80 lda #$80 ; $C4BF: A9 80
00C4C1 1 8D 3B 05 sta $053B ; $C4C1: 8D 3B 05
00C4C4 1 85 B7 sta PositionSignState ; $C4C4: 85 B7
00C4C6 1
00C4C6 1 20 78 E9 jsr EnableNmiAndWaitForFrame ; $C4C6: 20 78 E9
00C4C9 1
00C4C9 1 ; ----------------------------------------------------------------------------
00C4C9 1 ; Obtain two different values from $C850.
00C4C9 1 ; The first is saved in $34 and the second in $35.
00C4C9 1 ; ----------------------------------------------------------------------------
00C4C9 1
00C4C9 1 20 50 C8 jsr Random0To5 ; $C4C9: 20 50 C8
00C4CC 1 85 34 sta PlayerOneSelection ; $C4CC: 85 34
00C4CE 1
00C4CE 1 SelectDistinctSecondPlayerValue: ; $C4CE
00C4CE 1 20 50 C8 jsr Random0To5 ; $C4CE: 20 50 C8
00C4D1 1 C5 34 cmp PlayerOneSelection ; $C4D1: C5 34
00C4D3 1 F0 F9 beq SelectDistinctSecondPlayerValue
00C4D5 1 ; $C4D3: F0 F9
00C4D5 1
00C4D5 1 85 35 sta PlayerTwoSelection ; $C4D5: 85 35
00C4D7 1
00C4D7 1 ; ----------------------------------------------------------------------------
00C4D7 1 ; If $EF is nonzero, skip the player/control selection logic.
00C4D7 1 ; ----------------------------------------------------------------------------
00C4D7 1
00C4D7 1 A5 EF lda GameplaySuspended ; $C4D7: A5 EF
00C4D9 1 D0 31 bne CompleteMatchSetup ; $C4D9: D0 31
00C4DB 1
00C4DB 1 A5 40 lda ModeFlags ; $C4DB: A5 40
00C4DD 1 29 01 and #$01 ; $C4DD: 29 01
00C4DF 1 85 43 sta $43 ; $C4DF: 85 43
00C4E1 1
00C4E1 1 D0 09 bne DeriveSelectedSideFromMode
00C4E3 1 ; $C4E1: D0 09
00C4E3 1
00C4E3 1 ; ----------------------------------------------------------------------------
00C4E3 1 ; Choose a random low-bit value for $4B.
00C4E3 1 ; ----------------------------------------------------------------------------
00C4E3 1
00C4E3 1 20 F5 E5 jsr AdvanceRandomState ; $C4E3: 20 F5 E5
00C4E6 1 29 01 and #$01 ; $C4E6: 29 01
00C4E8 1 85 4B sta ActivePlayerSide ; $C4E8: 85 4B
00C4EA 1
00C4EA 1 10 09 bpl StartPlayerSelection ; $C4EA: 10 09
00C4EC 1 ; Always taken after AND #$01.
00C4EC 1
00C4EC 1 ; ----------------------------------------------------------------------------
00C4EC 1 ; Derive $4B from $43 when $43 is nonzero.
00C4EC 1 ; ----------------------------------------------------------------------------
00C4EC 1
00C4EC 1 DeriveSelectedSideFromMode: ; $C4EC
00C4EC 1 4A lsr ; $C4EC: 4A
00C4ED 1 85 4B sta ActivePlayerSide ; $C4ED: 85 4B
00C4EF 1
00C4EF 1 20 0A EB jsr QueueInlineObjectEvent ; $C4EF: 20 0A EB
00C4F2 1
00C4F2 1 ; Inline command data consumed by QueueInlineObjectEvent.
00C4F2 1 03 19 C8 .byte $03,$19,$C8 ; $C4F2-$C4F4
00C4F5 1
00C4F5 1 StartPlayerSelection: ; $C4F5
00C4F5 1 20 0A EB jsr QueueInlineObjectEvent ; $C4F5: 20 0A EB
00C4F8 1
00C4F8 1 ; Inline command data consumed by QueueInlineObjectEvent.
00C4F8 1 02 19 C8 .byte $02,$19,$C8 ; $C4F8-$C4FA
00C4FB 1
00C4FB 1 A9 01 lda #$01 ; $C4FB: A9 01
00C4FD 1 85 44 sta PlayerSelectionActive ; $C4FD: 85 44
00C4FF 1
00C4FF 1 ; ----------------------------------------------------------------------------
00C4FF 1 ; Wait while $43 remains nonnegative.
00C4FF 1 ;
00C4FF 1 ; $EB48 presumably updates asynchronous state, including $43.
00C4FF 1 ; ----------------------------------------------------------------------------
00C4FF 1
00C4FF 1 WaitForPlayerSelection: ; $C4FF
00C4FF 1 20 48 EB jsr SelectObjectEventBank1 ; $C4FF: 20 48 EB
00C502 1
00C502 1 A5 43 lda $43 ; $C502: A5 43
00C504 1 10 F9 bpl WaitForPlayerSelection
00C506 1 ; $C504: 10 F9
00C506 1
00C506 1 20 0A EB jsr QueueInlineObjectEvent ; $C506: 20 0A EB
00C509 1
00C509 1 ; Inline command data consumed by QueueInlineObjectEvent.
00C509 1 03 3E C4 .byte $03,$3E,$C4 ; $C509-$C50B
00C50C 1
00C50C 1 ; ----------------------------------------------------------------------------
00C50C 1 ; Run the main setup sequence.
00C50C 1 ; ----------------------------------------------------------------------------
00C50C 1
00C50C 1 CompleteMatchSetup: ; $C50C
00C50C 1 20 5A C8 jsr FillSelectionBackgroundBlocks ; $C50C: 20 5A C8
00C50F 1 20 DD C7 jsr QueuePlayerSelectionDisplay ; $C50F: 20 DD C7
00C512 1 20 E8 C8 jsr InitializeRandomBitfields ; $C512: 20 E8 C8
00C515 1 20 8B CF jsr QueuePlayerValueDisplay ; $C515: 20 8B CF
00C518 1
00C518 1 20 0A EB jsr QueueInlineObjectEvent ; $C518: 20 0A EB
00C51B 1
00C51B 1 ; Inline command data consumed by QueueInlineObjectEvent.
00C51B 1 09 37 CE .byte $09,$37,$CE ; $C51B-$C51D
00C51E 1
00C51E 1 ; ============================================================================
00C51E 1 ; $C51E-$C57E
00C51E 1 ; Conditional state initialization and message display.
00C51E 1 ; ============================================================================
00C51E 1
00C51E 1 InitializeRoundState: ; $C51E
00C51E 1 A5 EF lda GameplaySuspended ; $C51E: A5 EF
00C520 1 F0 08 beq EnableRoundAudio
00C522 1 ; $C520: F0 08
00C522 1
00C522 1 A5 33 lda RoundStateIndex ; $C522: A5 33
00C524 1 C9 12 cmp #$12 ; $C524: C9 12
00C526 1 90 3E bcc SelectRoundMusicCue
00C528 1 ; $C526: 90 3E
00C528 1
00C528 1 B0 0C bcs ResetRoundCounters ; $C528: B0 0C
00C52A 1 ; Effectively unconditional because either
00C52A 1 ; CMP result not taken by BCC has carry set.
00C52A 1
00C52A 1 ; ----------------------------------------------------------------------------
00C52A 1 ; Configure the APU and initialize a delay value.
00C52A 1 ; ----------------------------------------------------------------------------
00C52A 1
00C52A 1 EnableRoundAudio: ; $C52A
00C52A 1 A9 0F lda #$0F ; $C52A: A9 0F
00C52C 1 8D 00 01 sta $0100 ; $C52C: 8D 00 01
00C52F 1 8D 15 40 sta $4015 ; $C52F: 8D 15 40
00C532 1 ; Enable the four standard APU channels.
00C532 1
00C532 1 A9 08 lda #$08 ; $C532: A9 08
00C534 1 85 FD sta $FD ; $C534: 85 FD
00C536 1
00C536 1 ; ----------------------------------------------------------------------------
00C536 1 ; Clear game-state values and call the setup routine at $D06B.
00C536 1 ; A is zero after TXA.
00C536 1 ; ----------------------------------------------------------------------------
00C536 1
00C536 1 ResetRoundCounters: ; $C536
00C536 1 A2 00 ldx #$00 ; $C536: A2 00
00C538 1
00C538 1 86 67 stx PlayerOneScore ; $C538: 86 67
00C53A 1 86 68 stx PlayerTwoScore ; $C53A: 86 68
00C53C 1 86 33 stx RoundStateIndex ; $C53C: 86 33
00C53E 1
00C53E 1 8A txa ; $C53E: 8A
00C53F 1 20 6B D0 jsr InitializeObjectsFromTable ; $C53F: 20 6B D0
00C542 1
00C542 1 ; ----------------------------------------------------------------------------
00C542 1 ; Initialize position/state values and wait for $3C frames or ticks.
00C542 1 ; ----------------------------------------------------------------------------
00C542 1
00C542 1 A9 80 lda #$80 ; $C542: A9 80
00C544 1 8D 3B 05 sta $053B ; $C544: 8D 3B 05
00C547 1 85 B7 sta PositionSignState ; $C547: 85 B7
00C549 1
00C549 1 A9 3C lda #$3C ; $C549: A9 3C
00C54B 1 20 41 EB jsr StoreObjectEventBankValue ; $C54B: 20 41 EB
00C54E 1
00C54E 1 ; ----------------------------------------------------------------------------
00C54E 1 ; Draw an eight-character encoded message.
00C54E 1 ;
00C54E 1 ; The routine at $EA17 consumes the inline bytes immediately following
00C54E 1 ; the JSR. The first byte is the character count.
00C54E 1 ; ----------------------------------------------------------------------------
00C54E 1
00C54E 1 18 clc ; $C54E: 18
00C54F 1
00C54F 1 A9 20 lda #$20 ; $C54F: A9 20
00C551 1 A2 EC ldx #$EC ; $C551: A2 EC
00C553 1 A0 08 ldy #$08 ; $C553: A0 08
00C555 1
00C555 1 20 17 EA jsr CopyInlineDisplayRecord ; $C555: 20 17 EA
00C558 1
00C558 1 08 .byte $08 ; $C558: character count
00C559 1 19 15 0A 22 .byte $19,$15,$0A,$22 ; $C559-$C55C
00C55D 1 0B 0A 15 15 .byte $0B,$0A,$15,$15 ; $C55D-$C560
00C561 1
00C561 1 ; ----------------------------------------------------------------------------
00C561 1 ; Wait for another $3C frames or ticks.
00C561 1 ; ----------------------------------------------------------------------------
00C561 1
00C561 1 A9 3C lda #$3C ; $C561: A9 3C
00C563 1 20 41 EB jsr StoreObjectEventBankValue ; $C563: 20 41 EB
00C566 1
00C566 1 ; ----------------------------------------------------------------------------
00C566 1 ; Select a delay or mode value in $FD from the current value of $33.
00C566 1 ; ----------------------------------------------------------------------------
00C566 1
00C566 1 SelectRoundMusicCue: ; $C566
00C566 1 A5 33 lda RoundStateIndex ; $C566: A5 33
00C568 1 F0 09 beq PrepareRoundObjects ; $C568: F0 09
00C56A 1
00C56A 1 A2 20 ldx #$20 ; $C56A: A2 20
00C56C 1
00C56C 1 4A lsr ; $C56C: 4A
00C56D 1 90 02 bcc StoreRoundMusicCue ; $C56D: 90 02
00C56F 1
00C56F 1 A2 40 ldx #$40 ; $C56F: A2 40
00C571 1
00C571 1 StoreRoundMusicCue: ; $C571
00C571 1 86 FD stx $FD ; $C571: 86 FD
00C573 1
00C573 1 ; ----------------------------------------------------------------------------
00C573 1 ; Continue engine initialization.
00C573 1 ; ----------------------------------------------------------------------------
00C573 1
00C573 1 PrepareRoundObjects: ; $C573
00C573 1 20 DD C7 jsr QueuePlayerSelectionDisplay ; $C573: 20 DD C7
00C576 1 20 04 C9 jsr QueueRandomStateRecord ; $C576: 20 04 C9
00C579 1
00C579 1 A2 00 ldx #$00 ; $C579: A2 00
00C57B 1 86 45 stx MatchCompleteFlag ; $C57B: 86 45
00C57D 1 86 64 stx SecondarySequenceState ; $C57D: 86 64
00C57F 1
00C57F 1 ; ============================================================================
00C57F 1 ; $C57F-$C5FD
00C57F 1 ; Clear gameplay state, initialize object data, and prepare the next state.
00C57F 1 ;
00C57F 1 ; Entry:
00C57F 1 ; X = $00 from the preceding block at $C579.
00C57F 1 ; ============================================================================
00C57F 1
00C57F 1 ResetGameplayState: ; $C57F
00C57F 1 86 66 stx InningOrSharedScore ; $C57F: 86 66
00C581 1 86 5C stx BaseMotionActive ; $C581: 86 5C
00C583 1
00C583 1 CA dex ; $C583: CA
00C584 1 ; X = $FF
00C584 1
00C584 1 ; ----------------------------------------------------------------------------
00C584 1 ; Mark four state entries as inactive using $FF.
00C584 1 ; ----------------------------------------------------------------------------
00C584 1
00C584 1 8E 98 05 stx $0598 ; $C584: 8E 98 05
00C587 1 8E 99 05 stx $0599 ; $C587: 8E 99 05
00C58A 1 8E 9A 05 stx $059A ; $C58A: 8E 9A 05
00C58D 1 8E 9B 05 stx $059B ; $C58D: 8E 9B 05
00C590 1
00C590 1 ; ----------------------------------------------------------------------------
00C590 1 ; Initialize additional game-state structures.
00C590 1 ; ----------------------------------------------------------------------------
00C590 1
00C590 1 20 67 CF jsr QueueRoundNumberDisplay ; $C590: 20 67 CF
00C593 1
00C593 1 A9 00 lda #$00 ; $C593: A9 00
00C595 1 20 6B D0 jsr InitializeObjectsFromTable ; $C595: 20 6B D0
00C598 1
00C598 1 ; ----------------------------------------------------------------------------
00C598 1 ; Initialize signed position/state values.
00C598 1 ; ----------------------------------------------------------------------------
00C598 1
00C598 1 A9 80 lda #$80 ; $C598: A9 80
00C59A 1 8D 3B 05 sta $053B ; $C59A: 8D 3B 05
00C59D 1 85 B7 sta PositionSignState ; $C59D: 85 B7
00C59F 1
00C59F 1 ; ----------------------------------------------------------------------------
00C59F 1 ; Wait for or process $B4 ticks.
00C59F 1 ; ----------------------------------------------------------------------------
00C59F 1
00C59F 1 A9 B4 lda #$B4 ; $C59F: A9 B4
00C5A1 1 20 41 EB jsr StoreObjectEventBankValue ; $C5A1: 20 41 EB
00C5A4 1
00C5A4 1 ; ----------------------------------------------------------------------------
00C5A4 1 ; Contract:
00C5A4 1 ; Description: Internal round-setup continuation at random-direction initialization.
00C5A4 1 ; Entry: Parent routine state already initialized.
00C5A4 1 ; Returns/products: Continues round setup; no independent return contract.
00C5A4 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00C5A4 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00C5A4 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00C5A4 1 ; comparison, load, or store path and are not a stable API product.
00C5A4 1 ; Validation: Internal-entry contract; call sites: internal entry.
00C5A4 1 ; ----------------------------------------------------------------------------
00C5A4 1 ResumeRoundSetupAtRandomDirection:
00C5A4 1 20 1B C9 jsr QueueRandomDirectionRecord ; $C5A4: 20 1B C9
00C5A7 1
00C5A7 1 ; ----------------------------------------------------------------------------
00C5A7 1 ; Clear two state variables and initialize $46 to one.
00C5A7 1 ; ----------------------------------------------------------------------------
00C5A7 1
00C5A7 1 A2 00 ldx #$00 ; $C5A7: A2 00
00C5A9 1
00C5A9 1 86 62 stx PrimarySequenceState ; $C5A9: 86 62
00C5AB 1 86 63 stx TransitionSequenceState ; $C5AB: 86 63
00C5AD 1
00C5AD 1 E8 inx ; $C5AD: E8
00C5AE 1 ; X = $01
00C5AE 1
00C5AE 1 86 46 stx StateSequenceActive ; $C5AE: 86 46
00C5B0 1
00C5B0 1 ; ----------------------------------------------------------------------------
00C5B0 1 ; Invoke $CF51 with two different values.
00C5B0 1 ; ----------------------------------------------------------------------------
00C5B0 1
00C5B0 1 A9 03 lda #$03 ; $C5B0: A9 03
00C5B2 1 20 51 CF jsr ClearStateFieldPair ; $C5B2: 20 51 CF
00C5B5 1
00C5B5 1 A9 23 lda #$23 ; $C5B5: A9 23
00C5B7 1 20 51 CF jsr ClearStateFieldPair ; $C5B7: 20 51 CF
00C5BA 1
00C5BA 1 ; ----------------------------------------------------------------------------
00C5BA 1 ; Contract:
00C5BA 1 ; Description: Internal round-setup continuation at selection-display initialization.
00C5BA 1 ; Entry: Parent routine state already initialized.
00C5BA 1 ; Returns/products: Continues round setup; no independent return contract.
00C5BA 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00C5BA 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00C5BA 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00C5BA 1 ; comparison, load, or store path and are not a stable API product.
00C5BA 1 ; Validation: Internal-entry contract; call sites: internal entry.
00C5BA 1 ; ----------------------------------------------------------------------------
00C5BA 1 ResumeRoundSetupAtSelectionDisplay:
00C5BA 1 20 C9 C7 jsr ClearEightCharacterField ; $C5BA: 20 C9 C7
00C5BD 1
00C5BD 1 ; ----------------------------------------------------------------------------
00C5BD 1 ; Clear individual state entries.
00C5BD 1 ; ----------------------------------------------------------------------------
00C5BD 1
00C5BD 1 A9 00 lda #$00 ; $C5BD: A9 00
00C5BF 1
00C5BF 1 8D 97 05 sta $0597 ; $C5BF: 8D 97 05
00C5C2 1
00C5C2 1 8D 9C 05 sta $059C ; $C5C2: 8D 9C 05
00C5C5 1 8D 9D 05 sta $059D ; $C5C5: 8D 9D 05
00C5C8 1 8D 9E 05 sta $059E ; $C5C8: 8D 9E 05
00C5CB 1 8D 9F 05 sta $059F ; $C5CB: 8D 9F 05
00C5CE 1 8D A0 05 sta $05A0 ; $C5CE: 8D A0 05
00C5D1 1
00C5D1 1 8D A4 05 sta $05A4 ; $C5D1: 8D A4 05
00C5D4 1 8D A5 05 sta $05A5 ; $C5D4: 8D A5 05
00C5D7 1 8D A6 05 sta $05A6 ; $C5D7: 8D A6 05
00C5DA 1
00C5DA 1 ; ----------------------------------------------------------------------------
00C5DA 1 ; Clear the 38-byte range $056F-$0594.
00C5DA 1 ;
00C5DA 1 ; X counts from $25 down through $00.
00C5DA 1 ; ----------------------------------------------------------------------------
00C5DA 1
00C5DA 1 A2 25 ldx #$25 ; $C5DA: A2 25
00C5DC 1
00C5DC 1 ClearObjectMotionFields: ; $C5DC
00C5DC 1 9D 6F 05 sta $056F,x ; $C5DC: 9D 6F 05
00C5DF 1
00C5DF 1 CA dex ; $C5DF: CA
00C5E0 1 10 FA bpl ClearObjectMotionFields
00C5E2 1 ; $C5E0: 10 FA
00C5E2 1
00C5E2 1 ; ----------------------------------------------------------------------------
00C5E2 1 ; Conditional transition based on $33 and the comparison of $67 with $68.
00C5E2 1 ; ----------------------------------------------------------------------------
00C5E2 1
00C5E2 1 A5 33 lda RoundStateIndex ; $C5E2: A5 33
00C5E4 1 C9 11 cmp #$11 ; $C5E4: C9 11
00C5E6 1 D0 09 bne FinishGameplayReset ; $C5E6: D0 09
00C5E8 1
00C5E8 1 A5 67 lda PlayerOneScore ; $C5E8: A5 67
00C5EA 1 C5 68 cmp PlayerTwoScore ; $C5EA: C5 68
00C5EC 1 B0 03 bcs FinishGameplayReset ; $C5EC: B0 03
00C5EE 1
00C5EE 1 4C F7 C6 jmp CompleteMatchState ; $C5EE: 4C F7 C6
00C5F1 1
00C5F1 1 ; ----------------------------------------------------------------------------
00C5F1 1 ; Complete initialization and synchronize with the frame/update system.
00C5F1 1 ; ----------------------------------------------------------------------------
00C5F1 1
00C5F1 1 FinishGameplayReset: ; $C5F1
00C5F1 1 20 69 D0 jsr InitializeDefaultObjects ; $C5F1: 20 69 D0
00C5F4 1
00C5F4 1 A9 00 lda #$00 ; $C5F4: A9 00
00C5F6 1 8D 3B 05 sta $053B ; $C5F6: 8D 3B 05
00C5F9 1 85 B7 sta PositionSignState ; $C5F9: 85 B7
00C5FB 1
00C5FB 1 20 48 EB jsr SelectObjectEventBank1 ; $C5FB: 20 48 EB
00C5FE 1
00C5FE 1 ; ============================================================================
00C5FE 1 ; $C5FE-$C6E0
00C5FE 1 ; Main state initialization and processing loop
00C5FE 1 ; ============================================================================
00C5FE 1
00C5FE 1 RunRoundStateLoop: ; $C5FE
00C5FE 1 A4 60 ldy PendingStateTransition ; $C5FE: A4 60
00C600 1 F0 03 beq CheckRoundTransitionState ; $C600: F0 03
00C602 1
00C602 1 20 A2 C8 jsr InitializeObjectStateLookup ; $C602: 20 A2 C8
00C605 1
00C605 1 ; ----------------------------------------------------------------------------
00C605 1 ; Dispatch state-specific handlers when either $60 or $46 is nonzero.
00C605 1 ; ----------------------------------------------------------------------------
00C605 1
00C605 1 CheckRoundTransitionState: ; $C605
00C605 1 A5 60 lda PendingStateTransition ; $C605: A5 60
00C607 1 05 46 ora StateSequenceActive ; $C607: 05 46
00C609 1 F0 0E beq RunPrimaryRoundHandlers
00C60B 1 ; $C609: F0 0E
00C60B 1
00C60B 1 46 46 lsr StateSequenceActive ; $C60B: 46 46
00C60D 1
00C60D 1 20 0A EB jsr QueueInlineObjectEvent ; $C60D: 20 0A EB
00C610 1
00C610 1 ; Inline command record consumed by QueueInlineObjectEvent.
00C610 1 0D 77 D4 .byte $0D,$77,$D4 ; $C610-$C612
00C613 1
00C613 1 20 0A EB jsr QueueInlineObjectEvent ; $C613: 20 0A EB
00C616 1
00C616 1 ; Inline command record consumed by QueueInlineObjectEvent.
00C616 1 0F 81 D3 .byte $0F,$81,$D3 ; $C616-$C618
00C619 1
00C619 1 ; ----------------------------------------------------------------------------
00C619 1 ; Run the primary state handlers.
00C619 1 ; ----------------------------------------------------------------------------
00C619 1
00C619 1 RunPrimaryRoundHandlers: ; $C619
00C619 1 20 10 D6 jsr InitializeSecondaryActors ; $C619: 20 10 D6
00C61C 1 20 26 D1 jsr InitializeConditionalObject ; $C61C: 20 26 D1
00C61F 1
00C61F 1 ; ----------------------------------------------------------------------------
00C61F 1 ; Clear working state.
00C61F 1 ; ----------------------------------------------------------------------------
00C61F 1
00C61F 1 A2 00 ldx #$00 ; $C61F: A2 00
00C621 1
00C621 1 86 65 stx PendingScoreIncrement ; $C621: 86 65
00C623 1 86 5D stx BaseMotionPhase ; $C623: 86 5D
00C625 1 86 5E stx BaseMotionEventCount ; $C625: 86 5E
00C627 1 86 5F stx TrajectoryResult ; $C627: 86 5F
00C629 1 86 60 stx PendingStateTransition ; $C629: 86 60
00C62B 1 86 6D stx SpecialSequenceState ; $C62B: 86 6D
00C62D 1 86 6E stx ObjectTransitionState ; $C62D: 86 6E
00C62F 1 86 5C stx BaseMotionActive ; $C62F: 86 5C
00C631 1 86 7E stx ActionSequenceCounter ; $C631: 86 7E
00C633 1 86 86 stx TrajectoryEvaluationEnabled ; $C633: 86 86
00C635 1 86 85 stx $85 ; $C635: 86 85
00C637 1 86 83 stx ObjectApproachCount ; $C637: 86 83
00C639 1 86 6F stx PendingEvent ; $C639: 86 6F
00C63B 1 86 A2 stx ObjectSequenceState ; $C63B: 86 A2
00C63D 1 86 BC stx $BC ; $C63D: 86 BC
00C63F 1
00C63F 1 8E 6E 05 stx $056E ; $C63F: 8E 6E 05
00C642 1
00C642 1 86 9E stx $9E ; $C642: 86 9E
00C644 1
00C644 1 E8 inx ; $C644: E8
00C645 1 ; X = $01
00C645 1
00C645 1 86 96 stx $96 ; $C645: 86 96
00C647 1 86 97 stx $97 ; $C647: 86 97
00C649 1 86 98 stx $98 ; $C649: 86 98
00C64B 1
00C64B 1 ; ----------------------------------------------------------------------------
00C64B 1 ; Reset coordinate-related structures.
00C64B 1 ; ----------------------------------------------------------------------------
00C64B 1
00C64B 1 20 43 C9 jsr ClearBaseAccelerationFields ; $C64B: 20 43 C9
00C64E 1 20 4F C9 jsr ClearBasePositionFields ; $C64E: 20 4F C9
00C651 1
00C651 1 ; ----------------------------------------------------------------------------
00C651 1 ; Run three inline-command handlers.
00C651 1 ; ----------------------------------------------------------------------------
00C651 1
00C651 1 20 0A EB jsr QueueInlineObjectEvent ; $C651: 20 0A EB
00C654 1
00C654 1 25 5A D8 .byte $25,$5A,$D8 ; $C654-$C656
00C657 1
00C657 1 20 0A EB jsr QueueInlineObjectEvent ; $C657: 20 0A EB
00C65A 1
00C65A 1 0E 66 D1 .byte $0E,$66,$D1 ; $C65A-$C65C
00C65D 1
00C65D 1 20 0A EB jsr QueueInlineObjectEvent ; $C65D: 20 0A EB
00C660 1
00C660 1 1F 76 CA .byte $1F,$76,$CA ; $C660-$C662
00C663 1
00C663 1 ; ----------------------------------------------------------------------------
00C663 1 ; Process command $08.
00C663 1 ; ----------------------------------------------------------------------------
00C663 1
00C663 1 A2 08 ldx #$08 ; $C663: A2 08
00C665 1 20 4E EB jsr UpdateObjectEventBank_Exchange ; $C665: 20 4E EB
00C668 1
00C668 1 ; ----------------------------------------------------------------------------
00C668 1 ; Walk a 22-entry table in reverse.
00C668 1 ;
00C668 1 ; X begins at $15 and reaches $00. Each byte from $C6E1,X is passed in Y
00C668 1 ; to the routine at $EB66.
00C668 1 ; ----------------------------------------------------------------------------
00C668 1
00C668 1 A2 15 ldx #$15 ; $C668: A2 15
00C66A 1
00C66A 1 ProcessRoundEventSlotTable: ; $C66A
00C66A 1 BC E1 C6 ldy RoundEventSlotTable,x ; $C66A: BC E1 C6
00C66D 1 20 66 EB jsr DispatchNextQueuedEvent ; $C66D: 20 66 EB
00C670 1
00C670 1 CA dex ; $C670: CA
00C671 1 10 F7 bpl ProcessRoundEventSlotTable
00C673 1 ; $C671: 10 F7
00C673 1
00C673 1 ; ----------------------------------------------------------------------------
00C673 1 ; Write one inline character at the selected PPU destination.
00C673 1 ; ----------------------------------------------------------------------------
00C673 1
00C673 1 A9 3F lda #$3F ; $C673: A9 3F
00C675 1 A2 07 ldx #$07 ; $C675: A2 07
00C677 1 A0 01 ldy #$01 ; $C677: A0 01
00C679 1
00C679 1 20 17 EA jsr CopyInlineDisplayRecord ; $C679: 20 17 EA
00C67C 1
00C67C 1 01 28 .byte $01,$28 ; $C67C-$C67D
00C67E 1 ; One encoded character: $28.
00C67E 1
00C67E 1 ; ----------------------------------------------------------------------------
00C67E 1 ; If $60 is zero and $65 is nonzero, run the helper at $CFA6 and clear $65.
00C67E 1 ; ----------------------------------------------------------------------------
00C67E 1
00C67E 1 ApplyPendingScoreUpdate: ; $C67E
00C67E 1 A5 60 lda PendingStateTransition ; $C67E: A5 60
00C680 1 D0 0B bne StartPostRoundDelay ; $C680: D0 0B
00C682 1
00C682 1 A5 65 lda PendingScoreIncrement ; $C682: A5 65
00C684 1 F0 07 beq StartPostRoundDelay ; $C684: F0 07
00C686 1
00C686 1 20 A6 CF jsr UpdateCountersAndDisplay ; $C686: 20 A6 CF
00C689 1
00C689 1 A9 00 lda #$00 ; $C689: A9 00
00C68B 1 85 65 sta PendingScoreIncrement ; $C68B: 85 65
00C68D 1
00C68D 1 ; ----------------------------------------------------------------------------
00C68D 1 ; Wait for $6F to become zero, then count down $48.
00C68D 1 ; ----------------------------------------------------------------------------
00C68D 1
00C68D 1 StartPostRoundDelay: ; $C68D
00C68D 1 A9 1E lda #$1E ; $C68D: A9 1E
00C68F 1 85 48 sta $48 ; $C68F: 85 48
00C691 1
00C691 1 WaitPostRoundFrame: ; $C691
00C691 1 20 48 EB jsr SelectObjectEventBank1 ; $C691: 20 48 EB
00C694 1
00C694 1 A5 6F lda PendingEvent ; $C694: A5 6F
00C696 1 D0 F5 bne StartPostRoundDelay ; $C696: D0 F5
00C698 1
00C698 1 C6 48 dec $48 ; $C698: C6 48
00C69A 1 D0 F5 bne WaitPostRoundFrame ; $C69A: D0 F5
00C69C 1
00C69C 1 ; ----------------------------------------------------------------------------
00C69C 1 ; If both $45 and $46 are zero, return to the initialization point at $C5BA.
00C69C 1 ; ----------------------------------------------------------------------------
00C69C 1
00C69C 1 A5 45 lda MatchCompleteFlag ; $C69C: A5 45
00C69E 1 05 46 ora StateSequenceActive ; $C69E: 05 46
00C6A0 1 D0 03 bne ProcessPostRoundEvents
00C6A2 1 ; $C6A0: D0 03
00C6A2 1
00C6A2 1 4C BA C5 jmp ResumeRoundSetupAtSelectionDisplay ; $C6A2: 4C BA C5
00C6A5 1
00C6A5 1 ; ----------------------------------------------------------------------------
00C6A5 1 ; Process two indexed event slots and wait ten ticks.
00C6A5 1 ; ----------------------------------------------------------------------------
00C6A5 1
00C6A5 1 ProcessPostRoundEvents: ; $C6A5
00C6A5 1 A0 0D ldy #$0D ; $C6A5: A0 0D
00C6A7 1 20 66 EB jsr DispatchNextQueuedEvent ; $C6A7: 20 66 EB
00C6AA 1
00C6AA 1 A0 0F ldy #$0F ; $C6AA: A0 0F
00C6AC 1 20 66 EB jsr DispatchNextQueuedEvent ; $C6AC: 20 66 EB
00C6AF 1
00C6AF 1 A9 0A lda #$0A ; $C6AF: A9 0A
00C6B1 1 20 41 EB jsr StoreObjectEventBankValue ; $C6B1: 20 41 EB
00C6B4 1
00C6B4 1 ; ----------------------------------------------------------------------------
00C6B4 1 ; If $46 is active, decrement one of the two counters at $51/$52.
00C6B4 1 ; The selected counter depends on the low bit of $33.
00C6B4 1 ; ----------------------------------------------------------------------------
00C6B4 1
00C6B4 1 A5 46 lda StateSequenceActive ; $C6B4: A5 46
00C6B6 1 F0 0D beq CheckPostRoundContinuation ; $C6B6: F0 0D
00C6B8 1
00C6B8 1 A5 33 lda RoundStateIndex ; $C6B8: A5 33
00C6BA 1 29 01 and #$01 ; $C6BA: 29 01
00C6BC 1 AA tax ; $C6BC: AA
00C6BD 1
00C6BD 1 D6 51 dec Counter51,x ; $C6BD: D6 51
00C6BF 1 10 04 bpl CheckPostRoundContinuation ; $C6BF: 10 04
00C6C1 1
00C6C1 1 A9 08 lda #$08 ; $C6C1: A9 08
00C6C3 1 95 51 sta Counter51,x ; $C6C3: 95 51
00C6C5 1
00C6C5 1 ; ----------------------------------------------------------------------------
00C6C5 1 ; If $45 is zero, return to the setup point at $C5A4.
00C6C5 1 ; Otherwise, update state and advance $33.
00C6C5 1 ; ----------------------------------------------------------------------------
00C6C5 1
00C6C5 1 CheckPostRoundContinuation: ; $C6C5
00C6C5 1 A5 45 lda MatchCompleteFlag ; $C6C5: A5 45
00C6C7 1 D0 03 bne AdvanceRoundNumber ; $C6C7: D0 03
00C6C9 1
00C6C9 1 4C A4 C5 jmp ResumeRoundSetupAtRandomDirection ; $C6C9: 4C A4 C5
00C6CC 1
00C6CC 1 AdvanceRoundNumber: ; $C6CC
00C6CC 1 20 A6 CF jsr UpdateCountersAndDisplay ; $C6CC: 20 A6 CF
00C6CF 1
00C6CF 1 E6 33 inc RoundStateIndex ; $C6CF: E6 33
00C6D1 1
00C6D1 1 A5 33 lda RoundStateIndex ; $C6D1: A5 33
00C6D3 1 C9 12 cmp #$12 ; $C6D3: C9 12
00C6D5 1 F0 31 beq InitializeResultsPosition ; $C6D5: F0 31
00C6D7 1
00C6D7 1 20 48 EB jsr SelectObjectEventBank1 ; $C6D7: 20 48 EB
00C6DA 1
00C6DA 1 A5 EF lda GameplaySuspended ; $C6DA: A5 EF
00C6DC 1 D0 6C bne InitializeTitleScreen ; $C6DC: D0 6C
00C6DE 1
00C6DE 1 4C 66 C5 jmp SelectRoundMusicCue ; $C6DE: 4C 66 C5
00C6E1 1
00C6E1 1 ; ============================================================================
00C6E1 1 ; Table referenced by the loop at $C66A.
00C6E1 1 ;
00C6E1 1 ; The table begins at CPU $C6E1 and remains in the untouched ROM for the next
00C6E1 1 ; pass. Its first bytes are:
00C6E1 1 ;
00C6E1 1 ; $04,$06,$08,$0A,$0C,$0E,$10,$12 ...
00C6E1 1 ; ============================================================================
00C6E1 1
00C6E1 1 ; ============================================================================
00C6E1 1 ; $C6E1-$C6F6
00C6E1 1 ; Event-slot/index lookup table
00C6E1 1 ; ============================================================================
00C6E1 1
00C6E1 1 RoundEventSlotTable: ; $C6E1
00C6E1 1 04 06 08 0A .byte $04,$06,$08,$0A
00C6E5 1 0C 0E 10 12 .byte $0C,$0E,$10,$12
00C6E9 1 14 16 1E 20 .byte $14,$16,$1E,$20
00C6ED 1 22 24 26 11 .byte $22,$24,$26,$11
00C6F1 1 15 17 19 1D .byte $15,$17,$19,$1D
00C6F5 1 1F 29 .byte $1F,$29
00C6F7 1
00C6F7 1 ; ============================================================================
00C6F7 1 ; $C6F7-$C7B0
00C6F7 1 ; State completion, message display, PPU setup, and return to the main loop
00C6F7 1 ; ============================================================================
00C6F7 1
00C6F7 1 CompleteMatchState: ; $C6F7
00C6F7 1 E6 33 inc RoundStateIndex ; $C6F7: E6 33
00C6F9 1
00C6F9 1 A5 66 lda InningOrSharedScore ; $C6F9: A5 66
00C6FB 1 D0 0B bne InitializeResultsPosition
00C6FD 1 ; $C6FB: D0 0B
00C6FD 1
00C6FD 1 ; ----------------------------------------------------------------------------
00C6FD 1 ; Draw one encoded character.
00C6FD 1 ; ----------------------------------------------------------------------------
00C6FD 1
00C6FD 1 A9 20 lda #$20 ; $C6FD: A9 20
00C6FF 1 A2 B3 ldx #$B3 ; $C6FF: A2 B3
00C701 1 A0 01 ldy #$01 ; $C701: A0 01
00C703 1
00C703 1 20 17 EA jsr CopyInlineDisplayRecord ; $C703: 20 17 EA
00C706 1
00C706 1 01 32 .byte $01,$32 ; $C706-$C707
00C708 1
00C708 1 ; ----------------------------------------------------------------------------
00C708 1 ; Initialize signed position/state values.
00C708 1 ; ----------------------------------------------------------------------------
00C708 1
00C708 1 InitializeResultsPosition: ; $C708
00C708 1 A9 80 lda #$80 ; $C708: A9 80
00C70A 1 8D 3B 05 sta $053B ; $C70A: 8D 3B 05
00C70D 1 85 B7 sta PositionSignState ; $C70D: 85 B7
00C70F 1
00C70F 1 ; ----------------------------------------------------------------------------
00C70F 1 ; Draw a ten-character encoded message.
00C70F 1 ; ----------------------------------------------------------------------------
00C70F 1
00C70F 1 A9 20 lda #$20 ; $C70F: A9 20
00C711 1 A2 EB ldx #$EB ; $C711: A2 EB
00C713 1 A0 0A ldy #$0A ; $C713: A0 0A
00C715 1 18 clc ; $C715: 18
00C716 1
00C716 1 20 17 EA jsr CopyInlineDisplayRecord ; $C716: 20 17 EA
00C719 1
00C719 1 0A .byte $0A ; $C719
00C71A 1 25 10 0A 16 .byte $25,$10,$0A,$16,$0E ; $C71A-$C71E
00C71E 1 0E
00C71F 1 25 1C 0E 1D .byte $25,$1C,$0E,$1D,$25 ; $C71F-$C723
00C723 1 25
00C724 1
00C724 1 ; ----------------------------------------------------------------------------
00C724 1 ; Set timing, process event slot two, and invoke an inline command.
00C724 1 ; ----------------------------------------------------------------------------
00C724 1
00C724 1 A9 04 lda #$04 ; $C724: A9 04
00C726 1 85 FD sta $FD ; $C726: 85 FD
00C728 1
00C728 1 A0 02 ldy #$02 ; $C728: A0 02
00C72A 1 20 66 EB jsr DispatchNextQueuedEvent ; $C72A: 20 66 EB
00C72D 1
00C72D 1 20 0A EB jsr QueueInlineObjectEvent ; $C72D: 20 0A EB
00C730 1
00C730 1 02 88 C4 .byte $02,$88,$C4 ; $C730-$C732
00C733 1
00C733 1 ; ----------------------------------------------------------------------------
00C733 1 ; Wait for ten iterations of a $3C-tick delay.
00C733 1 ; ----------------------------------------------------------------------------
00C733 1
00C733 1 A9 0A lda #$0A ; $C733: A9 0A
00C735 1 85 49 sta $49 ; $C735: 85 49
00C737 1
00C737 1 ResultsDelayLoop: ; $C737
00C737 1 A9 3C lda #$3C ; $C737: A9 3C
00C739 1 20 41 EB jsr StoreObjectEventBankValue ; $C739: 20 41 EB
00C73C 1
00C73C 1 C6 49 dec $49 ; $C73C: C6 49
00C73E 1 D0 F7 bne ResultsDelayLoop ; $C73E: D0 F7
00C740 1
00C740 1 ; ----------------------------------------------------------------------------
00C740 1 ; Disable APU channels and clear state.
00C740 1 ; ----------------------------------------------------------------------------
00C740 1
00C740 1 A9 00 lda #$00 ; $C740: A9 00
00C742 1 8D 00 01 sta $0100 ; $C742: 8D 00 01
00C745 1 8D 15 40 sta APUSTATUS ; $C745: 8D 15 40
00C748 1 85 1E sta SessionActive ; $C748: 85 1E
00C74A 1
00C74A 1 ; ----------------------------------------------------------------------------
00C74A 1 ; Shared entry point used by RESET and other transition paths.
00C74A 1 ; ----------------------------------------------------------------------------
00C74A 1
00C74A 1 InitializeTitleScreen: ; $C74A
00C74A 1 20 9D EB jsr InitializeQueuedEventSystem ; $C74A: 20 9D EB
00C74D 1
00C74D 1 A9 00 lda #$00 ; $C74D: A9 00
00C74F 1 85 EF sta GameplaySuspended ; $C74F: 85 EF
00C751 1
00C751 1 E6 1D inc TransitionActive ; $C751: E6 1D
00C753 1
00C753 1 ; ----------------------------------------------------------------------------
00C753 1 ; Configure PPU shadow state.
00C753 1 ; ----------------------------------------------------------------------------
00C753 1
00C753 1 A9 80 lda #$80 ; $C753: A9 80
00C755 1 85 DD sta PpuCtrlShadow ; $C755: 85 DD
00C757 1
00C757 1 20 6C E9 jsr DisablePpuRendering ; $C757: 20 6C E9
00C75A 1
00C75A 1 A9 25 lda #$25 ; $C75A: A9 25
00C75C 1 20 85 E9 jsr FillPpuMemoryAfterValueSaved ; $C75C: 20 85 E9
00C75F 1
00C75F 1 ; ----------------------------------------------------------------------------
00C75F 1 ; $EA63 consumes the two bytes immediately following each JSR.
00C75F 1 ; ----------------------------------------------------------------------------
00C75F 1
00C75F 1 20 63 EA jsr ProcessInlinePpuStream ; $C75F: 20 63 EA
00C762 1
00C762 1 8D F8 .byte $8D,$F8 ; $C762-$C763
00C764 1
00C764 1 20 63 EA jsr ProcessInlinePpuStream ; $C764: 20 63 EA
00C767 1
00C767 1 00 C0 .byte $00,$C0 ; $C767-$C768
00C769 1
00C769 1 20 78 E9 jsr EnableNmiAndWaitForFrame ; $C769: 20 78 E9
00C76C 1
00C76C 1 ; ----------------------------------------------------------------------------
00C76C 1 ; Enable the standard APU channels and initialize timing.
00C76C 1 ; ----------------------------------------------------------------------------
00C76C 1
00C76C 1 A9 0F lda #$0F ; $C76C: A9 0F
00C76E 1 8D 00 01 sta $0100 ; $C76E: 8D 00 01
00C771 1 8D 15 40 sta APUSTATUS ; $C771: 8D 15 40
00C774 1
00C774 1 A9 08 lda #$08 ; $C774: A9 08
00C776 1 85 FD sta $FD ; $C776: 85 FD
00C778 1
00C778 1 ; ----------------------------------------------------------------------------
00C778 1 ; Refresh state and wait through three input-release cycles.
00C778 1 ;
00C778 1 ; The branch at $C78A targets $C77A, not $C783.
00C778 1 ; ----------------------------------------------------------------------------
00C778 1
00C778 1 C6 40 dec ModeFlags ; $C778: C6 40
00C77A 1
00C77A 1 RefreshTitleScreen: ; $C77A
00C77A 1 E6 40 inc ModeFlags ; $C77A: E6 40
00C77C 1
00C77C 1 20 CF E5 jsr QueueModeIndicatorTiles ; $C77C: 20 CF E5
00C77F 1
00C77F 1 A9 03 lda #$03 ; $C77F: A9 03
00C781 1 85 1B sta $1B ; $C781: 85 1B
00C783 1
00C783 1 WaitForTitleInputRelease: ; $C783
00C783 1 20 48 EB jsr SelectObjectEventBank1 ; $C783: 20 48 EB
00C786 1
00C786 1 A5 15 lda ControllerPressed1 ; $C786: A5 15
00C788 1 29 20 and #$20 ; $C788: 29 20
00C78A 1 D0 EE bne RefreshTitleScreen ; $C78A: D0 EE
00C78C 1
00C78C 1 A5 E3 lda FrameCounter ; $C78C: A5 E3
00C78E 1 D0 F3 bne WaitForTitleInputRelease ; $C78E: D0 F3
00C790 1
00C790 1 C6 1B dec $1B ; $C790: C6 1B
00C792 1 D0 EF bne WaitForTitleInputRelease ; $C792: D0 EF
00C794 1
00C794 1 ; ----------------------------------------------------------------------------
00C794 1 ; Restore transition state and return to the initialization loop.
00C794 1 ;
00C794 1 ; A is zero when execution reaches STA $1D because the successful DEC $1B
00C794 1 ; produced zero.
00C794 1 ; ----------------------------------------------------------------------------
00C794 1
00C794 1 85 1D sta TransitionActive ; $C794: 85 1D
00C796 1
00C796 1 A9 01 lda #$01 ; $C796: A9 01
00C798 1 85 EF sta GameplaySuspended ; $C798: 85 EF
00C79A 1
00C79A 1 A9 00 lda #$00 ; $C79A: A9 00
00C79C 1 8D 96 05 sta $0596 ; $C79C: 8D 96 05
00C79F 1 8D 00 01 sta $0100 ; $C79F: 8D 00 01
00C7A2 1 8D 15 40 sta APUSTATUS ; $C7A2: 8D 15 40
00C7A5 1
00C7A5 1 20 9D EB jsr InitializeQueuedEventSystem ; $C7A5: 20 9D EB
00C7A8 1
00C7A8 1 20 0A EB jsr QueueInlineObjectEvent ; $C7A8: 20 0A EB
00C7AB 1
00C7AB 1 03 88 C4 .byte $03,$88,$C4 ; $C7AB-$C7AD
00C7AE 1
00C7AE 1 4C AA C4 jmp InitializeSessionDisplay ; $C7AE: 4C AA C4
00C7B1 1
00C7B1 1 ; ============================================================================
00C7B1 1 ; $C7B1-$C7C8
00C7B1 1 ; Initialize object sorting/index tables.
00C7B1 1 ;
00C7B1 1 ; Called by RESET at $C422.
00C7B1 1 ; ============================================================================
00C7B1 1
00C7B1 1 ; ----------------------------------------------------------------------------
00C7B1 1 ; Contract:
00C7B1 1 ; Description: Initializes Sprite Sort Tables.
00C7B1 1 ; Entry: Registers: A, X
00C7B1 1 ; Returns/products: Registers/clobbers: A, X
00C7B1 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00C7B1 1 ; Memory effects: $0377, $038c, $0399
00C7B1 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00C7B1 1 ; comparison, load, or store path and are not a stable API product.
00C7B1 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00C7B1 1 ; ----------------------------------------------------------------------------
00C7B1 1 InitializeSpriteSortTables: ; $C7B1
00C7B1 1 A2 14 ldx #$14 ; $C7B1: A2 14
00C7B3 1
00C7B3 1 InitializeSpriteSortIndexLoop: ; $C7B3
00C7B3 1 8A txa ; $C7B3: 8A
00C7B4 1 0A asl ; $C7B4: 0A
00C7B5 1 ; A = X * 2
00C7B5 1
00C7B5 1 9D 77 03 sta $0377,x ; $C7B5: 9D 77 03
00C7B8 1
00C7B8 1 E0 0D cpx #$0D ; $C7B8: E0 0D
00C7BA 1 B0 03 bcs InitializeNextSpriteSortIndex ; $C7BA: B0 03
00C7BC 1
00C7BC 1 9D 8C 03 sta $038C,x ; $C7BC: 9D 8C 03
00C7BF 1
00C7BF 1 InitializeNextSpriteSortIndex: ; $C7BF
00C7BF 1 CA dex ; $C7BF: CA
00C7C0 1 D0 F1 bne InitializeSpriteSortIndexLoop
00C7C2 1 ; $C7C0: D0 F1
00C7C2 1
00C7C2 1 ; ----------------------------------------------------------------------------
00C7C2 1 ; X is zero when the loop terminates.
00C7C2 1 ; Clear two additional entries.
00C7C2 1 ; ----------------------------------------------------------------------------
00C7C2 1
00C7C2 1 8E 8C 03 stx $038C ; $C7C2: 8E 8C 03
00C7C5 1 8E 99 03 stx $0399 ; $C7C5: 8E 99 03
00C7C8 1
00C7C8 1 60 rts ; $C7C8: 60
00C7C9 1
00C7C9 1 ; ============================================================================
00C7C9 1 ; $C7C9-$C7DC
00C7C9 1 ; Draw eight blank encoded characters.
00C7C9 1 ;
00C7C9 1 ; Called earlier from the state-initialization sequence at $C5BA.
00C7C9 1 ; ============================================================================
00C7C9 1
00C7C9 1 ; ----------------------------------------------------------------------------
00C7C9 1 ; Contract:
00C7C9 1 ; Description: Clears or resets Eight Character Field.
00C7C9 1 ; Entry: No register input inferred
00C7C9 1 ; Returns/products: Registers/clobbers: A, X, Y; Flags: condition flags may carry result state
00C7C9 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00C7C9 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00C7C9 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00C7C9 1 ; comparison, load, or store path and are not a stable API product.
00C7C9 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00C7C9 1 ; ----------------------------------------------------------------------------
00C7C9 1 ClearEightCharacterField: ; $C7C9
00C7C9 1 18 clc ; $C7C9: 18
00C7CA 1
00C7CA 1 A9 20 lda #$20 ; $C7CA: A9 20
00C7CC 1 A2 EC ldx #$EC ; $C7CC: A2 EC
00C7CE 1 A0 08 ldy #$08 ; $C7CE: A0 08
00C7D0 1
00C7D0 1 20 17 EA jsr CopyInlineDisplayRecord ; $C7D0: 20 17 EA
00C7D3 1
00C7D3 1 ; Inline text consumed by $EA17:
00C7D3 1 ; count $08 followed by eight blank characters ($25).
00C7D3 1 08 .byte $08 ; $C7D3
00C7D4 1 25 25 25 25 .byte $25,$25,$25,$25 ; $C7D4-$C7D7
00C7D8 1 25 25 25 25 .byte $25,$25,$25,$25 ; $C7D8-$C7DB
00C7DC 1
00C7DC 1 60 rts ; $C7DC: 60
00C7DD 1
00C7DD 1 ; ============================================================================
00C7DD 1 ; $C7DD-$C819
00C7DD 1 ; Write a seven-byte PPU data sequence and update two OAM entries.
00C7DD 1 ; ============================================================================
00C7DD 1
00C7DD 1 ; ----------------------------------------------------------------------------
00C7DD 1 ; Contract:
00C7DD 1 ; Description: Queues Player Selection Display.
00C7DD 1 ; Entry: Registers: A, X, Y; Memory: $33, $34, $3e, $c02a, $c030, $e1, $13, $4b
00C7DD 1 ; Returns/products: Registers/clobbers: A, X, Y
00C7DD 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00C7DD 1 ; Memory effects: $02fd, $02ff, $32
00C7DD 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00C7DD 1 ; comparison, load, or store path and are not a stable API product.
00C7DD 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 2.
00C7DD 1 ; ----------------------------------------------------------------------------
00C7DD 1 QueuePlayerSelectionDisplay: ; $C7DD
00C7DD 1 18 clc ; $C7DD: 18
00C7DE 1
00C7DE 1 A9 3F lda #$3F ; $C7DE: A9 3F
00C7E0 1 A2 11 ldx #$11 ; $C7E0: A2 11
00C7E2 1 A0 07 ldy #$07 ; $C7E2: A0 07
00C7E4 1
00C7E4 1 20 17 EA jsr CopyInlineDisplayRecord ; $C7E4: 20 17 EA
00C7E7 1
00C7E7 1 ; ----------------------------------------------------------------------------
00C7E7 1 ; Inline data consumed by $EA17.
00C7E7 1 ;
00C7E7 1 ; The first byte is the length, followed by seven data bytes.
00C7E7 1 ; ----------------------------------------------------------------------------
00C7E7 1
00C7E7 1 07 .byte $07 ; $C7E7: length
00C7E8 1 00 27 00 30 .byte $00,$27,$00,$30 ; $C7E8-$C7EB
00C7EC 1 00 27 00 .byte $00,$27,$00 ; $C7EC-$C7EE
00C7EF 1
00C7EF 1 ; ----------------------------------------------------------------------------
00C7EF 1 ; Select one of the values at $34/$35 based on the low bit of $33.
00C7EF 1 ; Use that value as an index into the tables at $C02A and $C030.
00C7EF 1 ;
00C7EF 1 ; The resulting values are written into one pair of OAM entries.
00C7EF 1 ; ----------------------------------------------------------------------------
00C7EF 1
00C7EF 1 A5 33 lda RoundStateIndex ; $C7EF: A5 33
00C7F1 1 29 01 and #$01 ; $C7F1: 29 01
00C7F3 1
00C7F3 1 48 pha ; $C7F3: 48
00C7F4 1 ; Save the selected side.
00C7F4 1
00C7F4 1 AA tax ; $C7F4: AA
00C7F5 1 B4 34 ldy PlayerOneSelection,x ; $C7F5: B4 34
00C7F7 1
00C7F7 1 A6 3E ldx PpuQueueOffset ; $C7F7: A6 3E
00C7F9 1
00C7F9 1 B9 2A C0 lda $C02A,y ; $C7F9: B9 2A C0
00C7FC 1 9D FD 02 sta $02FD,x ; $C7FC: 9D FD 02
00C7FF 1
00C7FF 1 B9 30 C0 lda $C030,y ; $C7FF: B9 30 C0
00C802 1 9D FF 02 sta $02FF,x ; $C802: 9D FF 02
00C805 1
00C805 1 ; ----------------------------------------------------------------------------
00C805 1 ; Select the opposite $34/$35 entry and write the corresponding table values
00C805 1 ; into the other OAM pair.
00C805 1 ; ----------------------------------------------------------------------------
00C805 1
00C805 1 68 pla
00C806 1 49 01 eor #$01
00C808 1 AA tax
00C809 1
00C809 1 B4 34 ldy $34,x
00C80B 1 A6 3E ldx $3E
00C80D 1
00C80D 1 B9 2A C0 lda $C02A,y
00C810 1 9D F9 02 sta $02F9,x
00C813 1
00C813 1 B9 30 C0 lda $C030,y
00C816 1 9D FB 02 sta $02FB,x
00C819 1
00C819 1 60 rts
00C81A 1
00C81A 1 ; ============================================================================
00C81A 1 ; $C81A-$C84F
00C81A 1 ; Update paired selection indices from controller/state input.
00C81A 1 ;
00C81A 1 ; The routine works with two entries in the table at $32/$33. It selects an
00C81A 1 ; entry using $E1, modifies the selected value according to bits shifted from
00C81A 1 ; A, then verifies that the two entries are not equal.
00C81A 1 ; ============================================================================
00C81A 1
00C81A 1 UpdatePlayerSelections: ; $C81A
00C81A 1 20 48 EB jsr SelectObjectEventBank1 ; $C81A: 20 48 EB
00C81D 1
00C81D 1 SelectPlayerSelectionEntry: ; $C81D
00C81D 1 A5 E1 lda CurrentObjectIndex ; $C81D: A5 E1
00C81F 1 AA tax ; $C81F: AA
00C820 1
00C820 1 B4 13 ldy InputState1,x ; $C820: B4 13
00C822 1
00C822 1 45 4B eor ActivePlayerSide ; $C822: 45 4B
00C824 1 AA tax ; $C824: AA
00C825 1
00C825 1 98 tya ; $C825: 98
00C826 1 B4 32 ldy SelectionValue0,x ; $C826: B4 32
00C828 1
00C828 1 ; ----------------------------------------------------------------------------
00C828 1 ; Bit 0 selects whether to increment the current value.
00C828 1 ;
00C828 1 ; The value wraps from six back to zero.
00C828 1 ; ----------------------------------------------------------------------------
00C828 1
00C828 1 4A lsr ; $C828: 4A
00C829 1 90 07 bcc ApplySelectionDecrement
00C82B 1 ; $C829: 90 07
00C82B 1
00C82B 1 C8 iny ; $C82B: C8
00C82C 1
00C82C 1 C0 06 cpy #$06 ; $C82C: C0 06
00C82E 1 90 02 bcc ApplySelectionDecrement
00C830 1 ; $C82E: 90 02
00C830 1
00C830 1 A0 00 ldy #$00 ; $C830: A0 00
00C832 1
00C832 1 ; ----------------------------------------------------------------------------
00C832 1 ; Bit 1 selects whether to decrement the current value.
00C832 1 ;
00C832 1 ; The value wraps from zero to five.
00C832 1 ; ----------------------------------------------------------------------------
00C832 1
00C832 1 ApplySelectionDecrement: ; $C832
00C832 1 4A lsr ; $C832: 4A
00C833 1 90 05 bcc SavePlayerSelection ; $C833: 90 05
00C835 1
00C835 1 88 dey ; $C835: 88
00C836 1 10 02 bpl SavePlayerSelection ; $C836: 10 02
00C838 1
00C838 1 A0 05 ldy #$05 ; $C838: A0 05
00C83A 1
00C83A 1 SavePlayerSelection: ; $C83A
00C83A 1 94 32 sty SelectionValue0,x ; $C83A: 94 32
00C83C 1
00C83C 1 ; ----------------------------------------------------------------------------
00C83C 1 ; Select the opposite table entry and ensure both selections differ.
00C83C 1 ; If they are equal, wait for another update and retry.
00C83C 1 ; ----------------------------------------------------------------------------
00C83C 1
00C83C 1 8A txa ; $C83C: 8A
00C83D 1 49 01 eor #$01 ; $C83D: 49 01
00C83F 1 AA tax ; $C83F: AA
00C840 1
00C840 1 98 tya ; $C840: 98
00C841 1 D5 32 cmp SelectionValue0,x ; $C841: D5 32
00C843 1 F0 D8 beq SelectPlayerSelectionEntry
00C845 1 ; $C843: F0 D8
00C845 1
00C845 1 ; ----------------------------------------------------------------------------
00C845 1 ; Continue waiting while the selected input/state value is nonnegative.
00C845 1 ; Otherwise, decrement $43 and leave through the common engine exit.
00C845 1 ; ----------------------------------------------------------------------------
00C845 1
00C845 1 A6 E1 ldx CurrentObjectIndex ; $C845: A6 E1
00C847 1
00C847 1 B5 13 lda InputState1,x ; $C847: B5 13
00C849 1 10 CF bpl UpdatePlayerSelections ; $C849: 10 CF
00C84B 1
00C84B 1 C6 43 dec $43 ; $C84B: C6 43
00C84D 1
00C84D 1 4C 6A EB jmp CommonEngineExit ; $C84D: 4C 6A EB
00C850 1
00C850 1 ; ============================================================================
00C850 1 ; $C850-$C859
00C850 1 ; Generate a random value in the range $00-$05.
00C850 1 ; ============================================================================
00C850 1
00C850 1 ; ----------------------------------------------------------------------------
00C850 1 ; Contract:
00C850 1 ; Description: Implements Random 0 To 5.
00C850 1 ; Entry: Registers: A
00C850 1 ; Returns/products: Registers/clobbers: A; Flags: condition flags may carry result state
00C850 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00C850 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00C850 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00C850 1 ; comparison, load, or store path and are not a stable API product.
00C850 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 2.
00C850 1 ; ----------------------------------------------------------------------------
00C850 1 Random0To5: ; $C850
00C850 1 20 F5 E5 jsr AdvanceRandomState ; $C850: 20 F5 E5
00C853 1 29 07 and #$07 ; $C853: 29 07
00C855 1 C9 06 cmp #$06 ; $C855: C9 06
00C857 1 B0 F7 bcs Random0To5 ; $C857: B0 F7
00C859 1
00C859 1 60 rts ; $C859: 60
00C85A 1
00C85A 1 ; ============================================================================
00C85A 1 ; $C85A-$C87D
00C85A 1 ; Build four 16-byte PPU command/data blocks in the queue at $0300.
00C85A 1 ;
00C85A 1 ; The destination high byte begins at $21. Four blocks are generated for:
00C85A 1 ;
00C85A 1 ; $21xx
00C85A 1 ; $22xx
00C85A 1 ; $23xx
00C85A 1 ; $24xx
00C85A 1 ;
00C85A 1 ; Each block is filled with sixteen $26 bytes.
00C85A 1 ; ============================================================================
00C85A 1
00C85A 1 ; ----------------------------------------------------------------------------
00C85A 1 ; Contract:
00C85A 1 ; Description: Implements Fill Selection Background Blocks.
00C85A 1 ; Entry: Registers: A, X, Y; Memory: $4a
00C85A 1 ; Returns/products: Registers/clobbers: A, X, Y
00C85A 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00C85A 1 ; Memory effects: $44, $4a, $0300
00C85A 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00C85A 1 ; comparison, load, or store path and are not a stable API product.
00C85A 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00C85A 1 ; ----------------------------------------------------------------------------
00C85A 1 FillSelectionBackgroundBlocks: ; $C85A
00C85A 1 A9 00 lda #$00 ; $C85A: A9 00
00C85C 1 85 44 sta PlayerSelectionActive ; $C85C: 85 44
00C85E 1
00C85E 1 A9 88 lda #$88 ; $C85E: A9 88
00C860 1
00C860 1 FillNextBackgroundBlock: ; $C860
00C860 1 85 4A sta $4A ; $C860: 85 4A
00C862 1 AA tax ; $C862: AA
00C863 1
00C863 1 18 clc ; $C863: 18
00C864 1
00C864 1 A9 21 lda #$21 ; $C864: A9 21
00C866 1 A0 10 ldy #$10 ; $C866: A0 10
00C868 1 20 3E EA jsr AllocateDisplayBufferRecord ; $C868: 20 3E EA
00C86B 1
00C86B 1 ; ----------------------------------------------------------------------------
00C86B 1 ; Fill sixteen queue bytes with $26.
00C86B 1 ;
00C86B 1 ; X is expected to point into the PPU command queue after the setup call above.
00C86B 1 ; ----------------------------------------------------------------------------
00C86B 1
00C86B 1 A0 10 ldy #$10 ; $C86B: A0 10
00C86D 1 A9 26 lda #$26 ; $C86D: A9 26
00C86F 1
00C86F 1 FillBackgroundBlock: ; $C86F
00C86F 1 9D 00 03 sta $0300,x ; $C86F: 9D 00 03
00C872 1
00C872 1 E8 inx ; $C872: E8
00C873 1 88 dey ; $C873: 88
00C874 1 D0 F9 bne FillBackgroundBlock ; $C874: D0 F9
00C876 1
00C876 1 ; ----------------------------------------------------------------------------
00C876 1 ; Advance the saved queue/destination value by $20.
00C876 1 ; Continue until the addition carries.
00C876 1 ; ----------------------------------------------------------------------------
00C876 1
00C876 1 A5 4A lda $4A ; $C876: A5 4A
00C878 1 18 clc ; $C878: 18
00C879 1 69 20 adc #$20 ; $C879: 69 20
00C87B 1 90 E3 bcc FillNextBackgroundBlock ; $C87B: 90 E3
00C87D 1
00C87D 1 60 rts ; $C87D: 60
00C87E 1
00C87E 1 ; ============================================================================
00C87E 1 ; $C87E-$C8A1
00C87E 1 ; Derive paired state values in $0F and $10.
00C87E 1 ;
00C87E 1 ; Both outputs are cleared when $EF is nonzero. Otherwise, the routine combines
00C87E 1 ; bits from $40, $4B, and $33, then stores complementary values in $0F/$10.
00C87E 1 ; Carry from LSR $40 is used to conditionally increment each result.
00C87E 1 ; ============================================================================
00C87E 1
00C87E 1 ; ----------------------------------------------------------------------------
00C87E 1 ; Contract:
00C87E 1 ; Description: Calculates Controller Assignments.
00C87E 1 ; Entry: Registers: A; Memory: $ef, $40, $4b, $33
00C87E 1 ; Returns/products: Registers/clobbers: A
00C87E 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00C87E 1 ; Memory effects: $0f, $10
00C87E 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00C87E 1 ; comparison, load, or store path and are not a stable API product.
00C87E 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00C87E 1 ; ----------------------------------------------------------------------------
00C87E 1 CalculateControllerAssignments: ; $C87E
00C87E 1 A9 00 lda #$00 ; $C87E: A9 00
00C880 1 85 0F sta DerivedControl0 ; $C880: 85 0F
00C882 1 85 10 sta $10 ; $C882: 85 10
00C884 1
00C884 1 A5 EF lda GameplaySuspended ; $C884: A5 EF
00C886 1 D0 19 bne ControllerAssignmentReturn ; $C886: D0 19
00C888 1
00C888 1 A5 40 lda ModeFlags ; $C888: A5 40
00C88A 1 4A lsr ; $C88A: 4A
00C88B 1 ; Carry receives bit 0 of $40.
00C88B 1
00C88B 1 A5 40 lda ModeFlags ; $C88B: A5 40
00C88D 1 45 4B eor ActivePlayerSide ; $C88D: 45 4B
00C88F 1 45 33 eor RoundStateIndex ; $C88F: 45 33
00C891 1 29 01 and #$01 ; $C891: 29 01
00C893 1 85 10 sta $10 ; $C893: 85 10
00C895 1
00C895 1 90 02 bcc CalculateOppositeControllerAssignment ; $C895: 90 02
00C897 1
00C897 1 E6 10 inc $10 ; $C897: E6 10
00C899 1
00C899 1 CalculateOppositeControllerAssignment: ; $C899
00C899 1 49 01 eor #$01 ; $C899: 49 01
00C89B 1 85 0F sta DerivedControl0 ; $C89B: 85 0F
00C89D 1
00C89D 1 90 02 bcc ControllerAssignmentReturn ; $C89D: 90 02
00C89F 1
00C89F 1 E6 0F inc DerivedControl0 ; $C89F: E6 0F
00C8A1 1
00C8A1 1 ControllerAssignmentReturn: ; $C8A1
00C8A1 1 60 rts ; $C8A1: 60
00C8A2 1
00C8A2 1 ; ============================================================================
00C8A2 1 ; $C8A2-$C8BA
00C8A2 1 ; Initialize the four-byte table at $0598-$059B.
00C8A2 1 ;
00C8A2 1 ; For each Y value from 3 down to 1:
00C8A2 1 ; 1. Compute A = Y * 2.
00C8A2 1 ; 2. Search $9F-$A1 for a matching value.
00C8A2 1 ; 3. Store the matching X index into $0598,Y.
00C8A2 1 ; 4. Store $FF when no match is found.
00C8A2 1 ;
00C8A2 1 ; Finally, clear $0598 because Y is zero when the loop terminates.
00C8A2 1 ; ============================================================================
00C8A2 1
00C8A2 1 ; ----------------------------------------------------------------------------
00C8A2 1 ; Contract:
00C8A2 1 ; Description: Initializes Object State Lookup.
00C8A2 1 ; Entry: Registers: A, X, Y; Memory: $9f
00C8A2 1 ; Returns/products: Registers/clobbers: A, X, Y
00C8A2 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00C8A2 1 ; Memory effects: $0598
00C8A2 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00C8A2 1 ; comparison, load, or store path and are not a stable API product.
00C8A2 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00C8A2 1 ; ----------------------------------------------------------------------------
00C8A2 1 InitializeObjectStateLookup: ; $C8A2
00C8A2 1 A0 03 ldy #$03 ; $C8A2: A0 03
00C8A4 1
00C8A4 1 Routine_C8A4_NextEntry: ; $C8A4
00C8A4 1 98 tya ; $C8A4: 98
00C8A5 1 0A asl ; $C8A5: 0A
00C8A6 1 ; A = Y * 2
00C8A6 1
00C8A6 1 A2 02 ldx #$02 ; $C8A6: A2 02
00C8A8 1
00C8A8 1 Routine_C8A8_SearchValues: ; $C8A8
00C8A8 1 D5 9F cmp SecondaryActorState0,x ; $C8A8: D5 9F
00C8AA 1 F0 05 beq Routine_C8B1_SaveResult ; $C8AA: F0 05
00C8AC 1
00C8AC 1 CA dex ; $C8AC: CA
00C8AD 1 10 F9 bpl Routine_C8A8_SearchValues
00C8AF 1 ; $C8AD: 10 F9
00C8AF 1
00C8AF 1 A9 FF lda #$FF ; $C8AF: A9 FF
00C8B1 1 ; No matching entry was found.
00C8B1 1
00C8B1 1 Routine_C8B1_SaveResult: ; $C8B1
00C8B1 1 99 98 05 sta $0598,y ; $C8B1: 99 98 05
00C8B4 1
00C8B4 1 88 dey ; $C8B4: 88
00C8B5 1 D0 ED bne Routine_C8A4_NextEntry ; $C8B5: D0 ED
00C8B7 1
00C8B7 1 ; ----------------------------------------------------------------------------
00C8B7 1 ; Y is zero when the loop exits.
00C8B7 1 ; Clear the first table entry at $0598.
00C8B7 1 ; ----------------------------------------------------------------------------
00C8B7 1
00C8B7 1 8C 98 05 sty $0598 ; $C8B7: 8C 98 05
00C8BA 1
00C8BA 1 60 rts ; $C8BA: 60
00C8BB 1
00C8BB 1 ; ============================================================================
00C8BB 1 ; $C8BB-$C8E7
00C8BB 1 ; Expand a linked or variable-length record list into the buffer at $0400,X.
00C8BB 1 ;
00C8BB 1 ; Entry:
00C8BB 1 ; X appears to be the destination offset into $0400.
00C8BB 1 ; $00/$01 points to an inline or external pointer record.
00C8BB 1 ;
00C8BB 1 ; Operation:
00C8BB 1 ; 1. $E99A retrieves a pointer and returns its low byte in A.
00C8BB 1 ; 2. The high byte is read through ($00),Y.
00C8BB 1 ; 3. Each source record begins with a nonzero size/offset byte.
00C8BB 1 ; 4. The current source pointer is written to $0400,X as a low/high pair.
00C8BB 1 ; 5. The source pointer advances by (record byte * 4) + carry adjustment.
00C8BB 1 ; 6. A zero record byte terminates the list.
00C8BB 1 ;
00C8BB 1 ; Exit:
00C8BB 1 ; Y = $04
00C8BB 1 ; ============================================================================
00C8BB 1
00C8BB 1 ; ----------------------------------------------------------------------------
00C8BB 1 ; Contract:
00C8BB 1 ; Description: Implements Expand Record Pointer List.
00C8BB 1 ; Entry: Registers: A, X; Memory: (indirectptrlo), (recordptrlo), recordptrlo, recordptrhi
00C8BB 1 ; Returns/products: Registers/clobbers: A, X, Y
00C8BB 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00C8BB 1 ; Memory effects: recordptrlo, recordptrhi, $0400
00C8BB 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00C8BB 1 ; comparison, load, or store path and are not a stable API product.
00C8BB 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 5.
00C8BB 1 ; ----------------------------------------------------------------------------
00C8BB 1 ExpandRecordPointerList: ; $C8BB
00C8BB 1 20 9A E9 jsr DecodeInlineParameters ; $C8BB: 20 9A E9
00C8BE 1
00C8BE 1 85 02 sta RecordPtrLo ; $C8BE: 85 02
00C8C0 1 ; Save source pointer low byte.
00C8C0 1
00C8C0 1 B1 00 lda (IndirectPtrLo),y ; $C8C0: B1 00
00C8C2 1 85 03 sta RecordPtrHi ; $C8C2: 85 03
00C8C4 1 ; Save source pointer high byte.
00C8C4 1
00C8C4 1 A0 00 ldy #$00 ; $C8C4: A0 00
00C8C6 1
00C8C6 1 ; ----------------------------------------------------------------------------
00C8C6 1 ; Read the next record byte through pointer $02/$03.
00C8C6 1 ; A zero byte terminates the list.
00C8C6 1 ; ----------------------------------------------------------------------------
00C8C6 1
00C8C6 1 Routine_C8C6_ReadRecord: ; $C8C6
00C8C6 1 B1 02 lda (RecordPtrLo),y ; $C8C6: B1 02
00C8C8 1 F0 1B beq Routine_C8E5_Done ; $C8C8: F0 1B
00C8CA 1
00C8CA 1 ; ----------------------------------------------------------------------------
00C8CA 1 ; Store the current source pointer into the destination table.
00C8CA 1 ; Each destination entry is a two-byte pointer.
00C8CA 1 ; ----------------------------------------------------------------------------
00C8CA 1
00C8CA 1 A5 02 lda RecordPtrLo ; $C8CA: A5 02
00C8CC 1 9D 00 04 sta $0400,x ; $C8CC: 9D 00 04
00C8CF 1 E8 inx ; $C8CF: E8
00C8D0 1
00C8D0 1 A5 03 lda RecordPtrHi ; $C8D0: A5 03
00C8D2 1 9D 00 04 sta $0400,x ; $C8D2: 9D 00 04
00C8D5 1 E8 inx ; $C8D5: E8
00C8D6 1
00C8D6 1 ; ----------------------------------------------------------------------------
00C8D6 1 ; Advance the source pointer.
00C8D6 1 ;
00C8D6 1 ; Reload the record byte, multiply it by four, then add it to the pointer low
00C8D6 1 ; byte. SEC means the effective increment is:
00C8D6 1 ;
00C8D6 1 ; (record byte * 4) + 1
00C8D6 1 ;
00C8D6 1 ; If the low-byte addition carries, increment the pointer high byte.
00C8D6 1 ; ----------------------------------------------------------------------------
00C8D6 1
00C8D6 1 B1 02 lda (RecordPtrLo),y ; $C8D6: B1 02
00C8D8 1 0A asl ; $C8D8: 0A
00C8D9 1 0A asl ; $C8D9: 0A
00C8DA 1
00C8DA 1 38 sec ; $C8DA: 38
00C8DB 1 65 02 adc RecordPtrLo ; $C8DB: 65 02
00C8DD 1 85 02 sta RecordPtrLo ; $C8DD: 85 02
00C8DF 1
00C8DF 1 90 E5 bcc Routine_C8C6_ReadRecord ; $C8DF: 90 E5
00C8E1 1
00C8E1 1 E6 03 inc RecordPtrHi ; $C8E1: E6 03
00C8E3 1 B0 E1 bcs Routine_C8C6_ReadRecord ; $C8E3: B0 E1
00C8E5 1 ; Always taken because INC does not alter carry.
00C8E5 1
00C8E5 1 ; ----------------------------------------------------------------------------
00C8E5 1 ; Return with Y = 4.
00C8E5 1 ; ----------------------------------------------------------------------------
00C8E5 1
00C8E5 1 Routine_C8E5_Done: ; $C8E5
00C8E5 1 A0 04 ldy #$04 ; $C8E5: A0 04
00C8E7 1 60 rts ; $C8E7: 60
00C8E8 1
00C8E8 1 ; ============================================================================
00C8E8 1 ; $C8E8-$C903
00C8E8 1 ; Initialize paired counters and random bitfields.
00C8E8 1 ;
00C8E8 1 ; For X = 1 and X = 0:
00C8E8 1 ; $51,X is initialized to eight.
00C8E8 1 ; Eight random carry bits are shifted into $4F,X.
00C8E8 1 ; One additional random carry bit is shifted into $4D,X.
00C8E8 1 ; ============================================================================
00C8E8 1
00C8E8 1 ; ----------------------------------------------------------------------------
00C8E8 1 ; Contract:
00C8E8 1 ; Description: Initializes Random Bitfields.
00C8E8 1 ; Entry: Registers: A, X, Y
00C8E8 1 ; Returns/products: Registers/clobbers: A, X, Y
00C8E8 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00C8E8 1 ; Memory effects: counter51
00C8E8 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00C8E8 1 ; comparison, load, or store path and are not a stable API product.
00C8E8 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00C8E8 1 ; ----------------------------------------------------------------------------
00C8E8 1 InitializeRandomBitfields: ; $C8E8
00C8E8 1 A2 01 ldx #$01 ; $C8E8: A2 01
00C8EA 1
00C8EA 1 Routine_C8EA_NextEntry: ; $C8EA
00C8EA 1 A0 08 ldy #$08 ; $C8EA: A0 08
00C8EC 1
00C8EC 1 98 tya ; $C8EC: 98
00C8ED 1 95 51 sta Counter51,x ; $C8ED: 95 51
00C8EF 1
00C8EF 1 Routine_C8EF_BuildRandomBits: ; $C8EF
00C8EF 1 20 F5 E5 jsr AdvanceRandomState ; $C8EF: 20 F5 E5
00C8F2 1 C9 80 cmp #$80 ; $C8F2: C9 80
00C8F4 1 ; Carry reflects whether random value >= $80.
00C8F4 1
00C8F4 1 76 4F ror RandomBits0,x ; $C8F4: 76 4F
00C8F6 1 ; Shift the random carry bit into $4F,X.
00C8F6 1
00C8F6 1 88 dey ; $C8F6: 88
00C8F7 1 D0 F6 bne Routine_C8EF_BuildRandomBits
00C8F9 1 ; $C8F7: D0 F6
00C8F9 1
00C8F9 1 20 F5 E5 jsr AdvanceRandomState ; $C8F9: 20 F5 E5
00C8FC 1 C9 80 cmp #$80 ; $C8FC: C9 80
00C8FE 1
00C8FE 1 76 4D ror RandomState0,x ; $C8FE: 76 4D
00C900 1 ; Shift one random carry bit into $4D,X.
00C900 1
00C900 1 CA dex ; $C900: CA
00C901 1 10 E7 bpl Routine_C8EA_NextEntry ; $C901: 10 E7
00C903 1
00C903 1 60 rts ; $C903: 60
00C904 1
00C904 1 ; ============================================================================
00C904 1 ; $C904-$C91A
00C904 1 ; Dispatch one of two inline records according to the sign of $4D,X.
00C904 1 ;
00C904 1 ; X is selected from the low bit of $33.
00C904 1 ; ============================================================================
00C904 1
00C904 1 ; ----------------------------------------------------------------------------
00C904 1 ; Contract:
00C904 1 ; Description: Queues Random State Record.
00C904 1 ; Entry: Registers: A; Memory: roundstateindex, randomstate0
00C904 1 ; Returns/products: Registers/clobbers: A, X
00C904 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00C904 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00C904 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00C904 1 ; comparison, load, or store path and are not a stable API product.
00C904 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00C904 1 ; ----------------------------------------------------------------------------
00C904 1 QueueRandomStateRecord: ; $C904
00C904 1 A5 33 lda RoundStateIndex ; $C904: A5 33
00C906 1 29 01 and #$01 ; $C906: 29 01
00C908 1 AA tax ; $C908: AA
00C909 1
00C909 1 B5 4D lda RandomState0,x ; $C909: B5 4D
00C90B 1 30 07 bmi QueueAlternateRandomStateRecord ; $C90B: 30 07
00C90D 1
00C90D 1 20 BB C8 jsr ExpandRecordPointerList ; $C90D: 20 BB C8
00C910 1 ; Inline pointer/record consumed by $C8BB.
00C910 1 0C B4 ED .byte $0C,$B4,$ED ; $C910-$C912
00C913 1
00C913 1 60 rts ; $C913: 60
00C914 1
00C914 1 QueueAlternateRandomStateRecord: ; $C914
00C914 1 20 BB C8 jsr ExpandRecordPointerList ; $C914: 20 BB C8
00C917 1
00C917 1 ; Alternate inline pointer/record consumed by $C8BB.
00C917 1 0C 51 EC .byte $0C,$51,$EC ; $C917-$C919
00C91A 1
00C91A 1 60 rts ; $C91A: 60
00C91B 1
00C91B 1 ; ============================================================================
00C91B 1 ; $C91B-$C942
00C91B 1 ; Select and dispatch a record from the paired random state.
00C91B 1 ;
00C91B 1 ; The low bit of $33 selects X. $51,X determines how many times $4F,X is
00C91B 1 ; shifted right. If the selected carry is clear, the first record is used.
00C91B 1 ; If the carry is set, $4C is decremented and the second record is used.
00C91B 1 ; ============================================================================
00C91B 1
00C91B 1 ; ----------------------------------------------------------------------------
00C91B 1 ; Contract:
00C91B 1 ; Description: Queues Random Direction Record.
00C91B 1 ; Entry: Registers: A, Y; Memory: roundstateindex, counter51, randombits0, randomstate0
00C91B 1 ; Returns/products: Registers/clobbers: A, X, Y
00C91B 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00C91B 1 ; Memory effects: horizontaldirectionmask
00C91B 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00C91B 1 ; comparison, load, or store path and are not a stable API product.
00C91B 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00C91B 1 ; ----------------------------------------------------------------------------
00C91B 1 QueueRandomDirectionRecord: ; $C91B
00C91B 1 A5 33 lda RoundStateIndex ; $C91B: A5 33
00C91D 1 29 01 and #$01 ; $C91D: 29 01
00C91F 1 AA tax ; $C91F: AA
00C920 1
00C920 1 B4 51 ldy Counter51,x ; $C920: B4 51
00C922 1 F0 08 beq UseRandomDirectionSignBit ; $C922: F0 08
00C924 1
00C924 1 B5 4F lda RandomBits0,x ; $C924: B5 4F
00C926 1
00C926 1 SelectRandomDirectionBit: ; $C926
00C926 1 4A lsr ; $C926: 4A
00C927 1
00C927 1 88 dey ; $C927: 88
00C928 1 D0 FC bne SelectRandomDirectionBit
00C92A 1 ; $C928: D0 FC
00C92A 1
00C92A 1 F0 03 beq SaveDirectionSelection ; $C92A: F0 03
00C92C 1 ; Always taken because Y is zero.
00C92C 1 ; Carry from the final LSR is preserved.
00C92C 1
00C92C 1 UseRandomDirectionSignBit: ; $C92C
00C92C 1 B5 4D lda RandomState0,x ; $C92C: B5 4D
00C92E 1 0A asl ; $C92E: 0A
00C92F 1 ; Move bit 7 into carry.
00C92F 1
00C92F 1 SaveDirectionSelection: ; $C92F
00C92F 1 84 4C sty HorizontalDirectionMask ; $C92F: 84 4C
00C931 1
00C931 1 B0 07 bcs QueueAlternateDirectionRecord ; $C931: B0 07
00C933 1
00C933 1 20 BB C8 jsr ExpandRecordPointerList ; $C933: 20 BB C8
00C936 1
00C936 1 ; Inline pointer/record consumed by $C8BB.
00C936 1 00 39 ED .byte $00,$39,$ED ; $C936-$C938
00C939 1
00C939 1 60 rts ; $C939: 60
00C93A 1
00C93A 1 QueueAlternateDirectionRecord: ; $C93A
00C93A 1 C6 4C dec HorizontalDirectionMask ; $C93A: C6 4C
00C93C 1
00C93C 1 20 BB C8 jsr ExpandRecordPointerList ; $C93C: 20 BB C8
00C93F 1
00C93F 1 ; Alternate inline pointer/record consumed by $C8BB.
00C93F 1 00 D6 EB .byte $00,$D6,$EB ; $C93F-$C941
00C942 1
00C942 1 60 rts ; $C942: 60
00C943 1
00C943 1
00C943 1
00C943 1 ; ============================================================================
00C943 1 ; $C943-$C94E
00C943 1 ; Clear the base entries of three object-field arrays.
00C943 1 ; ============================================================================
00C943 1
00C943 1 ; ----------------------------------------------------------------------------
00C943 1 ; Contract:
00C943 1 ; Description: Clears or resets Base Acceleration Fields.
00C943 1 ; Entry: Registers: A
00C943 1 ; Returns/products: Registers/clobbers: A
00C943 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00C943 1 ; Memory effects: $0506, $0537, $0568
00C943 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00C943 1 ; comparison, load, or store path and are not a stable API product.
00C943 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 6.
00C943 1 ; ----------------------------------------------------------------------------
00C943 1 ClearBaseAccelerationFields: ; $C943
00C943 1 A9 00 lda #$00 ; $C943: A9 00
00C945 1
00C945 1 8D 06 05 sta $0506 ; $C945: 8D 06 05
00C948 1 8D 37 05 sta $0537 ; $C948: 8D 37 05
00C94B 1 8D 68 05 sta $0568 ; $C94B: 8D 68 05
00C94E 1
00C94E 1 60 rts ; $C94E: 60
00C94F 1
00C94F 1 ; ============================================================================
00C94F 1 ; $C94F-$C958
00C94F 1 ; Initialize the fields at $0509/$050A, $053A/$053B, and $056B/$056C
00C94F 1 ; with six inline zero bytes.
00C94F 1 ;
00C94F 1 ; Routine $C985 retrieves the address of the inline data and consumes all
00C94F 1 ; six bytes.
00C94F 1 ; ============================================================================
00C94F 1
00C94F 1 ; ----------------------------------------------------------------------------
00C94F 1 ; Contract:
00C94F 1 ; Description: Clears or resets Base Position Fields.
00C94F 1 ; Entry: No register input inferred
00C94F 1 ; Returns/products: No direct product inferred
00C94F 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00C94F 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00C94F 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00C94F 1 ; comparison, load, or store path and are not a stable API product.
00C94F 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 6.
00C94F 1 ; ----------------------------------------------------------------------------
00C94F 1 ClearBasePositionFields: ; $C94F
00C94F 1 20 85 C9 jsr LoadBaseMotionFieldsInline ; $C94F: 20 85 C9
00C952 1
00C952 1 00 00 .word $0000 ; $C952-$C953
00C954 1 00 00 .word $0000 ; $C954-$C955
00C956 1 00 00 .word $0000 ; $C956-$C957
00C958 1
00C958 1 60 rts ; $C958: 60
00C959 1
00C959 1 ; ============================================================================
00C959 1 ; $C959-$C962
00C959 1 ; Initialize the fields at $0507/$0508, $0538/$0539, and $0569/$056A
00C959 1 ; with six inline zero bytes.
00C959 1 ;
00C959 1 ; Routine $C963 retrieves the address of the inline data and consumes all
00C959 1 ; six bytes.
00C959 1 ; ============================================================================
00C959 1
00C959 1 ClearBaseMotionFields: ; $C959
00C959 1 20 63 C9 jsr LoadBasePositionFieldsInline ; $C959: 20 63 C9
00C95C 1
00C95C 1 00 00 .word $0000 ; $C95C-$C95D
00C95E 1 00 00 .word $0000 ; $C95E-$C95F
00C960 1 00 00 .word $0000 ; $C960-$C961
00C962 1
00C962 1 60 rts ; $C962: 60
00C963 1
00C963 1 ; ============================================================================
00C963 1 ; $C963-$C984
00C963 1 ; Load three 16-bit field values from inline data.
00C963 1 ;
00C963 1 ; $E99A retrieves the inline-data pointer:
00C963 1 ; X = first byte
00C963 1 ; A = second byte
00C963 1 ; $00/$01 points to the remaining bytes
00C963 1 ;
00C963 1 ; The six input bytes are stored as:
00C963 1 ;
00C963 1 ; byte 0 -> $0507
00C963 1 ; byte 1 -> $0508
00C963 1 ; byte 2 -> $0538
00C963 1 ; byte 3 -> $0539
00C963 1 ; byte 4 -> $0569
00C963 1 ; byte 5 -> $056A
00C963 1 ;
00C963 1 ; Exit:
00C963 1 ; Y = $04
00C963 1 ; ============================================================================
00C963 1 ; ============================================================================
00C963 1 ; $C963-$C984
00C963 1 ; Load the $09/$0A, $3A/$3B, and $6B/$6C field group.
00C963 1 ; ============================================================================
00C963 1
00C963 1 ; ----------------------------------------------------------------------------
00C963 1 ; Contract:
00C963 1 ; Description: Implements Load Base Position Fields Inline.
00C963 1 ; Entry: Registers: A, X, Y; Memory: (indirectptrlo)
00C963 1 ; Returns/products: Registers/clobbers: A, Y
00C963 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00C963 1 ; Memory effects: $0509, $050a, $053a, $053b, $056b, $056c
00C963 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00C963 1 ; comparison, load, or store path and are not a stable API product.
00C963 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 2.
00C963 1 ; ----------------------------------------------------------------------------
00C963 1 LoadBasePositionFieldsInline: ; $C963
00C963 1 20 9A E9 jsr DecodeInlineParameters ; $C963: 20 9A E9
00C966 1
00C966 1 8E 09 05 stx $0509 ; $C966: 8E 09 05
00C969 1 8D 0A 05 sta $050A ; $C969: 8D 0A 05
00C96C 1
00C96C 1 B1 00 lda (IndirectPtrLo),y ; $C96C: B1 00
00C96E 1 8D 3A 05 sta $053A ; $C96E: 8D 3A 05
00C971 1
00C971 1 C8 iny ; $C971: C8
00C972 1
00C972 1 B1 00 lda (IndirectPtrLo),y ; $C972: B1 00
00C974 1 8D 3B 05 sta $053B ; $C974: 8D 3B 05
00C977 1
00C977 1 C8 iny ; $C977: C8
00C978 1
00C978 1 B1 00 lda (IndirectPtrLo),y ; $C978: B1 00
00C97A 1 8D 6B 05 sta $056B ; $C97A: 8D 6B 05
00C97D 1
00C97D 1 C8 iny ; $C97D: C8
00C97E 1
00C97E 1 B1 00 lda (IndirectPtrLo),y ; $C97E: B1 00
00C980 1 8D 6C 05 sta $056C ; $C980: 8D 6C 05
00C983 1
00C983 1 C8 iny ; $C983: C8
00C984 1 60 rts ; $C984: 60
00C985 1
00C985 1 ; ============================================================================
00C985 1 ; $C985-$C9A6
00C985 1 ; Load the $07/$08, $38/$39, and $69/$6A field group.
00C985 1 ; ============================================================================
00C985 1
00C985 1 ; ----------------------------------------------------------------------------
00C985 1 ; Contract:
00C985 1 ; Description: Implements Load Base Motion Fields Inline.
00C985 1 ; Entry: Registers: A, X, Y; Memory: (indirectptrlo)
00C985 1 ; Returns/products: Registers/clobbers: A, Y
00C985 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00C985 1 ; Memory effects: $0507, $0508, $0538, $0539, $0569, $056a
00C985 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00C985 1 ; comparison, load, or store path and are not a stable API product.
00C985 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00C985 1 ; ----------------------------------------------------------------------------
00C985 1 LoadBaseMotionFieldsInline: ; $C985
00C985 1 20 9A E9 jsr DecodeInlineParameters ; $C985: 20 9A E9
00C988 1
00C988 1 8E 07 05 stx $0507 ; $C988: 8E 07 05
00C98B 1 8D 08 05 sta $0508 ; $C98B: 8D 08 05
00C98E 1
00C98E 1 B1 00 lda (IndirectPtrLo),y ; $C98E: B1 00
00C990 1 8D 38 05 sta $0538 ; $C990: 8D 38 05
00C993 1
00C993 1 C8 iny ; $C993: C8
00C994 1
00C994 1 B1 00 lda (IndirectPtrLo),y ; $C994: B1 00
00C996 1 8D 39 05 sta $0539 ; $C996: 8D 39 05
00C999 1
00C999 1 C8 iny ; $C999: C8
00C99A 1
00C99A 1 B1 00 lda (IndirectPtrLo),y ; $C99A: B1 00
00C99C 1 8D 69 05 sta $0569 ; $C99C: 8D 69 05
00C99F 1
00C99F 1 C8 iny ; $C99F: C8
00C9A0 1
00C9A0 1 B1 00 lda (IndirectPtrLo),y ; $C9A0: B1 00
00C9A2 1 8D 6A 05 sta $056A ; $C9A2: 8D 6A 05
00C9A5 1
00C9A5 1 C8 iny ; $C9A5: C8
00C9A6 1 60 rts ; $C9A6: 60
00C9A7 1
00C9A7 1 ; ============================================================================
00C9A7 1 ; $C9A7-$C9BF
00C9A7 1 ; Load two indexed 16-bit field values from inline data.
00C9A7 1 ;
00C9A7 1 ; Entry:
00C9A7 1 ; X = object-array offset
00C9A7 1 ;
00C9A7 1 ; The four input bytes are stored as:
00C9A7 1 ;
00C9A7 1 ; byte 0 -> $0509,X
00C9A7 1 ; byte 1 -> $050A,X
00C9A7 1 ; byte 2 -> $053A,X
00C9A7 1 ; byte 3 -> $053B,X
00C9A7 1 ;
00C9A7 1 ; Exit:
00C9A7 1 ; Y = $02
00C9A7 1 ; ============================================================================
00C9A7 1
00C9A7 1 LoadObjectPositionInline: ; $C9A7
00C9A7 1 20 9A E9 jsr DecodeInlineParameters ; $C9A7: 20 9A E9
00C9AA 1
00C9AA 1 9D 09 05 sta $0509,x ; $C9AA: 9D 09 05
00C9AD 1
00C9AD 1 B1 00 lda (IndirectPtrLo),y ; $C9AD: B1 00
00C9AF 1 9D 0A 05 sta $050A,x ; $C9AF: 9D 0A 05
00C9B2 1
00C9B2 1 C8 iny ; $C9B2: C8
00C9B3 1
00C9B3 1 B1 00 lda (IndirectPtrLo),y ; $C9B3: B1 00
00C9B5 1 9D 3A 05 sta $053A,x ; $C9B5: 9D 3A 05
00C9B8 1
00C9B8 1 C8 iny ; $C9B8: C8
00C9B9 1
00C9B9 1 B1 00 lda (IndirectPtrLo),y ; $C9B9: B1 00
00C9BB 1 9D 3B 05 sta $053B,x ; $C9BB: 9D 3B 05
00C9BE 1
00C9BE 1 C8 iny ; $C9BE: C8
00C9BF 1 60 rts ; $C9BF: 60
00C9C0 1
00C9C0 1 ; ============================================================================
00C9C0 1 ; $C9C0-$CA22
00C9C0 1 ; Compare an indexed object's position against the base object's position.
00C9C0 1 ;
00C9C0 1 ; Entry:
00C9C0 1 ; X = indexed object-array offset
00C9C0 1 ;
00C9C0 1 ; Return:
00C9C0 1 ; A = $00 when the comparison succeeds and state is updated
00C9C0 1 ; A = $01 when any comparison fails
00C9C0 1 ;
00C9C0 1 ; The routine performs three checks:
00C9C0 1 ; 1. $056B/$056C must be less than three.
00C9C0 1 ; 2. The horizontal distance must satisfy the signed threshold test.
00C9C0 1 ; 3. The vertical distance must satisfy the signed threshold test.
00C9C0 1 ; ============================================================================
00C9C0 1
00C9C0 1 ; ----------------------------------------------------------------------------
00C9C0 1 ; Contract:
00C9C0 1 ; Description: Implements Try Merge Object Into Base.
00C9C0 1 ; Entry: Registers: A, Y; Memory: $056b, $056c, $0509, $050a, $053a
00C9C0 1 ; Returns/products: Registers/clobbers: A, Y
00C9C0 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00C9C0 1 ; Memory effects: $050a, $053b, $056c, $056d, $056e, basemotionactive
00C9C0 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00C9C0 1 ; comparison, load, or store path and are not a stable API product.
00C9C0 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 3.
00C9C0 1 ; ----------------------------------------------------------------------------
00C9C0 1 TryMergeObjectIntoBase: ; $C9C0
00C9C0 1 AD 6B 05 lda $056B ; $C9C0: AD 6B 05
00C9C3 1 C9 00 cmp #$00 ; $C9C3: C9 00
00C9C5 1
00C9C5 1 AD 6C 05 lda $056C ; $C9C5: AD 6C 05
00C9C8 1 E9 03 sbc #$03 ; $C9C8: E9 03
00C9CA 1 ; Carry from CMP #$00 participates in this
00C9CA 1 ; subtraction because LDA does not alter carry.
00C9CA 1
00C9CA 1 10 54 bpl ObjectMergeFailed ; $C9CA: 10 54
00C9CC 1
00C9CC 1 ; ----------------------------------------------------------------------------
00C9CC 1 ; Calculate the signed difference between the base horizontal position and
00C9CC 1 ; the indexed object's horizontal position:
00C9CC 1 ;
00C9CC 1 ; base: $0509/$050A
00C9CC 1 ; indexed: $0509,X/$050A,X
00C9CC 1 ;
00C9CC 1 ; The low-byte difference is passed in Y and the high-byte difference in A
00C9CC 1 ; to the helper at $E7CB.
00C9CC 1 ; ----------------------------------------------------------------------------
00C9CC 1
00C9CC 1 38 sec ; $C9CC: 38
00C9CD 1
00C9CD 1 AD 09 05 lda $0509 ; $C9CD: AD 09 05
00C9D0 1 FD 09 05 sbc $0509,x ; $C9D0: FD 09 05
00C9D3 1 A8 tay ; $C9D3: A8
00C9D4 1
00C9D4 1 AD 0A 05 lda $050A ; $C9D4: AD 0A 05
00C9D7 1 FD 0A 05 sbc $050A,x ; $C9D7: FD 0A 05
00C9DA 1
00C9DA 1 20 CB E7 jsr AbsoluteValueAY ; $C9DA: 20 CB E7
00C9DD 1
00C9DD 1 ; ----------------------------------------------------------------------------
00C9DD 1 ; Test the normalized horizontal result.
00C9DD 1 ;
00C9DD 1 ; CPY #$80 establishes carry for the following SBC #$00. This effectively
00C9DD 1 ; includes Y's sign/high-bit state in the signed comparison.
00C9DD 1 ; ----------------------------------------------------------------------------
00C9DD 1
00C9DD 1 C0 80 cpy #$80 ; $C9DD: C0 80
00C9DF 1 E9 00 sbc #$00 ; $C9DF: E9 00
00C9E1 1
00C9E1 1 10 3D bpl ObjectMergeFailed ; $C9E1: 10 3D
00C9E3 1
00C9E3 1 ; ----------------------------------------------------------------------------
00C9E3 1 ; Repeat the same signed-distance calculation for the vertical position:
00C9E3 1 ;
00C9E3 1 ; base: $053A/$053B
00C9E3 1 ; indexed: $053A,X/$053B,X
00C9E3 1 ; ----------------------------------------------------------------------------
00C9E3 1
00C9E3 1 38 sec ; $C9E3: 38
00C9E4 1
00C9E4 1 AD 3A 05 lda $053A ; $C9E4: AD 3A 05
00C9E7 1 FD 3A 05 sbc $053A,x ; $C9E7: FD 3A 05
00C9EA 1 A8 tay ; $C9EA: A8
00C9EB 1
00C9EB 1 AD 3B 05 lda $053B ; $C9EB: AD 3B 05
00C9EE 1 FD 3B 05 sbc $053B,x ; $C9EE: FD 3B 05
00C9F1 1
00C9F1 1 20 CB E7 jsr AbsoluteValueAY ; $C9F1: 20 CB E7
00C9F4 1
00C9F4 1 C0 80 cpy #$80 ; $C9F4: C0 80
00C9F6 1 E9 00 sbc #$00 ; $C9F6: E9 00
00C9F8 1
00C9F8 1 10 26 bpl ObjectMergeFailed ; $C9F8: 10 26
00C9FA 1
00C9FA 1 ; ----------------------------------------------------------------------------
00C9FA 1 ; The indexed object passed all comparisons.
00C9FA 1 ;
00C9FA 1 ; Copy its high position bytes into the base object, set $056C to one,
00C9FA 1 ; clear the indexed object's values at $056D/$056E, and reset shared fields.
00C9FA 1 ; ----------------------------------------------------------------------------
00C9FA 1
00C9FA 1 BD 0A 05 lda $050A,x ; $C9FA: BD 0A 05
00C9FD 1 8D 0A 05 sta $050A ; $C9FD: 8D 0A 05
00CA00 1
00CA00 1 BD 3B 05 lda $053B,x ; $CA00: BD 3B 05
00CA03 1 8D 3B 05 sta $053B ; $CA03: 8D 3B 05
00CA06 1
00CA06 1 A9 01 lda #$01 ; $CA06: A9 01
00CA08 1 8D 6C 05 sta $056C ; $CA08: 8D 6C 05
00CA0B 1
00CA0B 1 A9 00 lda #$00 ; $CA0B: A9 00
00CA0D 1 9D 6D 05 sta $056D,x ; $CA0D: 9D 6D 05
00CA10 1 9D 6E 05 sta $056E,x ; $CA10: 9D 6E 05
00CA13 1
00CA13 1 20 43 C9 jsr ClearBaseAccelerationFields ; $CA13: 20 43 C9
00CA16 1 20 4F C9 jsr ClearBasePositionFields ; $CA16: 20 4F C9
00CA19 1
00CA19 1 E6 5E inc BaseMotionEventCount ; $CA19: E6 5E
00CA1B 1
00CA1B 1 A9 00 lda #$00 ; $CA1B: A9 00
00CA1D 1 85 5C sta BaseMotionActive ; $CA1D: 85 5C
00CA1F 1
00CA1F 1 60 rts ; $CA1F: 60
00CA20 1 ; Return A = $00.
00CA20 1
00CA20 1 ; ----------------------------------------------------------------------------
00CA20 1 ; Comparison failed.
00CA20 1 ; ----------------------------------------------------------------------------
00CA20 1
00CA20 1 ObjectMergeFailed: ; $CA20
00CA20 1 A9 01 lda #$01 ; $CA20: A9 01
00CA22 1 60 rts ; $CA22: 60
00CA23 1
00CA23 1 ; ============================================================================
00CA23 1 ; $CA23-$CA4B
00CA23 1 ; Initialize base movement and position fields.
00CA23 1 ;
00CA23 1 ; The routine has a secondary entry point at $CA2A. The primary entry at
00CA23 1 ; $CA23 clears $056A and branches directly to $CA2F because A is zero.
00CA23 1 ;
00CA23 1 ; Entry at $CA2A:
00CA23 1 ; A is stored into $056A before continuing.
00CA23 1 ;
00CA23 1 ; Inputs preserved into object fields:
00CA23 1 ; X -> $0508
00CA23 1 ; Y -> $0539
00CA23 1 ;
00CA23 1 ; Exit:
00CA23 1 ; $5C is incremented.
00CA23 1 ; ============================================================================
00CA23 1
00CA23 1 ; ----------------------------------------------------------------------------
00CA23 1 ; Contract:
00CA23 1 ; Description: Initializes Base Motion Zero.
00CA23 1 ; Entry: Registers: A, X, Y
00CA23 1 ; Returns/products: Registers/clobbers: A
00CA23 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00CA23 1 ; Memory effects: $056a, $0568, $0508, $0539, $0507, $0538, $0569
00CA23 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00CA23 1 ; comparison, load, or store path and are not a stable API product.
00CA23 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00CA23 1 ; ----------------------------------------------------------------------------
00CA23 1 InitializeBaseMotionZero: ; $CA23
00CA23 1 A9 00 lda #$00 ; $CA23: A9 00
00CA25 1 8D 6A 05 sta $056A ; $CA25: 8D 6A 05
00CA28 1
00CA28 1 F0 05 beq StoreBaseMotionInitialization
00CA2A 1 ; $CA28: F0 05
00CA2A 1 ; Always taken because A is zero.
00CA2A 1
00CA2A 1 ; ----------------------------------------------------------------------------
00CA2A 1 ; Alternate entry point.
00CA2A 1 ;
00CA2A 1 ; Callers entering at $CA2A can provide a nonzero value in A for $056A.
00CA2A 1 ; ----------------------------------------------------------------------------
00CA2A 1
00CA2A 1 ; ----------------------------------------------------------------------------
00CA2A 1 ; Contract:
00CA2A 1 ; Description: Initializes Base Motion.
00CA2A 1 ; Entry: Registers: A, X, Y
00CA2A 1 ; Returns/products: Registers/clobbers: A
00CA2A 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00CA2A 1 ; Memory effects: $056a, $0568, $0508, $0539, $0507, $0538, $0569, $0506
00CA2A 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00CA2A 1 ; comparison, load, or store path and are not a stable API product.
00CA2A 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00CA2A 1 ; ----------------------------------------------------------------------------
00CA2A 1 InitializeBaseMotion: ; $CA2A
00CA2A 1 8D 6A 05 sta $056A ; $CA2A: 8D 6A 05
00CA2D 1
00CA2D 1 A9 FF lda #$FF ; $CA2D: A9 FF
00CA2F 1
00CA2F 1 ; ----------------------------------------------------------------------------
00CA2F 1 ; Mark the base entry at $0568 and store the supplied X/Y field values.
00CA2F 1 ;
00CA2F 1 ; Primary entry stores $00 at $0568 because it branches directly here with
00CA2F 1 ; A equal to zero. Alternate entry stores $FF.
00CA2F 1 ; ----------------------------------------------------------------------------
00CA2F 1
00CA2F 1 StoreBaseMotionInitialization: ; $CA2F
00CA2F 1 8D 68 05 sta $0568 ; $CA2F: 8D 68 05
00CA32 1
00CA32 1 8E 08 05 stx $0508 ; $CA32: 8E 08 05
00CA35 1 8C 39 05 sty $0539 ; $CA35: 8C 39 05
00CA38 1
00CA38 1 ; ----------------------------------------------------------------------------
00CA38 1 ; Clear the remaining base position and movement fields.
00CA38 1 ; ----------------------------------------------------------------------------
00CA38 1
00CA38 1 A9 00 lda #$00 ; $CA38: A9 00
00CA3A 1
00CA3A 1 8D 07 05 sta $0507 ; $CA3A: 8D 07 05
00CA3D 1 8D 38 05 sta $0538 ; $CA3D: 8D 38 05
00CA40 1 8D 69 05 sta $0569 ; $CA40: 8D 69 05
00CA43 1
00CA43 1 8D 06 05 sta $0506 ; $CA43: 8D 06 05
00CA46 1 8D 37 05 sta $0537 ; $CA46: 8D 37 05
00CA49 1
00CA49 1 E6 5C inc BaseMotionActive ; $CA49: E6 5C
00CA4B 1
00CA4B 1 60 rts ; $CA4B: 60
00CA4C 1
00CA4C 1 ; ============================================================================
00CA4C 1 ; $CA4C-$CAD1
00CA4C 1 ; State progression and trajectory/update loop
00CA4C 1 ; ============================================================================
00CA4C 1
00CA4C 1 RunBaseTrajectorySequence: ; $CA4C
00CA4C 1 A5 5D lda BaseMotionPhase ; $CA4C: A5 5D
00CA4E 1 D0 04 bne AdvanceTrajectoryPhase
00CA50 1 ; $CA4E: D0 04
00CA50 1
00CA50 1 A9 40 lda #$40 ; $CA50: A9 40
00CA52 1 85 FE sta PendingAudioFlags ; $CA52: 85 FE
00CA54 1
00CA54 1 AdvanceTrajectoryPhase: ; $CA54
00CA54 1 E6 5D inc BaseMotionPhase ; $CA54: E6 5D
00CA56 1
00CA56 1 ; ----------------------------------------------------------------------------
00CA56 1 ; When the vertical high byte is nonnegative, derive new signed movement
00CA56 1 ; values from the current position fields.
00CA56 1 ; ----------------------------------------------------------------------------
00CA56 1
00CA56 1 AD 3B 05 lda $053B ; $CA56: AD 3B 05
00CA59 1 30 1C bmi UpdateTrajectoryFrame ; $CA59: 30 1C
00CA5B 1
00CA5B 1 ; ----------------------------------------------------------------------------
00CA5B 1 ; Derive $0508 from the negated high position at $050A.
00CA5B 1 ;
00CA5B 1 ; CMP #$80 followed by ROR is used twice to perform sign-aware shifting.
00CA5B 1 ; ----------------------------------------------------------------------------
00CA5B 1
00CA5B 1 A9 00 lda #$00 ; $CA5B: A9 00
00CA5D 1 38 sec ; $CA5D: 38
00CA5E 1 ED 0A 05 sbc $050A ; $CA5E: ED 0A 05
00CA61 1
00CA61 1 C9 80 cmp #$80 ; $CA61: C9 80
00CA63 1 6A ror ; $CA63: 6A
00CA64 1
00CA64 1 C9 80 cmp #$80 ; $CA64: C9 80
00CA66 1 6A ror ; $CA66: 6A
00CA67 1
00CA67 1 8D 08 05 sta $0508 ; $CA67: 8D 08 05
00CA6A 1
00CA6A 1 ; ----------------------------------------------------------------------------
00CA6A 1 ; Derive $0539 from $053B.
00CA6A 1 ; ----------------------------------------------------------------------------
00CA6A 1
00CA6A 1 A9 07 lda #$07 ; $CA6A: A9 07
00CA6C 1 38 sec ; $CA6C: 38
00CA6D 1 ED 3B 05 sbc $053B ; $CA6D: ED 3B 05
00CA70 1
00CA70 1 4A lsr ; $CA70: 4A
00CA71 1 4A lsr ; $CA71: 4A
00CA72 1
00CA72 1 09 C0 ora #$C0 ; $CA72: 09 C0
00CA74 1 8D 39 05 sta $0539 ; $CA74: 8D 39 05
00CA77 1
00CA77 1 ; ----------------------------------------------------------------------------
00CA77 1 ; Wait for a frame, then call $CBEC repeatedly until it returns carry set.
00CA77 1 ; ----------------------------------------------------------------------------
00CA77 1
00CA77 1 UpdateTrajectoryFrame: ; $CA77
00CA77 1 20 48 EB jsr SelectObjectEventBank1 ; $CA77: 20 48 EB
00CA7A 1
00CA7A 1 A2 00 ldx #$00 ; $CA7A: A2 00
00CA7C 1 20 EC CB jsr TestObjectCollision ; $CA7C: 20 EC CB
00CA7F 1 90 F6 bcc UpdateTrajectoryFrame ; $CA7F: 90 F6
00CA81 1
00CA81 1 20 D2 CA jsr EvaluateTrajectoryResult ; $CA81: 20 D2 CA
00CA84 1
00CA84 1 ; ----------------------------------------------------------------------------
00CA84 1 ; Continue the state loop until $056C reaches at least three.
00CA84 1 ; ----------------------------------------------------------------------------
00CA84 1
00CA84 1 AD 6C 05 lda $056C ; $CA84: AD 6C 05
00CA87 1 C9 03 cmp #$03 ; $CA87: C9 03
00CA89 1 90 C1 bcc RunBaseTrajectorySequence ; $CA89: 90 C1
00CA8B 1
00CA8B 1 ; ----------------------------------------------------------------------------
00CA8B 1 ; Select one of three inline command records.
00CA8B 1 ; ----------------------------------------------------------------------------
00CA8B 1
00CA8B 1 A5 5F lda TrajectoryResult ; $CA8B: A5 5F
00CA8D 1 30 21 bmi WaitForTrajectoryLimit
00CA8F 1 ; $CA8D: 30 21
00CA8F 1
00CA8F 1 A5 5D lda BaseMotionPhase ; $CA8F: A5 5D
00CA91 1 D0 17 bne QueueLaterTrajectoryCommand ; $CA91: D0 17
00CA93 1
00CA93 1 AD 0A 05 lda $050A ; $CA93: AD 0A 05
00CA96 1 30 09 bmi QueueNegativeTrajectoryCommand ; $CA96: 30 09
00CA98 1
00CA98 1 20 0A EB jsr QueueInlineObjectEvent ; $CA98: 20 0A EB
00CA9B 1
00CA9B 1 ; Inline command record consumed by QueueInlineObjectEvent.
00CA9B 1 24 A3 CD .byte $24,$A3,$CD ; $CA9B-$CA9D
00CA9E 1
00CA9E 1 4C B0 CA jmp WaitForTrajectoryLimit
00CAA1 1 ; $CA9E: 4C B0 CA
00CAA1 1
00CAA1 1 QueueNegativeTrajectoryCommand: ; $CAA1
00CAA1 1 20 0A EB jsr QueueInlineObjectEvent ; $CAA1: 20 0A EB
00CAA4 1
00CAA4 1 ; Inline command record consumed by QueueInlineObjectEvent.
00CAA4 1 26 A3 CD .byte $26,$A3,$CD ; $CAA4-$CAA6
00CAA7 1
00CAA7 1 4C B0 CA jmp WaitForTrajectoryLimit
00CAAA 1 ; $CAA7: 4C B0 CA
00CAAA 1
00CAAA 1 QueueLaterTrajectoryCommand: ; $CAAA
00CAAA 1 20 0A EB jsr QueueInlineObjectEvent ; $CAAA: 20 0A EB
00CAAD 1
00CAAD 1 ; Inline command record consumed by QueueInlineObjectEvent.
00CAAD 1 1A 97 CD .byte $1A,$97,$CD ; $CAAD-$CAAF
00CAB0 1
00CAB0 1 ; ----------------------------------------------------------------------------
00CAB0 1 ; Wait until the value derived by $CBEC reaches either:
00CAB0 1 ;
00CAB0 1 ; $056C or greater, or
00CAB0 1 ; at least $50.
00CAB0 1 ;
00CAB0 1 ; The returned A value is reduced by $38 and saved in $056E.
00CAB0 1 ; ----------------------------------------------------------------------------
00CAB0 1
00CAB0 1 WaitForTrajectoryLimit: ; $CAB0
00CAB0 1 20 48 EB jsr SelectObjectEventBank1 ; $CAB0: 20 48 EB
00CAB3 1
00CAB3 1 A2 00 ldx #$00 ; $CAB3: A2 00
00CAB5 1 20 EC CB jsr TestObjectCollision ; $CAB5: 20 EC CB
00CAB8 1
00CAB8 1 38 sec ; $CAB8: 38
00CAB9 1 E9 38 sbc #$38 ; $CAB9: E9 38
00CABB 1 8D 6E 05 sta $056E ; $CABB: 8D 6E 05
00CABE 1
00CABE 1 CD 6C 05 cmp $056C ; $CABE: CD 6C 05
00CAC1 1 B0 04 bcs FinishTrajectorySequence ; $CAC1: B0 04
00CAC3 1
00CAC3 1 C9 50 cmp #$50 ; $CAC3: C9 50
00CAC5 1 90 E9 bcc WaitForTrajectoryLimit
00CAC7 1 ; $CAC5: 90 E9
00CAC7 1
00CAC7 1 ; ----------------------------------------------------------------------------
00CAC7 1 ; Reset position structures and leave through the common engine exit.
00CAC7 1 ; A is zero after ClearBaseAccelerationFields, so $5C is cleared.
00CAC7 1 ; ----------------------------------------------------------------------------
00CAC7 1
00CAC7 1 FinishTrajectorySequence: ; $CAC7
00CAC7 1 20 4F C9 jsr ClearBasePositionFields ; $CAC7: 20 4F C9
00CACA 1 20 43 C9 jsr ClearBaseAccelerationFields ; $CACA: 20 43 C9
00CACD 1
00CACD 1 85 5C sta BaseMotionActive ; $CACD: 85 5C
00CACF 1
00CACF 1 4C 6A EB jmp CommonEngineExit ; $CACF: 4C 6A EB
00CAD2 1
00CAD2 1 ; ============================================================================
00CAD2 1 ; $CAD2-$CB34
00CAD2 1 ; Evaluate object state and select a transition based on position-derived data.
00CAD2 1 ;
00CAD2 1 ; The routine uses the current base-object coordinates to calculate an index
00CAD2 1 ; into the four-byte table at $CB35. The selected signed table value is saved
00CAD2 1 ; in $5F and controls subsequent state transitions.
00CAD2 1 ; ============================================================================
00CAD2 1
00CAD2 1 ; ----------------------------------------------------------------------------
00CAD2 1 ; Contract:
00CAD2 1 ; Description: Implements Evaluate Trajectory Result.
00CAD2 1 ; Entry: Registers: A, X, Y; Memory: trajectoryevaluationenabled, trajectoryresult, basemotioneventcount, $0509, $050a, $053a, $053b
00CAD2 1 ; Returns/products: Registers/clobbers: A, X, Y
00CAD2 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00CAD2 1 ; Memory effects: trajectoryresult, stateselector, $0598
00CAD2 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00CAD2 1 ; comparison, load, or store path and are not a stable API product.
00CAD2 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 2.
00CAD2 1 ; ----------------------------------------------------------------------------
00CAD2 1 EvaluateTrajectoryResult: ; $CAD2
00CAD2 1 A5 86 lda TrajectoryEvaluationEnabled ; $CAD2: A5 86
00CAD4 1 10 5E bpl TrajectoryResultReturn ; $CAD4: 10 5E
00CAD6 1
00CAD6 1 A5 5F lda TrajectoryResult ; $CAD6: A5 5F
00CAD8 1 05 5E ora BaseMotionEventCount ; $CAD8: 05 5E
00CADA 1 D0 58 bne TrajectoryResultReturn ; $CADA: D0 58
00CADC 1
00CADC 1 ; ----------------------------------------------------------------------------
00CADC 1 ; Normalize the base horizontal position.
00CADC 1 ;
00CADC 1 ; Input:
00CADC 1 ; Y = $0509
00CADC 1 ; A = $050A
00CADC 1 ;
00CADC 1 ; The helper at $E7CB processes the 16-bit value in A:Y.
00CADC 1 ; ----------------------------------------------------------------------------
00CADC 1
00CADC 1 AC 09 05 ldy $0509 ; $CADC: AC 09 05
00CADF 1 AD 0A 05 lda $050A ; $CADF: AD 0A 05
00CAE2 1
00CAE2 1 20 CB E7 jsr AbsoluteValueAY ; $CAE2: 20 CB E7
00CAE5 1
00CAE5 1 ; ----------------------------------------------------------------------------
00CAE5 1 ; Subtract eight from the normalized high/result byte and preserve it.
00CAE5 1 ; ----------------------------------------------------------------------------
00CAE5 1
00CAE5 1 38 sec ; $CAE5: 38
00CAE6 1 E9 08 sbc #$08 ; $CAE6: E9 08
00CAE8 1
00CAE8 1 48 pha ; $CAE8: 48
00CAE9 1
00CAE9 1 ; ----------------------------------------------------------------------------
00CAE9 1 ; Compare the normalized low result in Y against $053A, then subtract $053B.
00CAE9 1 ;
00CAE9 1 ; ASL followed by LDA #$00 / ROL converts the comparison result in carry into
00CAE9 1 ; a zero-or-one high component, which becomes an index contribution.
00CAE9 1 ; ----------------------------------------------------------------------------
00CAE9 1
00CAE9 1 CC 3A 05 cpy $053A ; $CAE9: CC 3A 05
00CAEC 1 ED 3B 05 sbc $053B ; $CAEC: ED 3B 05
00CAEF 1
00CAEF 1 0A asl ; $CAEF: 0A
00CAF0 1
00CAF0 1 A9 00 lda #$00 ; $CAF0: A9 00
00CAF2 1 2A rol ; $CAF2: 2A
00CAF3 1 AA tax ; $CAF3: AA
00CAF4 1
00CAF4 1 ; ----------------------------------------------------------------------------
00CAF4 1 ; Add the normalized position to $053A/$053B.
00CAF4 1 ; ----------------------------------------------------------------------------
00CAF4 1
00CAF4 1 98 tya ; $CAF4: 98
00CAF5 1 6D 3A 05 adc $053A ; $CAF5: 6D 3A 05
00CAF8 1
00CAF8 1 68 pla ; $CAF8: 68
00CAF9 1 6D 3B 05 adc $053B ; $CAF9: 6D 3B 05
00CAFC 1
00CAFC 1 ; ----------------------------------------------------------------------------
00CAFC 1 ; Convert the result and carry state into a table index.
00CAFC 1 ;
00CAFC 1 ; X receives a value in the range $00-$03.
00CAFC 1 ; ----------------------------------------------------------------------------
00CAFC 1
00CAFC 1 0A asl ; $CAFC: 0A
00CAFD 1
00CAFD 1 8A txa ; $CAFD: 8A
00CAFE 1 2A rol ; $CAFE: 2A
00CAFF 1 AA tax ; $CAFF: AA
00CB00 1
00CB00 1 BD 35 CB lda TrajectoryResultTable,x ; $CB00: BD 35 CB
00CB03 1 85 5F sta TrajectoryResult ; $CB03: 85 5F
00CB05 1
00CB05 1 10 2D bpl TrajectoryResultReturn ; $CB05: 10 2D
00CB07 1
00CB07 1 ; ----------------------------------------------------------------------------
00CB07 1 ; Handle the negative table-result path.
00CB07 1 ; ----------------------------------------------------------------------------
00CB07 1
00CB07 1 A5 88 lda MotionDirectionState ; $CB07: A5 88
00CB09 1 D0 13 bne ApplyNegativeTrajectoryResult
00CB0B 1 ; $CB09: D0 13
00CB0B 1
00CB0B 1 A9 02 lda #$02 ; $CB0B: A9 02
00CB0D 1 C5 62 cmp PrimarySequenceState ; $CB0D: C5 62
00CB0F 1 D0 0D bne ApplyNegativeTrajectoryResult
00CB11 1 ; $CB0F: D0 0D
00CB11 1
00CB11 1 0A asl ; $CB11: 0A
00CB12 1 ; A = $04
00CB12 1
00CB12 1 85 72 sta StateSelector ; $CB12: 85 72
00CB14 1
00CB14 1 A9 FF lda #$FF ; $CB14: A9 FF
00CB16 1 8D 98 05 sta $0598 ; $CB16: 8D 98 05
00CB19 1
00CB19 1 E6 46 inc StateSequenceActive ; $CB19: E6 46
00CB1B 1
00CB1B 1 4C E4 CC jmp AdvanceAlternateStateSequence
00CB1E 1 ; $CB1B: 4C E4 CC
00CB1E 1
00CB1E 1 ; ----------------------------------------------------------------------------
00CB1E 1 ; Update state variables and select one of two inline command records based on
00CB1E 1 ; the sign of $050A.
00CB1E 1 ; ----------------------------------------------------------------------------
00CB1E 1
00CB1E 1 ApplyNegativeTrajectoryResult: ; $CB1E
00CB1E 1 E6 60 inc PendingStateTransition ; $CB1E: E6 60
00CB20 1 C6 46 dec StateSequenceActive ; $CB20: C6 46
00CB22 1
00CB22 1 AD 0A 05 lda $050A ; $CB22: AD 0A 05
00CB25 1 30 07 bmi QueueNegativeResultCommand ; $CB25: 30 07
00CB27 1
00CB27 1 20 0A EB jsr QueueInlineObjectEvent ; $CB27: 20 0A EB
00CB2A 1
00CB2A 1 ; Inline command record consumed by QueueInlineObjectEvent.
00CB2A 1 18 4C CC .byte $18,$4C,$CC ; $CB2A-$CB2C
00CB2D 1
00CB2D 1 60 rts ; $CB2D: 60
00CB2E 1
00CB2E 1 QueueNegativeResultCommand: ; $CB2E
00CB2E 1 20 0A EB jsr QueueInlineObjectEvent ; $CB2E: 20 0A EB
00CB31 1
00CB31 1 ; Alternate inline command record consumed by QueueInlineObjectEvent.
00CB31 1 1C 4C CC .byte $1C,$4C,$CC ; $CB31-$CB33
00CB34 1
00CB34 1 TrajectoryResultReturn: ; $CB34
00CB34 1 60 rts ; $CB34: 60
00CB35 1
00CB35 1 ; ============================================================================
00CB35 1 ; $CB35-$CB38
00CB35 1 ; Signed state-result lookup table.
00CB35 1 ;
00CB35 1 ; Indexed by the two-bit value calculated at $CAFC-$CAFF.
00CB35 1 ; ============================================================================
00CB35 1
00CB35 1 TrajectoryResultTable: ; $CB35
00CB35 1 FF FF 01 00 .byte $FF,$FF,$01,$00
00CB39 1
00CB39 1 ; ============================================================================
00CB39 1 ; $CB39-$CB7C
00CB39 1 ; Save base coordinates, prepare three object records, and repeatedly update
00CB39 1 ; them until the first updated record produces a negative high byte.
00CB39 1 ; ============================================================================
00CB39 1
00CB39 1 SimulateObjectTrajectories: ; $CB39
00CB39 1 AD 02 05 lda $0502 ; $CB39: AD 02 05
00CB3C 1 85 53 sta SavedBaseXLo ; $CB3C: 85 53
00CB3E 1
00CB3E 1 AD 03 05 lda $0503 ; $CB3E: AD 03 05
00CB41 1 85 54 sta SavedBaseXHi ; $CB41: 85 54
00CB43 1
00CB43 1 AD 33 05 lda $0533 ; $CB43: AD 33 05
00CB46 1 85 55 sta SavedBaseYLo ; $CB46: 85 55
00CB48 1
00CB48 1 AD 34 05 lda $0534 ; $CB48: AD 34 05
00CB4B 1 85 56 sta SavedBaseYHi ; $CB4B: 85 56
00CB4D 1
00CB4D 1 20 4C EB jsr SelectObjectEventBank0 ; $CB4D: 20 4C EB
00CB50 1
00CB50 1 ; ----------------------------------------------------------------------------
00CB50 1 ; Prepare three object records.
00CB50 1 ;
00CB50 1 ; The records begin at offsets:
00CB50 1 ;
00CB50 1 ; X = $00
00CB50 1 ; X = $31
00CB50 1 ; X = $62
00CB50 1 ; ----------------------------------------------------------------------------
00CB50 1
00CB50 1 A2 00 ldx #$00 ; $CB50: A2 00
00CB52 1 20 7D CB jsr PrepareFixedPointObject
00CB55 1 ; $CB52: 20 7D CB
00CB55 1
00CB55 1 A2 31 ldx #$31 ; $CB55: A2 31
00CB57 1 20 7D CB jsr PrepareFixedPointObject
00CB5A 1 ; $CB57: 20 7D CB
00CB5A 1
00CB5A 1 A2 62 ldx #$62 ; $CB5A: A2 62
00CB5C 1 20 7D CB jsr PrepareFixedPointObject
00CB5F 1 ; $CB5C: 20 7D CB
00CB5F 1
00CB5F 1 ; ----------------------------------------------------------------------------
00CB5F 1 ; Initialize an update counter and enter the frame/update loop.
00CB5F 1 ; ----------------------------------------------------------------------------
00CB5F 1
00CB5F 1 A2 20 ldx #$20 ; $CB5F: A2 20
00CB61 1 86 61 stx UpdateCounter ; $CB61: 86 61
00CB63 1
00CB63 1 Routine_CB63_UpdateLoop: ; $CB63
00CB63 1 20 4C EB jsr SelectObjectEventBank0 ; $CB63: 20 4C EB
00CB66 1
00CB66 1 ; ----------------------------------------------------------------------------
00CB66 1 ; Update the third record first.
00CB66 1 ;
00CB66 1 ; If its resulting high byte is negative, restart the entire routine.
00CB66 1 ; ----------------------------------------------------------------------------
00CB66 1
00CB66 1 A2 62 ldx #$62 ; $CB66: A2 62
00CB68 1 20 C4 CB jsr IntegrateFixedPointObject
00CB6B 1 ; $CB68: 20 C4 CB
00CB6B 1
00CB6B 1 30 CC bmi SimulateObjectTrajectories ; $CB6B: 30 CC
00CB6D 1
00CB6D 1 ; ----------------------------------------------------------------------------
00CB6D 1 ; Update the remaining two records.
00CB6D 1 ; ----------------------------------------------------------------------------
00CB6D 1
00CB6D 1 A2 31 ldx #$31 ; $CB6D: A2 31
00CB6F 1 20 C4 CB jsr IntegrateFixedPointObject
00CB72 1 ; $CB6F: 20 C4 CB
00CB72 1
00CB72 1 A2 00 ldx #$00 ; $CB72: A2 00
00CB74 1 20 C4 CB jsr IntegrateFixedPointObject
00CB77 1 ; $CB74: 20 C4 CB
00CB77 1
00CB77 1 ; ----------------------------------------------------------------------------
00CB77 1 ; Continue for $20 update cycles, then restart the routine.
00CB77 1 ; ----------------------------------------------------------------------------
00CB77 1
00CB77 1 C6 61 dec UpdateCounter ; $CB77: C6 61
00CB79 1 D0 E8 bne Routine_CB63_UpdateLoop ; $CB79: D0 E8
00CB7B 1
00CB7B 1 F0 BC beq SimulateObjectTrajectories ; $CB7B: F0 BC
00CB7D 1 ; Always taken because $61 is zero.
00CB7D 1
00CB7D 1 ; ============================================================================
00CB7D 1 ; $CB7D-$CBC3
00CB7D 1 ; Prepare one fixed-point object record.
00CB7D 1 ;
00CB7D 1 ; Entry:
00CB7D 1 ; X = object-record offset
00CB7D 1 ;
00CB7D 1 ; Input fields:
00CB7D 1 ; $0506,X
00CB7D 1 ; $0507,X/$0508,X
00CB7D 1 ; $0509,X/$050A,X
00CB7D 1 ;
00CB7D 1 ; Output fields:
00CB7D 1 ; $0500,X/$0501,X
00CB7D 1 ; $0502,X/$0503,X
00CB7D 1 ; $0504,X/$0505,X
00CB7D 1 ; ============================================================================
00CB7D 1
00CB7D 1 PrepareFixedPointObject: ; $CB7D
00CB7D 1 A0 00 ldy #$00 ; $CB7D: A0 00
00CB7F 1
00CB7F 1 ; ----------------------------------------------------------------------------
00CB7F 1 ; Sign-extend $0506,X, multiply it by four, and store the result in
00CB7F 1 ; $0500,X/$0501,X.
00CB7F 1 ; ----------------------------------------------------------------------------
00CB7F 1
00CB7F 1 BD 06 05 lda $0506,x ; $CB7F: BD 06 05
00CB82 1 48 pha ; $CB82: 48
00CB83 1
00CB83 1 10 01 bpl Routine_CB86_FirstPositive
00CB85 1 ; $CB83: 10 01
00CB85 1
00CB85 1 88 dey ; $CB85: 88
00CB86 1 ; Y = $FF for a negative input.
00CB86 1
00CB86 1 Routine_CB86_FirstPositive: ; $CB86
00CB86 1 98 tya ; $CB86: 98
00CB87 1 9D 01 05 sta $0501,x ; $CB87: 9D 01 05
00CB8A 1
00CB8A 1 68 pla ; $CB8A: 68
00CB8B 1
00CB8B 1 0A asl ; $CB8B: 0A
00CB8C 1 3E 01 05 rol $0501,x ; $CB8C: 3E 01 05
00CB8F 1
00CB8F 1 0A asl ; $CB8F: 0A
00CB90 1 3E 01 05 rol $0501,x ; $CB90: 3E 01 05
00CB93 1
00CB93 1 9D 00 05 sta $0500,x ; $CB93: 9D 00 05
00CB96 1
00CB96 1 ; ----------------------------------------------------------------------------
00CB96 1 ; Sign-extend and scale $0507,X/$0508,X.
00CB96 1 ;
00CB96 1 ; The low byte is initially shifted into $05. The high byte and temporary
00CB96 1 ; value are then rotated to form the output at $0504,X/$0505,X.
00CB96 1 ; ----------------------------------------------------------------------------
00CB96 1
00CB96 1 A0 00 ldy #$00 ; $CB96: A0 00
00CB98 1
00CB98 1 BD 07 05 lda $0507,x ; $CB98: BD 07 05
00CB9B 1 0A asl ; $CB9B: 0A
00CB9C 1 85 05 sta MathTemp05 ; $CB9C: 85 05
00CB9E 1
00CB9E 1 BD 08 05 lda $0508,x ; $CB9E: BD 08 05
00CBA1 1 48 pha ; $CBA1: 48
00CBA2 1
00CBA2 1 10 01 bpl Routine_CBA5_SecondPositive
00CBA4 1 ; $CBA2: 10 01
00CBA4 1
00CBA4 1 88 dey ; $CBA4: 88
00CBA5 1 ; Y = $FF for a negative input.
00CBA5 1
00CBA5 1 Routine_CBA5_SecondPositive: ; $CBA5
00CBA5 1 98 tya ; $CBA5: 98
00CBA6 1 9D 05 05 sta $0505,x ; $CBA6: 9D 05 05
00CBA9 1
00CBA9 1 68 pla ; $CBA9: 68
00CBAA 1
00CBAA 1 2A rol ; $CBAA: 2A
00CBAB 1 3E 05 05 rol $0505,x ; $CBAB: 3E 05 05
00CBAE 1
00CBAE 1 06 05 asl MathTemp05 ; $CBAE: 06 05
00CBB0 1
00CBB0 1 2A rol ; $CBB0: 2A
00CBB1 1 3E 05 05 rol $0505,x ; $CBB1: 3E 05 05
00CBB4 1
00CBB4 1 9D 04 05 sta $0504,x ; $CBB4: 9D 04 05
00CBB7 1
00CBB7 1 ; ----------------------------------------------------------------------------
00CBB7 1 ; Copy the source position into the working position.
00CBB7 1 ; ----------------------------------------------------------------------------
00CBB7 1
00CBB7 1 BD 09 05 lda $0509,x ; $CBB7: BD 09 05
00CBBA 1 9D 02 05 sta $0502,x ; $CBBA: 9D 02 05
00CBBD 1
00CBBD 1 BD 0A 05 lda $050A,x ; $CBBD: BD 0A 05
00CBC0 1 9D 03 05 sta $0503,x ; $CBC0: 9D 03 05
00CBC3 1
00CBC3 1 60 rts ; $CBC3: 60
00CBC4 1
00CBC4 1 ; ============================================================================
00CBC4 1 ; $CBC4-$CBE9
00CBC4 1 ; Update one fixed-point object record.
00CBC4 1 ;
00CBC4 1 ; Entry:
00CBC4 1 ; X = object-record offset
00CBC4 1 ;
00CBC4 1 ; Operation:
00CBC4 1 ; velocity += acceleration
00CBC4 1 ; position += velocity
00CBC4 1 ;
00CBC4 1 ; The final A value is the updated position high byte, so callers can test its
00CBC4 1 ; sign immediately after return.
00CBC4 1 ; ============================================================================
00CBC4 1
00CBC4 1 IntegrateFixedPointObject: ; $CBC4
00CBC4 1 18 clc ; $CBC4: 18
00CBC5 1
00CBC5 1 ; ----------------------------------------------------------------------------
00CBC5 1 ; Add acceleration $0500/$0501 to velocity $0504/$0505.
00CBC5 1 ; ----------------------------------------------------------------------------
00CBC5 1
00CBC5 1 BD 00 05 lda $0500,x ; $CBC5: BD 00 05
00CBC8 1 7D 04 05 adc $0504,x ; $CBC8: 7D 04 05
00CBCB 1 9D 04 05 sta $0504,x ; $CBCB: 9D 04 05
00CBCE 1
00CBCE 1 BD 01 05 lda $0501,x ; $CBCE: BD 01 05
00CBD1 1 7D 05 05 adc $0505,x ; $CBD1: 7D 05 05
00CBD4 1 9D 05 05 sta $0505,x ; $CBD4: 9D 05 05
00CBD7 1
00CBD7 1 A8 tay ; $CBD7: A8
00CBD8 1 ; Preserve the updated velocity high byte.
00CBD8 1
00CBD8 1 ; ----------------------------------------------------------------------------
00CBD8 1 ; Add velocity $0504/$0505 to position $0502/$0503.
00CBD8 1 ; ----------------------------------------------------------------------------
00CBD8 1
00CBD8 1 18 clc ; $CBD8: 18
00CBD9 1
00CBD9 1 BD 04 05 lda $0504,x ; $CBD9: BD 04 05
00CBDC 1 7D 02 05 adc $0502,x ; $CBDC: 7D 02 05
00CBDF 1 9D 02 05 sta $0502,x ; $CBDF: 9D 02 05
00CBE2 1
00CBE2 1 98 tya ; $CBE2: 98
00CBE3 1
00CBE3 1 7D 03 05 adc $0503,x ; $CBE3: 7D 03 05
00CBE6 1 9D 03 05 sta $0503,x ; $CBE6: 9D 03 05
00CBE9 1
00CBE9 1 60 rts ; $CBE9: 60
00CBEA 1
00CBEA 1 ; ============================================================================
00CBEA 1 ; $CBEA-$CC00
00CBEA 1 ; Geometry/collision test helper
00CBEA 1 ;
00CBEA 1 ; Entry points:
00CBEA 1 ; $CBEA loads X from $E1.
00CBEA 1 ; $CBEC uses the X value supplied by the caller.
00CBEA 1 ; ============================================================================
00CBEA 1
00CBEA 1 ; ----------------------------------------------------------------------------
00CBEA 1 ; Contract:
00CBEA 1 ; Description: Implements Test Current Object Collision.
00CBEA 1 ; Entry: Registers: A; Memory: $e1
00CBEA 1 ; Returns/products: Registers/clobbers: A, X
00CBEA 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00CBEA 1 ; Memory effects: $b2, $b3, $b4, $b5
00CBEA 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00CBEA 1 ; comparison, load, or store path and are not a stable API product.
00CBEA 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 2.
00CBEA 1 ; ----------------------------------------------------------------------------
00CBEA 1 TestCurrentObjectCollision: ; $CBEA
00CBEA 1 A6 E1 ldx CurrentObjectIndex ; $CBEA: A6 E1
00CBEC 1
00CBEC 1 ; ----------------------------------------------------------------------------
00CBEC 1 ; Contract:
00CBEC 1 ; Description: Implements Test Object Collision.
00CBEC 1 ; Entry: Registers: A
00CBEC 1 ; Returns/products: Registers/clobbers: A
00CBEC 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00CBEC 1 ; Memory effects: $b2, $b3, $b4, $b5
00CBEC 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00CBEC 1 ; comparison, load, or store path and are not a stable API product.
00CBEC 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 2.
00CBEC 1 ; ----------------------------------------------------------------------------
00CBEC 1 TestObjectCollision: ; $CBEC
00CBEC 1 A9 00 lda #$00 ; $CBEC: A9 00
00CBEE 1
00CBEE 1 85 B2 sta $B2 ; $CBEE: 85 B2
00CBF0 1 85 B3 sta $B3 ; $CBF0: 85 B3
00CBF2 1 85 B4 sta $B4 ; $CBF2: 85 B4
00CBF4 1
00CBF4 1 A9 07 lda #$07 ; $CBF4: A9 07
00CBF6 1 85 B5 sta $B5 ; $CBF6: 85 B5
00CBF8 1
00CBF8 1 20 DD E4 jsr CalculateGeometryDifference ; $CBF8: 20 DD E4
00CBFB 1 20 02 E5 jsr EvaluateGeometryDifference ; $CBFB: 20 02 E5
00CBFE 1
00CBFE 1 C9 42 cmp #$42 ; $CBFE: C9 42
00CC00 1 60 rts ; $CC00: 60
00CC01 1
00CC01 1 ; ============================================================================
00CC01 1 ; $CC01-$CC3B
00CC01 1 ; Advance state $63, update display/event slots, and initialize the next
00CC01 1 ; state-dependent object or animation.
00CC01 1 ; ============================================================================
00CC01 1
00CC01 1 ; ----------------------------------------------------------------------------
00CC01 1 ; Contract:
00CC01 1 ; Description: Implements Advance Primary State Sequence.
00CC01 1 ; Entry: Registers: A; Memory: transitionsequencestate, $0596
00CC01 1 ; Returns/products: Registers/clobbers: A, Y; Flags: condition flags may carry result state
00CC01 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00CC01 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00CC01 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00CC01 1 ; comparison, load, or store path and are not a stable API product.
00CC01 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00CC01 1 ; ----------------------------------------------------------------------------
00CC01 1 AdvancePrimaryStateSequence: ; $CC01
00CC01 1 E6 63 inc TransitionSequenceState ; $CC01: E6 63
00CC03 1
00CC03 1 A5 63 lda TransitionSequenceState ; $CC03: A5 63
00CC05 1 C9 04 cmp #$04 ; $CC05: C9 04
00CC07 1 90 17 bcc HandleEarlyPrimaryState
00CC09 1 ; $CC07: 90 17
00CC09 1
00CC09 1 ; ----------------------------------------------------------------------------
00CC09 1 ; State $63 is four or greater.
00CC09 1 ;
00CC09 1 ; Process event slots $0F and $0D, execute an inline command, then call the
00CC09 1 ; helper at $CF4A. A delay/count value of $1E is selected.
00CC09 1 ; ----------------------------------------------------------------------------
00CC09 1
00CC09 1 A0 0F ldy #$0F ; $CC09: A0 0F
00CC0B 1 20 66 EB jsr DispatchNextQueuedEvent ; $CC0B: 20 66 EB
00CC0E 1
00CC0E 1 A0 0D ldy #$0D ; $CC0E: A0 0D
00CC10 1 20 66 EB jsr DispatchNextQueuedEvent ; $CC10: 20 66 EB
00CC13 1
00CC13 1 20 0A EB jsr QueueInlineObjectEvent ; $CC13: 20 0A EB
00CC16 1
00CC16 1 ; Inline command record consumed by QueueInlineObjectEvent.
00CC16 1 06 ED D9 .byte $06,$ED,$D9 ; $CC16-$CC18
00CC19 1
00CC19 1 20 4A CF jsr ClearPrimaryStateField ; $CC19: 20 4A CF
00CC1C 1
00CC1C 1 A9 1E lda #$1E ; $CC1C: A9 1E
00CC1E 1 D0 0A bne QueuePrimaryStateEvent ; $CC1E: D0 0A
00CC20 1 ; Always taken because A is nonzero.
00CC20 1
00CC20 1 ; ----------------------------------------------------------------------------
00CC20 1 ; State $63 is below four.
00CC20 1 ;
00CC20 1 ; Pass A = $63 + 2 to $CF2F, then select a value of $18.
00CC20 1 ; ----------------------------------------------------------------------------
00CC20 1
00CC20 1 HandleEarlyPrimaryState: ; $CC20
00CC20 1 18 clc ; $CC20: 18
00CC21 1
00CC21 1 A5 63 lda TransitionSequenceState ; $CC21: A5 63
00CC23 1 69 02 adc #$02 ; $CC23: 69 02
00CC25 1
00CC25 1 20 2F CF jsr BuildStateMarkerEntries ; $CC25: 20 2F CF
00CC28 1
00CC28 1 A9 18 lda #$18 ; $CC28: A9 18
00CC2A 1
00CC2A 1 ; ----------------------------------------------------------------------------
00CC2A 1 ; Pass the selected value, either $18 or $1E, to $CF11.
00CC2A 1 ; ----------------------------------------------------------------------------
00CC2A 1
00CC2A 1 QueuePrimaryStateEvent: ; $CC2A
00CC2A 1 20 11 CF jsr AddTimedStateEvent ; $CC2A: 20 11 CF
00CC2D 1
00CC2D 1 ; ----------------------------------------------------------------------------
00CC2D 1 ; Perform a one-time inline command when $0596 is zero.
00CC2D 1 ; ----------------------------------------------------------------------------
00CC2D 1
00CC2D 1 AD 96 05 lda $0596 ; $CC2D: AD 96 05
00CC30 1 D0 09 bne Routine_CC3B_Return ; $CC30: D0 09
00CC32 1
00CC32 1 EE 96 05 inc $0596 ; $CC32: EE 96 05
00CC35 1
00CC35 1 20 0A EB jsr QueueInlineObjectEvent ; $CC35: 20 0A EB
00CC38 1
00CC38 1 ; Inline command record consumed by QueueInlineObjectEvent.
00CC38 1 28 3B CC .byte $28,$3B,$CC ; $CC38-$CC3A
00CC3B 1
00CC3B 1 Routine_CC3B_Return: ; $CC3B
00CC3B 1 60 rts ; $CC3B: 60
00CC3C 1
00CC3C 1 ; ============================================================================
00CC3C 1 ; $CC3C-$CC4C
00CC3C 1 ; Timed state transition.
00CC3C 1 ;
00CC3C 1 ; Increment $03B1, wait for $3C ticks, restore $03B1, clear the one-time flag,
00CC3C 1 ; and leave through the common engine exit.
00CC3C 1 ; ============================================================================
00CC3C 1
00CC3C 1 RunPrimaryStateDelay: ; $CC3C
00CC3C 1 EE B1 03 inc $03B1 ; $CC3C: EE B1 03
00CC3F 1
00CC3F 1 A9 3C lda #$3C ; $CC3F: A9 3C
00CC41 1 20 41 EB jsr StoreObjectEventBankValue ; $CC41: 20 41 EB
00CC44 1
00CC44 1 CE B1 03 dec $03B1 ; $CC44: CE B1 03
00CC47 1 CE 96 05 dec $0596 ; $CC47: CE 96 05
00CC4A 1
00CC4A 1 4C 6A EB jmp CommonEngineExit ; $CC4A: 4C 6A EB
00CC4D 1
00CC4D 1 ; ============================================================================
00CC4D 1 ; $CC4D-$CC79
00CC4D 1 ; Advance state $62, update an indexed animation value, wait, restore it,
00CC4D 1 ; and leave through the common engine exit.
00CC4D 1 ; ============================================================================
00CC4D 1
00CC4D 1 AdvanceSecondaryStateSequence: ; $CC4D
00CC4D 1 A5 62 lda PrimarySequenceState ; $CC4D: A5 62
00CC4F 1 C9 02 cmp #$02 ; $CC4F: C9 02
00CC51 1 B0 05 bcs QueueSecondaryStateEvent ; $CC51: B0 05
00CC53 1
00CC53 1 ; ----------------------------------------------------------------------------
00CC53 1 ; Advance $62 while it is below two and run the associated setup helper.
00CC53 1 ; ----------------------------------------------------------------------------
00CC53 1
00CC53 1 E6 62 inc PrimarySequenceState ; $CC53: E6 62
00CC55 1 20 23 CF jsr QueuePrimaryStateMarker ; $CC55: 20 23 CF
00CC58 1
00CC58 1 ; ----------------------------------------------------------------------------
00CC58 1 ; Pass state value $06 to the helper at $CF11.
00CC58 1 ; ----------------------------------------------------------------------------
00CC58 1
00CC58 1 QueueSecondaryStateEvent: ; $CC58
00CC58 1 A9 06 lda #$06 ; $CC58: A9 06
00CC5A 1 20 11 CF jsr AddTimedStateEvent ; $CC5A: 20 11 CF
00CC5D 1
00CC5D 1 ; ----------------------------------------------------------------------------
00CC5D 1 ; Convert the current object index in $E1 to the corresponding animation-table
00CC5D 1 ; index, then increment $039A,X.
00CC5D 1 ; ----------------------------------------------------------------------------
00CC5D 1
00CC5D 1 A6 E1 ldx CurrentObjectIndex ; $CC5D: A6 E1
00CC5F 1 20 38 E7 jsr ConvertObjectOffsetToDisplayIndex ; $CC5F: 20 38 E7
00CC62 1
00CC62 1 FE 9A 03 inc $039A,x ; $CC62: FE 9A 03
00CC65 1
00CC65 1 ; ----------------------------------------------------------------------------
00CC65 1 ; Wait for $5A ticks.
00CC65 1 ; ----------------------------------------------------------------------------
00CC65 1
00CC65 1 A9 5A lda #$5A ; $CC65: A9 5A
00CC67 1 20 41 EB jsr StoreObjectEventBankValue ; $CC67: 20 41 EB
00CC6A 1
00CC6A 1 ; ----------------------------------------------------------------------------
00CC6A 1 ; Recalculate the animation-table index and restore $039A,X.
00CC6A 1 ; ----------------------------------------------------------------------------
00CC6A 1
00CC6A 1 A6 E1 ldx CurrentObjectIndex ; $CC6A: A6 E1
00CC6C 1 20 38 E7 jsr ConvertObjectOffsetToDisplayIndex ; $CC6C: 20 38 E7
00CC6F 1
00CC6F 1 DE 9A 03 dec $039A,x ; $CC6F: DE 9A 03
00CC72 1
00CC72 1 ; ----------------------------------------------------------------------------
00CC72 1 ; Process command $08 and leave through the common engine exit.
00CC72 1 ; ----------------------------------------------------------------------------
00CC72 1
00CC72 1 A2 08 ldx #$08 ; $CC72: A2 08
00CC74 1 20 2A EB jsr ProcessQueuedObjectEvent ; $CC74: 20 2A EB
00CC77 1
00CC77 1 4C 6A EB jmp CommonEngineExit ; $CC77: 4C 6A EB
00CC7A 1
00CC7A 1 ; ============================================================================
00CC7A 1 ; $CC7A-$CCB8
00CC7A 1 ; Advance states PrimarySequenceState and $64, run state-specific setup, and dispatch a
00CC7A 1 ; one-time inline command.
00CC7A 1 ; ============================================================================
00CC7A 1
00CC7A 1 AdvanceDualStateSequence: ; $CC7A
00CC7A 1 A9 0C lda #$0C ; $CC7A: A9 0C
00CC7C 1 20 11 CF jsr AddTimedStateEvent ; $CC7C: 20 11 CF
00CC7F 1
00CC7F 1 E6 62 inc PrimarySequenceState ; $CC7F: E6 62
00CC81 1 20 23 CF jsr QueuePrimaryStateMarker ; $CC81: 20 23 CF
00CC84 1
00CC84 1 A5 62 lda PrimarySequenceState ; $CC84: A5 62
00CC86 1 C9 03 cmp #$03 ; $CC86: C9 03
00CC88 1 90 20 bcc Routine_CCAA_OneTimeCommand
00CC8A 1 ; $CC88: 90 20
00CC8A 1 ; ----------------------------------------------------------------------------
00CC8A 1 ; PrimarySequenceState has reached three.
00CC8A 1 ; ----------------------------------------------------------------------------
00CC8A 1
00CC8A 1 A9 12 lda #$12 ; $CC8A: A9 12
00CC8C 1 20 11 CF jsr AddTimedStateEvent ; $CC8C: 20 11 CF
00CC8F 1
00CC8F 1 20 4A CF jsr ClearPrimaryStateField ; $CC8F: 20 4A CF
00CC92 1
00CC92 1 E6 64 inc SecondarySequenceState ; $CC92: E6 64
00CC94 1 20 2A CF jsr QueueSecondaryStateMarker ; $CC94: 20 2A CF
00CC97 1
00CC97 1 A5 64 lda SecondarySequenceState ; $CC97: A5 64
00CC99 1 C9 03 cmp #$03 ; $CC99: C9 03
00CC9B 1 90 0D bcc Routine_CCAA_OneTimeCommand
00CC9D 1 ; $CC9B: 90 0D
00CC9D 1
00CC9D 1 ; ----------------------------------------------------------------------------
00CC9D 1 ; Both state counters have reached their thresholds.
00CC9D 1 ; ----------------------------------------------------------------------------
00CC9D 1
00CC9D 1 A9 43 lda #$43 ; $CC9D: A9 43
00CC9F 1 20 51 CF jsr ClearStateFieldPair ; $CC9F: 20 51 CF
00CCA2 1
00CCA2 1 A9 3C lda #$3C ; $CCA2: A9 3C
00CCA4 1 20 11 CF jsr AddTimedStateEvent ; $CCA4: 20 11 CF
00CCA7 1
00CCA7 1 20 22 CE jsr FinishStateProgression ; $CCA7: 20 22 CE
00CCAA 1
00CCAA 1 ; ----------------------------------------------------------------------------
00CCAA 1 ; Execute this inline command once while $0596 is zero.
00CCAA 1 ; ----------------------------------------------------------------------------
00CCAA 1
00CCAA 1 Routine_CCAA_OneTimeCommand: ; $CCAA
00CCAA 1 AD 96 05 lda $0596 ; $CCAA: AD 96 05
00CCAD 1 D0 09 bne Routine_CCB8_Return ; $CCAD: D0 09
00CCAF 1
00CCAF 1 EE 96 05 inc $0596 ; $CCAF: EE 96 05
00CCB2 1
00CCB2 1 20 0A EB jsr QueueInlineObjectEvent ; $CCB2: 20 0A EB
00CCB5 1
00CCB5 1 ; Inline command record consumed by QueueInlineObjectEvent.
00CCB5 1 28 B8 CC .byte $28,$B8,$CC ; $CCB5-$CCB7
00CCB8 1
00CCB8 1 Routine_CCB8_Return: ; $CCB8
00CCB8 1 60 rts ; $CCB8: 60
00CCB9 1
00CCB9 1 ; ============================================================================
00CCB9 1 ; $CCB9-$CCE3
00CCB9 1 ; Timed animation/state sequence.
00CCB9 1 ;
00CCB9 1 ; $03B1 is decremented twice, incremented once, then decremented again with
00CCB9 1 ; delays between each change. It is finally set to $47.
00CCB9 1 ; ============================================================================
00CCB9 1
00CCB9 1 RunDualStateAnimation: ; $CCB9
00CCB9 1 CE B1 03 dec $03B1 ; $CCB9: CE B1 03
00CCBC 1
00CCBC 1 A9 14 lda #$14 ; $CCBC: A9 14
00CCBE 1 20 41 EB jsr StoreObjectEventBankValue ; $CCBE: 20 41 EB
00CCC1 1
00CCC1 1 CE B1 03 dec $03B1 ; $CCC1: CE B1 03
00CCC4 1
00CCC4 1 A9 14 lda #$14 ; $CCC4: A9 14
00CCC6 1 20 41 EB jsr StoreObjectEventBankValue ; $CCC6: 20 41 EB
00CCC9 1
00CCC9 1 ; ----------------------------------------------------------------------------
00CCC9 1 ; Secondary entry point referenced by the inline command at $CCB5.
00CCC9 1 ; ----------------------------------------------------------------------------
00CCC9 1
00CCC9 1 RunDualStateAnimationTail: ; $CCC9
00CCC9 1 EE B1 03 inc $03B1 ; $CCC9: EE B1 03
00CCCC 1
00CCCC 1 A9 14 lda #$14 ; $CCCC: A9 14
00CCCE 1 20 41 EB jsr StoreObjectEventBankValue ; $CCCE: 20 41 EB
00CCD1 1
00CCD1 1 CE B1 03 dec $03B1 ; $CCD1: CE B1 03
00CCD4 1
00CCD4 1 A9 3C lda #$3C ; $CCD4: A9 3C
00CCD6 1 20 41 EB jsr StoreObjectEventBankValue ; $CCD6: 20 41 EB
00CCD9 1
00CCD9 1 A9 47 lda #$47 ; $CCD9: A9 47
00CCDB 1 8D B1 03 sta $03B1 ; $CCDB: 8D B1 03
00CCDE 1
00CCDE 1 CE 96 05 dec $0596 ; $CCDE: CE 96 05
00CCE1 1
00CCE1 1 4C 6A EB jmp CommonEngineExit ; $CCE1: 4C 6A EB
00CCE4 1
00CCE4 1 ; ============================================================================
00CCE4 1 ; $CCE4-$CD17
00CCE4 1 ; Alternate state transition entered from $CB1B.
00CCE4 1 ; ============================================================================
00CCE4 1
00CCE4 1 AdvanceAlternateStateSequence: ; $CCE4
00CCE4 1 E6 64 inc SecondarySequenceState ; $CCE4: E6 64
00CCE6 1
00CCE6 1 20 2A CF jsr QueueSecondaryStateMarker ; $CCE6: 20 2A CF
00CCE9 1
00CCE9 1 A9 12 lda #$12 ; $CCE9: A9 12
00CCEB 1 20 11 CF jsr AddTimedStateEvent ; $CCEB: 20 11 CF
00CCEE 1
00CCEE 1 A5 64 lda SecondarySequenceState ; $CCEE: A5 64
00CCF0 1 C9 03 cmp #$03 ; $CCF0: C9 03
00CCF2 1 90 0E bcc Routine_CD02_OptionalSetup
00CCF4 1 ; $CCF2: 90 0E
00CCF4 1
00CCF4 1 ; ----------------------------------------------------------------------------
00CCF4 1 ; State $64 has reached three.
00CCF4 1 ; ----------------------------------------------------------------------------
00CCF4 1
00CCF4 1 A9 3C lda #$3C ; $CCF4: A9 3C
00CCF6 1 20 11 CF jsr AddTimedStateEvent ; $CCF6: 20 11 CF
00CCF9 1
00CCF9 1 20 22 CE jsr FinishStateProgression ; $CCF9: 20 22 CE
00CCFC 1 20 45 CF jsr ClearBothStateFields ; $CCFC: 20 45 CF
00CCFF 1
00CCFF 1 4C 09 CD jmp Routine_CD09_OneTimeCommand
00CD02 1 ; $CCFF: 4C 09 CD
00CD02 1
00CD02 1 ; ----------------------------------------------------------------------------
00CD02 1 ; Run $CF4A only when $46 is nonzero.
00CD02 1 ; ----------------------------------------------------------------------------
00CD02 1
00CD02 1 Routine_CD02_OptionalSetup: ; $CD02
00CD02 1 A5 46 lda StateSequenceActive ; $CD02: A5 46
00CD04 1 F0 03 beq Routine_CD09_OneTimeCommand
00CD06 1 ; $CD04: F0 03
00CD06 1
00CD06 1 20 4A CF jsr ClearPrimaryStateField ; $CD06: 20 4A CF
00CD09 1
00CD09 1 ; ----------------------------------------------------------------------------
00CD09 1 ; Execute a second one-time inline command.
00CD09 1 ; ----------------------------------------------------------------------------
00CD09 1
00CD09 1 Routine_CD09_OneTimeCommand: ; $CD09
00CD09 1 AD 96 05 lda $0596 ; $CD09: AD 96 05
00CD0C 1 D0 09 bne Routine_CD17_Return ; $CD0C: D0 09
00CD0E 1
00CD0E 1 EE 96 05 inc $0596 ; $CD0E: EE 96 05
00CD11 1
00CD11 1 20 0A EB jsr QueueInlineObjectEvent ; $CD11: 20 0A EB
00CD14 1
00CD14 1 ; Inline command record consumed by QueueInlineObjectEvent.
00CD14 1 28 17 CD .byte $28,$17,$CD ; $CD14-$CD16
00CD17 1
00CD17 1 Routine_CD17_Return: ; $CD17
00CD17 1 60 rts ; $CD17: 60
00CD18 1
00CD18 1 ; ============================================================================
00CD18 1 ; $CD18-$CD21
00CD18 1 ; Select a state path using $72.
00CD18 1 ; ============================================================================
00CD18 1
00CD18 1 DispatchStateSelectorAnimation: ; $CD18
00CD18 1 A6 72 ldx StateSelector ; $CD18: A6 72
00CD1A 1
00CD1A 1 E0 04 cpx #$04 ; $CD1A: E0 04
00CD1C 1 F0 9B beq RunDualStateAnimation ; $CD1C: F0 9B
00CD1E 1 ; Branches backward to the timed sequence.
00CD1E 1
00CD1E 1 A0 4A ldy #$4A ; $CD1E: A0 4A
00CD20 1 D0 2F bne StoreStateAnimationParameters ; $CD20: D0 2F
00CD22 1 ; Always taken because Y is nonzero.
00CD22 1
00CD22 1 ; ============================================================================
00CD22 1 ; $CD22-$CD2D
00CD22 1 ; Four parallel three-entry tables.
00CD22 1 ;
00CD22 1 ; X is expected to contain a value from $00-$02 when these tables are used by
00CD22 1 ; the routine beginning at $CD42.
00CD22 1 ; ============================================================================
00CD22 1
00CD22 1 StateHorizontalLowTable: ; $CD22
00CD22 1 00 80 00 .byte $00,$80,$00
00CD25 1
00CD25 1 StateHorizontalHighTable: ; $CD25
00CD25 1 09 FF F7 .byte $09,$FF,$F7
00CD28 1
00CD28 1 StateVerticalLowTable: ; $CD28
00CD28 1 00 00 00 .byte $00,$00,$00
00CD2B 1
00CD2B 1 StateVerticalHighTable: ; $CD2B
00CD2B 1 02 0A 02 .byte $02,$0A,$02
00CD2E 1
00CD2E 1 ; ============================================================================
00CD2E 1 ; $CD2E-$CD41
00CD2E 1 ; Run state $42 and dispatch a one-time inline command.
00CD2E 1 ; ============================================================================
00CD2E 1
00CD2E 1 ; ----------------------------------------------------------------------------
00CD2E 1 ; Contract:
00CD2E 1 ; Description: Queues Selected State Marker.
00CD2E 1 ; Entry: Memory: $0596
00CD2E 1 ; Returns/products: Registers/clobbers: A
00CD2E 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00CD2E 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00CD2E 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00CD2E 1 ; comparison, load, or store path and are not a stable API product.
00CD2E 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00CD2E 1 ; ----------------------------------------------------------------------------
00CD2E 1 QueueSelectedStateMarker: ; $CD2E
00CD2E 1 A9 42 lda #$42 ; $CD2E: A9 42
00CD30 1 20 11 CF jsr AddTimedStateEvent ; $CD30: 20 11 CF
00CD33 1
00CD33 1 AD 96 05 lda $0596 ; $CD33: AD 96 05
00CD36 1 D0 09 bne Routine_CD41_Return ; $CD36: D0 09
00CD38 1
00CD38 1 EE 96 05 inc $0596 ; $CD38: EE 96 05
00CD3B 1
00CD3B 1 20 0A EB jsr QueueInlineObjectEvent ; $CD3B: 20 0A EB
00CD3E 1
00CD3E 1 ; Inline command record consumed by QueueInlineObjectEvent.
00CD3E 1 28 41 CD .byte $28,$41,$CD ; $CD3E-$CD40
00CD41 1
00CD41 1 Routine_CD41_Return: ; $CD41
00CD41 1 60 rts ; $CD41: 60
00CD42 1
00CD42 1 ; ============================================================================
00CD42 1 ; $CD42-$CD97
00CD42 1 ; Configure fields from the tables above, play a timed animation sequence,
00CD42 1 ; then restore state and leave through the common engine exit.
00CD42 1 ; ============================================================================
00CD42 1
00CD42 1 RunSelectedStateAnimation: ; $CD42
00CD42 1 A6 72 ldx StateSelector ; $CD42: A6 72
00CD44 1
00CD44 1 E0 04 cpx #$04 ; $CD44: E0 04
00CD46 1 D0 07 bne LoadStateAnimationParameters ; $CD46: D0 07
00CD48 1
00CD48 1 ; ----------------------------------------------------------------------------
00CD48 1 ; Special path for state four.
00CD48 1 ; ----------------------------------------------------------------------------
00CD48 1
00CD48 1 A9 49 lda #$49 ; $CD48: A9 49
00CD4A 1 8D B1 03 sta $03B1 ; $CD4A: 8D B1 03
00CD4D 1
00CD4D 1 D0 2C bne WaitForStateAnimation ; $CD4D: D0 2C
00CD4F 1 ; Always taken because A is nonzero.
00CD4F 1
00CD4F 1 ; ----------------------------------------------------------------------------
00CD4F 1 ; Table-driven path for states zero through two.
00CD4F 1 ;
00CD4F 1 ; Y begins at $4C and is stored into $03B1.
00CD4F 1 ; ----------------------------------------------------------------------------
00CD4F 1
00CD4F 1 LoadStateAnimationParameters: ; $CD4F
00CD4F 1 A0 4C ldy #$4C ; $CD4F: A0 4C
00CD51 1
00CD51 1
00CD51 1 StoreStateAnimationParameters: ; $CD51
00CD51 1 8C B1 03 sty $03B1 ; $CD51: 8C B1 03
00CD54 1
00CD54 1 BD 21 CD lda $CD21,x ; $CD54: BD 21 CD
00CD57 1 8D 0B 05 sta $050B ; $CD57: 8D 0B 05
00CD5A 1
00CD5A 1 BD 24 CD lda $CD24,x ; $CD5A: BD 24 CD
00CD5D 1 8D 0C 05 sta $050C ; $CD5D: 8D 0C 05
00CD60 1
00CD60 1 BD 27 CD lda $CD27,x ; $CD60: BD 27 CD
00CD63 1 8D 3C 05 sta $053C ; $CD63: 8D 3C 05
00CD66 1
00CD66 1 BD 2A CD lda $CD2A,x ; $CD66: BD 2A CD
00CD69 1 8D 3D 05 sta $053D ; $CD69: 8D 3D 05
00CD6C 1 ; ----------------------------------------------------------------------------
00CD6C 1 ; Run the indexed helper and wait for $60 ticks.
00CD6C 1 ; ----------------------------------------------------------------------------
00CD6C 1
00CD6C 1 A2 02 ldx #$02 ; $CD6C: A2 02
00CD6E 1 20 B7 E6 jsr ClearMovementTransforms ; $CD6E: 20 B7 E6
00CD71 1
00CD71 1 A9 60 lda #$60 ; $CD71: A9 60
00CD73 1 20 41 EB jsr StoreObjectEventBankValue ; $CD73: 20 41 EB
00CD76 1
00CD76 1 A9 4B lda #$4B ; $CD76: A9 4B
00CD78 1 8D B1 03 sta $03B1 ; $CD78: 8D B1 03
00CD7B 1
00CD7B 1 ; ----------------------------------------------------------------------------
00CD7B 1 ; Wait for $3C ticks.
00CD7B 1 ; ----------------------------------------------------------------------------
00CD7B 1
00CD7B 1 WaitForStateAnimation: ; $CD7B
00CD7B 1 A9 3C lda #$3C ; $CD7B: A9 3C
00CD7D 1 20 41 EB jsr StoreObjectEventBankValue ; $CD7D: 20 41 EB
00CD80 1
00CD80 1 ; ----------------------------------------------------------------------------
00CD80 1 ; Initialize indexed fields using inline data consumed by $C9A7.
00CD80 1 ;
00CD80 1 ; The first inline byte, $02, is metadata consumed by the return-address
00CD80 1 ; helper. The following four bytes initialize the indexed fields:
00CD80 1 ;
00CD80 1 ; $00,$00,$C0,$F6
00CD80 1 ; ----------------------------------------------------------------------------
00CD80 1
00CD80 1 20 A7 C9 jsr LoadObjectPositionInline
00CD83 1 ; $CD80: 20 A7 C9
00CD83 1
00CD83 1 02 .byte $02 ; $CD83: inline metadata/count
00CD84 1 00 00 C0 F6 .byte $00,$00,$C0,$F6 ; $CD84-$CD87: field data
00CD88 1
00CD88 1 ; ----------------------------------------------------------------------------
00CD88 1 ; Run the indexed helper again and set the final animation/state value.
00CD88 1 ; ----------------------------------------------------------------------------
00CD88 1
00CD88 1 A2 02 ldx #$02 ; $CD88: A2 02
00CD8A 1 20 B7 E6 jsr ClearMovementTransforms ; $CD8A: 20 B7 E6
00CD8D 1
00CD8D 1 A9 47 lda #$47 ; $CD8D: A9 47
00CD8F 1 8D B1 03 sta $03B1 ; $CD8F: 8D B1 03
00CD92 1
00CD92 1 CE 96 05 dec $0596 ; $CD92: CE 96 05
00CD95 1
00CD95 1 4C 6A EB jmp CommonEngineExit ; $CD95: 4C 6A EB
00CD98 1
00CD98 1 ; ============================================================================
00CD98 1 ; $CD98-$CDA6
00CD98 1 ; Set state $6D to two, run state/action $2A, and leave through the common
00CD98 1 ; engine exit.
00CD98 1 ; ============================================================================
00CD98 1
00CD98 1 StartHomeRunSequence: ; $CD98
00CD98 1 A9 02 lda #$02 ; $CD98: A9 02
00CD9A 1 85 6D sta SpecialSequenceState ; $CD9A: 85 6D
00CD9C 1
00CD9C 1 A9 2A lda #$2A ; $CD9C: A9 2A
00CD9E 1 20 11 CF jsr AddTimedStateEvent ; $CD9E: 20 11 CF
00CDA1 1
00CDA1 1 4C 6A EB jmp CommonEngineExit ; $CDA1: 4C 6A EB
00CDA4 1
00CDA4 1 ; ============================================================================
00CDA4 1 ; $CDA4-$CE19
00CDA4 1 ; Initialize state $6D, run an animation sequence, draw an encoded message,
00CDA4 1 ; and repeatedly copy palette/data bytes into the PPU command queue.
00CDA4 1 ; ============================================================================
00CDA4 1
00CDA4 1 RunHomeRunCelebration: ; $CDA4
00CDA4 1 A9 01 lda #$01 ; $CDA4: A9 01
00CDA6 1 85 FD sta $FD ; $CDA6: 85 FD
00CDA8 1
00CDA8 1 A9 04 lda #$04 ; $CDA8: A9 04
00CDAA 1 85 6D sta SpecialSequenceState ; $CDAA: 85 6D
00CDAC 1
00CDAC 1 ; ----------------------------------------------------------------------------
00CDAC 1 ; Dispatch an inline command through QueueInlineObjectEvent.
00CDAC 1 ; ----------------------------------------------------------------------------
00CDAC 1
00CDAC 1 20 0A EB jsr QueueInlineObjectEvent ; $CDAC: 20 0A EB
00CDAF 1
00CDAF 1 ; Inline command record consumed by QueueInlineObjectEvent.
00CDAF 1 15 D8 CD .byte $15,$D8,$CD ; $CDAF-$CDB1
00CDB2 1
00CDB2 1 ; ----------------------------------------------------------------------------
00CDB2 1 ; Increment the current object's animation index twice.
00CDB2 1 ; ----------------------------------------------------------------------------
00CDB2 1
00CDB2 1 A6 E1 ldx CurrentObjectIndex ; $CDB2: A6 E1
00CDB4 1 20 38 E7 jsr ConvertObjectOffsetToDisplayIndex ; $CDB4: 20 38 E7
00CDB7 1
00CDB7 1 FE 9A 03 inc $039A,x ; $CDB7: FE 9A 03
00CDBA 1 FE 9A 03 inc $039A,x ; $CDBA: FE 9A 03
00CDBD 1
00CDBD 1 ; ----------------------------------------------------------------------------
00CDBD 1 ; Wait $14 ticks, increment the animation index once more, then wait again.
00CDBD 1 ; ----------------------------------------------------------------------------
00CDBD 1
00CDBD 1 HomeRunAnimationLoop: ; $CDBD
00CDBD 1 A9 14 lda #$14 ; $CDBD: A9 14
00CDBF 1 20 41 EB jsr StoreObjectEventBankValue ; $CDBF: 20 41 EB
00CDC2 1
00CDC2 1 A6 E1 ldx CurrentObjectIndex ; $CDC2: A6 E1
00CDC4 1 20 38 E7 jsr ConvertObjectOffsetToDisplayIndex ; $CDC4: 20 38 E7
00CDC7 1
00CDC7 1 FE 9A 03 inc $039A,x ; $CDC7: FE 9A 03
00CDCA 1
00CDCA 1 A9 14 lda #$14 ; $CDCA: A9 14
00CDCC 1 20 41 EB jsr StoreObjectEventBankValue ; $CDCC: 20 41 EB
00CDCF 1
00CDCF 1 ; ----------------------------------------------------------------------------
00CDCF 1 ; Decrement the animation index. Repeat while the result is nonzero.
00CDCF 1 ; ----------------------------------------------------------------------------
00CDCF 1
00CDCF 1 A6 E1 ldx CurrentObjectIndex ; $CDCF: A6 E1
00CDD1 1 20 38 E7 jsr ConvertObjectOffsetToDisplayIndex ; $CDD1: 20 38 E7
00CDD4 1
00CDD4 1 DE 9A 03 dec $039A,x ; $CDD4: DE 9A 03
00CDD7 1 D0 E4 bne HomeRunAnimationLoop
00CDD9 1 ; $CDD7: D0 E4
00CDD9 1
00CDD9 1 ; ----------------------------------------------------------------------------
00CDD9 1 ; Draw an eight-character encoded message.
00CDD9 1 ; ----------------------------------------------------------------------------
00CDD9 1
00CDD9 1 A9 20 lda #$20 ; $CDD9: A9 20
00CDDB 1 A2 EC ldx #$EC ; $CDDB: A2 EC
00CDDD 1 A0 08 ldy #$08 ; $CDDD: A0 08
00CDDF 1 18 clc ; $CDDF: 18
00CDE0 1
00CDE0 1 20 17 EA jsr CopyInlineDisplayRecord ; $CDE0: 20 17 EA
00CDE3 1
00CDE3 1 08 .byte $08 ; $CDE3: character count
00CDE4 1 11 18 16 0E .byte $11,$18,$16,$0E ; $CDE4-$CDE7
00CDE8 1 25 1B 1E 17 .byte $25,$1B,$1E,$17 ; $CDE8-$CDEB
00CDEC 1
00CDEC 1 ; ----------------------------------------------------------------------------
00CDEC 1 ; Set up the table-copy loop.
00CDEC 1 ; ----------------------------------------------------------------------------
00CDEC 1
00CDEC 1 ResetCelebrationColorIndex: ; $CDEC
00CDEC 1 A0 07 ldy #$07 ; $CDEC: A0 07
00CDEE 1
00CDEE 1 SaveCelebrationColorIndex: ; $CDEE
00CDEE 1 84 70 sty $70 ; $CDEE: 84 70
00CDF0 1
00CDF0 1 A9 06 lda #$06 ; $CDF0: A9 06
00CDF2 1 8D C6 05 sta $05C6 ; $CDF2: 8D C6 05
00CDF5 1
00CDF5 1 ; ----------------------------------------------------------------------------
00CDF5 1 ; Wait for six frames/ticks. Set bit 7 of $FE after each wait.
00CDF5 1 ; ----------------------------------------------------------------------------
00CDF5 1
00CDF5 1 WaitCelebrationColorFrame: ; $CDF5
00CDF5 1 20 48 EB jsr SelectObjectEventBank1 ; $CDF5: 20 48 EB
00CDF8 1
00CDF8 1 A5 FE lda PendingAudioFlags ; $CDF8: A5 FE
00CDFA 1 09 80 ora #$80 ; $CDFA: 09 80
00CDFC 1 85 FE sta PendingAudioFlags ; $CDFC: 85 FE
00CDFE 1
00CDFE 1 CE C6 05 dec $05C6 ; $CDFE: CE C6 05
00CE01 1 D0 F2 bne WaitCelebrationColorFrame ; $CE01: D0 F2
00CE03 1
00CE03 1 ; ----------------------------------------------------------------------------
00CE03 1 ; Start a one-byte PPU command.
00CE03 1 ; ----------------------------------------------------------------------------
00CE03 1
00CE03 1 A9 3F lda #$3F ; $CE03: A9 3F
00CE05 1 A2 07 ldx #$07 ; $CE05: A2 07
00CE07 1 A0 01 ldy #$01 ; $CE07: A0 01
00CE09 1 18 clc ; $CE09: 18
00CE0A 1
00CE0A 1 20 3E EA jsr AllocateDisplayBufferRecord ; $CE0A: 20 3E EA
00CE0D 1
00CE0D 1 ; ----------------------------------------------------------------------------
00CE0D 1 ; Append one byte from the table at $CE1A.
00CE0D 1 ; ----------------------------------------------------------------------------
00CE0D 1
00CE0D 1 A4 70 ldy TableCopyIndex ; $CE0D: A4 70
00CE0F 1
00CE0F 1 B9 1A CE lda CelebrationPaletteSequence,y ; $CE0F: B9 1A CE
00CE12 1 9D 00 03 sta $0300,x ; $CE12: 9D 00 03
00CE15 1
00CE15 1 88 dey ; $CE15: 88
00CE16 1 10 D6 bpl SaveCelebrationColorIndex ; $CE16: 10 D6
00CE18 1
00CE18 1 30 D2 bmi ResetCelebrationColorIndex
00CE1A 1 ; $CE18: 30 D2
00CE1A 1 ; Always taken after Y becomes negative.
00CE1A 1
00CE1A 1 ; ============================================================================
00CE1A 1 ; $CE1A-$CE21
00CE1A 1 ; Eight-byte lookup table used by the loop above.
00CE1A 1 ; ============================================================================
00CE1A 1
00CE1A 1 CelebrationPaletteSequence: ; $CE1A
00CE1A 1 30 21 33 24 .byte $30,$21,$33,$24
00CE1E 1 36 27 39 2A .byte $36,$27,$39,$2A
00CE22 1
00CE22 1 ; ============================================================================
00CE22 1 ; $CE22-$CE31
00CE22 1 ; Clear active state, advance $45, process event slot $11, then leave through
00CE22 1 ; command $08.
00CE22 1 ; ============================================================================
00CE22 1
00CE22 1 ; ----------------------------------------------------------------------------
00CE22 1 ; Contract:
00CE22 1 ; Description: Implements Finish State Progression.
00CE22 1 ; Entry: Registers: A
00CE22 1 ; Returns/products: Registers/clobbers: A, X, Y
00CE22 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00CE22 1 ; Memory effects: basemotionactive
00CE22 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00CE22 1 ; comparison, load, or store path and are not a stable API product.
00CE22 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 2.
00CE22 1 ; ----------------------------------------------------------------------------
00CE22 1 FinishStateProgression: ; $CE22
00CE22 1 A9 00 lda #$00 ; $CE22: A9 00
00CE24 1 85 5C sta BaseMotionActive ; $CE24: 85 5C
00CE26 1
00CE26 1 E6 45 inc MatchCompleteFlag ; $CE26: E6 45
00CE28 1
00CE28 1 A0 11 ldy #$11 ; $CE28: A0 11
00CE2A 1 20 66 EB jsr DispatchNextQueuedEvent ; $CE2A: 20 66 EB
00CE2D 1
00CE2D 1 A2 08 ldx #$08 ; $CE2D: A2 08
00CE2F 1 4C 2A EB jmp ProcessQueuedObjectEvent ; $CE2F: 4C 2A EB
00CE32 1
00CE32 1 ; ============================================================================
00CE32 1 ; $CE32-$CEA4
00CE32 1 ; Search a timing/state table, map selected values to flags, display the
00CE32 1 ; corresponding message, and loop until the state condition is complete.
00CE32 1 ; ============================================================================
00CE32 1
00CE32 1 RunEventAnnouncementLoop: ; $CE32
00CE32 1 A9 00 lda #$00 ; $CE32: A9 00
00CE34 1 85 6F sta PendingEvent ; $CE34: 85 6F
00CE36 1
00CE36 1 ReloadAnnouncementDelay: ; $CE36
00CE36 1 A9 01 lda #$01 ; $CE36: A9 01
00CE38 1
00CE38 1 WaitAnnouncementDelay: ; $CE38
00CE38 1 20 41 EB jsr StoreObjectEventBankValue ; $CE38: 20 41 EB
00CE3B 1
00CE3B 1 ; ----------------------------------------------------------------------------
00CE3B 1 ; Compare the current index in $6A with the limit in $69.
00CE3B 1 ; If equal, restart the search from its initial state.
00CE3B 1 ; ----------------------------------------------------------------------------
00CE3B 1
00CE3B 1 A6 6A ldx EventReadIndex ; $CE3B: A6 6A
00CE3D 1 E4 69 cpx EventWriteIndex ; $CE3D: E4 69
00CE3F 1 F0 F1 beq RunEventAnnouncementLoop ; $CE3F: F0 F1
00CE41 1
00CE41 1 CA dex ; $CE41: CA
00CE42 1 10 02 bpl FindReadyAnnouncement ; $CE42: 10 02
00CE44 1
00CE44 1 A2 03 ldx #$03 ; $CE44: A2 03
00CE46 1
00CE46 1 ; ----------------------------------------------------------------------------
00CE46 1 ; Search backward for a zero timer/state entry in $05AD-$05B0.
00CE46 1 ; Nonzero entries return to $CE36, reloading the delay value with one.
00CE46 1 ; ----------------------------------------------------------------------------
00CE46 1
00CE46 1 FindReadyAnnouncement: ; $CE46
00CE46 1 BD AD 05 lda $05AD,x ; $CE46: BD AD 05
00CE49 1 D0 EB bne ReloadAnnouncementDelay ; $CE49: D0 EB
00CE4B 1
00CE4B 1 86 6A stx EventReadIndex ; $CE4B: 86 6A
00CE4D 1 E6 6F inc PendingEvent ; $CE4D: E6 6F
00CE4F 1
00CE4F 1 BD A9 05 lda $05A9,x ; $CE4F: BD A9 05
00CE52 1 8D BA 05 sta $05BA ; $CE52: 8D BA 05
00CE55 1
00CE55 1 ; ----------------------------------------------------------------------------
00CE55 1 ; Wait one frame and retrieve the selected table value.
00CE55 1 ; ----------------------------------------------------------------------------
00CE55 1
00CE55 1 20 48 EB jsr SelectObjectEventBank1 ; $CE55: 20 48 EB
00CE58 1
00CE58 1 AC BA 05 ldy $05BA ; $CE58: AC BA 05
00CE5B 1
00CE5B 1 C0 3C cpy #$3C ; $CE5B: C0 3C
00CE5D 1 D0 12 bne MapAnnouncementToAudioFlag ; $CE5D: D0 12
00CE5F 1
00CE5F 1 ; ----------------------------------------------------------------------------
00CE5F 1 ; Special handling for value $3C.
00CE5F 1 ; ----------------------------------------------------------------------------
00CE5F 1
00CE5F 1 A5 69 lda EventWriteIndex ; $CE5F: A5 69
00CE61 1 85 6A sta EventReadIndex ; $CE61: 85 6A
00CE63 1
00CE63 1 A5 33 lda RoundStateIndex ; $CE63: A5 33
00CE65 1 C9 10 cmp #$10 ; $CE65: C9 10
00CE67 1 90 08 bcc MapAnnouncementToAudioFlag ; $CE67: 90 08
00CE69 1
00CE69 1 D0 31 bne DisplayBlankAnnouncement
00CE6B 1 ; $CE69: D0 31
00CE6B 1
00CE6B 1 A5 67 lda PlayerOneScore ; $CE6B: A5 67
00CE6D 1 C5 68 cmp PlayerTwoScore ; $CE6D: C5 68
00CE6F 1 90 2B bcc DisplayBlankAnnouncement
00CE71 1 ; $CE6F: 90 2B
00CE71 1
00CE71 1 ; ----------------------------------------------------------------------------
00CE71 1 ; Map selected Y values to a bit/flag value in X.
00CE71 1 ; ----------------------------------------------------------------------------
00CE71 1
00CE71 1 MapAnnouncementToAudioFlag: ; $CE71
00CE71 1 A2 00 ldx #$00 ; $CE71: A2 00
00CE73 1
00CE73 1 C0 06 cpy #$06 ; $CE73: C0 06
00CE75 1 D0 02 bne CheckAnnouncement12 ; $CE75: D0 02
00CE77 1
00CE77 1 A2 08 ldx #$08 ; $CE77: A2 08
00CE79 1
00CE79 1 CheckAnnouncement12: ; $CE79
00CE79 1 C0 12 cpy #$12 ; $CE79: C0 12
00CE7B 1 D0 02 bne CheckAnnouncement42 ; $CE7B: D0 02
00CE7D 1
00CE7D 1 A2 01 ldx #$01 ; $CE7D: A2 01
00CE7F 1
00CE7F 1 CheckAnnouncement42: ; $CE7F
00CE7F 1 C0 42 cpy #$42 ; $CE7F: C0 42
00CE81 1 D0 02 bne CheckAnnouncement0C ; $CE81: D0 02
00CE83 1
00CE83 1 A2 02 ldx #$02 ; $CE83: A2 02
00CE85 1
00CE85 1 CheckAnnouncement0C: ; $CE85
00CE85 1 C0 0C cpy #$0C ; $CE85: C0 0C
00CE87 1 D0 02 bne CheckAnnouncement18 ; $CE87: D0 02
00CE89 1
00CE89 1 A2 10 ldx #$10 ; $CE89: A2 10
00CE8B 1
00CE8B 1 CheckAnnouncement18: ; $CE8B
00CE8B 1 C0 18 cpy #$18 ; $CE8B: C0 18
00CE8D 1 D0 02 bne SaveAnnouncementAudioFlag ; $CE8D: D0 02
00CE8F 1
00CE8F 1 A2 08 ldx #$08 ; $CE8F: A2 08
00CE91 1
00CE91 1 SaveAnnouncementAudioFlag: ; $CE91
00CE91 1 86 FE stx PendingAudioFlags ; $CE91: 86 FE
00CE93 1
00CE93 1 98 tya ; $CE93: 98
00CE94 1 20 A5 CE jsr DisplayAnnouncementPair
00CE97 1 ; $CE94: 20 A5 CE
00CE97 1
00CE97 1 A9 3C lda #$3C ; $CE97: A9 3C
00CE99 1 20 41 EB jsr StoreObjectEventBankValue ; $CE99: 20 41 EB
00CE9C 1
00CE9C 1 ; ----------------------------------------------------------------------------
00CE9C 1 ; Display the default message.
00CE9C 1 ; ----------------------------------------------------------------------------
00CE9C 1
00CE9C 1 DisplayBlankAnnouncement: ; $CE9C
00CE9C 1 A9 00 lda #$00 ; $CE9C: A9 00
00CE9E 1 20 A5 CE jsr DisplayAnnouncementPair
00CEA1 1 ; $CE9E: 20 A5 CE
00CEA1 1
00CEA1 1 ; ----------------------------------------------------------------------------
00CEA1 1 ; Continue at the wait call without reloading A with one.
00CEA1 1 ;
00CEA1 1 ; This distinct target is required for the original D0 93 branch operand:
00CEA1 1 ;
00CEA1 1 ; $CEA3: D0 93 -> $CE38
00CEA1 1 ; ----------------------------------------------------------------------------
00CEA1 1
00CEA1 1 A9 05 lda #$05 ; $CEA1: A9 05
00CEA3 1 D0 93 bne WaitAnnouncementDelay ; $CEA3: D0 93
00CEA5 1 ; Always taken because A is nonzero.
00CEA5 1
00CEA5 1 ; ============================================================================
00CEA5 1 ; $CEA5-$CEC8
00CEA5 1 ; Queue a six-byte encoded message selected by A.
00CEA5 1 ;
00CEA5 1 ; Entry:
00CEA5 1 ; A = offset into the encoded text table at $CEC9.
00CEA5 1 ; ============================================================================
00CEA5 1
00CEA5 1 DisplayAnnouncementPair: ; $CEA5
00CEA5 1 48 pha ; $CEA5: 48
00CEA6 1
00CEA6 1 A0 23 ldy #$23 ; $CEA6: A0 23
00CEA8 1 20 AE CE jsr QueueAnnouncementText ; $CEA8: 20 AE CE
00CEAB 1
00CEAB 1 68 pla ; $CEAB: 68
00CEAC 1
00CEAC 1 ; ----------------------------------------------------------------------------
00CEAC 1 ; Secondary entry point.
00CEAC 1 ;
00CEAC 1 ; Entry:
00CEAC 1 ; A = text-table offset.
00CEAC 1 ; The destination selector is changed to $2B.
00CEAC 1 ; ----------------------------------------------------------------------------
00CEAC 1
00CEAC 1 DisplaySecondaryAnnouncement: ; $CEAC
00CEAC 1 A0 2B ldy #$2B ; $CEAC: A0 2B
00CEAE 1
00CEAE 1 ; ----------------------------------------------------------------------------
00CEAE 1 ; Contract:
00CEAE 1 ; Description: Queues Announcement Text.
00CEAE 1 ; Entry: Registers: A, X, Y; Memory: announcementtexttable
00CEAE 1 ; Returns/products: Registers/clobbers: A, X, Y
00CEAE 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00CEAE 1 ; Memory effects: textcopycount, $0300
00CEAE 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00CEAE 1 ; comparison, load, or store path and are not a stable API product.
00CEAE 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00CEAE 1 ; ----------------------------------------------------------------------------
00CEAE 1 QueueAnnouncementText: ; $CEAE
00CEAE 1 48 pha ; $CEAE: 48
00CEAF 1 18 clc ; $CEAF: 18
00CEB0 1
00CEB0 1 98 tya ; $CEB0: 98
00CEB1 1 A2 37 ldx #$37 ; $CEB1: A2 37
00CEB3 1 A0 06 ldy #$06 ; $CEB3: A0 06
00CEB5 1
00CEB5 1 84 6B sty TextCopyCount ; $CEB5: 84 6B
00CEB7 1
00CEB7 1 20 3E EA jsr AllocateDisplayBufferRecord ; $CEB7: 20 3E EA
00CEBA 1
00CEBA 1 68 pla ; $CEBA: 68
00CEBB 1 A8 tay ; $CEBB: A8
00CEBC 1
00CEBC 1 CopyAnnouncementText: ; $CEBC
00CEBC 1 B9 C9 CE lda AnnouncementTextTable,y ; $CEBC: B9 C9 CE
00CEBF 1 9D 00 03 sta $0300,x ; $CEBF: 9D 00 03
00CEC2 1
00CEC2 1 C8 iny ; $CEC2: C8
00CEC3 1 E8 inx ; $CEC3: E8
00CEC4 1
00CEC4 1 C6 6B dec TextCopyCount ; $CEC4: C6 6B
00CEC6 1 D0 F4 bne CopyAnnouncementText ; $CEC6: D0 F4
00CEC8 1
00CEC8 1 60 rts ; $CEC8: 60
00CEC9 1
00CEC9 1 ; ============================================================================
00CEC9 1 ; Encoded text/data table begins at CPU $CEC9.
00CEC9 1 ; ============================================================================
00CEC9 1
00CEC9 1 ; ============================================================================
00CEC9 1 ; $CEC9-$CF10
00CEC9 1 ; Encoded six-character message table.
00CEC9 1 ;
00CEC9 1 ; Routine $CEA5 selects an entry by passing an offset in A, then copies six
00CEC9 1 ; bytes beginning at AnnouncementTextTable + A.
00CEC9 1 ;
00CEC9 1 ; Known offsets used by the preceding routine include:
00CEC9 1 ;
00CEC9 1 ; $00, $06, $0C, $12, $18, $1E, $24, $2A, $30, $36, $3C, $42
00CEC9 1 ;
00CEC9 1 ; Each entry is exactly six bytes.
00CEC9 1 ; ============================================================================
00CEC9 1
00CEC9 1 AnnouncementTextTable: ; $CEC9
00CEC9 1
00CEC9 1 AnnouncementTextBlank: ; $CEC9, offset $00
00CEC9 1 25 25 25 25 .byte $25,$25,$25,$25,$25,$25
00CECD 1 25 25
00CECF 1
00CECF 1 AnnouncementTextFoul: ; $CECF, offset $06
00CECF 1 25 0F 18 1E .byte $25,$0F,$18,$1E,$15,$25
00CED3 1 15 25
00CED5 1
00CED5 1 AnnouncementTextStrike: ; $CED5, offset $0C
00CED5 1 1C 1D 1B 12 .byte $1C,$1D,$1B,$12,$14,$0E
00CED9 1 14 0E
00CEDB 1
00CEDB 1 AnnouncementTextOut: ; $CEDB, offset $12
00CEDB 1 25 18 1E 1D .byte $25,$18,$1E,$1D,$25,$25
00CEDF 1 25 25
00CEE1 1
00CEE1 1 AnnouncementTextBall: ; $CEE1, offset $18
00CEE1 1 25 0B 0A 15 .byte $25,$0B,$0A,$15,$15,$25
00CEE5 1 15 25
00CEE7 1
00CEE7 1 AnnouncementTextWalk: ; $CEE7, offset $1E
00CEE7 1 25 20 0A 15 .byte $25,$20,$0A,$15,$14,$25
00CEEB 1 14 25
00CEED 1
00CEED 1 AnnouncementTextSingle: ; $CEED, offset $24
00CEED 1 1C 12 17 10 .byte $1C,$12,$17,$10,$15,$0E
00CEF1 1 15 0E
00CEF3 1
00CEF3 1 AnnouncementTextTwoBase: ; $CEF3, offset $2A
00CEF3 1 02 25 0B 0A .byte $02,$25,$0B,$0A,$1C,$0E
00CEF7 1 1C 0E
00CEF9 1
00CEF9 1 AnnouncementTextThreeBase: ; $CEF9, offset $30
00CEF9 1 03 25 0B 0A .byte $03,$25,$0B,$0A,$1C,$0E
00CEFD 1 1C 0E
00CEFF 1
00CEFF 1 AnnouncementTextDeadBall: ; $CEFF, offset $36
00CEFF 1 0D 25 0B 0A .byte $0D,$25,$0B,$0A,$15,$15
00CF03 1 15 15
00CF05 1
00CF05 1 AnnouncementTextChange: ; $CF05, offset $3C
00CF05 1 0C 11 0A 17 .byte $0C,$11,$0A,$17,$10,$0E
00CF09 1 10 0E
00CF0B 1
00CF0B 1 AnnouncementTextSafe: ; $CF0B, offset $42
00CF0B 1 25 1C 0A 0F .byte $25,$1C,$0A,$0F,$0E,$25
00CF0F 1 0E 25
00CF11 1
00CF11 1 ; ============================================================================
00CF11 1 ; $CF11-$CF22
00CF11 1 ; Move backward through a four-entry circular index and initialize the
00CF11 1 ; corresponding timer/state fields.
00CF11 1 ;
00CF11 1 ; Input:
00CF11 1 ; A = value stored into $05A9,X
00CF11 1 ;
00CF11 1 ; Operation:
00CF11 1 ; Decrement $69, wrapping from $00 to $03.
00CF11 1 ; Store the caller-supplied A value into $05A9,X.
00CF11 1 ; Initialize $05AD,X to $14.
00CF11 1 ;
00CF11 1 ; Output:
00CF11 1 ; X = updated index
00CF11 1 ; $69 = updated index
00CF11 1 ; ============================================================================
00CF11 1
00CF11 1 ; ----------------------------------------------------------------------------
00CF11 1 ; Contract:
00CF11 1 ; Description: Implements Add Timed State Event.
00CF11 1 ; Entry: Registers: A, X; Memory: eventwriteindex
00CF11 1 ; Returns/products: Registers/clobbers: A, X
00CF11 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00CF11 1 ; Memory effects: eventwriteindex, $05a9, $05ad
00CF11 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00CF11 1 ; comparison, load, or store path and are not a stable API product.
00CF11 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 9.
00CF11 1 ; ----------------------------------------------------------------------------
00CF11 1 AddTimedStateEvent: ; $CF11
00CF11 1 A6 69 ldx EventWriteIndex ; $CF11: A6 69
00CF13 1
00CF13 1 CA dex ; $CF13: CA
00CF14 1 10 02 bpl Routine_CF18_SaveIndex ; $CF14: 10 02
00CF16 1
00CF16 1 A2 03 ldx #$03 ; $CF16: A2 03
00CF18 1 ; Wrap the index from zero to three.
00CF18 1
00CF18 1 Routine_CF18_SaveIndex: ; $CF18
00CF18 1 86 69 stx EventWriteIndex ; $CF18: 86 69
00CF1A 1
00CF1A 1 9D A9 05 sta $05A9,x ; $CF1A: 9D A9 05
00CF1D 1 ; Store the caller-supplied state value.
00CF1D 1
00CF1D 1 A9 14 lda #$14 ; $CF1D: A9 14
00CF1F 1 9D AD 05 sta $05AD,x ; $CF1F: 9D AD 05
00CF22 1 ; Initialize the associated timer.
00CF22 1
00CF22 1 60 rts ; $CF22: 60
00CF23 1
00CF23 1 ; ============================================================================
00CF23 1 ; $CF23-$CF44
00CF23 1 ; Select a state-dependent value, construct a one-byte PPU queue entry,
00CF23 1 ; and append tile/data byte $AE.
00CF23 1 ;
00CF23 1 ; Two entry points exist:
00CF23 1 ;
00CF23 1 ; $CF23 derives a value from $62 using base $22.
00CF23 1 ; $CF2A derives a value from $64 using base $42.
00CF23 1 ;
00CF23 1 ; Both paths continue through $CF2F.
00CF23 1 ; ============================================================================
00CF23 1
00CF23 1 ; ----------------------------------------------------------------------------
00CF23 1 ; Contract:
00CF23 1 ; Description: Queues Primary State Marker.
00CF23 1 ; Entry: Registers: A; Memory: primarysequencestate, secondarysequencestate
00CF23 1 ; Returns/products: Registers/clobbers: A, X, Y
00CF23 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00CF23 1 ; Memory effects: $0300
00CF23 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00CF23 1 ; comparison, load, or store path and are not a stable API product.
00CF23 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 2.
00CF23 1 ; ----------------------------------------------------------------------------
00CF23 1 QueuePrimaryStateMarker: ; $CF23
00CF23 1 18 clc ; $CF23: 18
00CF24 1
00CF24 1 A9 22 lda #$22 ; $CF24: A9 22
00CF26 1 65 62 adc PrimarySequenceState ; $CF26: 65 62
00CF28 1
00CF28 1 D0 05 bne BuildStateMarkerEntries ; $CF28: D0 05
00CF2A 1 ; Always taken unless the addition wraps
00CF2A 1 ; exactly to zero.
00CF2A 1
00CF2A 1 ; ----------------------------------------------------------------------------
00CF2A 1 ; Secondary entry point used by callers that derive the value from $64.
00CF2A 1 ; ----------------------------------------------------------------------------
00CF2A 1
00CF2A 1 ; ----------------------------------------------------------------------------
00CF2A 1 ; Contract:
00CF2A 1 ; Description: Queues Secondary State Marker.
00CF2A 1 ; Entry: Registers: A; Memory: secondarysequencestate
00CF2A 1 ; Returns/products: Registers/clobbers: A, X, Y
00CF2A 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00CF2A 1 ; Memory effects: $0300
00CF2A 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00CF2A 1 ; comparison, load, or store path and are not a stable API product.
00CF2A 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 2.
00CF2A 1 ; ----------------------------------------------------------------------------
00CF2A 1 QueueSecondaryStateMarker: ; $CF2A
00CF2A 1 18 clc ; $CF2A: 18
00CF2B 1
00CF2B 1 A9 42 lda #$42 ; $CF2B: A9 42
00CF2D 1 65 64 adc SecondarySequenceState ; $CF2D: 65 64
00CF2F 1
00CF2F 1 ; ----------------------------------------------------------------------------
00CF2F 1 ; Preserve the calculated value, perform the first setup call, then use the
00CF2F 1 ; saved value as X for the PPU queue helper.
00CF2F 1 ; ----------------------------------------------------------------------------
00CF2F 1
00CF2F 1 ; ----------------------------------------------------------------------------
00CF2F 1 ; Contract:
00CF2F 1 ; Description: Implements Build State Marker Entries.
00CF2F 1 ; Entry: Registers: A
00CF2F 1 ; Returns/products: Registers/clobbers: A, X, Y
00CF2F 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00CF2F 1 ; Memory effects: $0300
00CF2F 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00CF2F 1 ; comparison, load, or store path and are not a stable API product.
00CF2F 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00CF2F 1 ; ----------------------------------------------------------------------------
00CF2F 1 BuildStateMarkerEntries: ; $CF2F
00CF2F 1 48 pha ; $CF2F: 48
00CF30 1 AA tax ; $CF30: AA
00CF31 1
00CF31 1 A9 23 lda #$23 ; $CF31: A9 23
00CF33 1 20 3A CF jsr QueueStateMarkerEntry ; $CF33: 20 3A CF
00CF36 1
00CF36 1 68 pla ; $CF36: 68
00CF37 1 AA tax ; $CF37: AA
00CF38 1
00CF38 1 A9 2B lda #$2B ; $CF38: A9 2B
00CF3A 1
00CF3A 1 ; ----------------------------------------------------------------------------
00CF3A 1 ; Secondary helper entry.
00CF3A 1 ;
00CF3A 1 ; Entry:
00CF3A 1 ; A = destination selector/address component
00CF3A 1 ; X = state-derived coordinate/index
00CF3A 1 ;
00CF3A 1 ; Queue one data byte and append $AE.
00CF3A 1 ; ----------------------------------------------------------------------------
00CF3A 1
00CF3A 1 ; ----------------------------------------------------------------------------
00CF3A 1 ; Contract:
00CF3A 1 ; Description: Queues State Marker Entry.
00CF3A 1 ; Entry: Registers: A
00CF3A 1 ; Returns/products: Registers/clobbers: A, Y
00CF3A 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00CF3A 1 ; Memory effects: $0300
00CF3A 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00CF3A 1 ; comparison, load, or store path and are not a stable API product.
00CF3A 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00CF3A 1 ; ----------------------------------------------------------------------------
00CF3A 1 QueueStateMarkerEntry: ; $CF3A
00CF3A 1 A0 01 ldy #$01 ; $CF3A: A0 01
00CF3C 1
00CF3C 1 20 3E EA jsr AllocateDisplayBufferRecord ; $CF3C: 20 3E EA
00CF3F 1
00CF3F 1 A9 AE lda #$AE ; $CF3F: A9 AE
00CF41 1 9D 00 03 sta $0300,x ; $CF41: 9D 00 03
00CF44 1
00CF44 1 60 rts ; $CF44: 60
00CF45 1
00CF45 1 ; ============================================================================
00CF45 1 ; $CF45-$CF66
00CF45 1 ; Queue two related three-character display fields.
00CF45 1 ;
00CF45 1 ; Entry points:
00CF45 1 ; $CF45 queues fields using selectors $43 and $23.
00CF45 1 ; $CF4A queues only the field using selector $23.
00CF45 1 ; $CF51 accepts a selector in A.
00CF45 1 ; $CF5C performs the final three-character blank-field write.
00CF45 1 ; ============================================================================
00CF45 1
00CF45 1 ; ----------------------------------------------------------------------------
00CF45 1 ; Contract:
00CF45 1 ; Description: Clears or resets Both State Fields.
00CF45 1 ; Entry: Registers: A
00CF45 1 ; Returns/products: Registers/clobbers: A, X, Y; Flags: condition flags may carry result state
00CF45 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00CF45 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00CF45 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00CF45 1 ; comparison, load, or store path and are not a stable API product.
00CF45 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00CF45 1 ; ----------------------------------------------------------------------------
00CF45 1 ClearBothStateFields: ; $CF45
00CF45 1 A9 43 lda #$43 ; $CF45: A9 43
00CF47 1 20 51 CF jsr ClearStateFieldPair ; $CF47: 20 51 CF
00CF4A 1
00CF4A 1 ; ----------------------------------------------------------------------------
00CF4A 1 ; Secondary entry point.
00CF4A 1 ; ----------------------------------------------------------------------------
00CF4A 1
00CF4A 1 ; ----------------------------------------------------------------------------
00CF4A 1 ; Contract:
00CF4A 1 ; Description: Clears or resets Primary State Field.
00CF4A 1 ; Entry: Registers: A
00CF4A 1 ; Returns/products: Registers/clobbers: A, X, Y; Flags: condition flags may carry result state
00CF4A 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00CF4A 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00CF4A 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00CF4A 1 ; comparison, load, or store path and are not a stable API product.
00CF4A 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 3.
00CF4A 1 ; ----------------------------------------------------------------------------
00CF4A 1 ClearPrimaryStateField: ; $CF4A
00CF4A 1 A9 23 lda #$23 ; $CF4A: A9 23
00CF4C 1 20 51 CF jsr ClearStateFieldPair ; $CF4C: 20 51 CF
00CF4F 1
00CF4F 1 A9 03 lda #$03 ; $CF4F: A9 03
00CF51 1
00CF51 1 ; ----------------------------------------------------------------------------
00CF51 1 ; Preserve the caller-supplied value in A and X.
00CF51 1 ;
00CF51 1 ; The first blank field uses destination selector $23.
00CF51 1 ; ----------------------------------------------------------------------------
00CF51 1
00CF51 1 ; ----------------------------------------------------------------------------
00CF51 1 ; Contract:
00CF51 1 ; Description: Clears or resets State Field Pair.
00CF51 1 ; Entry: Registers: A
00CF51 1 ; Returns/products: Registers/clobbers: A, X, Y; Flags: condition flags may carry result state
00CF51 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00CF51 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00CF51 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00CF51 1 ; comparison, load, or store path and are not a stable API product.
00CF51 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 5.
00CF51 1 ; ----------------------------------------------------------------------------
00CF51 1 ClearStateFieldPair: ; $CF51
00CF51 1 48 pha ; $CF51: 48
00CF52 1 AA tax ; $CF52: AA
00CF53 1
00CF53 1 A9 23 lda #$23 ; $CF53: A9 23
00CF55 1 20 5C CF jsr QueueThreeBlanks ; $CF55: 20 5C CF
00CF58 1
00CF58 1 68 pla ; $CF58: 68
00CF59 1 AA tax ; $CF59: AA
00CF5A 1
00CF5A 1 A9 2B lda #$2B ; $CF5A: A9 2B
00CF5C 1
00CF5C 1 ; ----------------------------------------------------------------------------
00CF5C 1 ; Queue a three-character blank field.
00CF5C 1 ;
00CF5C 1 ; Entry:
00CF5C 1 ; A = destination selector/address component
00CF5C 1 ; X = caller-supplied coordinate or index
00CF5C 1 ;
00CF5C 1 ; The routine at $EA17 consumes the four inline bytes following the JSR:
00CF5C 1 ; one length byte followed by three encoded blank characters.
00CF5C 1 ; ----------------------------------------------------------------------------
00CF5C 1
00CF5C 1 ; ----------------------------------------------------------------------------
00CF5C 1 ; Contract:
00CF5C 1 ; Description: Queues Three Blanks.
00CF5C 1 ; Entry: No register input inferred
00CF5C 1 ; Returns/products: Registers/clobbers: Y; Flags: condition flags may carry result state
00CF5C 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00CF5C 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00CF5C 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00CF5C 1 ; comparison, load, or store path and are not a stable API product.
00CF5C 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00CF5C 1 ; ----------------------------------------------------------------------------
00CF5C 1 QueueThreeBlanks: ; $CF5C
00CF5C 1 A0 03 ldy #$03 ; $CF5C: A0 03
00CF5E 1 18 clc ; $CF5E: 18
00CF5F 1
00CF5F 1 20 17 EA jsr CopyInlineDisplayRecord ; $CF5F: 20 17 EA
00CF62 1
00CF62 1 03 .byte $03 ; $CF62: character count
00CF63 1 25 25 25 .byte $25,$25,$25 ; $CF63-$CF65
00CF66 1
00CF66 1 60 rts ; $CF66: 60
00CF67 1
00CF67 1 ; ============================================================================
00CF67 1 ; $CF67-$CF8A
00CF67 1 ; Build a four-byte PPU queue entry using the current state in $33.
00CF67 1 ;
00CF67 1 ; The helper at $EA3E creates a four-byte queue record and returns its data
00CF67 1 ; position in X. This routine then fills the record with values derived from
00CF67 1 ; $33.
00CF67 1 ; ============================================================================
00CF67 1
00CF67 1 ; ----------------------------------------------------------------------------
00CF67 1 ; Contract:
00CF67 1 ; Description: Queues Round Number Display.
00CF67 1 ; Entry: Registers: A, Y; Memory: roundstateindex
00CF67 1 ; Returns/products: Registers/clobbers: A, X, Y
00CF67 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00CF67 1 ; Memory effects: $0300, $0301, $0302, $0303
00CF67 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00CF67 1 ; comparison, load, or store path and are not a stable API product.
00CF67 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00CF67 1 ; ----------------------------------------------------------------------------
00CF67 1 QueueRoundNumberDisplay: ; $CF67
00CF67 1 A9 2A lda #$2A ; $CF67: A9 2A
00CF69 1 A2 82 ldx #$82 ; $CF69: A2 82
00CF6B 1 A0 04 ldy #$04 ; $CF6B: A0 04
00CF6D 1 18 clc ; $CF6D: 18
00CF6E 1
00CF6E 1 20 3E EA jsr AllocateDisplayBufferRecord ; $CF6E: 20 3E EA
00CF71 1
00CF71 1 ; ----------------------------------------------------------------------------
00CF71 1 ; Derive the first byte from half of $33, rounded upward.
00CF71 1 ;
00CF71 1 ; Y = ($33 >> 1) + 1
00CF71 1 ; ----------------------------------------------------------------------------
00CF71 1
00CF71 1 A5 33 lda RoundStateIndex ; $CF71: A5 33
00CF73 1 4A lsr ; $CF73: 4A
00CF74 1 A8 tay ; $CF74: A8
00CF75 1 C8 iny ; $CF75: C8
00CF76 1
00CF76 1 98 tya ; $CF76: 98
00CF77 1 9D 00 03 sta $0300,x ; $CF77: 9D 00 03
00CF7A 1
00CF7A 1 ; ----------------------------------------------------------------------------
00CF7A 1 ; Store $3B as the second byte.
00CF7A 1 ;
00CF7A 1 ; Carry remains clear from the preceding LSR because $33 is expected to be
00CF7A 1 ; even or within the state range used by this routine.
00CF7A 1 ; ----------------------------------------------------------------------------
00CF7A 1
00CF7A 1 A9 3B lda #$3B ; $CF7A: A9 3B
00CF7C 1 9D 01 03 sta $0301,x ; $CF7C: 9D 01 03
00CF7F 1
00CF7F 1 ; ----------------------------------------------------------------------------
00CF7F 1 ; Calculate the third byte:
00CF7F 1 ;
00CF7F 1 ; (($3B - $1C) << 1) = $3E
00CF7F 1 ;
00CF7F 1 ; SEC is not issued here. Carry from the preceding operations is intentionally
00CF7F 1 ; used by the original code.
00CF7F 1 ; ----------------------------------------------------------------------------
00CF7F 1
00CF7F 1 E9 1C sbc #$1C ; $CF7F: E9 1C
00CF81 1 0A asl ; $CF81: 0A
00CF82 1 9D 02 03 sta $0302,x ; $CF82: 9D 02 03
00CF85 1
00CF85 1 ; ----------------------------------------------------------------------------
00CF85 1 ; Calculate the fourth byte from the shifted result plus one.
00CF85 1 ; ----------------------------------------------------------------------------
00CF85 1
00CF85 1 69 01 adc #$01 ; $CF85: 69 01
00CF87 1 9D 03 03 sta $0303,x ; $CF87: 9D 03 03
00CF8A 1
00CF8A 1 60 rts ; $CF8A: 60
00CF8B 1
00CF8B 1 ; ============================================================================
00CF8B 1 ; $CF8B-$CFA5
00CF8B 1 ; Build a two-byte PPU queue entry using values selected by $34 and $35.
00CF8B 1 ;
00CF8B 1 ; The routine at $EA3E creates a two-byte queue record. The two data bytes are
00CF8B 1 ; read from the lookup table at $C024 using $34 and $35 as indices.
00CF8B 1 ; ============================================================================
00CF8B 1
00CF8B 1 ; ----------------------------------------------------------------------------
00CF8B 1 ; Contract:
00CF8B 1 ; Description: Queues Player Value Display.
00CF8B 1 ; Entry: Registers: A; Memory: playeroneselection, $c024, playertwoselection
00CF8B 1 ; Returns/products: Registers/clobbers: A, X, Y
00CF8B 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00CF8B 1 ; Memory effects: $0300, $0301
00CF8B 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00CF8B 1 ; comparison, load, or store path and are not a stable API product.
00CF8B 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00CF8B 1 ; ----------------------------------------------------------------------------
00CF8B 1 QueuePlayerValueDisplay: ; $CF8B
00CF8B 1 A9 2A lda #$2A ; $CF8B: A9 2A
00CF8D 1 A2 A2 ldx #$A2 ; $CF8D: A2 A2
00CF8F 1 A0 02 ldy #$02 ; $CF8F: A0 02
00CF91 1
00CF91 1 38 sec ; $CF91: 38
00CF92 1 20 3E EA jsr AllocateDisplayBufferRecord ; $CF92: 20 3E EA
00CF95 1
00CF95 1 ; ----------------------------------------------------------------------------
00CF95 1 ; Select the first byte using $34.
00CF95 1 ; ----------------------------------------------------------------------------
00CF95 1
00CF95 1 A4 34 ldy PlayerOneSelection ; $CF95: A4 34
00CF97 1
00CF97 1 B9 24 C0 lda $C024,y ; $CF97: B9 24 C0
00CF9A 1 9D 00 03 sta $0300,x ; $CF9A: 9D 00 03
00CF9D 1
00CF9D 1 ; ----------------------------------------------------------------------------
00CF9D 1 ; Select the second byte using $35.
00CF9D 1 ; ----------------------------------------------------------------------------
00CF9D 1
00CF9D 1 A4 35 ldy PlayerTwoSelection ; $CF9D: A4 35
00CF9F 1
00CF9F 1 B9 24 C0 lda $C024,y ; $CF9F: B9 24 C0
00CFA2 1 9D 01 03 sta $0301,x ; $CFA2: 9D 01 03
00CFA5 1
00CFA5 1 60 rts ; $CFA5: 60
00CFA6 1
00CFA6 1 ; ============================================================================
00CFA6 1 ; $CFA6-$D01C
00CFA6 1 ; Update one of two counters, update a shared total, and build several PPU
00CFA6 1 ; queue entries representing the resulting values.
00CFA6 1 ; ============================================================================
00CFA6 1
00CFA6 1 ; ----------------------------------------------------------------------------
00CFA6 1 ; Contract:
00CFA6 1 ; Description: Updates Counters And Display.
00CFA6 1 ; Entry: Registers: A, X, Y; Memory: roundstateindex, $67, pendingscoreincrement, inningorsharedscore, playeronescore
00CFA6 1 ; Returns/products: Registers/clobbers: A, X, Y
00CFA6 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00CFA6 1 ; Memory effects: $67, inningorsharedscore, $0307, $0301, $0300, $0306
00CFA6 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00CFA6 1 ; comparison, load, or store path and are not a stable API product.
00CFA6 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 2.
00CFA6 1 ; ----------------------------------------------------------------------------
00CFA6 1 UpdateCountersAndDisplay: ; $CFA6
00CFA6 1 A5 33 lda RoundStateIndex ; $CFA6: A5 33
00CFA8 1 29 01 and #$01 ; $CFA8: 29 01
00CFAA 1 AA tax ; $CFAA: AA
00CFAB 1 ; Select counter $67 or $68.
00CFAB 1
00CFAB 1 ; ----------------------------------------------------------------------------
00CFAB 1 ; Add $65 to the selected counter, saturating the result at $63.
00CFAB 1 ; ----------------------------------------------------------------------------
00CFAB 1
00CFAB 1 18 clc ; $CFAB: 18
00CFAC 1
00CFAC 1 B5 67 lda PlayerOneScore,x ; $CFAC: B5 67
00CFAE 1 65 65 adc PendingScoreIncrement ; $CFAE: 65 65
00CFB0 1
00CFB0 1 C9 64 cmp #$64 ; $CFB0: C9 64
00CFB2 1 90 02 bcc SaveSaturatedSideCounter
00CFB4 1 ; $CFB2: 90 02
00CFB4 1
00CFB4 1 A9 63 lda #$63 ; $CFB4: A9 63
00CFB6 1
00CFB6 1 SaveSaturatedSideCounter: ; $CFB6
00CFB6 1 95 67 sta PlayerOneScore,x ; $CFB6: 95 67
00CFB8 1
00CFB8 1 ; ----------------------------------------------------------------------------
00CFB8 1 ; Add $65 to the shared value at $66 and reduce it using the conversion helper
00CFB8 1 ; at $D01D.
00CFB8 1 ; ----------------------------------------------------------------------------
00CFB8 1
00CFB8 1 18 clc ; $CFB8: 18
00CFB9 1
00CFB9 1 A5 66 lda InningOrSharedScore ; $CFB9: A5 66
00CFBB 1 65 65 adc PendingScoreIncrement ; $CFBB: 65 65
00CFBD 1
00CFBD 1 20 1D D0 jsr DivideABy10 ; $CFBD: 20 1D D0
00CFC0 1 85 66 sta InningOrSharedScore ; $CFC0: 85 66
00CFC2 1
00CFC2 1 ; ----------------------------------------------------------------------------
00CFC2 1 ; Derive a PPU queue position from the selected side in X.
00CFC2 1 ;
00CFC2 1 ; The ROR sequence incorporates X's bit value into A before adding $94.
00CFC2 1 ; ----------------------------------------------------------------------------
00CFC2 1
00CFC2 1 B5 67 lda PlayerOneScore,x ; $CFC2: B5 67
00CFC4 1 48 pha ; $CFC4: 48
00CFC5 1
00CFC5 1 8A txa ; $CFC5: 8A
00CFC6 1 4A lsr ; $CFC6: 4A
00CFC7 1 6A ror ; $CFC7: 6A
00CFC8 1 6A ror ; $CFC8: 6A
00CFC9 1 6A ror ; $CFC9: 6A
00CFCA 1
00CFCA 1 69 94 adc #$94 ; $CFCA: 69 94
00CFCC 1 AA tax ; $CFCC: AA
00CFCD 1
00CFCD 1 ; ----------------------------------------------------------------------------
00CFCD 1 ; Create a two-byte PPU queue entry.
00CFCD 1 ; ----------------------------------------------------------------------------
00CFCD 1
00CFCD 1 A9 20 lda #$20 ; $CFCD: A9 20
00CFCF 1 A0 02 ldy #$02 ; $CFCF: A0 02
00CFD1 1
00CFD1 1 20 3E EA jsr AllocateDisplayBufferRecord ; $CFD1: 20 3E EA
00CFD4 1
00CFD4 1 ; ----------------------------------------------------------------------------
00CFD4 1 ; Convert the selected counter into display digits.
00CFD4 1 ;
00CFD4 1 ; Routine $D01D returns:
00CFD4 1 ; A = remainder/digit-like value
00CFD4 1 ; Y = quotient-like value
00CFD4 1 ; ----------------------------------------------------------------------------
00CFD4 1
00CFD4 1 68 pla ; $CFD4: 68
00CFD5 1 20 1D D0 jsr DivideABy10 ; $CFD5: 20 1D D0
00CFD8 1
00CFD8 1 9D 07 03 sta $0307,x ; $CFD8: 9D 07 03
00CFDB 1
00CFDB 1 69 27 adc #$27 ; $CFDB: 69 27
00CFDD 1 9D 01 03 sta $0301,x ; $CFDD: 9D 01 03
00CFE0 1
00CFE0 1 ; ----------------------------------------------------------------------------
00CFE0 1 ; Build the associated leading digit or blank character.
00CFE0 1 ; ----------------------------------------------------------------------------
00CFE0 1
00CFE0 1 98 tya ; $CFE0: 98
00CFE1 1 F0 04 beq BlankLeadingCounterDigit
00CFE3 1 ; $CFE1: F0 04
00CFE3 1
00CFE3 1 69 28 adc #$28 ; $CFE3: 69 28
00CFE5 1 D0 04 bne StoreCounterDisplayDigits ; $CFE5: D0 04
00CFE7 1 ; Always taken for the expected input range.
00CFE7 1
00CFE7 1 BlankLeadingCounterDigit: ; $CFE7
00CFE7 1 A0 25 ldy #$25 ; $CFE7: A0 25
00CFE9 1 ; Encoded blank character.
00CFE9 1
00CFE9 1 A9 33 lda #$33 ; $CFE9: A9 33
00CFEB 1
00CFEB 1 StoreCounterDisplayDigits: ; $CFEB
00CFEB 1 9D 00 03 sta $0300,x ; $CFEB: 9D 00 03
00CFEE 1
00CFEE 1 98 tya ; $CFEE: 98
00CFEF 1 9D 06 03 sta $0306,x ; $CFEF: 9D 06 03
00CFF2 1
00CFF2 1 ; ----------------------------------------------------------------------------
00CFF2 1 ; Build a second two-byte queue entry selected by the low bit of $33.
00CFF2 1 ; ----------------------------------------------------------------------------
00CFF2 1
00CFF2 1 A5 33 lda RoundStateIndex ; $CFF2: A5 33
00CFF4 1 4A lsr ; $CFF4: 4A
00CFF5 1
00CFF5 1 A9 A4 lda #$A4 ; $CFF5: A9 A4
00CFF7 1 90 02 bcc SelectPlayerDisplayQueueOffset ; $CFF7: 90 02
00CFF9 1
00CFF9 1 69 1F adc #$1F ; $CFF9: 69 1F
00CFFB 1
00CFFB 1 SelectPlayerDisplayQueueOffset: ; $CFFB
00CFFB 1 AA tax ; $CFFB: AA
00CFFC 1
00CFFC 1 A9 2A lda #$2A ; $CFFC: A9 2A
00CFFE 1 A0 02 ldy #$02 ; $CFFE: A0 02
00D000 1 18 clc ; $D000: 18
00D001 1
00D001 1 20 3E EA jsr AllocateDisplayBufferRecord ; $D001: 20 3E EA
00D004 1
00D004 1 ; ----------------------------------------------------------------------------
00D004 1 ; Build a final one-byte queue entry.
00D004 1 ; ----------------------------------------------------------------------------
00D004 1
00D004 1 A5 33 lda RoundStateIndex ; $D004: A5 33
00D006 1 4A lsr ; $D006: 4A
00D007 1 90 02 bcc SelectSharedCounterQueueOffset ; $D007: 90 02
00D009 1
00D009 1 69 1F adc #$1F ; $D009: 69 1F
00D00B 1
00D00B 1 SelectSharedCounterQueueOffset: ; $D00B
00D00B 1 69 8B adc #$8B ; $D00B: 69 8B
00D00D 1 AA tax ; $D00D: AA
00D00E 1
00D00E 1 A9 20 lda #$20 ; $D00E: A9 20
00D010 1 A0 01 ldy #$01 ; $D010: A0 01
00D012 1
00D012 1 20 3E EA jsr AllocateDisplayBufferRecord ; $D012: 20 3E EA
00D015 1
00D015 1 A5 66 lda InningOrSharedScore ; $D015: A5 66
00D017 1 69 28 adc #$28 ; $D017: 69 28
00D019 1 9D 00 03 sta $0300,x ; $D019: 9D 00 03
00D01C 1
00D01C 1 60 rts ; $D01C: 60
00D01D 1
00D01D 1 ; ============================================================================
00D01D 1 ; $D01D-$D027
00D01D 1 ; Divide an unsigned 8-bit value by ten.
00D01D 1 ;
00D01D 1 ; Entry:
00D01D 1 ; A = unsigned value to divide
00D01D 1 ;
00D01D 1 ; Exit:
00D01D 1 ; A = remainder, range $00-$09
00D01D 1 ; Y = quotient
00D01D 1 ;
00D01D 1 ; The routine repeatedly subtracts ten until the subtraction underflows,
00D01D 1 ; then adds ten back to restore the nonnegative remainder.
00D01D 1 ; ============================================================================
00D01D 1
00D01D 1 ; ----------------------------------------------------------------------------
00D01D 1 ; Contract:
00D01D 1 ; Description: Implements Divide A By 1 0.
00D01D 1 ; Entry: Registers: A, Y
00D01D 1 ; Returns/products: Registers/clobbers: A, Y; Flags: condition flags may carry result state
00D01D 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00D01D 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00D01D 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00D01D 1 ; comparison, load, or store path and are not a stable API product.
00D01D 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 4.
00D01D 1 ; ----------------------------------------------------------------------------
00D01D 1 DivideABy10: ; $D01D
00D01D 1 A0 FF ldy #$FF ; $D01D: A0 FF
00D01F 1 ; The first INY changes this to zero.
00D01F 1
00D01F 1 Routine_D01F_SubtractTen: ; $D01F
00D01F 1 38 sec ; $D01F: 38
00D020 1 E9 0A sbc #$0A ; $D020: E9 0A
00D022 1
00D022 1 C8 iny ; $D022: C8
00D023 1 B0 FA bcs Routine_D01F_SubtractTen
00D025 1 ; $D023: B0 FA
00D025 1
00D025 1 69 0A adc #$0A ; $D025: 69 0A
00D027 1 ; Carry is clear after the failed subtraction,
00D027 1 ; so this restores the remainder without an
00D027 1 ; extra increment.
00D027 1
00D027 1 60 rts ; $D027: 60
00D028 1
00D028 1 ; ============================================================================
00D028 1 ; $D028-$D068
00D028 1 ; Display and format the value at $71.
00D028 1 ; ============================================================================
00D028 1
00D028 1 DisplaySharedCounter: ; $D028
00D028 1 18 clc ; $D028: 18
00D029 1
00D029 1 A9 2A lda #$2A ; $D029: A9 2A
00D02B 1 A2 2D ldx #$2D ; $D02B: A2 2D
00D02D 1 A0 05 ldy #$05 ; $D02D: A0 05
00D02F 1
00D02F 1 20 17 EA jsr CopyInlineDisplayRecord ; $D02F: 20 17 EA
00D032 1
00D032 1 05 .byte $05 ; $D032
00D033 1 25 25 25 39 .byte $25,$25,$25,$39,$3A ; $D033-$D037
00D037 1 3A
00D038 1
00D038 1 A5 71 lda DisplayCounterValue ; $D038: A5 71
00D03A 1 C9 64 cmp #$64 ; $D03A: C9 64
00D03C 1 90 09 bcc ConvertSharedCounterToDigits ; $D03C: 90 09
00D03E 1
00D03E 1 A9 01 lda #$01 ; $D03E: A9 01
00D040 1 9D FB 02 sta $02FB,x ; $D040: 9D FB 02
00D043 1
00D043 1 A5 71 lda DisplayCounterValue ; $D043: A5 71
00D045 1 E9 64 sbc #$64 ; $D045: E9 64
00D047 1
00D047 1 ConvertSharedCounterToDigits: ; $D047
00D047 1 20 1D D0 jsr DivideABy10 ; $D047: 20 1D D0
00D04A 1
00D04A 1 9D FD 02 sta $02FD,x ; $D04A: 9D FD 02
00D04D 1
00D04D 1 98 tya ; $D04D: 98
00D04E 1 9D FC 02 sta $02FC,x ; $D04E: 9D FC 02
00D051 1
00D051 1 A9 5A lda #$5A ; $D051: A9 5A
00D053 1 20 41 EB jsr StoreObjectEventBankValue ; $D053: 20 41 EB
00D056 1
00D056 1 18 clc ; $D056: 18
00D057 1
00D057 1 A9 2A lda #$2A ; $D057: A9 2A
00D059 1 A2 2D ldx #$2D ; $D059: A2 2D
00D05B 1 A0 05 ldy #$05 ; $D05B: A0 05
00D05D 1
00D05D 1 20 17 EA jsr CopyInlineDisplayRecord ; $D05D: 20 17 EA
00D060 1
00D060 1 05 .byte $05 ; $D060
00D061 1 26 26 26 26 .byte $26,$26,$26,$26,$26 ; $D061-$D065
00D065 1 26
00D066 1
00D066 1 4C 6A EB jmp CommonEngineExit ; $D066: 4C 6A EB
00D069 1
00D069 1 ; ============================================================================
00D069 1 ; $D069-$D09F
00D069 1 ; Initialize object position and sprite fields from the structured table at
00D069 1 ; $D0A0.
00D069 1 ;
00D069 1 ; Two entry points exist:
00D069 1 ;
00D069 1 ; $D069 initializes A to $23 before using it as the initial table offset.
00D069 1 ; $D06B uses the caller-supplied A value as the initial table offset.
00D069 1 ;
00D069 1 ; Table records are seven bytes long. A zero byte in ObjectInitializationTable,Y terminates
00D069 1 ; the record list.
00D069 1 ; ============================================================================
00D069 1
00D069 1 ; ----------------------------------------------------------------------------
00D069 1 ; Contract:
00D069 1 ; Description: Initializes Default Objects.
00D069 1 ; Entry: Registers: A, X, Y; Memory: objectinitializationtable, objectinitxlowfield, objectinitxhighfield, objectinitylowfield, objectinityhighfield, objectinitframefield, objectinitattributefield
00D069 1 ; Returns/products: Registers/clobbers: A, X, Y
00D069 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00D069 1 ; Memory effects: $0509, $050a, $053a, $053b, $039b, $03b0
00D069 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00D069 1 ; comparison, load, or store path and are not a stable API product.
00D069 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00D069 1 ; ----------------------------------------------------------------------------
00D069 1 InitializeDefaultObjects: ; $D069
00D069 1 A9 23 lda #$23 ; $D069: A9 23
00D06B 1
00D06B 1 ; ----------------------------------------------------------------------------
00D06B 1 ; Secondary entry point.
00D06B 1 ;
00D06B 1 ; Entry:
00D06B 1 ; A = initial offset into ObjectInitializationTable
00D06B 1 ; ----------------------------------------------------------------------------
00D06B 1
00D06B 1 ; ----------------------------------------------------------------------------
00D06B 1 ; Contract:
00D06B 1 ; Description: Initializes Objects From Table.
00D06B 1 ; Entry: Registers: A, X, Y; Memory: objectinitializationtable, objectinitxlowfield, objectinitxhighfield, objectinitylowfield, objectinityhighfield, objectinitframefield, objectinitattributefield
00D06B 1 ; Returns/products: Registers/clobbers: A, X, Y
00D06B 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00D06B 1 ; Memory effects: $0509, $050a, $053a, $053b, $039b, $03b0
00D06B 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00D06B 1 ; comparison, load, or store path and are not a stable API product.
00D06B 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 2.
00D06B 1 ; ----------------------------------------------------------------------------
00D06B 1 InitializeObjectsFromTable: ; $D06B
00D06B 1 A8 tay ; $D06B: A8
00D06C 1
00D06C 1 InitializeNextObjectRecord: ; $D06C
00D06C 1 BE A0 D0 ldx ObjectInitializationTable,y ; $D06C: BE A0 D0
00D06F 1 F0 2E beq ObjectInitializationReturn ; $D06F: F0 2E
00D071 1
00D071 1 ; ----------------------------------------------------------------------------
00D071 1 ; Copy four position bytes from the table into the object arrays selected by X.
00D071 1 ; ----------------------------------------------------------------------------
00D071 1
00D071 1 B9 A3 D0 lda ObjectInitXLowField,y ; $D071: B9 A3 D0
00D074 1 9D 09 05 sta $0509,x ; $D074: 9D 09 05
00D077 1
00D077 1 B9 A4 D0 lda ObjectInitXHighField,y ; $D077: B9 A4 D0
00D07A 1 9D 0A 05 sta $050A,x ; $D07A: 9D 0A 05
00D07D 1
00D07D 1 B9 A5 D0 lda ObjectInitYLowField,y ; $D07D: B9 A5 D0
00D080 1 9D 3A 05 sta $053A,x ; $D080: 9D 3A 05
00D083 1
00D083 1 B9 A6 D0 lda ObjectInitYHighField,y ; $D083: B9 A6 D0
00D086 1 9D 3B 05 sta $053B,x ; $D086: 9D 3B 05
00D089 1
00D089 1 ; ----------------------------------------------------------------------------
00D089 1 ; Convert the object-array offset into the associated sprite-array index.
00D089 1 ; ----------------------------------------------------------------------------
00D089 1
00D089 1 8A txa ; $D089: 8A
00D08A 1 4A lsr ; $D08A: 4A
00D08B 1 AA tax ; $D08B: AA
00D08C 1
00D08C 1 ; ----------------------------------------------------------------------------
00D08C 1 ; Copy the sprite tile/frame value.
00D08C 1 ; ----------------------------------------------------------------------------
00D08C 1
00D08C 1 B9 A1 D0 lda ObjectInitFrameField,y ; $D08C: B9 A1 D0
00D08F 1 9D 9B 03 sta $039B,x ; $D08F: 9D 9B 03
00D092 1
00D092 1 ; ----------------------------------------------------------------------------
00D092 1 ; Copy the optional sprite attribute/value when it is nonzero.
00D092 1 ; ----------------------------------------------------------------------------
00D092 1
00D092 1 B9 A2 D0 lda ObjectInitAttributeField,y ; $D092: B9 A2 D0
00D095 1 F0 03 beq AdvanceObjectInitRecord ; $D095: F0 03
00D097 1
00D097 1 9D B0 03 sta $03B0,x ; $D097: 9D B0 03
00D09A 1
00D09A 1 ; ----------------------------------------------------------------------------
00D09A 1 ; Advance to the next seven-byte record.
00D09A 1 ;
00D09A 1 ; Carry is expected to be clear after the table and store operations.
00D09A 1 ; ----------------------------------------------------------------------------
00D09A 1
00D09A 1 AdvanceObjectInitRecord: ; $D09A
00D09A 1 98 tya ; $D09A: 98
00D09B 1 69 07 adc #$07 ; $D09B: 69 07
00D09D 1 D0 CC bne InitializeObjectsFromTable ; $D09D: D0 CC
00D09F 1 ; Effectively loops until a terminating record.
00D09F 1
00D09F 1 ObjectInitializationReturn: ; $D09F
00D09F 1 60 rts ; $D09F: 60
00D0A0 1
00D0A0 1 ; ============================================================================
00D0A0 1 ; Structured seven-byte object table begins at CPU $D0A0.
00D0A0 1 ;
00D0A0 1 ; Record format inferred during the first pass:
00D0A0 1 ;
00D0A0 1 ; +0 object-array offset
00D0A0 1 ; +1 sprite tile/frame
00D0A0 1 ; +2 optional sprite attribute/value
00D0A0 1 ; +3 $0509,X
00D0A0 1 ; +4 $050A,X
00D0A0 1 ; +5 $053A,X
00D0A0 1 ; +6 $053B,X
00D0A0 1 ; ============================================================================
00D0A0 1
00D0A0 1 ; ============================================================================
00D0A0 1 ; $D0A0-$D125
00D0A0 1 ; Object initialization table used by InitializeDefaultObjects/InitializeObjectsFromTable.
00D0A0 1 ;
00D0A0 1 ; Each record is seven bytes:
00D0A0 1 ;
00D0A0 1 ; +0 object-array offset in X
00D0A0 1 ; +1 value stored at $039B,(X / 2)
00D0A0 1 ; +2 optional value stored at $03B0,(X / 2)
00D0A0 1 ; +3 value stored at $0509,X
00D0A0 1 ; +4 value stored at $050A,X
00D0A0 1 ; +5 value stored at $053A,X
00D0A0 1 ; +6 value stored at $053B,X
00D0A0 1 ;
00D0A0 1 ; A zero object-array offset terminates the table.
00D0A0 1 ; ============================================================================
00D0A0 1
00D0A0 1 ObjectInitializationTable:
00D0A0 1
00D0A0 1 ; ----------------------------------------------------------------------------
00D0A0 1 ; Record 0
00D0A0 1 ;
00D0A0 1 ; Object offset: $06
00D0A0 1 ; Sprite index: $03
00D0A0 1 ; ----------------------------------------------------------------------------
00D0A0 1
00D0A0 1 ObjectInit_D0A0: ; $D0A0
00D0A0 1 06 .byte $06 ; Object-array offset
00D0A1 1 7A .byte $7A ; $039B + (X / 2)
00D0A2 1 7A .byte $7A ; $03B0 + (X / 2)
00D0A3 1 CD FE .byte $CD,$FE ; $0509/$050A
00D0A5 1 4C F8 .byte $4C,$F8 ; $053A/$053B
00D0A7 1
00D0A7 1 ; ----------------------------------------------------------------------------
00D0A7 1 ; Record 1
00D0A7 1 ; ----------------------------------------------------------------------------
00D0A7 1
00D0A7 1 ObjectInit_D0A7: ; $D0A7
00D0A7 1 08 .byte $08
00D0A8 1 7A .byte $7A
00D0A9 1 7A .byte $7A
00D0AA 1 00 FC .byte $00,$FC
00D0AC 1 00 F7 .byte $00,$F7
00D0AE 1
00D0AE 1 ; ----------------------------------------------------------------------------
00D0AE 1 ; Record 2
00D0AE 1 ; ----------------------------------------------------------------------------
00D0AE 1
00D0AE 1 ObjectInit_D0AE: ; $D0AE
00D0AE 1 0A .byte $0A
00D0AF 1 7A .byte $7A
00D0B0 1 7A .byte $7A
00D0B1 1 00 FB .byte $00,$FB
00D0B3 1 00 F7 .byte $00,$F7
00D0B5 1
00D0B5 1 ; ----------------------------------------------------------------------------
00D0B5 1 ; Record 3
00D0B5 1 ; ----------------------------------------------------------------------------
00D0B5 1
00D0B5 1 ObjectInit_D0B5: ; $D0B5
00D0B5 1 0C .byte $0C
00D0B6 1 7A .byte $7A
00D0B7 1 7A .byte $7A
00D0B8 1 00 FA .byte $00,$FA
00D0BA 1 00 F7 .byte $00,$F7
00D0BC 1
00D0BC 1 ; ----------------------------------------------------------------------------
00D0BC 1 ; Record 4
00D0BC 1 ; ----------------------------------------------------------------------------
00D0BC 1
00D0BC 1 ObjectInit_D0BC: ; $D0BC
00D0BC 1 02 .byte $02
00D0BD 1 6E .byte $6E
00D0BE 1 47 .byte $47
00D0BF 1 00 00 .byte $00,$00
00D0C1 1 C0 F6 .byte $C0,$F6
00D0C3 1
00D0C3 1 ; ----------------------------------------------------------------------------
00D0C3 1 ; Record 5
00D0C3 1 ; ----------------------------------------------------------------------------
00D0C3 1
00D0C3 1 ObjectInit_D0C3: ; $D0C3
00D0C3 1 04 .byte $04
00D0C4 1 59 .byte $59
00D0C5 1 11 .byte $11
00D0C6 1 00 00 .byte $00,$00
00D0C8 1 22 F7 .byte $22,$F7
00D0CA 1
00D0CA 1 ; ----------------------------------------------------------------------------
00D0CA 1 ; Record 6
00D0CA 1 ; ----------------------------------------------------------------------------
00D0CA 1
00D0CA 1 ObjectInit_D0CA: ; $D0CA
00D0CA 1 0E .byte $0E
00D0CB 1 5B .byte $5B
00D0CC 1 08 .byte $08
00D0CD 1 00 00 .byte $00,$00
00D0CF 1 48 02 .byte $48,$02
00D0D1 1
00D0D1 1 ; ----------------------------------------------------------------------------
00D0D1 1 ; Record 7
00D0D1 1 ; ----------------------------------------------------------------------------
00D0D1 1
00D0D1 1 ObjectInit_D0D1: ; $D0D1
00D0D1 1 10 .byte $10
00D0D2 1 5B .byte $5B
00D0D3 1 2F .byte $2F
00D0D4 1 00 08 .byte $00,$08
00D0D6 1 00 05 .byte $00,$05
00D0D8 1
00D0D8 1 ; ----------------------------------------------------------------------------
00D0D8 1 ; Record 8
00D0D8 1 ; ----------------------------------------------------------------------------
00D0D8 1
00D0D8 1 ObjectInit_D0D8: ; $D0D8
00D0D8 1 12 .byte $12
00D0D9 1 5B .byte $5B
00D0DA 1 2F .byte $2F
00D0DB 1 00 04 .byte $00,$04
00D0DD 1 00 09 .byte $00,$09
00D0DF 1
00D0DF 1 ; ----------------------------------------------------------------------------
00D0DF 1 ; Record 9
00D0DF 1 ; ----------------------------------------------------------------------------
00D0DF 1
00D0DF 1 ObjectInit_D0DF: ; $D0DF
00D0DF 1 14 .byte $14
00D0E0 1 5B .byte $5B
00D0E1 1 2F .byte $2F
00D0E2 1 00 FC .byte $00,$FC
00D0E4 1 00 09 .byte $00,$09
00D0E6 1
00D0E6 1 ; ----------------------------------------------------------------------------
00D0E6 1 ; Record 10
00D0E6 1 ; ----------------------------------------------------------------------------
00D0E6 1
00D0E6 1 ObjectInit_D0E6: ; $D0E6
00D0E6 1 16 .byte $16
00D0E7 1 5B .byte $5B
00D0E8 1 2F .byte $2F
00D0E9 1 00 F8 .byte $00,$F8
00D0EB 1 00 05 .byte $00,$05
00D0ED 1
00D0ED 1 ; ----------------------------------------------------------------------------
00D0ED 1 ; Record 11
00D0ED 1 ; ----------------------------------------------------------------------------
00D0ED 1
00D0ED 1 ObjectInit_D0ED: ; $D0ED
00D0ED 1 18 .byte $18
00D0EE 1 69 .byte $69
00D0EF 1 00 .byte $00 ; Optional $03B0 value is not written
00D0F0 1 00 0B .byte $00,$0B
00D0F2 1 00 01 .byte $00,$01
00D0F4 1
00D0F4 1 ; ----------------------------------------------------------------------------
00D0F4 1 ; Record 12
00D0F4 1 ; ----------------------------------------------------------------------------
00D0F4 1
00D0F4 1 ObjectInit_D0F4: ; $D0F4
00D0F4 1 1A .byte $1A
00D0F5 1 69 .byte $69
00D0F6 1 00 .byte $00
00D0F7 1 00 01 .byte $00,$01
00D0F9 1 00 0A .byte $00,$0A
00D0FB 1
00D0FB 1 ; ----------------------------------------------------------------------------
00D0FB 1 ; Record 13
00D0FB 1 ; ----------------------------------------------------------------------------
00D0FB 1
00D0FB 1 ObjectInit_D0FB: ; $D0FB
00D0FB 1 1C .byte $1C
00D0FC 1 69 .byte $69
00D0FD 1 00 .byte $00
00D0FE 1 00 F5 .byte $00,$F5
00D100 1 00 01 .byte $00,$01
00D102 1
00D102 1 ; ----------------------------------------------------------------------------
00D102 1 ; Record 14
00D102 1 ; ----------------------------------------------------------------------------
00D102 1
00D102 1 ObjectInit_D102: ; $D102
00D102 1 1E .byte $1E
00D103 1 67 .byte $67
00D104 1 00 .byte $00
00D105 1 00 0C .byte $00,$0C
00D107 1 00 12 .byte $00,$12
00D109 1
00D109 1 ; ----------------------------------------------------------------------------
00D109 1 ; Record 15
00D109 1 ; ----------------------------------------------------------------------------
00D109 1
00D109 1 ObjectInit_D109: ; $D109
00D109 1 20 .byte $20
00D10A 1 67 .byte $67
00D10B 1 00 .byte $00
00D10C 1 00 00 .byte $00,$00
00D10E 1 00 17 .byte $00,$17
00D110 1
00D110 1 ; ----------------------------------------------------------------------------
00D110 1 ; Record 16
00D110 1 ; ----------------------------------------------------------------------------
00D110 1
00D110 1 ObjectInit_D110: ; $D110
00D110 1 22 .byte $22
00D111 1 67 .byte $67
00D112 1 00 .byte $00
00D113 1 00 F4 .byte $00,$F4
00D115 1 00 12 .byte $00,$12
00D117 1
00D117 1 ; ----------------------------------------------------------------------------
00D117 1 ; Record 17
00D117 1 ; ----------------------------------------------------------------------------
00D117 1
00D117 1 ObjectInit_D117: ; $D117
00D117 1 24 .byte $24
00D118 1 69 .byte $69
00D119 1 00 .byte $00
00D11A 1 00 13 .byte $00,$13
00D11C 1 00 0B .byte $00,$0B
00D11E 1
00D11E 1 ; ----------------------------------------------------------------------------
00D11E 1 ; Record 18
00D11E 1 ; ----------------------------------------------------------------------------
00D11E 1
00D11E 1 ObjectInit_D11E: ; $D11E
00D11E 1 26 .byte $26
00D11F 1 69 .byte $69
00D120 1 00 .byte $00
00D121 1 00 ED .byte $00,$ED
00D123 1 00 0B .byte $00,$0B
00D125 1
00D125 1 ; ----------------------------------------------------------------------------
00D125 1 ; Table terminator
00D125 1 ; ----------------------------------------------------------------------------
00D125 1
00D125 1 ObjectInitTable_End: ; $D125
00D125 1 00 .byte $00
00D126 1
00D126 1 ; ============================================================================
00D126 1 ; Field aliases used by the table-reading routine.
00D126 1 ;
00D126 1 ; These labels correspond to fields in the first record. Indexed accesses use
00D126 1 ; Y as the record offset, so the same labels describe every seven-byte record.
00D126 1 ; ============================================================================
00D126 1
00D126 1 ObjectInitFrameField = ObjectInitializationTable + 1
00D126 1 ObjectInitAttributeField = ObjectInitializationTable + 2
00D126 1 ObjectInitXLowField = ObjectInitializationTable + 3
00D126 1 ObjectInitXHighField = ObjectInitializationTable + 4
00D126 1 ObjectInitYLowField = ObjectInitializationTable + 5
00D126 1 ObjectInitYHighField = ObjectInitializationTable + 6
00D126 1
00D126 1 ; ============================================================================
00D126 1 ; $D126-$D14A
00D126 1 ; Conditionally initialize object fields and an animation value.
00D126 1 ;
00D126 1 ; The routine checks the signed state bytes at $0599 and $059A. Processing
00D126 1 ; continues only when:
00D126 1 ;
00D126 1 ; $0599 is nonnegative
00D126 1 ; $059A is negative
00D126 1 ;
00D126 1 ; Otherwise, the routine returns immediately.
00D126 1 ; ============================================================================
00D126 1
00D126 1 ; ----------------------------------------------------------------------------
00D126 1 ; Contract:
00D126 1 ; Description: Initializes Conditional Object.
00D126 1 ; Entry: Registers: A, X; Memory: $0599, $059a
00D126 1 ; Returns/products: Registers/clobbers: A, X
00D126 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00D126 1 ; Memory effects: objectselectionlowerbound, $03b8
00D126 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00D126 1 ; comparison, load, or store path and are not a stable API product.
00D126 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00D126 1 ; ----------------------------------------------------------------------------
00D126 1 InitializeConditionalObject: ; $D126
00D126 1 A9 00 lda #$00 ; $D126: A9 00
00D128 1 85 A5 sta ObjectSelectionLowerBound ; $D128: 85 A5
00D12A 1
00D12A 1 ; ----------------------------------------------------------------------------
00D12A 1 ; Return if $0599 is negative.
00D12A 1 ; ----------------------------------------------------------------------------
00D12A 1
00D12A 1 AD 99 05 lda $0599 ; $D12A: AD 99 05
00D12D 1 30 1B bmi ConditionalObjectInitReturn ; $D12D: 30 1B
00D12F 1
00D12F 1 ; ----------------------------------------------------------------------------
00D12F 1 ; Return if $059A is nonnegative.
00D12F 1 ; ----------------------------------------------------------------------------
00D12F 1
00D12F 1 AD 9A 05 lda $059A ; $D12F: AD 9A 05
00D132 1 10 16 bpl ConditionalObjectInitReturn ; $D132: 10 16
00D134 1
00D134 1 ; ----------------------------------------------------------------------------
00D134 1 ; Initialize indexed object fields.
00D134 1 ;
00D134 1 ; Routine $C9A7 consumes the five bytes immediately following the JSR:
00D134 1 ;
00D134 1 ; $10 inline metadata/object offset
00D134 1 ; $00,$07,$00,$00 four field values
00D134 1 ;
00D134 1 ; Based on Routine_C9A7, the four field bytes are stored into:
00D134 1 ;
00D134 1 ; $0509,X = $00
00D134 1 ; $050A,X = $07
00D134 1 ; $053A,X = $00
00D134 1 ; $053B,X = $00
00D134 1 ; ============================================================================
00D134 1
00D134 1 20 A7 C9 jsr LoadObjectPositionInline
00D137 1 ; $D134: 20 A7 C9
00D137 1
00D137 1 10 .byte $10 ; $D137: inline metadata/object offset
00D138 1 00 07 00 00 .byte $00,$07,$00,$00 ; $D138-$D13B: field data
00D13C 1
00D13C 1 ; ----------------------------------------------------------------------------
00D13C 1 ; Set the working value at $A5, then run the indexed helper at $E6B7.
00D13C 1 ; ----------------------------------------------------------------------------
00D13C 1
00D13C 1 A2 10 ldx #$10 ; $D13C: A2 10
00D13E 1 86 A5 stx ObjectSelectionLowerBound ; $D13E: 86 A5
00D140 1
00D140 1 20 B7 E6 jsr ClearMovementTransforms ; $D140: 20 B7 E6
00D143 1 B0 05 bcs ConditionalObjectInitReturn ; $D143: B0 05
00D145 1
00D145 1 ; ----------------------------------------------------------------------------
00D145 1 ; On success, set the animation/state value at $03B8 to $2A.
00D145 1 ; ----------------------------------------------------------------------------
00D145 1
00D145 1 A9 2A lda #$2A ; $D145: A9 2A
00D147 1 8D B8 03 sta $03B8 ; $D147: 8D B8 03
00D14A 1
00D14A 1 ConditionalObjectInitReturn: ; $D14A
00D14A 1 60 rts ; $D14A: 60
00D14B 1
00D14B 1 ; ============================================================================
00D14B 1 ; $D14B-$D166
00D14B 1 ; Lookup tables used by the routines beginning around $D167 and $D1D0.
00D14B 1 ;
00D14B 1 ; The exact semantic meanings remain provisional in the first pass, but later
00D14B 1 ; indexed references establish these boundaries:
00D14B 1 ;
00D14B 1 ; $D14B-$D153 nine-byte lookup table
00D14B 1 ; $D154-$D15C nine-byte lookup table
00D14B 1 ; $D15D-$D161 five-byte lookup table
00D14B 1 ; $D162-$D166 five-byte lookup table
00D14B 1 ; ============================================================================
00D14B 1
00D14B 1 ; ----------------------------------------------------------------------------
00D14B 1 ; Nine-byte threshold or selection table.
00D14B 1 ;
00D14B 1 ; Later code searches this table using X values below nine.
00D14B 1 ; ----------------------------------------------------------------------------
00D14B 1
00D14B 1 PitchDirectionThresholdTable: ; $D14B
00D14B 1 00 4E 77 8C .byte $00,$4E,$77,$8C
00D14F 1 94 A7 D0 E5 .byte $94,$A7,$D0,$E5
00D153 1 ED .byte $ED
00D154 1
00D154 1 ; ----------------------------------------------------------------------------
00D154 1 ; Nine-byte result table paired with PitchDirectionThresholdTable.
00D154 1 ;
00D154 1 ; Entries appear to be returned or stored after a matching threshold is found
00D154 1 ; in PitchDirectionThresholdTable.
00D154 1 ; ----------------------------------------------------------------------------
00D154 1
00D154 1 PitchDirectionResultTable: ; $D154
00D154 1 00 05 01 04 .byte $00,$05,$01,$04
00D158 1 06 0A 02 08 .byte $06,$0A,$02,$08
00D15C 1 09 .byte $09
00D15D 1
00D15D 1 ; ----------------------------------------------------------------------------
00D15D 1 ; Five-byte threshold or selection table.
00D15D 1 ; ----------------------------------------------------------------------------
00D15D 1
00D15D 1 PitchTypeThresholdTable: ; $D15D
00D15D 1 00 1A 80 9A .byte $00,$1A,$80,$9A,$C0
00D161 1 C0
00D162 1
00D162 1 ; ----------------------------------------------------------------------------
00D162 1 ; Five-byte result table paired with PitchTypeThresholdTable.
00D162 1 ; ----------------------------------------------------------------------------
00D162 1
00D162 1 PitchTypeResultTable: ; $D162
00D162 1 00 04 08 00 .byte $00,$04,$08,$00,$04
00D166 1 04
00D167 1
00D167 1 ; ============================================================================
00D167 1 ; $D167-$D18A
00D167 1 ; Conditional command dispatch followed by state and object-field
00D167 1 ; initialization.
00D167 1 ; ============================================================================
00D167 1
00D167 1 InitializePrimaryGameplayActor: ; $D167
00D167 1 A5 0F lda DerivedControl0 ; $D167: A5 0F
00D169 1 D0 06 bne ClearPrimaryActorState ; $D169: D0 06
00D16B 1
00D16B 1 20 0A EB jsr QueueInlineObjectEvent ; $D16B: 20 0A EB
00D16E 1
00D16E 1 ; Inline command record consumed by QueueInlineObjectEvent.
00D16E 1 19 F7 D3 .byte $19,$F7,$D3 ; $D16E-$D170
00D171 1
00D171 1 ; ----------------------------------------------------------------------------
00D171 1 ; Clear working state variables.
00D171 1 ; ----------------------------------------------------------------------------
00D171 1
00D171 1 ClearPrimaryActorState: ; $D171
00D171 1 A9 00 lda #$00 ; $D171: A9 00
00D173 1
00D173 1 85 9D sta CurrentActionState ; $D173: 85 9D
00D175 1 85 81 sta RandomValue81 ; $D175: 85 81
00D177 1 85 82 sta ActorActionComplete ; $D177: 85 82
00D179 1 85 7F sta SelectedStateCount ; $D179: 85 7F
00D17B 1 85 87 sta ObjectProximityState ; $D17B: 85 87
00D17D 1
00D17D 1 ; ----------------------------------------------------------------------------
00D17D 1 ; Initialize the base object fields using the six inline bytes following the
00D17D 1 ; call to LoadBasePositionFieldsInline.
00D17D 1 ;
00D17D 1 ; Routine $C963 stores these bytes as:
00D17D 1 ;
00D17D 1 ; $0509 = $00
00D17D 1 ; $050A = $00
00D17D 1 ; $053A = $46
00D17D 1 ; $053B = $02
00D17D 1 ; $056B = $00
00D17D 1 ; $056C = $02
00D17D 1 ; ----------------------------------------------------------------------------
00D17D 1
00D17D 1 20 63 C9 jsr LoadBasePositionFieldsInline ; $D17D: 20 63 C9
00D180 1
00D180 1 00 00 .byte $00,$00 ; $D180-$D181
00D182 1 46 02 .byte $46,$02 ; $D182-$D183
00D184 1 00 02 .byte $00,$02 ; $D184-$D185
00D186 1
00D186 1 ; ----------------------------------------------------------------------------
00D186 1 ; Initialize the animation/state value at $03B2.
00D186 1 ; ----------------------------------------------------------------------------
00D186 1
00D186 1 A9 11 lda #$11 ; $D186: A9 11
00D188 1 8D B2 03 sta $03B2 ; $D188: 8D B2 03
00D18B 1
00D18B 1 ; ============================================================================
00D18B 1 ; $D18B-$D1CF
00D18B 1 ; Generate a randomized loop count, animate $03B7, optionally run an extra
00D18B 1 ; timing sequence, and dispatch an inline command.
00D18B 1 ; ============================================================================
00D18B 1
00D18B 1 RunPitcherWindupSequence: ; $D18B
00D18B 1 20 F5 E5 jsr AdvanceRandomState ; $D18B: 20 F5 E5
00D18E 1 85 73 sta WindupLoopCounter ; $D18E: 85 73
00D190 1
00D190 1 ; ----------------------------------------------------------------------------
00D190 1 ; Transform the random byte into a value whose upper six bits are set.
00D190 1 ;
00D190 1 ; A = ((random >> 2) OR random OR $FC)
00D190 1 ;
00D190 1 ; This produces a short increment loop ending when WindupLoopCounter wraps to zero.
00D190 1 ; ----------------------------------------------------------------------------
00D190 1
00D190 1 4A lsr ; $D190: 4A
00D191 1 4A lsr ; $D191: 4A
00D192 1
00D192 1 05 73 ora WindupLoopCounter ; $D192: 05 73
00D194 1 09 FC ora #$FC ; $D194: 09 FC
00D196 1 85 73 sta WindupLoopCounter ; $D196: 85 73
00D198 1
00D198 1 D0 08 bne SetWindupFrame ; $D198: D0 08
00D19A 1 ; Normally taken because OR #$FC makes the
00D19A 1 ; result nonzero.
00D19A 1
00D19A 1 ; ----------------------------------------------------------------------------
00D19A 1 ; Alternate entry when the transformed value is zero.
00D19A 1 ; ----------------------------------------------------------------------------
00D19A 1
00D19A 1 RunWindupAlternateFrame: ; $D19A
00D19A 1 CE B7 03 dec $03B7 ; $D19A: CE B7 03
00D19D 1
00D19D 1 A9 0F lda #$0F ; $D19D: A9 0F
00D19F 1 20 41 EB jsr StoreObjectEventBankValue ; $D19F: 20 41 EB
00D1A2 1
00D1A2 1 ; ----------------------------------------------------------------------------
00D1A2 1 ; Set animation/frame $03B7 to seven and wait $3C ticks.
00D1A2 1 ; ----------------------------------------------------------------------------
00D1A2 1
00D1A2 1 SetWindupFrame: ; $D1A2
00D1A2 1 A9 07 lda #$07 ; $D1A2: A9 07
00D1A4 1 8D B7 03 sta $03B7 ; $D1A4: 8D B7 03
00D1A7 1
00D1A7 1 A9 3C lda #$3C ; $D1A7: A9 3C
00D1A9 1 20 41 EB jsr StoreObjectEventBankValue ; $D1A9: 20 41 EB
00D1AC 1
00D1AC 1 ; ----------------------------------------------------------------------------
00D1AC 1 ; Increment $73 until it wraps to zero.
00D1AC 1 ;
00D1AC 1 ; Each nonzero result loops through the frame-decrement and short-delay path
00D1AC 1 ; at $D19A before restoring frame seven and waiting again.
00D1AC 1 ; ----------------------------------------------------------------------------
00D1AC 1
00D1AC 1 E6 73 inc WindupLoopCounter ; $D1AC: E6 73
00D1AE 1 D0 EA bne RunWindupAlternateFrame
00D1B0 1 ; $D1AE: D0 EA
00D1B0 1
00D1B0 1 ; ----------------------------------------------------------------------------
00D1B0 1 ; Advance the animation/frame once after the randomized loop completes.
00D1B0 1 ; ----------------------------------------------------------------------------
00D1B0 1
00D1B0 1 EE B7 03 inc $03B7 ; $D1B0: EE B7 03
00D1B3 1
00D1B3 1 ; ----------------------------------------------------------------------------
00D1B3 1 ; Skip the optional two-step animation when $0599 is negative.
00D1B3 1 ; ----------------------------------------------------------------------------
00D1B3 1
00D1B3 1 AD 99 05 lda $0599 ; $D1B3: AD 99 05
00D1B6 1 30 10 bmi FinishWindupSequence ; $D1B6: 30 10
00D1B8 1
00D1B8 1 A9 1E lda #$1E ; $D1B8: A9 1E
00D1BA 1 20 41 EB jsr StoreObjectEventBankValue ; $D1BA: 20 41 EB
00D1BD 1
00D1BD 1 EE B7 03 inc $03B7 ; $D1BD: EE B7 03
00D1C0 1
00D1C0 1 A9 1E lda #$1E ; $D1C0: A9 1E
00D1C2 1 20 41 EB jsr StoreObjectEventBankValue ; $D1C2: 20 41 EB
00D1C5 1
00D1C5 1 CE B7 03 dec $03B7 ; $D1C5: CE B7 03
00D1C8 1
00D1C8 1 ; ----------------------------------------------------------------------------
00D1C8 1 ; Dispatch the next state through an inline command record.
00D1C8 1 ; ----------------------------------------------------------------------------
00D1C8 1
00D1C8 1 FinishWindupSequence: ; $D1C8
00D1C8 1 20 0A EB jsr QueueInlineObjectEvent ; $D1C8: 20 0A EB
00D1CB 1
00D1CB 1 ; Inline command record consumed by QueueInlineObjectEvent.
00D1CB 1 17 AC D2 .byte $17,$AC,$D2 ; $D1CB-$D1CD
00D1CE 1
00D1CE 1 E6 7E inc ActionSequenceCounter ; $D1CE: E6 7E
00D1D0 1
00D1D0 1 ; ============================================================================
00D1D0 1 ; $D1D0-$D2A3
00D1D0 1 ; Randomized decision, animation, movement adjustment, and state transition.
00D1D0 1 ; ============================================================================
00D1D0 1
00D1D0 1 SelectPitchAction: ; $D1D0
00D1D0 1 20 48 EB jsr SelectObjectEventBank1 ; $D1D0: 20 48 EB
00D1D3 1
00D1D3 1 A5 10 lda $10 ; $D1D3: A5 10
00D1D5 1 D0 33 bne UseControllerPitchSelection
00D1D7 1 ; $D1D5: D0 33
00D1D7 1
00D1D7 1 ; ----------------------------------------------------------------------------
00D1D7 1 ; Wait $3C ticks before making a randomized selection.
00D1D7 1 ; ----------------------------------------------------------------------------
00D1D7 1
00D1D7 1 A9 3C lda #$3C ; $D1D7: A9 3C
00D1D9 1 20 41 EB jsr StoreObjectEventBankValue ; $D1D9: 20 41 EB
00D1DC 1
00D1DC 1 20 F5 E5 jsr AdvanceRandomState ; $D1DC: 20 F5 E5
00D1DF 1
00D1DF 1 ; ----------------------------------------------------------------------------
00D1DF 1 ; Search backward through $9F-$A1 for an entry below eight.
00D1DF 1 ;
00D1DF 1 ; X begins at two. The first entry below eight determines X.
00D1DF 1 ; ----------------------------------------------------------------------------
00D1DF 1
00D1DF 1 A2 02 ldx #$02 ; $D1DF: A2 02
00D1E1 1
00D1E1 1 FindAvailablePitchState: ; $D1E1
00D1E1 1 B4 9F ldy SecondaryActorState0,x ; $D1E1: B4 9F
00D1E3 1
00D1E3 1 C0 08 cpy #$08 ; $D1E3: C0 08
00D1E5 1 90 03 bcc SelectPitchType
00D1E7 1 ; $D1E5: 90 03
00D1E7 1
00D1E7 1 CA dex ; $D1E7: CA
00D1E8 1 10 F7 bpl FindAvailablePitchState
00D1EA 1 ; $D1E8: 10 F7
00D1EA 1
00D1EA 1 ; ----------------------------------------------------------------------------
00D1EA 1 ; Rotate the random value, then select from paired tables at $D15D/$D162.
00D1EA 1 ; ----------------------------------------------------------------------------
00D1EA 1
00D1EA 1 SelectPitchType: ; $D1EA
00D1EA 1 6A ror ; $D1EA: 6A
00D1EB 1
00D1EB 1 A2 05 ldx #$05 ; $D1EB: A2 05
00D1ED 1
00D1ED 1 SearchPitchTypeThresholds: ; $D1ED
00D1ED 1 CA dex ; $D1ED: CA
00D1EE 1
00D1EE 1 DD 5D D1 cmp PitchTypeThresholdTable,x ; $D1EE: DD 5D D1
00D1F1 1 90 FA bcc SearchPitchTypeThresholds
00D1F3 1 ; $D1F1: 90 FA
00D1F3 1
00D1F3 1 BD 62 D1 lda PitchTypeResultTable,x ; $D1F3: BD 62 D1
00D1F6 1 85 21 sta SelectedPitchAction ; $D1F6: 85 21
00D1F8 1
00D1F8 1 ; ----------------------------------------------------------------------------
00D1F8 1 ; Make a second randomized table selection using $D14B/$D154.
00D1F8 1 ; ----------------------------------------------------------------------------
00D1F8 1
00D1F8 1 20 F5 E5 jsr AdvanceRandomState ; $D1F8: 20 F5 E5
00D1FB 1
00D1FB 1 A2 09 ldx #$09 ; $D1FB: A2 09
00D1FD 1
00D1FD 1 SearchPitchDirectionThresholds: ; $D1FD
00D1FD 1 CA dex ; $D1FD: CA
00D1FE 1
00D1FE 1 DD 4B D1 cmp PitchDirectionThresholdTable,x ; $D1FE: DD 4B D1
00D201 1 90 FA bcc SearchPitchDirectionThresholds
00D203 1 ; $D201: 90 FA
00D203 1
00D203 1 BD 54 D1 lda PitchDirectionResultTable,x ; $D203: BD 54 D1
00D206 1 85 91 sta $91 ; $D206: 85 91
00D208 1
00D208 1 B0 08 bcs AnimatePitchStart ; $D208: B0 08
00D20A 1 ; Always taken after the table search succeeds.
00D20A 1
00D20A 1 ; ----------------------------------------------------------------------------
00D20A 1 ; Alternate path used when $10 is nonzero.
00D20A 1 ; ----------------------------------------------------------------------------
00D20A 1
00D20A 1 UseControllerPitchSelection: ; $D20A
00D20A 1 A5 14 lda InputState2 ; $D20A: A5 14
00D20C 1 85 21 sta SelectedPitchAction ; $D20C: 85 21
00D20E 1
00D20E 1 A5 18 lda InputAux2 ; $D20E: A5 18
00D210 1 10 BE bpl SelectPitchAction ; $D210: 10 BE
00D212 1
00D212 1 ; ----------------------------------------------------------------------------
00D212 1 ; Process event slot $17 and dispatch the next state.
00D212 1 ; ----------------------------------------------------------------------------
00D212 1
00D212 1 AnimatePitchStart: ; $D212
00D212 1 A0 17 ldy #$17 ; $D212: A0 17
00D214 1 20 66 EB jsr DispatchNextQueuedEvent ; $D214: 20 66 EB
00D217 1
00D217 1 20 48 EB jsr SelectObjectEventBank1 ; $D217: 20 48 EB
00D21A 1
00D21A 1 20 0A EB jsr QueueInlineObjectEvent ; $D21A: 20 0A EB
00D21D 1
00D21D 1 ; Inline command record consumed by QueueInlineObjectEvent.
00D21D 1 13 DA D6 .byte $13,$DA,$D6 ; $D21D-$D21F
00D220 1
00D220 1 ; ----------------------------------------------------------------------------
00D220 1 ; Animate $03B7 from $0C through $0F with a ten-tick delay between frames.
00D220 1 ; ----------------------------------------------------------------------------
00D220 1
00D220 1 A9 0C lda #$0C ; $D220: A9 0C
00D222 1 8D B7 03 sta $03B7 ; $D222: 8D B7 03
00D225 1
00D225 1 PitchStartAnimationLoop: ; $D225
00D225 1 A9 0A lda #$0A ; $D225: A9 0A
00D227 1 20 41 EB jsr StoreObjectEventBankValue ; $D227: 20 41 EB
00D22A 1
00D22A 1 EE B7 03 inc $03B7 ; $D22A: EE B7 03
00D22D 1
00D22D 1 AD B7 03 lda $03B7 ; $D22D: AD B7 03
00D230 1 C9 0F cmp #$0F ; $D230: C9 0F
00D232 1 90 F1 bcc PitchStartAnimationLoop
00D234 1 ; $D232: 90 F1
00D234 1
00D234 1 ; ----------------------------------------------------------------------------
00D234 1 ; Use bits 2-3 of $21 to select entries from the tables at $D2A4-$D2AC.
00D234 1 ; ----------------------------------------------------------------------------
00D234 1
00D234 1 A5 21 lda SelectedPitchAction ; $D234: A5 21
00D236 1 4A lsr ; $D236: 4A
00D237 1 4A lsr ; $D237: 4A
00D238 1
00D238 1 29 03 and #$03 ; $D238: 29 03
00D23A 1 AA tax ; $D23A: AA
00D23B 1
00D23B 1 BD AA D2 lda PitchRenderFlagTable,x ; $D23B: BD AA D2
00D23E 1 85 FF sta RenderStateFlags ; $D23E: 85 FF
00D240 1
00D240 1 ; ----------------------------------------------------------------------------
00D240 1 ; Combine a random value with the signed table at $D2A4, then use the result as
00D240 1 ; Y to select a delay from the table at $D2A7.
00D240 1 ; ----------------------------------------------------------------------------
00D240 1
00D240 1 20 F5 E5 jsr AdvanceRandomState ; $D240: 20 F5 E5
00D243 1
00D243 1 09 F0 ora #$F0 ; $D243: 09 F0
00D245 1 FD A4 D2 sbc PitchVelocityBiasTable,x ; $D245: FD A4 D2
00D248 1 A8 tay ; $D248: A8
00D249 1
00D249 1 BD A7 D2 lda PitchDelayTable,x ; $D249: BD A7 D2
00D24C 1 85 94 sta PitchUpdateDelay ; $D24C: 85 94
00D24E 1
00D24E 1 ; ----------------------------------------------------------------------------
00D24E 1 ; Initialize base movement state.
00D24E 1 ;
00D24E 1 ; Y from the preceding calculation is passed to InitializeBaseMotionZero.
00D24E 1 ; ----------------------------------------------------------------------------
00D24E 1
00D24E 1 A2 00 ldx #$00 ; $D24E: A2 00
00D250 1 20 23 CA jsr InitializeBaseMotionZero ; $D250: 20 23 CA
00D253 1
00D253 1 ; ----------------------------------------------------------------------------
00D253 1 ; Generate and transform another random value through the helper at $C036.
00D253 1 ; The result is stored as both $71 and $81.
00D253 1 ; ----------------------------------------------------------------------------
00D253 1
00D253 1 20 F5 E5 jsr AdvanceRandomState ; $D253: 20 F5 E5
00D256 1 20 36 C0 jsr $C036 ; $D256: 20 36 C0
00D259 1
00D259 1 85 71 sta DisplayCounterValue ; $D259: 85 71
00D25B 1 85 81 sta RandomValue81 ; $D25B: 85 81
00D25D 1
00D25D 1 E6 9D inc CurrentActionState ; $D25D: E6 9D
00D25F 1
00D25F 1 ; ----------------------------------------------------------------------------
00D25F 1 ; Dispatch the next state through an inline command.
00D25F 1 ; ----------------------------------------------------------------------------
00D25F 1
00D25F 1 20 0A EB jsr QueueInlineObjectEvent ; $D25F: 20 0A EB
00D262 1
00D262 1 ; Inline command record consumed by QueueInlineObjectEvent.
00D262 1 04 85 D7 .byte $04,$85,$D7 ; $D262-$D264
00D265 1
00D265 1 ; ----------------------------------------------------------------------------
00D265 1 ; Wait using the selected delay value from $94.
00D265 1 ; ----------------------------------------------------------------------------
00D265 1
00D265 1 UpdatePitchMovement: ; $D265
00D265 1 A5 94 lda PitchUpdateDelay ; $D265: A5 94
00D267 1 20 41 EB jsr StoreObjectEventBankValue ; $D267: 20 41 EB
00D26A 1
00D26A 1 ; ----------------------------------------------------------------------------
00D26A 1 ; Choose a direction/control value.
00D26A 1 ; ----------------------------------------------------------------------------
00D26A 1
00D26A 1 A5 10 lda $10 ; $D26A: A5 10
00D26C 1 D0 0D bne UsePitchControllerInput ; $D26C: D0 0D
00D26E 1
00D26E 1 A5 91 lda PitchDirectionDecision ; $D26E: A5 91
00D270 1
00D270 1 AE 3B 05 ldx $053B ; $D270: AE 3B 05
00D273 1 E0 FD cpx #$FD ; $D273: E0 FD
00D275 1 10 06 bpl ApplyPitchHorizontalInput ; $D275: 10 06
00D277 1
00D277 1 4A lsr ; $D277: 4A
00D278 1 4A lsr ; $D278: 4A
00D279 1
00D279 1 D0 02 bne ApplyPitchHorizontalInput ; $D279: D0 02
00D27B 1
00D27B 1 UsePitchControllerInput: ; $D27B
00D27B 1 A5 14 lda InputState2 ; $D27B: A5 14
00D27D 1
00D27D 1 ; ----------------------------------------------------------------------------
00D27D 1 ; Adjust the signed high movement byte at $0508 according to bits in A.
00D27D 1 ; ----------------------------------------------------------------------------
00D27D 1
00D27D 1 ApplyPitchHorizontalInput: ; $D27D
00D27D 1 4A lsr ; $D27D: 4A
00D27E 1 90 05 bcc ApplyPitchLeftInput
00D280 1 ; $D27E: 90 05
00D280 1
00D280 1 EE 08 05 inc $0508 ; $D280: EE 08 05
00D283 1 B0 06 bcs SetPitchMovementFlags ; $D283: B0 06
00D285 1 ; Always taken because LSR set carry.
00D285 1
00D285 1 ApplyPitchLeftInput: ; $D285
00D285 1 4A lsr ; $D285: 4A
00D286 1 90 07 bcc CheckPitchVerticalLimit
00D288 1 ; $D286: 90 07
00D288 1
00D288 1 CE 08 05 dec $0508 ; $D288: CE 08 05
00D28B 1
00D28B 1 SetPitchMovementFlags: ; $D28B
00D28B 1 A9 08 lda #$08 ; $D28B: A9 08
00D28D 1 85 FF sta RenderStateFlags ; $D28D: 85 FF
00D28F 1
00D28F 1 ; ----------------------------------------------------------------------------
00D28F 1 ; Continue until the vertical high position reaches $FA or greater.
00D28F 1 ; ----------------------------------------------------------------------------
00D28F 1
00D28F 1 CheckPitchVerticalLimit: ; $D28F
00D28F 1 AD 3B 05 lda $053B ; $D28F: AD 3B 05
00D292 1 C9 FA cmp #$FA ; $D292: C9 FA
00D294 1 10 CF bpl UpdatePitchMovement
00D296 1 ; $D294: 10 CF
00D296 1
00D296 1 ; ----------------------------------------------------------------------------
00D296 1 ; Set the final animation value, dispatch the next state, and leave.
00D296 1 ; ----------------------------------------------------------------------------
00D296 1
00D296 1 A9 2F lda #$2F ; $D296: A9 2F
00D298 1 8D B7 03 sta $03B7 ; $D298: 8D B7 03
00D29B 1
00D29B 1 20 0A EB jsr QueueInlineObjectEvent ; $D29B: 20 0A EB
00D29E 1
00D29E 1 ; Inline command record consumed by QueueInlineObjectEvent.
00D29E 1 21 27 D0 .byte $21,$27,$D0 ; $D29E-$D2A0
00D2A1 1
00D2A1 1 4C 6A EB jmp CommonEngineExit ; $D2A1: 4C 6A EB
00D2A4 1
00D2A4 1 ; ============================================================================
00D2A4 1 ; $D2A4-$D2AC
00D2A4 1 ; Three parallel three-byte lookup tables selected by bits 2-3 of $21.
00D2A4 1 ; ============================================================================
00D2A4 1
00D2A4 1 PitchVelocityBiasTable: ; $D2A4
00D2A4 1 37 47 27 .byte $37,$47,$27
00D2A7 1
00D2A7 1 PitchDelayTable: ; $D2A7
00D2A7 1 05 04 06 .byte $05,$04,$06
00D2AA 1
00D2AA 1 PitchRenderFlagTable: ; $D2AA
00D2AA 1 02 01 04 .byte $02,$01,$04
00D2AD 1
00D2AD 1 ; ============================================================================
00D2AD 1 ; $D2AD-$D329
00D2AD 1 ; Timed selection loop, player/input selection, event processing, and state
00D2AD 1 ; transition.
00D2AD 1 ; ============================================================================
00D2AD 1
00D2AD 1 SelectBatterAction: ; $D2AD
00D2AD 1 A9 30 lda #$30 ; $D2AD: A9 30
00D2AF 1 8D C8 05 sta $05C8 ; $D2AF: 8D C8 05
00D2B2 1
00D2B2 1 ; ----------------------------------------------------------------------------
00D2B2 1 ; Wait for a frame and evaluate the current input/state.
00D2B2 1 ; ----------------------------------------------------------------------------
00D2B2 1
00D2B2 1 WaitForBatterAction: ; $D2B2
00D2B2 1 20 48 EB jsr SelectObjectEventBank1 ; $D2B2: 20 48 EB
00D2B5 1
00D2B5 1 A5 10 lda $10 ; $D2B5: A5 10
00D2B7 1 D0 1B bne UseBatterControllerInput ; $D2B7: D0 1B
00D2B9 1
00D2B9 1 A5 82 lda ActorActionComplete ; $D2B9: A5 82
00D2BB 1 D0 F0 bne SelectBatterAction ; $D2BB: D0 F0
00D2BD 1
00D2BD 1 ; ----------------------------------------------------------------------------
00D2BD 1 ; Check three entries at $0575, $0573, and $0571.
00D2BD 1 ;
00D2BD 1 ; If any entry is nonzero, control branches forward to $D32A.
00D2BD 1 ; ----------------------------------------------------------------------------
00D2BD 1
00D2BD 1 A2 04 ldx #$04 ; $D2BD: A2 04
00D2BF 1
00D2BF 1 CheckActiveFieldObjects: ; $D2BF
00D2BF 1 BD 75 05 lda $0575,x ; $D2BF: BD 75 05
00D2C2 1 D0 66 bne SelectActionFromObjectState ; $D2C2: D0 66
00D2C4 1
00D2C4 1 CA dex ; $D2C4: CA
00D2C5 1 CA dex ; $D2C5: CA
00D2C6 1 10 F7 bpl CheckActiveFieldObjects
00D2C8 1 ; $D2C6: 10 F7
00D2C8 1
00D2C8 1 ; ----------------------------------------------------------------------------
00D2C8 1 ; Count down $05C8 while no active entry is found.
00D2C8 1 ; ----------------------------------------------------------------------------
00D2C8 1
00D2C8 1 CE C8 05 dec $05C8 ; $D2C8: CE C8 05
00D2CB 1 D0 E5 bne WaitForBatterAction ; $D2CB: D0 E5
00D2CD 1
00D2CD 1 ; ----------------------------------------------------------------------------
00D2CD 1 ; If the random value is below $46, continue at $D2D9.
00D2CD 1 ; Otherwise, use the current input byte at $18.
00D2CD 1 ; ----------------------------------------------------------------------------
00D2CD 1
00D2CD 1 20 F5 E5 jsr AdvanceRandomState ; $D2CD: 20 F5 E5
00D2D0 1 C9 46 cmp #$46 ; $D2D0: C9 46
00D2D2 1 90 05 bcc SelectBatterActionSlot ; $D2D2: 90 05
00D2D4 1
00D2D4 1 UseBatterControllerInput: ; $D2D4
00D2D4 1 A5 18 lda InputAux2 ; $D2D4: A5 18
00D2D6 1 0A asl ; $D2D6: 0A
00D2D7 1 10 D9 bpl WaitForBatterAction ; $D2D7: 10 D9
00D2D9 1
00D2D9 1 ; ----------------------------------------------------------------------------
00D2D9 1 ; Search backward through $9F-$A1 for an entry below eight.
00D2D9 1 ; ----------------------------------------------------------------------------
00D2D9 1
00D2D9 1 SelectBatterActionSlot: ; $D2D9
00D2D9 1 A2 03 ldx #$03 ; $D2D9: A2 03
00D2DB 1
00D2DB 1 FindAvailableBatterActionSlot: ; $D2DB
00D2DB 1 CA dex ; $D2DB: CA
00D2DC 1 30 CF bmi SelectBatterAction ; $D2DC: 30 CF
00D2DE 1
00D2DE 1 B5 9F lda SecondaryActorState0,x ; $D2DE: B5 9F
00D2E0 1 C9 08 cmp #$08 ; $D2E0: C9 08
00D2E2 1 B0 F7 bcs FindAvailableBatterActionSlot ; $D2E2: B0 F7
00D2E4 1
00D2E4 1 E6 7F inc SelectedStateCount ; $D2E4: E6 7F
00D2E6 1
00D2E6 1 ; ----------------------------------------------------------------------------
00D2E6 1 ; Select the working value for $21.
00D2E6 1 ; ----------------------------------------------------------------------------
00D2E6 1
00D2E6 1 A5 10 lda $10 ; $D2E6: A5 10
00D2E8 1 D0 0D bne UseBatterInputAction ; $D2E8: D0 0D
00D2EA 1
00D2EA 1 A5 9F lda SecondaryActorState0 ; $D2EA: A5 9F
00D2EC 1 C9 02 cmp #$02 ; $D2EC: C9 02
00D2EE 1 D0 07 bne UseBatterInputAction ; $D2EE: D0 07
00D2F0 1
00D2F0 1 20 F5 E5 jsr AdvanceRandomState ; $D2F0: 20 F5 E5
00D2F3 1 29 01 and #$01 ; $D2F3: 29 01
00D2F5 1 10 02 bpl SaveBatterAction ; $D2F5: 10 02
00D2F7 1 ; Always taken after AND #$01.
00D2F7 1
00D2F7 1 UseBatterInputAction: ; $D2F7
00D2F7 1 A5 14 lda InputState2 ; $D2F7: A5 14
00D2F9 1
00D2F9 1 SaveBatterAction: ; $D2F9
00D2F9 1 85 21 sta SelectedPitchAction ; $D2F9: 85 21
00D2FB 1
00D2FB 1 ; ----------------------------------------------------------------------------
00D2FB 1 ; Process event slots $0E and $11.
00D2FB 1 ; ----------------------------------------------------------------------------
00D2FB 1
00D2FB 1 A0 0E ldy #$0E ; $D2FB: A0 0E
00D2FD 1 20 66 EB jsr DispatchNextQueuedEvent ; $D2FD: 20 66 EB
00D300 1
00D300 1 A0 11 ldy #$11 ; $D300: A0 11
00D302 1 20 66 EB jsr DispatchNextQueuedEvent ; $D302: 20 66 EB
00D305 1
00D305 1 ; ----------------------------------------------------------------------------
00D305 1 ; Initialize animation frame $0C, wait ten ticks, then run the helper at $D33C.
00D305 1 ; ----------------------------------------------------------------------------
00D305 1
00D305 1 A9 0C lda #$0C ; $D305: A9 0C
00D307 1 8D B7 03 sta $03B7 ; $D307: 8D B7 03
00D30A 1
00D30A 1 A9 0A lda #$0A ; $D30A: A9 0A
00D30C 1 20 41 EB jsr StoreObjectEventBankValue ; $D30C: 20 41 EB
00D30F 1
00D30F 1 20 3C D3 jsr DispatchActionType ; $D30F: 20 3C D3
00D312 1
00D312 1 E6 9D inc CurrentActionState ; $D312: E6 9D
00D314 1 CE B7 03 dec $03B7 ; $D314: CE B7 03
00D317 1
00D317 1 ; ----------------------------------------------------------------------------
00D317 1 ; Dispatch the next state through an inline command.
00D317 1 ; ----------------------------------------------------------------------------
00D317 1
00D317 1 20 0A EB jsr QueueInlineObjectEvent ; $D317: 20 0A EB
00D31A 1
00D31A 1 ; Inline command record consumed by QueueInlineObjectEvent.
00D31A 1 11 D7 D5 .byte $11,$D7,$D5 ; $D31A-$D31C
00D31D 1
00D31D 1 A9 1E lda #$1E ; $D31D: A9 1E
00D31F 1 20 41 EB jsr StoreObjectEventBankValue ; $D31F: 20 41 EB
00D322 1
00D322 1 A9 2F lda #$2F ; $D322: A9 2F
00D324 1 8D A2 03 sta $03A2 ; $D324: 8D A2 03
00D327 1
00D327 1 4C 6A EB jmp CommonEngineExit ; $D327: 4C 6A EB
00D32A 1
00D32A 1 ; ============================================================================
00D32A 1 ; $D32A-$D338
00D32A 1 ; Select an action value from a three-byte lookup table.
00D32A 1 ;
00D32A 1 ; Entry:
00D32A 1 ; X = object or player index
00D32A 1 ;
00D32A 1 ; Operation:
00D32A 1 ; 1. Increment $7F.
00D32A 1 ; 2. Divide X by two.
00D32A 1 ; 3. Use the resulting index to read $0599-$059B.
00D32A 1 ; 4. Divide that value by two.
00D32A 1 ; 5. Use the result as an index into ObjectActionLookupTable.
00D32A 1 ; 6. Branch back to $D2F9 with the selected value in A.
00D32A 1 ;
00D32A 1 ; The table values are all nonzero, so the final BNE is effectively
00D32A 1 ; unconditional for valid indices.
00D32A 1 ; ============================================================================
00D32A 1
00D32A 1 SelectActionFromObjectState: ; $D32A
00D32A 1 E6 7F inc SelectedStateCount ; $D32A: E6 7F
00D32C 1
00D32C 1 8A txa ; $D32C: 8A
00D32D 1 4A lsr ; $D32D: 4A
00D32E 1 AA tax ; $D32E: AA
00D32F 1
00D32F 1 BD 99 05 lda $0599,x ; $D32F: BD 99 05
00D332 1 4A lsr ; $D332: 4A
00D333 1 AA tax ; $D333: AA
00D334 1
00D334 1 BD 38 D3 lda $D338,x ; $D334: BD 38 D3
00D337 1 D0 C0 bne SaveBatterAction ; $D337: D0 C0
00D339 1
00D339 1 ; ============================================================================
00D339 1 ; $D339-$D33B
00D339 1 ; Action/control lookup table.
00D339 1 ;
00D339 1 ; Indexed by half of the selected value from $0599-$059B.
00D339 1 ; ============================================================================
00D339 1
00D339 1 ObjectActionLookupTable: ; $D339
00D339 1 01 08 02 .byte $01,$08,$02
00D33C 1
00D33C 1 ; ============================================================================
00D33C 1 ; $D33C-$D381
00D33C 1 ; Select one of three state paths using $21 and the values at $9F-$A1.
00D33C 1 ;
00D33C 1 ; The routine can:
00D33C 1 ; Set $059D to $01 and dispatch command $10
00D33C 1 ; Set $059E to $02 and dispatch command $12
00D33C 1 ; Set $05A0 to $03 and dispatch command $16
00D33C 1 ; ============================================================================
00D33C 1
00D33C 1 ; ----------------------------------------------------------------------------
00D33C 1 ; Contract:
00D33C 1 ; Description: Implements Dispatch Action Type.
00D33C 1 ; Entry: Registers: A, X; Memory: selectedpitchaction, secondaryactorstate0
00D33C 1 ; Returns/products: Registers/clobbers: A, X
00D33C 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00D33C 1 ; Memory effects: $059d
00D33C 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00D33C 1 ; comparison, load, or store path and are not a stable API product.
00D33C 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00D33C 1 ; ----------------------------------------------------------------------------
00D33C 1 DispatchActionType: ; $D33C
00D33C 1 A5 21 lda SelectedPitchAction ; $D33C: A5 21
00D33E 1 29 0B and #$0B ; $D33E: 29 0B
00D340 1 D0 1F bne Routine_D361_TestBits ; $D340: D0 1F
00D342 1
00D342 1 ; ----------------------------------------------------------------------------
00D342 1 ; Search the three entries at $9F-$A1 in reverse order.
00D342 1 ; ----------------------------------------------------------------------------
00D342 1
00D342 1 A2 02 ldx #$02 ; $D342: A2 02
00D344 1
00D344 1 Routine_D344_SearchEntries: ; $D344
00D344 1 B5 9F lda SecondaryActorState0,x ; $D344: B5 9F
00D346 1 C9 08 cmp #$08 ; $D346: C9 08
00D348 1 B0 08 bcs Routine_D352_NextEntry ; $D348: B0 08
00D34A 1
00D34A 1 C9 06 cmp #$06 ; $D34A: C9 06
00D34C 1 B0 25 bcs Routine_D373_State3 ; $D34C: B0 25
00D34E 1
00D34E 1 C9 04 cmp #$04 ; $D34E: C9 04
00D350 1 B0 15 bcs Routine_D367_State2 ; $D350: B0 15
00D352 1
00D352 1 Routine_D352_NextEntry: ; $D352
00D352 1 CA dex ; $D352: CA
00D353 1 10 EF bpl Routine_D344_SearchEntries
00D355 1 ; $D353: 10 EF
00D355 1
00D355 1 ; ----------------------------------------------------------------------------
00D355 1 ; State 1.
00D355 1 ; ----------------------------------------------------------------------------
00D355 1
00D355 1 Routine_D355_State1: ; $D355
00D355 1 A9 01 lda #$01 ; $D355: A9 01
00D357 1 8D 9D 05 sta $059D ; $D357: 8D 9D 05
00D35A 1
00D35A 1 20 0A EB jsr QueueInlineObjectEvent ; $D35A: 20 0A EB
00D35D 1
00D35D 1 ; Inline command record consumed by QueueInlineObjectEvent.
00D35D 1 10 AB E3 .byte $10,$AB,$E3 ; $D35D-$D35F
00D360 1
00D360 1 60 rts ; $D360: 60
00D361 1
00D361 1 ; ----------------------------------------------------------------------------
00D361 1 ; When $21 & $0B is nonzero, test its low two bits.
00D361 1 ;
00D361 1 ; Bit 0 selects state 1.
00D361 1 ; Bit 1 selects state 3.
00D361 1 ; Otherwise, state 2 is selected.
00D361 1 ; ----------------------------------------------------------------------------
00D361 1
00D361 1 Routine_D361_TestBits: ; $D361
00D361 1 4A lsr ; $D361: 4A
00D362 1 B0 F1 bcs Routine_D355_State1 ; $D362: B0 F1
00D364 1
00D364 1 4A lsr ; $D364: 4A
00D365 1 B0 0C bcs Routine_D373_State3 ; $D365: B0 0C
00D367 1
00D367 1 ; ----------------------------------------------------------------------------
00D367 1 ; State 2.
00D367 1 ; ----------------------------------------------------------------------------
00D367 1
00D367 1 Routine_D367_State2: ; $D367
00D367 1 A9 02 lda #$02 ; $D367: A9 02
00D369 1 8D 9E 05 sta $059E ; $D369: 8D 9E 05
00D36C 1
00D36C 1 20 0A EB jsr QueueInlineObjectEvent ; $D36C: 20 0A EB
00D36F 1
00D36F 1 ; Inline command record consumed by QueueInlineObjectEvent.
00D36F 1 12 AB E3 .byte $12,$AB,$E3 ; $D36F-$D371
00D372 1
00D372 1 60 rts ; $D372: 60
00D373 1
00D373 1 ; ----------------------------------------------------------------------------
00D373 1 ; State 3.
00D373 1 ; ----------------------------------------------------------------------------
00D373 1
00D373 1 Routine_D373_State3: ; $D373
00D373 1 A9 03 lda #$03 ; $D373: A9 03
00D375 1 8D A0 05 sta $05A0 ; $D375: 8D A0 05
00D378 1
00D378 1 20 0A EB jsr QueueInlineObjectEvent ; $D378: 20 0A EB
00D37B 1
00D37B 1 ; Inline command record consumed by QueueInlineObjectEvent.
00D37B 1 16 AB E3 .byte $16,$AB,$E3 ; $D37B-$D37D
00D37E 1
00D37E 1 CE B7 03 dec $03B7 ; $D37E: CE B7 03
00D381 1
00D381 1 60 rts ; $D381: 60
00D382 1
00D382 1 ; ============================================================================
00D382 1 ; $D382-$D3EF
00D382 1 ; Derive an index from input state, apply signed coordinate offsets, constrain
00D382 1 ; the resulting positions, update object state, and repeat.
00D382 1 ; ============================================================================
00D382 1
00D382 1 MoveControlledObject: ; $D382
00D382 1 20 48 EB jsr SelectObjectEventBank1 ; $D382: 20 48 EB
00D385 1
00D385 1 ; ----------------------------------------------------------------------------
00D385 1 ; Derive a small index in Y from the value at $13.
00D385 1 ;
00D385 1 ; The value is ORed with $F0, then shifted right until carry clears.
00D385 1 ; Y begins at $FF and is incremented once per shift.
00D385 1 ; ----------------------------------------------------------------------------
00D385 1
00D385 1 A0 FF ldy #$FF ; $D385: A0 FF
00D387 1
00D387 1 A5 13 lda InputState1 ; $D387: A5 13
00D389 1 09 F0 ora #$F0 ; $D389: 09 F0
00D38B 1
00D38B 1 Routine_D38B_FindIndex: ; $D38B
00D38B 1 C8 iny ; $D38B: C8
00D38C 1 4A lsr ; $D38C: 4A
00D38D 1 90 FC bcc Routine_D38B_FindIndex ; $D38D: 90 FC
00D38F 1
00D38F 1 84 05 sty MathTemp05 ; $D38F: 84 05
00D391 1
00D391 1 ; ----------------------------------------------------------------------------
00D391 1 ; Load a signed horizontal offset from the table at $D3F0.
00D391 1 ;
00D391 1 ; X is used as the sign-extension byte:
00D391 1 ;
00D391 1 ; X = $00 for nonnegative offsets
00D391 1 ; X = $FF for negative offsets
00D391 1 ; ----------------------------------------------------------------------------
00D391 1
00D391 1 A2 00 ldx #$00 ; $D391: A2 00
00D393 1
00D393 1 B9 F0 D3 lda ControlledHorizontalOffsetTable,y ; $D393: B9 F0 D3
00D396 1 10 01 bpl Routine_D399_AddHorizontal
00D398 1 ; $D396: 10 01
00D398 1
00D398 1 CA dex ; $D398: CA
00D399 1 ; X = $FF
00D399 1
00D399 1 Routine_D399_AddHorizontal: ; $D399
00D399 1 18 clc ; $D399: 18
00D39A 1
00D39A 1 6D 0F 05 adc $050F ; $D39A: 6D 0F 05
00D39D 1 A8 tay ; $D39D: A8
00D39E 1 85 AE sta CalculatedCoordinateLow ; $D39E: 85 AE
00D3A0 1
00D3A0 1 8A txa ; $D3A0: 8A
00D3A1 1 6D 10 05 adc $0510 ; $D3A1: 6D 10 05
00D3A4 1 85 AF sta CalculatedCoordinateHigh ; $D3A4: 85 AF
00D3A6 1
00D3A6 1 ; ----------------------------------------------------------------------------
00D3A6 1 ; Normalize or transform the signed horizontal coordinate in A:Y.
00D3A6 1 ; ----------------------------------------------------------------------------
00D3A6 1
00D3A6 1 20 CB E7 jsr AbsoluteValueAY ; $D3A6: 20 CB E7
00D3A9 1 AA tax ; $D3A9: AA
00D3AA 1
00D3AA 1 ; ----------------------------------------------------------------------------
00D3AA 1 ; Accept the new horizontal coordinate only when it lies inside the permitted
00D3AA 1 ; range.
00D3AA 1 ;
00D3AA 1 ; The two-stage signed test uses Y as the low byte and X/A as the high byte.
00D3AA 1 ; ----------------------------------------------------------------------------
00D3AA 1
00D3AA 1 C0 60 cpy #$60 ; $D3AA: C0 60
00D3AC 1 E9 01 sbc #$01 ; $D3AC: E9 01
00D3AE 1 10 11 bpl Routine_D3C1_Vertical ; $D3AE: 10 11
00D3B0 1
00D3B0 1 8A txa ; $D3B0: 8A
00D3B1 1
00D3B1 1 C0 00 cpy #$00 ; $D3B1: C0 00
00D3B3 1 E9 01 sbc #$01 ; $D3B3: E9 01
00D3B5 1 30 0A bmi Routine_D3C1_Vertical ; $D3B5: 30 0A
00D3B7 1
00D3B7 1 A5 AE lda CalculatedCoordinateLow ; $D3B7: A5 AE
00D3B9 1 8D 0F 05 sta $050F ; $D3B9: 8D 0F 05
00D3BC 1
00D3BC 1 A5 AF lda CalculatedCoordinateHigh ; $D3BC: A5 AF
00D3BE 1 8D 10 05 sta $0510 ; $D3BE: 8D 10 05
00D3C1 1
00D3C1 1 ; ----------------------------------------------------------------------------
00D3C1 1 ; Load a signed vertical offset from the overlapping table at $D3F3.
00D3C1 1 ; ----------------------------------------------------------------------------
00D3C1 1
00D3C1 1 Routine_D3C1_Vertical: ; $D3C1
00D3C1 1 A4 05 ldy MathTemp05 ; $D3C1: A4 05
00D3C3 1 A2 00 ldx #$00 ; $D3C3: A2 00
00D3C5 1
00D3C5 1 B9 F3 D3 lda ControlledVerticalOffsetTable,y ; $D3C5: B9 F3 D3
00D3C8 1 10 01 bpl Routine_D3CB_AddVertical
00D3CA 1 ; $D3C8: 10 01
00D3CA 1
00D3CA 1 CA dex ; $D3CA: CA
00D3CB 1 ; X = $FF
00D3CB 1
00D3CB 1 Routine_D3CB_AddVertical: ; $D3CB
00D3CB 1 18 clc ; $D3CB: 18
00D3CC 1
00D3CC 1 6D 40 05 adc $0540 ; $D3CC: 6D 40 05
00D3CF 1 A8 tay ; $D3CF: A8
00D3D0 1
00D3D0 1 8A txa ; $D3D0: 8A
00D3D1 1 6D 41 05 adc $0541 ; $D3D1: 6D 41 05
00D3D4 1 AA tax ; $D3D4: AA
00D3D5 1
00D3D5 1 ; ----------------------------------------------------------------------------
00D3D5 1 ; Accept the vertical coordinate only when it lies inside the permitted range.
00D3D5 1 ; ----------------------------------------------------------------------------
00D3D5 1
00D3D5 1 C0 C0 cpy #$C0 ; $D3D5: C0 C0
00D3D7 1 E9 F8 sbc #$F8 ; $D3D7: E9 F8
00D3D9 1 10 0D bpl Routine_D3E8_UpdateObject
00D3DB 1 ; $D3D9: 10 0D
00D3DB 1
00D3DB 1 8A txa ; $D3DB: 8A
00D3DC 1
00D3DC 1 C0 A0 cpy #$A0 ; $D3DC: C0 A0
00D3DE 1 E9 F7 sbc #$F7 ; $D3DE: E9 F7
00D3E0 1 30 06 bmi Routine_D3E8_UpdateObject
00D3E2 1 ; $D3E0: 30 06
00D3E2 1
00D3E2 1 8C 40 05 sty $0540 ; $D3E2: 8C 40 05
00D3E5 1 8E 41 05 stx $0541 ; $D3E5: 8E 41 05
00D3E8 1
00D3E8 1 ; ----------------------------------------------------------------------------
00D3E8 1 ; Update object six, then repeat the routine.
00D3E8 1 ; ----------------------------------------------------------------------------
00D3E8 1
00D3E8 1 Routine_D3E8_UpdateObject: ; $D3E8
00D3E8 1 A2 06 ldx #$06 ; $D3E8: A2 06
00D3EA 1 20 B7 E6 jsr ClearMovementTransforms ; $D3EA: 20 B7 E6
00D3ED 1
00D3ED 1 4C 82 D3 jmp MoveControlledObject ; $D3ED: 4C 82 D3
00D3F0 1
00D3F0 1 ; ============================================================================
00D3F0 1 ; Temporary aliases for the lookup data immediately following the routine.
00D3F0 1 ; Remove these aliases when the $D3F0 data block is decoded.
00D3F0 1 ; ============================================================================
00D3F0 1
00D3F0 1 ControlledHorizontalOffsetTable: ; $D3F0
00D3F0 1 01 FF 00 .byte $01,$FF,$00
00D3F3 1
00D3F3 1 ControlledVerticalOffsetTable: ; $D3F3
00D3F3 1 00 00 FF 01 .byte $00,$00,$FF,$01,$00
00D3F7 1 00
00D3F8 1
00D3F8 1 ; ============================================================================
00D3F8 1 ; $D3F8-$D477
00D3F8 1 ; Randomized timing and coordinate-validation routine.
00D3F8 1 ; ============================================================================
00D3F8 1
00D3F8 1 RunControlledActorDelay: ; $D3F8
00D3F8 1 A9 14 lda #$14 ; $D3F8: A9 14
00D3FA 1 85 92 sta ActionDelayCounter ; $D3FA: 85 92
00D3FC 1
00D3FC 1 ; ----------------------------------------------------------------------------
00D3FC 1 ; Run $EB4C twenty times while setting $13 to $80 between iterations.
00D3FC 1 ; ----------------------------------------------------------------------------
00D3FC 1
00D3FC 1 Routine_D3FC_InitialDelay: ; $D3FC
00D3FC 1 20 4C EB jsr SelectObjectEventBank0 ; $D3FC: 20 4C EB
00D3FF 1
00D3FF 1 A9 80 lda #$80 ; $D3FF: A9 80
00D401 1 85 13 sta InputState1 ; $D401: 85 13
00D403 1
00D403 1 C6 92 dec ActionDelayCounter ; $D403: C6 92
00D405 1 D0 F5 bne Routine_D3FC_InitialDelay
00D407 1 ; $D405: D0 F5
00D407 1
00D407 1 ; ----------------------------------------------------------------------------
00D407 1 ; Generate a random value from zero through ten.
00D407 1 ; ----------------------------------------------------------------------------
00D407 1
00D407 1 SelectControlledActorDelay: ; $D407
00D407 1 20 F5 E5 jsr AdvanceRandomState ; $D407: 20 F5 E5
00D40A 1
00D40A 1 29 0F and #$0F ; $D40A: 29 0F
00D40C 1 C9 0B cmp #$0B ; $D40C: C9 0B
00D40E 1 B0 F7 bcs SelectControlledActorDelay
00D410 1 ; $D40E: B0 F7
00D410 1
00D410 1 ; ----------------------------------------------------------------------------
00D410 1 ; Convert values ten and below into a signed countdown-like value.
00D410 1 ;
00D410 1 ; Carry remains set after CMP when A is ten, otherwise it is clear. The
00D410 1 ; subtraction intentionally uses that carry state.
00D410 1 ; ----------------------------------------------------------------------------
00D410 1
00D410 1 E9 0A sbc #$0A ; $D410: E9 0A
00D412 1 85 92 sta ActionDelayCounter ; $D412: 85 92
00D414 1
00D414 1 ; ----------------------------------------------------------------------------
00D414 1 ; Wait until the high position byte at $053B becomes negative.
00D414 1 ; ----------------------------------------------------------------------------
00D414 1
00D414 1 WaitForActorAscent: ; $D414
00D414 1 20 48 EB jsr SelectObjectEventBank1 ; $D414: 20 48 EB
00D417 1
00D417 1 AE 3B 05 ldx $053B ; $D417: AE 3B 05
00D41A 1 CA dex ; $D41A: CA
00D41B 1 10 F7 bpl WaitForActorAscent
00D41D 1 ; $D41B: 10 F7
00D41D 1
00D41D 1 ; ----------------------------------------------------------------------------
00D41D 1 ; Increment the countdown and wait until $053B reaches at least $FD.
00D41D 1 ; ----------------------------------------------------------------------------
00D41D 1
00D41D 1 WaitForActorDescent: ; $D41D
00D41D 1 E6 92 inc ActionDelayCounter ; $D41D: E6 92
00D41F 1
00D41F 1 20 48 EB jsr SelectObjectEventBank1 ; $D41F: 20 48 EB
00D422 1
00D422 1 AD 3B 05 lda $053B ; $D422: AD 3B 05
00D425 1 C9 FD cmp #$FD ; $D425: C9 FD
00D427 1 10 F4 bpl WaitForActorDescent
00D429 1 ; $D427: 10 F4
00D429 1
00D429 1 ; ----------------------------------------------------------------------------
00D429 1 ; Generate a random byte. Values below two take the alternate timing path.
00D429 1 ; ----------------------------------------------------------------------------
00D429 1
00D429 1 20 F5 E5 jsr AdvanceRandomState ; $D429: 20 F5 E5
00D42C 1
00D42C 1 C9 02 cmp #$02 ; $D42C: C9 02
00D42E 1 90 31 bcc SelectActorAlternateDelay
00D430 1 ; $D42E: 90 31
00D430 1
00D430 1 ; ----------------------------------------------------------------------------
00D430 1 ; Normalize the current horizontal position in A:Y.
00D430 1 ; ----------------------------------------------------------------------------
00D430 1
00D430 1 AA tax ; $D430: AA
00D431 1
00D431 1 AC 09 05 ldy $0509 ; $D431: AC 09 05
00D434 1 AD 0A 05 lda $050A ; $D434: AD 0A 05
00D437 1
00D437 1 20 CB E7 jsr AbsoluteValueAY ; $D437: 20 CB E7
00D43A 1
00D43A 1 ; ----------------------------------------------------------------------------
00D43A 1 ; Validate the normalized coordinate against two bounds.
00D43A 1 ;
00D43A 1 ; X still contains the random byte selected at $D429.
00D43A 1 ; ----------------------------------------------------------------------------
00D43A 1
00D43A 1 E0 DC cpx #$DC ; $D43A: E0 DC
00D43C 1 B0 37 bcs FinishControlledActorDelay ; $D43C: B0 37
00D43E 1
00D43E 1 C0 20 cpy #$20 ; $D43E: C0 20
00D440 1 E9 00 sbc #$00 ; $D440: E9 00
00D442 1 90 04 bcc RunActorDelayCountdown ; $D442: 90 04
00D444 1
00D444 1 E0 38 cpx #$38 ; $D444: E0 38
00D446 1 B0 2D bcs FinishControlledActorDelay ; $D446: B0 2D
00D448 1
00D448 1 ; ----------------------------------------------------------------------------
00D448 1 ; Wait while counting $92 down through zero.
00D448 1 ; ----------------------------------------------------------------------------
00D448 1
00D448 1 RunActorDelayCountdown: ; $D448
00D448 1 20 48 EB jsr SelectObjectEventBank1 ; $D448: 20 48 EB
00D44B 1
00D44B 1 C6 92 dec ActionDelayCounter ; $D44B: C6 92
00D44D 1 10 F9 bpl RunActorDelayCountdown ; $D44D: 10 F9
00D44F 1
00D44F 1 ; ----------------------------------------------------------------------------
00D44F 1 ; Run another fixed twenty-iteration delay.
00D44F 1 ; ----------------------------------------------------------------------------
00D44F 1
00D44F 1 A9 14 lda #$14 ; $D44F: A9 14
00D451 1 85 92 sta ActionDelayCounter ; $D451: 85 92
00D453 1
00D453 1 RunActorFinalDelay: ; $D453
00D453 1 20 4C EB jsr SelectObjectEventBank0 ; $D453: 20 4C EB
00D456 1
00D456 1 A9 80 lda #$80 ; $D456: A9 80
00D458 1 85 13 sta InputState1 ; $D458: 85 13
00D45A 1
00D45A 1 C6 92 dec ActionDelayCounter ; $D45A: C6 92
00D45C 1 D0 F5 bne RunActorFinalDelay ; $D45C: D0 F5
00D45E 1
00D45E 1 4C 6A EB jmp CommonEngineExit ; $D45E: 4C 6A EB
00D461 1
00D461 1 ; ----------------------------------------------------------------------------
00D461 1 ; Alternate randomized delay path for values below two.
00D461 1 ; ----------------------------------------------------------------------------
00D461 1
00D461 1 SelectActorAlternateDelay: ; $D461
00D461 1 20 F5 E5 jsr AdvanceRandomState ; $D461: 20 F5 E5
00D464 1
00D464 1 29 07 and #$07 ; $D464: 29 07
00D466 1 69 04 adc #$04 ; $D466: 69 04
00D468 1 85 92 sta ActionDelayCounter ; $D468: 85 92
00D46A 1
00D46A 1 RunActorAlternateDelay: ; $D46A
00D46A 1 20 4C EB jsr SelectObjectEventBank0 ; $D46A: 20 4C EB
00D46D 1
00D46D 1 A9 80 lda #$80 ; $D46D: A9 80
00D46F 1 85 13 sta InputState1 ; $D46F: 85 13
00D471 1
00D471 1 C6 92 dec ActionDelayCounter ; $D471: C6 92
00D473 1 D0 F5 bne RunActorAlternateDelay
00D475 1 ; $D473: D0 F5
00D475 1
00D475 1 FinishControlledActorDelay: ; $D475
00D475 1 4C 6A EB jmp CommonEngineExit ; $D475: 4C 6A EB
00D478 1
00D478 1 ; ============================================================================
00D478 1 ; $D478-$D4FE
00D478 1 ; Initialize object six, transform coordinates, and run a state-controlled
00D478 1 ; animation loop.
00D478 1 ; ============================================================================
00D478 1
00D478 1 RunFielderAnimationSequence: ; $D478
00D478 1 A9 00 lda #$00 ; $D478: A9 00
00D47A 1 85 87 sta ObjectProximityState ; $D47A: 85 87
00D47C 1
00D47C 1 ; ----------------------------------------------------------------------------
00D47C 1 ; Initialize indexed fields for object offset $06.
00D47C 1 ;
00D47C 1 ; Routine $C9A7 consumes five inline bytes:
00D47C 1 ;
00D47C 1 ; $06 object offset/metadata
00D47C 1 ; $F0,$FE,$20,$F8 four field values
00D47C 1 ; ----------------------------------------------------------------------------
00D47C 1
00D47C 1 20 A7 C9 jsr LoadObjectPositionInline
00D47F 1 ; $D47C: 20 A7 C9
00D47F 1
00D47F 1 06 .byte $06 ; $D47F
00D480 1 F0 FE 20 F8 .byte $F0,$FE,$20,$F8 ; $D480-$D483
00D484 1
00D484 1 ; ----------------------------------------------------------------------------
00D484 1 ; XOR both bytes of the coordinate at $050F/$0510 with $4C.
00D484 1 ; ----------------------------------------------------------------------------
00D484 1
00D484 1 AD 0F 05 lda $050F ; $D484: AD 0F 05
00D487 1 45 4C eor HorizontalDirectionMask ; $D487: 45 4C
00D489 1 8D 0F 05 sta $050F ; $D489: 8D 0F 05
00D48C 1
00D48C 1 AD 10 05 lda $0510 ; $D48C: AD 10 05
00D48F 1 45 4C eor HorizontalDirectionMask ; $D48F: 45 4C
00D491 1 8D 10 05 sta $0510 ; $D491: 8D 10 05
00D494 1
00D494 1 ; ----------------------------------------------------------------------------
00D494 1 ; Initialize animation and timing state.
00D494 1 ; ----------------------------------------------------------------------------
00D494 1
00D494 1 A9 00 lda #$00 ; $D494: A9 00
00D496 1 8D B3 03 sta $03B3 ; $D496: 8D B3 03
00D499 1
00D499 1 A9 1E lda #$1E ; $D499: A9 1E
00D49B 1 20 41 EB jsr StoreObjectEventBankValue ; $D49B: 20 41 EB
00D49E 1
00D49E 1 ; ----------------------------------------------------------------------------
00D49E 1 ; Shared loop restart point.
00D49E 1 ; ----------------------------------------------------------------------------
00D49E 1
00D49E 1 ResetFielderAnimationCounters: ; $D49E
00D49E 1 A9 00 lda #$00 ; $D49E: A9 00
00D4A0 1 85 8D sta FielderInputBalance ; $D4A0: 85 8D
00D4A2 1
00D4A2 1 A9 0B lda #$0B ; $D4A2: A9 0B
00D4A4 1 85 8C sta FielderAnimationCountdown ; $D4A4: 85 8C
00D4A6 1
00D4A6 1 ; ----------------------------------------------------------------------------
00D4A6 1 ; Wait until $13 becomes negative.
00D4A6 1 ; ----------------------------------------------------------------------------
00D4A6 1
00D4A6 1 WaitForFielderInput: ; $D4A6
00D4A6 1 20 48 EB jsr SelectObjectEventBank1 ; $D4A6: 20 48 EB
00D4A9 1
00D4A9 1 A5 13 lda InputState1 ; $D4A9: A5 13
00D4AB 1 10 F9 bpl WaitForFielderInput
00D4AD 1 ; $D4AB: 10 F9
00D4AD 1
00D4AD 1 ; ----------------------------------------------------------------------------
00D4AD 1 ; Initialize the per-cycle counter and advance the animation.
00D4AD 1 ; ----------------------------------------------------------------------------
00D4AD 1
00D4AD 1 AdvanceFielderAnimationCycle: ; $D4AD
00D4AD 1 A9 03 lda #$03 ; $D4AD: A9 03
00D4AF 1 85 0C sta $0C ; $D4AF: 85 0C
00D4B1 1
00D4B1 1 EE B3 03 inc $03B3 ; $D4B1: EE B3 03
00D4B4 1
00D4B4 1 ; ----------------------------------------------------------------------------
00D4B4 1 ; A state condition at $82/$87 can branch to the next routine at $D4FF.
00D4B4 1 ; ----------------------------------------------------------------------------
00D4B4 1
00D4B4 1 CheckFielderAnimationState: ; $D4B4
00D4B4 1 A5 82 lda ActorActionComplete ; $D4B4: A5 82
00D4B6 1 D0 06 bne UpdateFielderAnimationFrame ; $D4B6: D0 06
00D4B8 1
00D4B8 1 A5 87 lda ObjectProximityState ; $D4B8: A5 87
00D4BA 1 C9 01 cmp #$01 ; $D4BA: C9 01
00D4BC 1 F0 41 beq SelectRandomMotionParameters ; $D4BC: F0 41
00D4BE 1
00D4BE 1 ; ----------------------------------------------------------------------------
00D4BE 1 ; Wait one frame and compare the animation value against five.
00D4BE 1 ; ----------------------------------------------------------------------------
00D4BE 1
00D4BE 1 UpdateFielderAnimationFrame: ; $D4BE
00D4BE 1 20 48 EB jsr SelectObjectEventBank1 ; $D4BE: 20 48 EB
00D4C1 1
00D4C1 1 38 sec ; $D4C1: 38
00D4C2 1
00D4C2 1 AD B3 03 lda $03B3 ; $D4C2: AD B3 03
00D4C5 1 E9 05 sbc #$05 ; $D4C5: E9 05
00D4C7 1 F0 1E beq ReverseFielderAnimation ; $D4C7: F0 1E
00D4C9 1
00D4C9 1 ; ----------------------------------------------------------------------------
00D4C9 1 ; Adjust $8D according to the sign of $13.
00D4C9 1 ; ----------------------------------------------------------------------------
00D4C9 1
00D4C9 1 A5 13 lda InputState1 ; $D4C9: A5 13
00D4CB 1 30 08 bmi UpdateFielderAnimationCounters
00D4CD 1 ; $D4CB: 30 08
00D4CD 1
00D4CD 1 C6 8D dec FielderInputBalance ; $D4CD: C6 8D
00D4CF 1 10 E3 bpl CheckFielderAnimationState ; $D4CF: 10 E3
00D4D1 1
00D4D1 1 E6 8D inc FielderInputBalance ; $D4D1: E6 8D
00D4D3 1 10 DF bpl CheckFielderAnimationState ; $D4D3: 10 DF
00D4D5 1
00D4D5 1 ; ----------------------------------------------------------------------------
00D4D5 1 ; Update loop counters.
00D4D5 1 ; ----------------------------------------------------------------------------
00D4D5 1
00D4D5 1 UpdateFielderAnimationCounters: ; $D4D5
00D4D5 1 E6 8D inc FielderInputBalance ; $D4D5: E6 8D
00D4D7 1
00D4D7 1 C6 8C dec FielderAnimationCountdown ; $D4D7: C6 8C
00D4D9 1 C6 0C dec $0C ; $D4D9: C6 0C
00D4DB 1 D0 D7 bne CheckFielderAnimationState ; $D4DB: D0 D7
00D4DD 1
00D4DD 1 ; ----------------------------------------------------------------------------
00D4DD 1 ; Repeat until the animation value reaches five.
00D4DD 1 ; ----------------------------------------------------------------------------
00D4DD 1
00D4DD 1 AE B3 03 ldx $03B3 ; $D4DD: AE B3 03
00D4E0 1 E0 05 cpx #$05 ; $D4E0: E0 05
00D4E2 1 F0 DA beq UpdateFielderAnimationFrame ; $D4E2: F0 DA
00D4E4 1
00D4E4 1 4C AD D4 jmp AdvanceFielderAnimationCycle ; $D4E4: 4C AD D4
00D4E7 1
00D4E7 1 ; ----------------------------------------------------------------------------
00D4E7 1 ; Handle animation value five.
00D4E7 1 ; ----------------------------------------------------------------------------
00D4E7 1
00D4E7 1 ReverseFielderAnimation: ; $D4E7
00D4E7 1 85 8D sta FielderInputBalance ; $D4E7: 85 8D
00D4E9 1 ; A is zero after SBC #$05 succeeded.
00D4E9 1
00D4E9 1 A5 13 lda InputState1 ; $D4E9: A5 13
00D4EB 1 30 D1 bmi UpdateFielderAnimationFrame ; $D4EB: 30 D1
00D4ED 1
00D4ED 1 CE B3 03 dec $03B3 ; $D4ED: CE B3 03
00D4F0 1
00D4F0 1 A9 02 lda #$02 ; $D4F0: A9 02
00D4F2 1 20 41 EB jsr StoreObjectEventBankValue ; $D4F2: 20 41 EB
00D4F5 1
00D4F5 1 AD B3 03 lda $03B3 ; $D4F5: AD B3 03
00D4F8 1 C9 00 cmp #$00 ; $D4F8: C9 00
00D4FA 1 D0 EB bne ReverseFielderAnimation ; $D4FA: D0 EB
00D4FC 1
00D4FC 1 4C 9E D4 jmp ResetFielderAnimationCounters
00D4FF 1 ; $D4FC: 4C 9E D4
00D4FF 1
00D4FF 1
00D4FF 1 ; ============================================================================
00D4FF 1 ; $D4FF-$D51B
00D4FF 1 ; Select a threshold index and calculate a randomized value.
00D4FF 1 ; ============================================================================
00D4FF 1
00D4FF 1 SelectRandomMotionParameters: ; $D4FF
00D4FF 1 A2 05 ldx #$05 ; $D4FF: A2 05
00D501 1
00D501 1 ; ----------------------------------------------------------------------------
00D501 1 ; Generate one random value.
00D501 1 ;
00D501 1 ; The same random value is compared against multiple thresholds while X
00D501 1 ; counts downward. The loop at $D50A returns to the CMP at $D504, not to the
00D501 1 ; random-number call.
00D501 1 ; ----------------------------------------------------------------------------
00D501 1
00D501 1 20 F5 E5 jsr AdvanceRandomState ; $D501: 20 F5 E5
00D504 1
00D504 1 SearchMotionThreshold: ; $D504
00D504 1 DD BD D5 cmp $D5BD,x ; $D504: DD BD D5
00D507 1 B0 07 bcs StartRandomMotion ; $D507: B0 07
00D509 1
00D509 1 CA dex ; $D509: CA
00D50A 1 D0 F8 bne SearchMotionThreshold
00D50C 1 ; $D50A: D0 F8
00D50C 1
00D50C 1 ; ----------------------------------------------------------------------------
00D50C 1 ; No nonzero threshold index was selected.
00D50C 1 ;
00D50C 1 ; X is zero here. Save it to $81 and branch back to the earlier wait loop.
00D50C 1 ; ----------------------------------------------------------------------------
00D50C 1
00D50C 1 86 81 stx RandomValue81 ; $D50C: 86 81
00D50E 1 F0 AE beq UpdateFielderAnimationFrame ; $D50E: F0 AE
00D510 1 ; Always taken because X is zero.
00D510 1
00D510 1 ; ----------------------------------------------------------------------------
00D510 1 ; A threshold was selected.
00D510 1 ;
00D510 1 ; Advance state and combine a new random value with the indexed base value at
00D510 1 ; $D5B8,X.
00D510 1 ; ----------------------------------------------------------------------------
00D510 1
00D510 1 StartRandomMotion: ; $D510
00D510 1 E6 46 inc StateSequenceActive ; $D510: E6 46
00D512 1
00D512 1 20 F5 E5 jsr AdvanceRandomState ; $D512: 20 F5 E5
00D515 1 29 1F and #$1F ; $D515: 29 1F
00D517 1
00D517 1 7D B8 D5 adc $D5B8,x ; $D517: 7D B8 D5
00D51A 1 85 8E sta RandomHorizontalMotion ; $D51A: 85 8E
00D51C 1
00D51C 1 ; ============================================================================
00D51C 1 ; $D51C-$D53F
00D51C 1 ; Select a second table index and perform the first signed calculation.
00D51C 1 ; ============================================================================
00D51C 1
00D51C 1 A2 0A ldx #$0A ; $D51C: A2 0A
00D51E 1
00D51E 1 A5 8D lda FielderInputBalance ; $D51E: A5 8D
00D520 1 85 88 sta MotionDirectionState ; $D520: 85 88
00D522 1 F0 09 beq SelectRandomMotionOffset
00D524 1 ; $D522: F0 09
00D524 1
00D524 1 ; ----------------------------------------------------------------------------
00D524 1 ; Generate random values until one satisfies a threshold selected from the
00D524 1 ; table using base address $D5CE.
00D524 1 ;
00D524 1 ; X is decremented before each comparison.
00D524 1 ; ----------------------------------------------------------------------------
00D524 1
00D524 1 SearchMotionAngleThreshold: ; $D524
00D524 1 20 F5 E5 jsr AdvanceRandomState ; $D524: 20 F5 E5
00D527 1
00D527 1 CompareMotionAngleThreshold: ; $D527
00D527 1 CA dex ; $D527: CA
00D528 1
00D528 1 DD CE D5 cmp $D5CE,x ; $D528: DD CE D5
00D52B 1 90 FA bcc CompareMotionAngleThreshold
00D52D 1 ; $D52B: 90 FA
00D52D 1
00D52D 1 ; ----------------------------------------------------------------------------
00D52D 1 ; Generate another random value. Its low bit is added to the indexed value
00D52D 1 ; read using table base $D5C3.
00D52D 1 ; ----------------------------------------------------------------------------
00D52D 1
00D52D 1 SelectRandomMotionOffset: ; $D52D
00D52D 1 20 F5 E5 jsr AdvanceRandomState ; $D52D: 20 F5 E5
00D530 1
00D530 1 29 01 and #$01 ; $D530: 29 01
00D532 1 7D C3 D5 adc $D5C3,x ; $D532: 7D C3 D5
00D535 1 A8 tay ; $D535: A8
00D536 1
00D536 1 ; ----------------------------------------------------------------------------
00D536 1 ; Pass A = $8E, X = 0, and the selected Y value to the math helper at $E855.
00D536 1 ;
00D536 1 ; Save the returned Y value in $8F and preserve A on the stack.
00D536 1 ; ----------------------------------------------------------------------------
00D536 1
00D536 1 A2 00 ldx #$00 ; $D536: A2 00
00D538 1
00D538 1 A5 8E lda RandomHorizontalMotion ; $D538: A5 8E
00D53A 1 20 55 E8 jsr CalculateVectorFromRotatedMask ; $D53A: 20 55 E8
00D53D 1
00D53D 1 84 8F sty CalculatedVerticalMotion ; $D53D: 84 8F
00D53F 1 48 pha ; $D53F: 48
00D540 1
00D540 1 ; ============================================================================
00D540 1 ; $D540-$D560
00D540 1 ; Construct a randomized signed value in $90, perform a second calculation,
00D540 1 ; then pass both calculated values to InitializeBaseMotion.
00D540 1 ;
00D540 1 ; Entry:
00D540 1 ; A contains the first result from $E855, preserved on the stack.
00D540 1 ; Y contains the corresponding secondary result.
00D540 1 ; ============================================================================
00D540 1
00D540 1 38 sec ; $D540: 38
00D541 1
00D541 1 A5 8C lda FielderAnimationCountdown ; $D541: A5 8C
00D543 1 E9 05 sbc #$05 ; $D543: E9 05
00D545 1
00D545 1 ; ----------------------------------------------------------------------------
00D545 1 ; Scale the signed result.
00D545 1 ;
00D545 1 ; SEC followed by ROL shifts the value left while forcing bit zero to one.
00D545 1 ; Three additional ASL instructions multiply the result by eight.
00D545 1 ; ----------------------------------------------------------------------------
00D545 1
00D545 1 38 sec ; $D545: 38
00D546 1 2A rol ; $D546: 2A
00D547 1 0A asl ; $D547: 0A
00D548 1 0A asl ; $D548: 0A
00D549 1 0A asl ; $D549: 0A
00D54A 1
00D54A 1 85 90 sta RandomVerticalMotion ; $D54A: 85 90
00D54C 1
00D54C 1 ; ----------------------------------------------------------------------------
00D54C 1 ; Add a random five-bit value, then conditionally mirror/sign-adjust it using
00D54C 1 ; the value at $4C.
00D54C 1 ; ----------------------------------------------------------------------------
00D54C 1
00D54C 1 20 F5 E5 jsr AdvanceRandomState ; $D54C: 20 F5 E5
00D54F 1 29 1F and #$1F ; $D54F: 29 1F
00D551 1
00D551 1 65 90 adc RandomVerticalMotion ; $D551: 65 90
00D553 1 45 4C eor HorizontalDirectionMask ; $D553: 45 4C
00D555 1 85 90 sta RandomVerticalMotion ; $D555: 85 90
00D557 1
00D557 1 ; ----------------------------------------------------------------------------
00D557 1 ; Run the signed math helper again.
00D557 1 ;
00D557 1 ; X is cleared, A contains $90, and Y remains the result from the previous
00D557 1 ; $E855 call.
00D557 1 ; ----------------------------------------------------------------------------
00D557 1
00D557 1 A2 00 ldx #$00 ; $D557: A2 00
00D559 1
00D559 1 20 55 E8 jsr CalculateVectorFromRotatedMask ; $D559: 20 55 E8
00D55C 1 AA tax ; $D55C: AA
00D55D 1 ; Preserve the second result in X.
00D55D 1
00D55D 1 68 pla ; $D55D: 68
00D55E 1 ; Restore the first result in A.
00D55E 1
00D55E 1 20 2A CA jsr InitializeBaseMotion ; $D55E: 20 2A CA
00D561 1
00D561 1 ; ============================================================================
00D561 1 ; $D561-$D57A
00D561 1 ; Configure transition state, process event slot four, wait for a frame,
00D561 1 ; and dispatch two inline command records.
00D561 1 ; ============================================================================
00D561 1
00D561 1 C6 86 dec TrajectoryEvaluationEnabled ; $D561: C6 86
00D563 1
00D563 1 A9 10 lda #$10 ; $D563: A9 10
00D565 1 85 FE sta PendingAudioFlags ; $D565: 85 FE
00D567 1
00D567 1 ; ----------------------------------------------------------------------------
00D567 1 ; Process event slot four.
00D567 1 ; ----------------------------------------------------------------------------
00D567 1
00D567 1 A0 04 ldy #$04 ; $D567: A0 04
00D569 1 20 66 EB jsr DispatchNextQueuedEvent ; $D569: 20 66 EB
00D56C 1
00D56C 1 ; ----------------------------------------------------------------------------
00D56C 1 ; Synchronize with the frame/update system.
00D56C 1 ; ----------------------------------------------------------------------------
00D56C 1
00D56C 1 20 48 EB jsr SelectObjectEventBank1 ; $D56C: 20 48 EB
00D56F 1
00D56F 1 ; ----------------------------------------------------------------------------
00D56F 1 ; Dispatch the first inline command record.
00D56F 1 ; ----------------------------------------------------------------------------
00D56F 1
00D56F 1 20 0A EB jsr QueueInlineObjectEvent ; $D56F: 20 0A EB
00D572 1
00D572 1 25 30 DC .byte $25,$30,$DC ; $D572-$D574
00D575 1
00D575 1 ; ----------------------------------------------------------------------------
00D575 1 ; Dispatch the second inline command record.
00D575 1 ; ----------------------------------------------------------------------------
00D575 1
00D575 1 20 0A EB jsr QueueInlineObjectEvent ; $D575: 20 0A EB
00D578 1
00D578 1 29 4C CB .byte $29,$4C,$CB ; $D578-$D57A
00D57B 1
00D57B 1 ; ============================================================================
00D57B 1 ; $D57B-$D598
00D57B 1 ; Short delay followed by an animation loop.
00D57B 1 ; ============================================================================
00D57B 1
00D57B 1 A9 02 lda #$02 ; $D57B: A9 02
00D57D 1 20 41 EB jsr StoreObjectEventBankValue ; $D57D: 20 41 EB
00D580 1
00D580 1 A9 40 lda #$40 ; $D580: A9 40
00D582 1 85 FE sta PendingAudioFlags ; $D582: 85 FE
00D584 1
00D584 1 ; ----------------------------------------------------------------------------
00D584 1 ; If the current animation value is already five or greater, skip the loop
00D584 1 ; and continue at $D599.
00D584 1 ; ----------------------------------------------------------------------------
00D584 1
00D584 1 UpdateMotionEndAnimation: ; $D584
00D584 1 AD B3 03 lda $03B3 ; $D584: AD B3 03
00D587 1 C9 05 cmp #$05 ; $D587: C9 05
00D589 1 B0 0E bcs FinishRandomMotionSequence
00D58B 1 ; $D589: B0 0E
00D58B 1
00D58B 1 ; ----------------------------------------------------------------------------
00D58B 1 ; Increment the animation value, wait eight ticks, and reduce $8D by two.
00D58B 1 ;
00D58B 1 ; Continue while the second decrement leaves $8D nonnegative.
00D58B 1 ; ----------------------------------------------------------------------------
00D58B 1
00D58B 1 EE B3 03 inc $03B3 ; $D58B: EE B3 03
00D58E 1
00D58E 1 A9 08 lda #$08 ; $D58E: A9 08
00D590 1 20 41 EB jsr StoreObjectEventBankValue ; $D590: 20 41 EB
00D593 1
00D593 1 C6 8D dec FielderInputBalance ; $D593: C6 8D
00D595 1 C6 8D dec FielderInputBalance ; $D595: C6 8D
00D597 1
00D597 1 10 EB bpl UpdateMotionEndAnimation
00D599 1 ; $D597: 10 EB
00D599 1 ; ============================================================================
00D599 1 ; $D599-$D5B8
00D599 1 ; Process two event slots, dispatch two inline commands, wait, advance state,
00D599 1 ; and leave through the common engine exit.
00D599 1 ; ============================================================================
00D599 1
00D599 1 FinishRandomMotionSequence: ; $D599
00D599 1 A0 13 ldy #$13 ; $D599: A0 13
00D59B 1 20 66 EB jsr DispatchNextQueuedEvent ; $D59B: 20 66 EB
00D59E 1
00D59E 1 A0 0F ldy #$0F ; $D59E: A0 0F
00D5A0 1 20 66 EB jsr DispatchNextQueuedEvent ; $D5A0: 20 66 EB
00D5A3 1
00D5A3 1 ; ----------------------------------------------------------------------------
00D5A3 1 ; Dispatch the first inline command record.
00D5A3 1 ; ----------------------------------------------------------------------------
00D5A3 1
00D5A3 1 20 0A EB jsr QueueInlineObjectEvent ; $D5A3: 20 0A EB
00D5A6 1
00D5A6 1 06 ED D9 .byte $06,$ED,$D9 ; $D5A6-$D5A8
00D5A9 1
00D5A9 1 ; ----------------------------------------------------------------------------
00D5A9 1 ; Dispatch the second inline command record.
00D5A9 1 ; ----------------------------------------------------------------------------
00D5A9 1
00D5A9 1 20 0A EB jsr QueueInlineObjectEvent ; $D5A9: 20 0A EB
00D5AC 1
00D5AC 1 11 D7 D5 .byte $11,$D7,$D5 ; $D5AC-$D5AE
00D5AF 1
00D5AF 1 ; ----------------------------------------------------------------------------
00D5AF 1 ; Wait $3C ticks, advance $A2, and leave through the common exit.
00D5AF 1 ; ----------------------------------------------------------------------------
00D5AF 1
00D5AF 1 A9 3C lda #$3C ; $D5AF: A9 3C
00D5B1 1 20 41 EB jsr StoreObjectEventBankValue ; $D5B1: 20 41 EB
00D5B4 1
00D5B4 1 E6 A2 inc ObjectSequenceState ; $D5B4: E6 A2
00D5B6 1
00D5B6 1 4C 6A EB jmp CommonEngineExit ; $D5B6: 4C 6A EB
00D5B9 1
00D5B9 1 ; ============================================================================
00D5B9 1 ; $D5B9-$D5D7
00D5B9 1 ; Lookup data used by SelectRandomMotionParameters.
00D5B9 1 ;
00D5B9 1 ; Several instructions intentionally use base addresses immediately before
00D5B9 1 ; these tables. The labels below reflect the actual bytes, while the code
00D5B9 1 ; continues to use the original literal operand addresses:
00D5B9 1 ;
00D5B9 1 ; ADC $D5B8,X
00D5B9 1 ; CMP $D5BD,X
00D5B9 1 ; ADC $D5C3,X
00D5B9 1 ; CMP $D5CE,X
00D5B9 1 ; ============================================================================
00D5B9 1
00D5B9 1 ; ----------------------------------------------------------------------------
00D5B9 1 ; $D5B9-$D5BD
00D5B9 1 ; Five randomized base values.
00D5B9 1 ;
00D5B9 1 ; Accessed through:
00D5B9 1 ;
00D5B9 1 ; ADC $D5B8,X
00D5B9 1 ;
00D5B9 1 ; Expected X values are $01-$05:
00D5B9 1 ;
00D5B9 1 ; X=$01 -> $D5B9 = $C0
00D5B9 1 ; X=$02 -> $D5BA = $E0
00D5B9 1 ; X=$03 -> $D5BB = $00
00D5B9 1 ; X=$04 -> $D5BC = $40
00D5B9 1 ; X=$05 -> $D5BD = $60
00D5B9 1 ; ----------------------------------------------------------------------------
00D5B9 1
00D5B9 1 RandomMotionBaseTable: ; $D5B9
00D5B9 1 C0 E0 00 40 .byte $C0,$E0,$00,$40,$60
00D5BD 1 60
00D5BE 1
00D5BE 1 ; ----------------------------------------------------------------------------
00D5BE 1 ; $D5BE-$D5C2
00D5BE 1 ; Five threshold values.
00D5BE 1 ;
00D5BE 1 ; Accessed through:
00D5BE 1 ;
00D5BE 1 ; CMP $D5BD,X
00D5BE 1 ;
00D5BE 1 ; Expected X values are $01-$05:
00D5BE 1 ;
00D5BE 1 ; X=$01 -> $D5BE = $00
00D5BE 1 ; X=$02 -> $D5BF = $4B
00D5BE 1 ; X=$03 -> $D5C0 = $85
00D5BE 1 ; X=$04 -> $D5C1 = $BC
00D5BE 1 ; X=$05 -> $D5C2 = $F0
00D5BE 1 ; ----------------------------------------------------------------------------
00D5BE 1
00D5BE 1 RandomMotionThresholdTable: ; $D5BE
00D5BE 1 00 4B 85 BC .byte $00,$4B,$85,$BC,$F0
00D5C2 1 F0
00D5C3 1
00D5C3 1 ; ----------------------------------------------------------------------------
00D5C3 1 ; $D5C3-$D5CC
00D5C3 1 ; Ten offset/result values.
00D5C3 1 ;
00D5C3 1 ; Accessed directly through:
00D5C3 1 ;
00D5C3 1 ; ADC $D5C3,X
00D5C3 1 ; ----------------------------------------------------------------------------
00D5C3 1
00D5C3 1 RandomMotionAngleTable: ; $D5C3
00D5C3 1 01 06 09 0C .byte $01,$06,$09,$0C,$12
00D5C7 1 12
00D5C8 1 16 18 1C 1E .byte $16,$18,$1C,$1E,$20
00D5CC 1 20
00D5CD 1
00D5CD 1 ; ----------------------------------------------------------------------------
00D5CD 1 ; $D5CD
00D5CD 1 ; Standalone value immediately before the next threshold table.
00D5CD 1 ;
00D5CD 1 ; Its use is not yet confirmed during the first pass.
00D5CD 1 ; ----------------------------------------------------------------------------
00D5CD 1
00D5CD 1 RandomMotionAnglePadding: ; $D5CD
00D5CD 1 02 .byte $02
00D5CE 1
00D5CE 1 ; ----------------------------------------------------------------------------
00D5CE 1 ; $D5CE-$D5D7
00D5CE 1 ; Ten threshold values.
00D5CE 1 ;
00D5CE 1 ; Accessed through:
00D5CE 1 ;
00D5CE 1 ; CMP $D5CE,X
00D5CE 1 ;
00D5CE 1 ; The search starts with X=$0A and decrements X before comparing, so the first
00D5CE 1 ; access uses X=$09 and reads $D5D7.
00D5CE 1 ; ----------------------------------------------------------------------------
00D5CE 1
00D5CE 1 RandomMotionAngleThresholdTable: ; $D5CE
00D5CE 1 00 0A 19 37 .byte $00,$0A,$19,$37,$55
00D5D2 1 55
00D5D3 1 87 B9 DC EB .byte $87,$B9,$DC,$EB,$F5
00D5D7 1 F5
00D5D8 1
00D5D8 1 ; ============================================================================
00D5D8 1 ; $D5D8-$D60F
00D5D8 1 ; Wait for a group of state and movement fields to clear.
00D5D8 1 ;
00D5D8 1 ; The routine initializes a $3C-frame countdown in $76. While any monitored
00D5D8 1 ; field remains nonzero, the countdown is reset to $3C. Once every field is
00D5D8 1 ; zero, $76 counts down to zero.
00D5D8 1 ; ============================================================================
00D5D8 1
00D5D8 1 WaitForMotionToSettle: ; $D5D8
00D5D8 1 A9 3C lda #$3C ; $D5D8: A9 3C
00D5DA 1 85 76 sta MotionSettledCountdown ; $D5DA: 85 76
00D5DC 1
00D5DC 1 ; ----------------------------------------------------------------------------
00D5DC 1 ; Wait for the next frame/update.
00D5DC 1 ; ----------------------------------------------------------------------------
00D5DC 1
00D5DC 1 Routine_D5DC_WaitFrame: ; $D5DC
00D5DC 1 20 48 EB jsr SelectObjectEventBank1 ; $D5DC: 20 48 EB
00D5DF 1
00D5DF 1 ; ----------------------------------------------------------------------------
00D5DF 1 ; Combine the monitored state fields.
00D5DF 1 ;
00D5DF 1 ; Any nonzero field restarts the routine at $D5D8, resetting the countdown.
00D5DF 1 ; ----------------------------------------------------------------------------
00D5DF 1
00D5DF 1 A5 6F lda PendingEvent ; $D5DF: A5 6F
00D5E1 1
00D5E1 1 0D 73 05 ora $0573 ; $D5E1: 0D 73 05
00D5E4 1 0D 74 05 ora $0574 ; $D5E4: 0D 74 05
00D5E7 1 0D 75 05 ora $0575 ; $D5E7: 0D 75 05
00D5EA 1 0D 76 05 ora $0576 ; $D5EA: 0D 76 05
00D5ED 1 0D 77 05 ora $0577 ; $D5ED: 0D 77 05
00D5F0 1 0D 78 05 ora $0578 ; $D5F0: 0D 78 05
00D5F3 1 0D 79 05 ora $0579 ; $D5F3: 0D 79 05
00D5F6 1 0D 7A 05 ora $057A ; $D5F6: 0D 7A 05
00D5F9 1
00D5F9 1 0D 08 05 ora $0508 ; $D5F9: 0D 08 05
00D5FC 1 0D 39 05 ora $0539 ; $D5FC: 0D 39 05
00D5FF 1 0D 6A 05 ora $056A ; $D5FF: 0D 6A 05
00D602 1
00D602 1 D0 D4 bne WaitForMotionToSettle ; $D602: D0 D4
00D604 1
00D604 1 ; ----------------------------------------------------------------------------
00D604 1 ; All monitored values are zero. Count down $76 while continuing to wait for
00D604 1 ; frames and recheck every field.
00D604 1 ; ----------------------------------------------------------------------------
00D604 1
00D604 1 C6 76 dec MotionSettledCountdown ; $D604: C6 76
00D606 1 D0 D4 bne Routine_D5DC_WaitFrame ; $D606: D0 D4
00D608 1
00D608 1 ; ----------------------------------------------------------------------------
00D608 1 ; Process command $08 and leave through the common engine exit.
00D608 1 ; ----------------------------------------------------------------------------
00D608 1
00D608 1 A2 08 ldx #$08 ; $D608: A2 08
00D60A 1 20 2A EB jsr ProcessQueuedObjectEvent ; $D60A: 20 2A EB
00D60D 1
00D60D 1 4C 6A EB jmp CommonEngineExit ; $D60D: 4C 6A EB
00D610 1
00D610 1 ; ============================================================================
00D610 1 ; $D610-$D65D
00D610 1 ; Initialize animation values, create three indexed object records, and select
00D610 1 ; an additional record according to the active object-state entries.
00D610 1 ; ============================================================================
00D610 1
00D610 1 ; ----------------------------------------------------------------------------
00D610 1 ; Contract:
00D610 1 ; Description: Initializes Secondary Actors.
00D610 1 ; Entry: Registers: A; Memory: $059b, $059a, $0599, $0598
00D610 1 ; Returns/products: Registers/clobbers: A, X
00D610 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00D610 1 ; Memory effects: $03b4, $03b5, $03b6, $039f, $03a0, $03a1
00D610 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00D610 1 ; comparison, load, or store path and are not a stable API product.
00D610 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00D610 1 ; ----------------------------------------------------------------------------
00D610 1 InitializeSecondaryActors: ; $D610
00D610 1 A9 7A lda #$7A ; $D610: A9 7A
00D612 1
00D612 1 ; ----------------------------------------------------------------------------
00D612 1 ; Initialize three animation/state entries in each of two arrays.
00D612 1 ; ----------------------------------------------------------------------------
00D612 1
00D612 1 8D B4 03 sta $03B4 ; $D612: 8D B4 03
00D615 1 8D B5 03 sta $03B5 ; $D615: 8D B5 03
00D618 1 8D B6 03 sta $03B6 ; $D618: 8D B6 03
00D61B 1
00D61B 1 8D 9F 03 sta $039F ; $D61B: 8D 9F 03
00D61E 1 8D A0 03 sta $03A0 ; $D61E: 8D A0 03
00D621 1 8D A1 03 sta $03A1 ; $D621: 8D A1 03
00D624 1
00D624 1 ; ----------------------------------------------------------------------------
00D624 1 ; Initialize object offset $08.
00D624 1 ;
00D624 1 ; Routine $C9A7 consumes five inline bytes:
00D624 1 ;
00D624 1 ; $08 object offset/metadata
00D624 1 ; $00,$04,$00,$F6 four field values
00D624 1 ; ----------------------------------------------------------------------------
00D624 1
00D624 1 20 A7 C9 jsr LoadObjectPositionInline
00D627 1 ; $D624: 20 A7 C9
00D627 1
00D627 1 08 .byte $08 ; $D627
00D628 1 00 04 00 F6 .byte $00,$04,$00,$F6 ; $D628-$D62B
00D62C 1
00D62C 1 ; ----------------------------------------------------------------------------
00D62C 1 ; Initialize object offset $0A.
00D62C 1 ; ----------------------------------------------------------------------------
00D62C 1
00D62C 1 20 A7 C9 jsr LoadObjectPositionInline
00D62F 1 ; $D62C: 20 A7 C9
00D62F 1
00D62F 1 0A .byte $0A ; $D62F
00D630 1 00 05 00 F6 .byte $00,$05,$00,$F6 ; $D630-$D633
00D634 1
00D634 1 ; ----------------------------------------------------------------------------
00D634 1 ; Initialize object offset $0C.
00D634 1 ; ----------------------------------------------------------------------------
00D634 1
00D634 1 20 A7 C9 jsr LoadObjectPositionInline
00D637 1 ; $D634: 20 A7 C9
00D637 1
00D637 1 0C .byte $0C ; $D637
00D638 1 00 06 00 F6 .byte $00,$06,$00,$F6 ; $D638-$D63B
00D63C 1
00D63C 1 ; ----------------------------------------------------------------------------
00D63C 1 ; Search the object-state entries $059B through $0598 for value $06.
00D63C 1 ;
00D63C 1 ; If any entry contains $06, execution continues at $D656. Otherwise, A is
00D63C 1 ; changed to $FF and execution branches forward to $D66A.
00D63C 1 ; ----------------------------------------------------------------------------
00D63C 1
00D63C 1 A9 06 lda #$06 ; $D63C: A9 06
00D63E 1
00D63E 1 CD 9B 05 cmp $059B ; $D63E: CD 9B 05
00D641 1 F0 13 beq InitializeState6Actor
00D643 1 ; $D641: F0 13
00D643 1
00D643 1 CD 9A 05 cmp $059A ; $D643: CD 9A 05
00D646 1 F0 0E beq InitializeState6Actor
00D648 1 ; $D646: F0 0E
00D648 1
00D648 1 CD 99 05 cmp $0599 ; $D648: CD 99 05
00D64B 1 F0 09 beq InitializeState6Actor
00D64D 1 ; $D64B: F0 09
00D64D 1
00D64D 1 CD 98 05 cmp $0598 ; $D64D: CD 98 05
00D650 1 F0 04 beq InitializeState6Actor
00D652 1 ; $D650: F0 04
00D652 1
00D652 1 A9 FF lda #$FF ; $D652: A9 FF
00D654 1 D0 14 bne StoreState6Actor ; $D654: D0 14
00D656 1 ; Always taken because A is nonzero.
00D656 1
00D656 1 ; ----------------------------------------------------------------------------
00D656 1 ; Initialize object offset $0C with an alternate field set when state $06 was
00D656 1 ; found in one of the four object-state entries.
00D656 1 ; ----------------------------------------------------------------------------
00D656 1
00D656 1 InitializeState6Actor: ; $D656
00D656 1 20 A7 C9 jsr LoadObjectPositionInline
00D659 1 ; $D656: 20 A7 C9
00D659 1
00D659 1 0C .byte $0C ; $D659
00D65A 1 80 F8 80 00 .byte $80,$F8,$80,$00 ; $D65A-$D65D
00D65E 1
00D65E 1 ; ============================================================================
00D65E 1 ; $D65E-$D69A
00D65E 1 ; Configure object $0C, search active object-state entries for value $04,
00D65E 1 ; optionally initialize object $0A, and update animation values.
00D65E 1 ; ============================================================================
00D65E 1
00D65E 1 A9 1A lda #$1A ; $D65E: A9 1A
00D660 1 8D B6 03 sta $03B6 ; $D660: 8D B6 03
00D663 1
00D663 1 A9 4F lda #$4F ; $D663: A9 4F
00D665 1 8D A1 03 sta $03A1 ; $D665: 8D A1 03
00D668 1
00D668 1 ; ----------------------------------------------------------------------------
00D668 1 ; Set object-state entry $059B and zero-page working state $A1 to $06.
00D668 1 ; ----------------------------------------------------------------------------
00D668 1
00D668 1 A9 06 lda #$06 ; $D668: A9 06
00D66A 1
00D66A 1 StoreState6Actor: ; $D66A
00D66A 1 8D 9B 05 sta $059B ; $D66A: 8D 9B 05
00D66D 1 85 A1 sta SecondaryActorState2 ; $D66D: 85 A1
00D66F 1
00D66F 1 ; ----------------------------------------------------------------------------
00D66F 1 ; Update object offset $0C.
00D66F 1 ; ----------------------------------------------------------------------------
00D66F 1
00D66F 1 A2 0C ldx #$0C ; $D66F: A2 0C
00D671 1 20 B7 E6 jsr ClearMovementTransforms ; $D671: 20 B7 E6
00D674 1
00D674 1 ; ----------------------------------------------------------------------------
00D674 1 ; Search state entries $059A-$0598 for value $04.
00D674 1 ;
00D674 1 ; If no entry contains $04, A becomes $FF and execution branches to $D69D.
00D674 1 ; That branch intentionally skips the LDA #$04 at $D69B while entering the
00D674 1 ; following STA instruction.
00D674 1 ; ----------------------------------------------------------------------------
00D674 1
00D674 1 A9 04 lda #$04 ; $D674: A9 04
00D676 1
00D676 1 CD 9A 05 cmp $059A ; $D676: CD 9A 05
00D679 1 F0 0E beq InitializeState4Actor
00D67B 1 ; $D679: F0 0E
00D67B 1
00D67B 1 CD 99 05 cmp $0599 ; $D67B: CD 99 05
00D67E 1 F0 09 beq InitializeState4Actor
00D680 1 ; $D67E: F0 09
00D680 1
00D680 1 CD 98 05 cmp $0598 ; $D680: CD 98 05
00D683 1 F0 04 beq InitializeState4Actor
00D685 1 ; $D683: F0 04
00D685 1
00D685 1 A9 FF lda #$FF ; $D685: A9 FF
00D687 1 D0 14 bne StoreState4Actor ; $D687: D0 14
00D689 1 ; Always taken because A is nonzero.
00D689 1
00D689 1 ; ----------------------------------------------------------------------------
00D689 1 ; Initialize object offset $0A when state $04 was found.
00D689 1 ;
00D689 1 ; Routine $C9A7 consumes five inline bytes:
00D689 1 ;
00D689 1 ; $0A object offset/metadata
00D689 1 ; $00,$FF,$00,$08 four field values
00D689 1 ; ----------------------------------------------------------------------------
00D689 1
00D689 1 InitializeState4Actor: ; $D689
00D689 1 20 A7 C9 jsr LoadObjectPositionInline
00D68C 1 ; $D689: 20 A7 C9
00D68C 1
00D68C 1 0A .byte $0A ; $D68C
00D68D 1 00 FF 00 08 .byte $00,$FF,$00,$08 ; $D68D-$D690
00D691 1
00D691 1 ; ----------------------------------------------------------------------------
00D691 1 ; Update the corresponding animation values.
00D691 1 ; ----------------------------------------------------------------------------
00D691 1
00D691 1 A9 1D lda #$1D ; $D691: A9 1D
00D693 1 8D B5 03 sta $03B5 ; $D693: 8D B5 03
00D696 1
00D696 1 A9 55 lda #$55 ; $D696: A9 55
00D698 1 8D A0 03 sta $03A0 ; $D698: 8D A0 03
00D69B 1 ; ============================================================================
00D69B 1 ; $D69B-$D6DA
00D69B 1 ; Configure object $0A, search for state $02, optionally initialize object
00D69B 1 ; $08, configure its animation fields, and clear $0598.
00D69B 1 ; ============================================================================
00D69B 1
00D69B 1 A9 04 lda #$04 ; $D69B: A9 04
00D69D 1
00D69D 1 ; ----------------------------------------------------------------------------
00D69D 1 ; Shared entry from the earlier state search.
00D69D 1 ;
00D69D 1 ; Normal flow stores $04. The branch from $D687 enters here with A = $FF.
00D69D 1 ; ----------------------------------------------------------------------------
00D69D 1
00D69D 1 StoreState4Actor: ; $D69D
00D69D 1 8D 9A 05 sta $059A ; $D69D: 8D 9A 05
00D6A0 1 85 A0 sta SecondaryActorState1 ; $D6A0: 85 A0
00D6A2 1
00D6A2 1 ; ----------------------------------------------------------------------------
00D6A2 1 ; Update object offset $0A.
00D6A2 1 ; ----------------------------------------------------------------------------
00D6A2 1
00D6A2 1 A2 0A ldx #$0A ; $D6A2: A2 0A
00D6A4 1 20 B7 E6 jsr ClearMovementTransforms ; $D6A4: 20 B7 E6
00D6A7 1
00D6A7 1 ; ----------------------------------------------------------------------------
00D6A7 1 ; Search state entries $0599 and $0598 for value $02.
00D6A7 1 ;
00D6A7 1 ; If neither entry contains $02, A becomes $FF and execution enters the shared
00D6A7 1 ; store at $D6CB.
00D6A7 1 ; ----------------------------------------------------------------------------
00D6A7 1
00D6A7 1 A9 02 lda #$02 ; $D6A7: A9 02
00D6A9 1
00D6A9 1 CD 99 05 cmp $0599 ; $D6A9: CD 99 05
00D6AC 1 F0 09 beq InitializeState2Actor
00D6AE 1 ; $D6AC: F0 09
00D6AE 1
00D6AE 1 CD 98 05 cmp $0598 ; $D6AE: CD 98 05
00D6B1 1 F0 04 beq InitializeState2Actor
00D6B3 1 ; $D6B1: F0 04
00D6B3 1
00D6B3 1 A9 FF lda #$FF ; $D6B3: A9 FF
00D6B5 1 D0 14 bne StoreState2Actor ; $D6B5: D0 14
00D6B7 1 ; Always taken because A is nonzero.
00D6B7 1
00D6B7 1 ; ----------------------------------------------------------------------------
00D6B7 1 ; Initialize object offset $08 when state $02 was found.
00D6B7 1 ;
00D6B7 1 ; Routine $C9A7 consumes five inline bytes:
00D6B7 1 ;
00D6B7 1 ; $08 object offset/metadata
00D6B7 1 ; $00,$07,$80,$00 four field values
00D6B7 1 ; ----------------------------------------------------------------------------
00D6B7 1
00D6B7 1 InitializeState2Actor: ; $D6B7
00D6B7 1 20 A7 C9 jsr LoadObjectPositionInline
00D6BA 1 ; $D6B7: 20 A7 C9
00D6BA 1
00D6BA 1 08 .byte $08 ; $D6BA
00D6BB 1 00 07 80 00 .byte $00,$07,$80,$00 ; $D6BB-$D6BE
00D6BF 1
00D6BF 1 ; ----------------------------------------------------------------------------
00D6BF 1 ; Configure the object's animation values.
00D6BF 1 ; ----------------------------------------------------------------------------
00D6BF 1
00D6BF 1 A9 1D lda #$1D ; $D6BF: A9 1D
00D6C1 1 8D B4 03 sta $03B4 ; $D6C1: 8D B4 03
00D6C4 1
00D6C4 1 A9 55 lda #$55 ; $D6C4: A9 55
00D6C6 1 8D 9F 03 sta $039F ; $D6C6: 8D 9F 03
00D6C9 1
00D6C9 1 A9 02 lda #$02 ; $D6C9: A9 02
00D6CB 1
00D6CB 1 ; ----------------------------------------------------------------------------
00D6CB 1 ; Shared store.
00D6CB 1 ;
00D6CB 1 ; Normal flow stores $02. The branch from $D6B5 enters with A = $FF.
00D6CB 1 ; ----------------------------------------------------------------------------
00D6CB 1
00D6CB 1 StoreState2Actor: ; $D6CB
00D6CB 1 8D 99 05 sta $0599 ; $D6CB: 8D 99 05
00D6CE 1 85 9F sta SecondaryActorState0 ; $D6CE: 85 9F
00D6D0 1
00D6D0 1 ; ----------------------------------------------------------------------------
00D6D0 1 ; Update object offset $08.
00D6D0 1 ; ----------------------------------------------------------------------------
00D6D0 1
00D6D0 1 A2 08 ldx #$08 ; $D6D0: A2 08
00D6D2 1 20 B7 E6 jsr ClearMovementTransforms ; $D6D2: 20 B7 E6
00D6D5 1
00D6D5 1 ; ----------------------------------------------------------------------------
00D6D5 1 ; Clear the first state entry and return.
00D6D5 1 ; ----------------------------------------------------------------------------
00D6D5 1
00D6D5 1 A9 00 lda #$00 ; $D6D5: A9 00
00D6D7 1 8D 98 05 sta $0598 ; $D6D7: 8D 98 05
00D6DA 1
00D6DA 1 60 rts ; $D6DA: 60
00D6DB 1
00D6DB 1 ; ============================================================================
00D6DB 1 ; $D6DB-$D6F8
00D6DB 1 ; Initial delay and frame-loop setup.
00D6DB 1 ; ============================================================================
00D6DB 1
00D6DB 1 RunObjectApproachSequence: ; $D6DB
00D6DB 1 A9 1E lda #$1E ; $D6DB: A9 1E
00D6DD 1 20 41 EB jsr StoreObjectEventBankValue ; $D6DD: 20 41 EB
00D6E0 1
00D6E0 1 ; ----------------------------------------------------------------------------
00D6E0 1 ; Clear state $82 and initialize countdown $78 to $1E.
00D6E0 1 ; ----------------------------------------------------------------------------
00D6E0 1
00D6E0 1 A9 00 lda #$00 ; $D6E0: A9 00
00D6E2 1 85 82 sta ActorActionComplete ; $D6E2: 85 82
00D6E4 1 ResetObjectApproachTimer:
00D6E4 1 A9 1E lda #$1E ; $D6E4: A9 1E
00D6E6 1 85 78 sta StateTimer78 ; $D6E6: 85 78
00D6E8 1
00D6E8 1 ; ----------------------------------------------------------------------------
00D6E8 1 ; Decrement the countdown and wait for a frame.
00D6E8 1 ; ----------------------------------------------------------------------------
00D6E8 1
00D6E8 1 UpdateObjectApproachTimer: ; $D6E8
00D6E8 1 C6 78 dec StateTimer78 ; $D6E8: C6 78
00D6EA 1 UpdateObjectApproachFrame:
00D6EA 1 20 48 EB jsr SelectObjectEventBank1 ; $D6EA: 20 48 EB
00D6ED 1
00D6ED 1 ; ----------------------------------------------------------------------------
00D6ED 1 ; Increment $83 while $8C is below nine.
00D6ED 1 ; ----------------------------------------------------------------------------
00D6ED 1
00D6ED 1 A5 8C lda FielderAnimationCountdown ; $D6ED: A5 8C
00D6EF 1 C9 09 cmp #$09 ; $D6EF: C9 09
00D6F1 1 B0 02 bcs CheckObjectApproachState ; $D6F1: B0 02
00D6F3 1
00D6F3 1 E6 83 inc ObjectApproachCount ; $D6F3: E6 83
00D6F5 1
00D6F5 1 ; ----------------------------------------------------------------------------
00D6F5 1 ; If state $82 is nonzero, branch forward to $D745.
00D6F5 1 ; ----------------------------------------------------------------------------
00D6F5 1
00D6F5 1 CheckObjectApproachState: ; $D6F5
00D6F5 1 A5 82 lda ActorActionComplete ; $D6F5: A5 82
00D6F7 1 D0 4C bne EvaluateObjectApproachCompletion ; $D6F7: D0 4C
00D6F9 1
00D6F9 1 ; ============================================================================
00D6F9 1 ; $D6F9-$D744
00D6F9 1 ; Compare base and object-six coordinates, update $87 when horizontal
00D6F9 1 ; separation exceeds a threshold, and derive a flag in $84.
00D6F9 1 ; ============================================================================
00D6F9 1
00D6F9 1 AC 3A 05 ldy $053A ; $D6F9: AC 3A 05
00D6FC 1 AD 3B 05 lda $053B ; $D6FC: AD 3B 05
00D6FF 1
00D6FF 1 ; ----------------------------------------------------------------------------
00D6FF 1 ; Subtract object-six's vertical coordinate from the base coordinate.
00D6FF 1 ;
00D6FF 1 ; Low bytes:
00D6FF 1 ; $053A - $0540
00D6FF 1 ;
00D6FF 1 ; High bytes:
00D6FF 1 ; $053B - $0541
00D6FF 1 ; ----------------------------------------------------------------------------
00D6FF 1
00D6FF 1 CC 40 05 cpy $0540 ; $D6FF: CC 40 05
00D702 1 ED 41 05 sbc $0541 ; $D702: ED 41 05
00D705 1
00D705 1 C9 00 cmp #$00 ; $D705: C9 00
00D707 1 10 2D bpl UpdateObjectCoordinateFlag
00D709 1 ; $D707: 10 2D
00D709 1
00D709 1 ; ----------------------------------------------------------------------------
00D709 1 ; Perform the distance check only while $8C is below nine.
00D709 1 ; ----------------------------------------------------------------------------
00D709 1
00D709 1 A5 8C lda FielderAnimationCountdown ; $D709: A5 8C
00D70B 1 C9 09 cmp #$09 ; $D70B: C9 09
00D70D 1 B0 23 bcs AddDoubleObjectProximityCount
00D70F 1 ; $D70D: B0 23
00D70F 1
00D70F 1 ; ----------------------------------------------------------------------------
00D70F 1 ; Calculate the horizontal difference:
00D70F 1 ;
00D70F 1 ; ($0509/$050A) - ($050F/$0510)
00D70F 1 ;
00D70F 1 ; Each result byte is XORed with $4C.
00D70F 1 ; ----------------------------------------------------------------------------
00D70F 1
00D70F 1 38 sec ; $D70F: 38
00D710 1
00D710 1 AD 09 05 lda $0509 ; $D710: AD 09 05
00D713 1 ED 0F 05 sbc $050F ; $D713: ED 0F 05
00D716 1 45 4C eor HorizontalDirectionMask ; $D716: 45 4C
00D718 1 A8 tay ; $D718: A8
00D719 1
00D719 1 AD 0A 05 lda $050A ; $D719: AD 0A 05
00D71C 1 ED 10 05 sbc $0510 ; $D71C: ED 10 05
00D71F 1 45 4C eor HorizontalDirectionMask ; $D71F: 45 4C
00D721 1 AA tax ; $D721: AA
00D722 1
00D722 1 ; ----------------------------------------------------------------------------
00D722 1 ; Subtract $0180 from the signed 16-bit difference in X:Y.
00D722 1 ; ----------------------------------------------------------------------------
00D722 1
00D722 1 38 sec ; $D722: 38
00D723 1
00D723 1 98 tya ; $D723: 98
00D724 1 E9 80 sbc #$80 ; $D724: E9 80
00D726 1 A8 tay ; $D726: A8
00D727 1
00D727 1 8A txa ; $D727: 8A
00D728 1 E9 00 sbc #$00 ; $D728: E9 00
00D72A 1 AA tax ; $D72A: AA
00D72B 1
00D72B 1 ; ----------------------------------------------------------------------------
00D72B 1 ; Compare the adjusted value against $0110.
00D72B 1 ;
00D72B 1 ; Carry is established by CPY #$10 and used by SBC #$01.
00D72B 1 ; If the value is below the threshold, skip the first increment of $87.
00D72B 1 ; ----------------------------------------------------------------------------
00D72B 1
00D72B 1 C0 10 cpy #$10 ; $D72B: C0 10
00D72D 1
00D72D 1 8A txa ; $D72D: 8A
00D72E 1 E9 01 sbc #$01 ; $D72E: E9 01
00D730 1 90 02 bcc AddObjectProximityCount
00D732 1 ; $D730: 90 02
00D732 1
00D732 1 AddDoubleObjectProximityCount: ; $D732
00D732 1 E6 87 inc ObjectProximityState ; $D732: E6 87
00D734 1
00D734 1 AddObjectProximityCount: ; $D734
00D734 1 E6 87 inc ObjectProximityState ; $D734: E6 87
00D736 1
00D736 1 ; ----------------------------------------------------------------------------
00D736 1 ; Normalize the base horizontal coordinate and derive a flag in $84.
00D736 1 ; ----------------------------------------------------------------------------
00D736 1
00D736 1 UpdateObjectCoordinateFlag: ; $D736
00D736 1 AC 09 05 ldy $0509 ; $D736: AC 09 05
00D739 1 AD 0A 05 lda $050A ; $D739: AD 0A 05
00D73C 1
00D73C 1 20 CB E7 jsr AbsoluteValueAY ; $D73C: 20 CB E7
00D73F 1
00D73F 1 C0 60 cpy #$60 ; $D73F: C0 60
00D741 1 E9 00 sbc #$00 ; $D741: E9 00
00D743 1
00D743 1 66 84 ror ObjectApproachDirectionFlag ; $D743: 66 84
00D745 1
00D745 1 ; ============================================================================
00D745 1 ; $D745-$D768
00D745 1 ; Evaluate countdown and state flags after the coordinate checks.
00D745 1 ; ============================================================================
00D745 1
00D745 1 EvaluateObjectApproachCompletion: ; $D745
00D745 1 A5 82 lda ActorActionComplete ; $D745: A5 82
00D747 1 F0 9B beq ResetObjectApproachTimer ; $D747: F0 9B
00D749 1
00D749 1 ; ----------------------------------------------------------------------------
00D749 1 ; Return to the main frame loop while countdown $78 remains nonzero.
00D749 1 ; ----------------------------------------------------------------------------
00D749 1
00D749 1 A5 78 lda StateTimer78 ; $D749: A5 78
00D74B 1 D0 9B bne UpdateObjectApproachTimer ; $D74B: D0 9B
00D74D 1
00D74D 1 ; ----------------------------------------------------------------------------
00D74D 1 ; Shift $8D right once.
00D74D 1 ;
00D74D 1 ; If the result is nonzero, return to the frame wait at $D6EA.
00D74D 1 ; ----------------------------------------------------------------------------
00D74D 1
00D74D 1 A5 8D lda FielderInputBalance ; $D74D: A5 8D
00D74F 1 4A lsr ; $D74F: 4A
00D750 1 D0 98 bne UpdateObjectApproachFrame ; $D750: D0 98
00D752 1
00D752 1 ; ----------------------------------------------------------------------------
00D752 1 ; If $83 is already nonzero, continue at AdvanceObjectApproachState.
00D752 1 ; ----------------------------------------------------------------------------
00D752 1
00D752 1 A5 83 lda ObjectApproachCount ; $D752: A5 83
00D754 1 D0 13 bne AdvanceObjectApproachState ; $D754: D0 13
00D756 1
00D756 1 ; ----------------------------------------------------------------------------
00D756 1 ; If $84 is nonnegative, continue at AdvanceObjectApproachState.
00D756 1 ; Otherwise, invoke the state-transition helper at $CC01.
00D756 1 ; ----------------------------------------------------------------------------
00D756 1
00D756 1 A5 84 lda ObjectApproachDirectionFlag ; $D756: A5 84
00D758 1 10 0F bpl AdvanceObjectApproachState ; $D758: 10 0F
00D75A 1
00D75A 1 20 01 CC jsr AdvancePrimaryStateSequence ; $D75A: 20 01 CC
00D75D 1
00D75D 1 ; ----------------------------------------------------------------------------
00D75D 1 ; When $63 equals four, increment $6E and $46.
00D75D 1 ; All other cases continue at $D783.
00D75D 1 ; ----------------------------------------------------------------------------
00D75D 1
00D75D 1 A5 63 lda TransitionSequenceState ; $D75D: A5 63
00D75F 1 C9 04 cmp #$04 ; $D75F: C9 04
00D761 1 D0 20 bne ExitObjectApproachState ; $D761: D0 20
00D763 1
00D763 1 E6 6E inc ObjectTransitionState ; $D763: E6 6E
00D765 1 E6 46 inc StateSequenceActive ; $D765: E6 46
00D767 1
00D767 1 D0 1A bne ExitObjectApproachState ; $D767: D0 1A
00D769 1 ; Normally unconditional after INC $46.
00D769 1
00D769 1 ; ============================================================================
00D769 1 ; Temporary external labels referenced by this stride.
00D769 1 ;
00D769 1 ; Remove each alias when its containing block is decoded.
00D769 1 ; ============================================================================
00D769 1
00D769 1 ; ============================================================================
00D769 1 ; $D769-$D785
00D769 1 ; Advance the dual-state sequence after the monitored object conditions have
00D769 1 ; completed.
00D769 1 ;
00D769 1 ; This path:
00D769 1 ; 1. Advances the $62/$64 state sequence.
00D769 1 ; 2. Checks whether $62 reached state three.
00D769 1 ; 3. If so, activates state flag $46.
00D769 1 ; 4. Waits $1E ticks.
00D769 1 ; 5. Sets animation/frame $03B3 to $7A.
00D769 1 ; 6. Processes event slot $0D.
00D769 1 ; 7. Leaves through the common engine exit.
00D769 1 ; ============================================================================
00D769 1
00D769 1 AdvanceObjectApproachState: ; $D769
00D769 1 20 7A CC jsr AdvanceDualStateSequence
00D76C 1 ; $D769: 20 7A CC
00D76C 1
00D76C 1 A5 62 lda PrimarySequenceState ; $D76C: A5 62
00D76E 1 C9 03 cmp #$03 ; $D76E: C9 03
00D770 1 D0 11 bne ExitObjectApproachState ; $D770: D0 11
00D772 1
00D772 1 ; ----------------------------------------------------------------------------
00D772 1 ; State $62 reached three.
00D772 1 ; Activate the next state and run a short timed animation.
00D772 1 ; ----------------------------------------------------------------------------
00D772 1
00D772 1 E6 46 inc StateSequenceActive ; $D772: E6 46
00D774 1
00D774 1 A9 1E lda #$1E ; $D774: A9 1E
00D776 1 20 41 EB jsr StoreObjectEventBankValue ; $D776: 20 41 EB
00D779 1
00D779 1 A9 7A lda #$7A ; $D779: A9 7A
00D77B 1 8D B3 03 sta $03B3 ; $D77B: 8D B3 03
00D77E 1
00D77E 1 ; ----------------------------------------------------------------------------
00D77E 1 ; Process event slot $0D.
00D77E 1 ; ----------------------------------------------------------------------------
00D77E 1
00D77E 1 A0 0D ldy #$0D ; $D77E: A0 0D
00D780 1 20 66 EB jsr DispatchNextQueuedEvent ; $D780: 20 66 EB
00D783 1
00D783 1 ; ----------------------------------------------------------------------------
00D783 1 ; Common exit.
00D783 1 ;
00D783 1 ; The BNE at $D770 branches directly here.
00D783 1 ; ----------------------------------------------------------------------------
00D783 1
00D783 1 ExitObjectApproachState: ; $D783
00D783 1 4C 6A EB jmp CommonEngineExit ; $D783: 4C 6A EB
00D786 1
00D786 1 ; ============================================================================
00D786 1 ; $D786-$D7AA
00D786 1 ; Wait for the base vertical coordinate to reach $F6, clear motion state,
00D786 1 ; advance the object state, and dispatch two inline commands.
00D786 1 ; ============================================================================
00D786 1
00D786 1 WaitForVerticalPositionF6: ; $D786
00D786 1 20 48 EB jsr SelectObjectEventBank1 ; $D786: 20 48 EB
00D789 1
00D789 1 A2 04 ldx #$04 ; $D789: A2 04
00D78B 1 38 sec ; $D78B: 38
00D78C 1
00D78C 1 AD 3B 05 lda $053B ; $D78C: AD 3B 05
00D78F 1 E9 F6 sbc #$F6 ; $D78F: E9 F6
00D791 1 D0 F3 bne WaitForVerticalPositionF6
00D793 1 ; $D791: D0 F3
00D793 1
00D793 1 ; ----------------------------------------------------------------------------
00D793 1 ; Clear active motion and value state, then advance $82.
00D793 1 ; ----------------------------------------------------------------------------
00D793 1
00D793 1 85 5C sta BaseMotionActive ; $D793: 85 5C
00D795 1 ; A is zero after the successful comparison.
00D795 1
00D795 1 85 81 sta RandomValue81 ; $D795: 85 81
00D797 1
00D797 1 E6 82 inc ActorActionComplete ; $D797: E6 82
00D799 1
00D799 1 20 E6 E3 jsr InitializeBaseObjectFromCurrent ; $D799: 20 E6 E3
00D79C 1
00D79C 1 ; ----------------------------------------------------------------------------
00D79C 1 ; Dispatch two inline command records.
00D79C 1 ; ----------------------------------------------------------------------------
00D79C 1
00D79C 1 20 0A EB jsr QueueInlineObjectEvent ; $D79C: 20 0A EB
00D79F 1
00D79F 1 11 D7 D5 .byte $11,$D7,$D5 ; $D79F-$D7A1
00D7A2 1
00D7A2 1 20 0A EB jsr QueueInlineObjectEvent ; $D7A2: 20 0A EB
00D7A5 1
00D7A5 1 1D AA D7 .byte $1D,$AA,$D7 ; $D7A5-$D7A7
00D7A8 1
00D7A8 1 4C 8B E0 jmp ObjectStateDispatch_NextPath ; $D7A8: 4C 8B E0
00D7AB 1
00D7AB 1 ; ============================================================================
00D7AB 1 ; $D7AB-$D7C9
00D7AB 1 ; Initialize an object timer, wait for four monitored object fields to clear,
00D7AB 1 ; then count the timer down to zero.
00D7AB 1 ;
00D7AB 1 ; Entry:
00D7AB 1 ; CurrentObjectIndex selects the timer at $05B1,X.
00D7AB 1 ; ============================================================================
00D7AB 1
00D7AB 1 WaitForObjectFieldsToClear: ; $D7AB
00D7AB 1 A6 E1 ldx CurrentObjectIndex ; $D7AB: A6 E1
00D7AD 1
00D7AD 1 A9 32 lda #$32 ; $D7AD: A9 32
00D7AF 1 9D B1 05 sta $05B1,x ; $D7AF: 9D B1 05
00D7B2 1
00D7B2 1 WaitForObjectFieldsFrame: ; $D7B2
00D7B2 1 20 48 EB jsr SelectObjectEventBank1 ; $D7B2: 20 48 EB
00D7B5 1
00D7B5 1 AD 73 05 lda $0573 ; $D7B5: AD 73 05
00D7B8 1 0D 75 05 ora $0575 ; $D7B8: 0D 75 05
00D7BB 1 0D 77 05 ora $0577 ; $D7BB: 0D 77 05
00D7BE 1 0D 79 05 ora $0579 ; $D7BE: 0D 79 05
00D7C1 1
00D7C1 1 D0 E8 bne WaitForObjectFieldsToClear
00D7C3 1 ; $D7C1: D0 E8
00D7C3 1
00D7C3 1 ; ----------------------------------------------------------------------------
00D7C3 1 ; Once all monitored fields are zero, count down $05B1,X.
00D7C3 1 ;
00D7C3 1 ; If the countdown remains nonzero, wait for another frame but do not
00D7C3 1 ; reinitialize the timer.
00D7C3 1 ; ----------------------------------------------------------------------------
00D7C3 1
00D7C3 1 A6 E1 ldx CurrentObjectIndex ; $D7C3: A6 E1
00D7C5 1
00D7C5 1 DE B1 05 dec $05B1,x ; $D7C5: DE B1 05
00D7C8 1 D0 E8 bne WaitForObjectFieldsFrame
00D7CA 1 ; $D7C8: D0 E8
00D7CA 1
00D7CA 1 ; ============================================================================
00D7CA 1 ; $D7CA-$D800
00D7CA 1 ; Process event slots, initialize animation and movement, wait for a vertical
00D7CA 1 ; position condition, then clear the active action state.
00D7CA 1 ; ============================================================================
00D7CA 1
00D7CA 1 A0 11 ldy #$11 ; $D7CA: A0 11
00D7CC 1 20 66 EB jsr DispatchNextQueuedEvent ; $D7CC: 20 66 EB
00D7CF 1
00D7CF 1 A0 04 ldy #$04 ; $D7CF: A0 04
00D7D1 1 20 66 EB jsr DispatchNextQueuedEvent ; $D7D1: 20 66 EB
00D7D4 1
00D7D4 1 ; ----------------------------------------------------------------------------
00D7D4 1 ; Clear the sequence counter and wait $14 ticks.
00D7D4 1 ; ----------------------------------------------------------------------------
00D7D4 1
00D7D4 1 A9 00 lda #$00 ; $D7D4: A9 00
00D7D6 1 85 7E sta ActionSequenceCounter ; $D7D6: 85 7E
00D7D8 1
00D7D8 1 A9 14 lda #$14 ; $D7D8: A9 14
00D7DA 1 20 41 EB jsr StoreObjectEventBankValue ; $D7DA: 20 41 EB
00D7DD 1
00D7DD 1 ; ----------------------------------------------------------------------------
00D7DD 1 ; Advance animation state and initialize base motion.
00D7DD 1 ; ----------------------------------------------------------------------------
00D7DD 1
00D7DD 1 EE B2 03 inc $03B2 ; $D7DD: EE B2 03
00D7E0 1
00D7E0 1 A9 10 lda #$10 ; $D7E0: A9 10
00D7E2 1 8D B7 03 sta $03B7 ; $D7E2: 8D B7 03
00D7E5 1
00D7E5 1 A2 00 ldx #$00 ; $D7E5: A2 00
00D7E7 1 A0 20 ldy #$20 ; $D7E7: A0 20
00D7E9 1
00D7E9 1 20 23 CA jsr InitializeBaseMotionZero
00D7EC 1 ; $D7E9: 20 23 CA
00D7EC 1
00D7EC 1 ; ----------------------------------------------------------------------------
00D7EC 1 ; Wait until the signed vertical high byte becomes nonnegative and reaches at
00D7EC 1 ; least $02.
00D7EC 1 ; ----------------------------------------------------------------------------
00D7EC 1
00D7EC 1 WaitForVerticalPosition02: ; $D7EC
00D7EC 1 20 48 EB jsr SelectObjectEventBank1 ; $D7EC: 20 48 EB
00D7EF 1
00D7EF 1 AD 3B 05 lda $053B ; $D7EF: AD 3B 05
00D7F2 1 C9 02 cmp #$02 ; $D7F2: C9 02
00D7F4 1 30 F6 bmi WaitForVerticalPosition02
00D7F6 1 ; $D7F4: 30 F6
00D7F6 1
00D7F6 1 ; ----------------------------------------------------------------------------
00D7F6 1 ; Run the helper for object offset $0E, then clear action and motion state.
00D7F6 1 ; ----------------------------------------------------------------------------
00D7F6 1
00D7F6 1 A2 0E ldx #$0E ; $D7F6: A2 0E
00D7F8 1 20 E8 E3 jsr CopyCurrentObjectPositionToBaseAfterIndex ; $D7F8: 20 E8 E3
00D7FB 1
00D7FB 1 A9 00 lda #$00 ; $D7FB: A9 00
00D7FD 1 85 9D sta CurrentActionState ; $D7FD: 85 9D
00D7FF 1 85 5C sta BaseMotionActive ; $D7FF: 85 5C
00D801 1
00D801 1 20 0A EB jsr QueueInlineObjectEvent ; $D801: 20 0A EB
00D804 1
00D804 1 ; Inline command record consumed by QueueInlineObjectEvent.
00D804 1 17 AC D2 .byte $17,$AC,$D2 ; $D804-$D806
00D807 1
00D807 1 20 0A EB jsr QueueInlineObjectEvent ; $D807: 20 0A EB
00D80A 1
00D80A 1 ; Inline command record consumed by QueueInlineObjectEvent.
00D80A 1 11 D7 D5 .byte $11,$D7,$D5 ; $D80A-$D80C
00D80D 1
00D80D 1 4C 6A EB jmp CommonEngineExit ; $D80D: 4C 6A EB
00D810 1
00D810 1 ; ============================================================================
00D810 1 ; $D810-$D836
00D810 1 ; Select an animation frame and delay using table-driven state.
00D810 1 ;
00D810 1 ; Entry:
00D810 1 ; A = base state or animation index
00D810 1 ; X = object/sprite-array index
00D810 1 ; $CB = additional index offset
00D810 1 ;
00D810 1 ; Operation:
00D810 1 ; 1. Add $CB to A and preserve the resulting table index.
00D810 1 ; 2. Update the object through $E6B7.
00D810 1 ; 3. Depending on carry and the current animation frame, optionally select
00D810 1 ; a replacement frame from the table at $D837.
00D810 1 ; 4. Load a delay from the table at $D84F.
00D810 1 ; 5. Tail-call the delay helper at $EB41.
00D810 1 ; ============================================================================
00D810 1
00D810 1 SelectAnimationFrameAndDelay: ; $D810
00D810 1 18 clc ; $D810: 18
00D811 1 65 CB adc $CB ; $D811: 65 CB
00D813 1 48 pha ; $D813: 48
00D814 1 ; Preserve the calculated table index.
00D814 1
00D814 1 20 B7 E6 jsr ClearMovementTransforms ; $D814: 20 B7 E6
00D817 1
00D817 1 68 pla ; $D817: 68
00D818 1 A8 tay ; $D818: A8
00D819 1 ; Y = table index.
00D819 1
00D819 1 ; ----------------------------------------------------------------------------
00D819 1 ; Carry from $E6B7 selects whether the animation-frame update is skipped.
00D819 1 ; ----------------------------------------------------------------------------
00D819 1
00D819 1 B0 16 bcs SelectAnimationDelay ; $D819: B0 16
00D81B 1
00D81B 1 ; ----------------------------------------------------------------------------
00D81B 1 ; Read the current animation frame, then increment it.
00D81B 1 ;
00D81B 1 ; The original value remains in A for the following table comparisons.
00D81B 1 ; ----------------------------------------------------------------------------
00D81B 1
00D81B 1 BD 9A 03 lda $039A,x ; $D81B: BD 9A 03
00D81E 1 FE 9A 03 inc $039A,x ; $D81E: FE 9A 03
00D821 1
00D821 1 ; ----------------------------------------------------------------------------
00D821 1 ; Compare the original frame against two table thresholds.
00D821 1 ;
00D821 1 ; If it falls within the selected range, replace the animation frame with a
00D821 1 ; value from the table at $D837.
00D821 1 ; ----------------------------------------------------------------------------
00D821 1
00D821 1 D9 43 D8 cmp AnimationFrameLimitTable,y ; $D821: D9 43 D8
00D824 1 B0 05 bcs CheckLowerFrameBound ; $D824: B0 05
00D826 1
00D826 1 D9 37 D8 cmp AnimationFrameBaseTable,y ; $D826: D9 37 D8
00D829 1 B0 06 bcs SelectAnimationDelay ; $D829: B0 06
00D82B 1
00D82B 1 CheckLowerFrameBound: ; $D82B
00D82B 1 B9 37 D8 lda AnimationFrameBaseTable,y ; $D82B: B9 37 D8
00D82E 1 9D 9A 03 sta $039A,x ; $D82E: 9D 9A 03
00D831 1
00D831 1 ; ----------------------------------------------------------------------------
00D831 1 ; Select the delay associated with the table entry and tail-call $EB41.
00D831 1 ; ----------------------------------------------------------------------------
00D831 1
00D831 1 SelectAnimationDelay: ; $D831
00D831 1 B9 4F D8 lda AnimationFrameDelayTable,y ; $D831: B9 4F D8
00D834 1 4C 41 EB jmp StoreObjectEventBankValue ; $D834: 4C 41 EB
00D837 1
00D837 1 ; ============================================================================
00D837 1 ; $D837-$D85A
00D837 1 ; Parallel animation-frame and delay lookup tables.
00D837 1 ;
00D837 1 ; SelectAnimationFrameAndDelay uses the same Y index with all three tables:
00D837 1 ;
00D837 1 ; AnimationFrameBaseTable,Y = replacement or lower animation frame
00D837 1 ; AnimationFrameLimitTable,Y = upper animation-frame threshold
00D837 1 ; AnimationFrameDelayTable,Y = animation delay
00D837 1 ;
00D837 1 ; Each table contains twelve entries.
00D837 1 ; ============================================================================
00D837 1
00D837 1 ; ----------------------------------------------------------------------------
00D837 1 ; Replacement/lower animation frames.
00D837 1 ; ----------------------------------------------------------------------------
00D837 1
00D837 1 AnimationFrameBaseTable: ; $D837
00D837 1 4D 50 53 56 .byte $4D,$50,$53,$56
00D83B 1 5C 61 1A 1E .byte $5C,$61,$1A,$1E
00D83F 1 23 27 2F 32 .byte $23,$27,$2F,$32
00D843 1
00D843 1 ; ----------------------------------------------------------------------------
00D843 1 ; Upper animation-frame thresholds.
00D843 1 ; ----------------------------------------------------------------------------
00D843 1
00D843 1 AnimationFrameLimitTable: ; $D843
00D843 1 4F 52 55 58 .byte $4F,$52,$55,$58
00D847 1 5D 63 1C 20 .byte $5D,$63,$1C,$20
00D84B 1 25 29 31 34 .byte $25,$29,$31,$34
00D84F 1
00D84F 1 ; ----------------------------------------------------------------------------
00D84F 1 ; Delay associated with each animation range.
00D84F 1 ;
00D84F 1 ; Most ranges wait six ticks. Entry four uses nine ticks.
00D84F 1 ; ----------------------------------------------------------------------------
00D84F 1
00D84F 1 AnimationFrameDelayTable: ; $D84F
00D84F 1 06 06 06 06 .byte $06,$06,$06,$06
00D853 1 09 06 06 06 .byte $09,$06,$06,$06
00D857 1 06 06 06 06 .byte $06,$06,$06,$06
00D85B 1
00D85B 1 ; ============================================================================
00D85B 1 ; $D85B-$D884
00D85B 1 ; Process three object-state entries.
00D85B 1 ;
00D85B 1 ; For each nonnegative entry in $0599-$059B:
00D85B 1 ; 1. Dispatch an object-specific inline command.
00D85B 1 ; 2. Wait for the next frame before checking the following entry.
00D85B 1 ;
00D85B 1 ; Negative entries are inactive and skip their associated command.
00D85B 1 ; ============================================================================
00D85B 1
00D85B 1 ProcessSecondaryObjectStates: ; $D85B
00D85B 1 AD 99 05 lda $0599 ; $D85B: AD 99 05
00D85E 1 30 06 bmi CheckObjectState059A ; $D85E: 30 06
00D860 1
00D860 1 20 0A EB jsr QueueInlineObjectEvent ; $D860: 20 0A EB
00D863 1
00D863 1 ; Inline command record consumed by QueueInlineObjectEvent.
00D863 1 08 84 D8 .byte $08,$84,$D8 ; $D863-$D865
00D866 1
00D866 1 ; ----------------------------------------------------------------------------
00D866 1 ; Wait for a frame before processing the second state entry.
00D866 1 ;
00D866 1 ; A negative first entry branches directly here.
00D866 1 ; ----------------------------------------------------------------------------
00D866 1
00D866 1 CheckObjectState059A: ; $D866
00D866 1 20 48 EB jsr SelectObjectEventBank1 ; $D866: 20 48 EB
00D869 1
00D869 1 AD 9A 05 lda $059A ; $D869: AD 9A 05
00D86C 1 30 06 bmi CheckObjectState059B ; $D86C: 30 06
00D86E 1
00D86E 1 20 0A EB jsr QueueInlineObjectEvent ; $D86E: 20 0A EB
00D871 1
00D871 1 ; Inline command record consumed by QueueInlineObjectEvent.
00D871 1 0A 84 D8 .byte $0A,$84,$D8 ; $D871-$D873
00D874 1
00D874 1 ; ----------------------------------------------------------------------------
00D874 1 ; Wait for a frame before processing the third state entry.
00D874 1 ;
00D874 1 ; A negative second entry branches directly here.
00D874 1 ; ----------------------------------------------------------------------------
00D874 1
00D874 1 CheckObjectState059B: ; $D874
00D874 1 20 48 EB jsr SelectObjectEventBank1 ; $D874: 20 48 EB
00D877 1
00D877 1 AD 9B 05 lda $059B ; $D877: AD 9B 05
00D87A 1 30 06 bmi FinishSecondaryObjectStates
00D87C 1 ; $D87A: 30 06
00D87C 1
00D87C 1 20 0A EB jsr QueueInlineObjectEvent ; $D87C: 20 0A EB
00D87F 1
00D87F 1 ; Inline command record consumed by QueueInlineObjectEvent.
00D87F 1 0C 84 D8 .byte $0C,$84,$D8 ; $D87F-$D881
00D882 1
00D882 1 ; ----------------------------------------------------------------------------
00D882 1 ; Leave through the common engine exit.
00D882 1 ; ----------------------------------------------------------------------------
00D882 1
00D882 1 FinishSecondaryObjectStates: ; $D882
00D882 1 4C 6A EB jmp CommonEngineExit ; $D882: 4C 6A EB
00D885 1
00D885 1 ; ============================================================================
00D885 1 ; $D885-$D8C2
00D885 1 ; Update one secondary object's active state.
00D885 1 ;
00D885 1 ; Entry:
00D885 1 ; X = object-array offset supplied by the inline command record:
00D885 1 ; $08, $0A, or $0C
00D885 1 ;
00D885 1 ; The routine updates the indexed timer/state fields, performs collision or
00D885 1 ; geometry checks, waits for frame updates, and dispatches to later state paths.
00D885 1 ; ============================================================================
00D885 1
00D885 1 UpdateSecondaryObjectState: ; $D885
00D885 1 20 68 DA jsr GetCurrentObjectStateIndex
00D888 1 ; $D885: 20 68 DA
00D888 1
00D888 1 ; ----------------------------------------------------------------------------
00D888 1 ; Increment this object's state/timer at $0595,X.
00D888 1 ;
00D888 1 ; If the incremented value is nonzero, skip the initialization delay and
00D888 1 ; continue at $D897.
00D888 1 ; ----------------------------------------------------------------------------
00D888 1
00D888 1 FE 95 05 inc $0595,x ; $D888: FE 95 05
00D88B 1 D0 0A bne SecondaryObject_CheckRegion
00D88D 1 ; $D88B: D0 0A
00D88D 1
00D88D 1 ; ----------------------------------------------------------------------------
00D88D 1 ; Handle wraparound from $FF to $00.
00D88D 1 ;
00D88D 1 ; The helper at $DBB8 returns a delay value in A, which is passed directly to
00D88D 1 ; the timing helper at $EB41.
00D88D 1 ; ----------------------------------------------------------------------------
00D88D 1 SecondaryObject_RetryDelay:
00D88D 1 20 B8 DB jsr SelectSecondaryObjectDelay ; $D88D: 20 B8 DB
00D890 1 20 41 EB jsr StoreObjectEventBankValue ; $D890: 20 41 EB
00D893 1
00D893 1 A5 7F lda SelectedStateCount ; $D893: A5 7F
00D895 1 D0 2C bne SecondaryObject_ActivateTimer
00D897 1 ; $D895: D0 2C
00D897 1
00D897 1 ; ----------------------------------------------------------------------------
00D897 1 ; Run the object's geometry/update helpers.
00D897 1 ;
00D897 1 ; If $E55F returns carry set, restart at $D88D and choose another delay.
00D897 1 ; ----------------------------------------------------------------------------
00D897 1
00D897 1 SecondaryObject_CheckRegion: ; $D897
00D897 1 20 81 E4 jsr SelectGeometryRecord_44 ; $D897: 20 81 E4
00D89A 1 20 5F E5 jsr ApplyCurrentObjectGeometry ; $D89A: 20 5F E5
00D89D 1 B0 EE bcs SecondaryObject_RetryDelay
00D89F 1 ; $D89D: B0 EE
00D89F 1
00D89F 1 ; ----------------------------------------------------------------------------
00D89F 1 ; Update object data, recalculate X, then clear $96,X.
00D89F 1 ;
00D89F 1 ; The helper at GetCurrentObjectStateIndex appears to restore or derive the
00D89F 1 ; object-relative index required by the indexed store.
00D89F 1 ; ----------------------------------------------------------------------------
00D89F 1
00D89F 1 20 81 DA jsr UpdateCurrentObjectAnimation
00D8A2 1 ; $D89F: 20 81 DA
00D8A2 1 20 68 DA jsr GetCurrentObjectStateIndex
00D8A5 1 ; $D8A2: 20 68 DA
00D8A5 1
00D8A5 1 A9 00 lda #$00 ; $D8A5: A9 00
00D8A7 1 95 96 sta $96,x ; $D8A7: 95 96
00D8A9 1
00D8A9 1 ; ----------------------------------------------------------------------------
00D8A9 1 ; Wait for the next frame and evaluate the current global state.
00D8A9 1 ; ----------------------------------------------------------------------------
00D8A9 1
00D8A9 1 SecondaryObject_WaitFrame: ; $D8A9
00D8A9 1 20 48 EB jsr SelectObjectEventBank1 ; $D8A9: 20 48 EB
00D8AC 1
00D8AC 1 A5 86 lda TrajectoryEvaluationEnabled ; $D8AC: A5 86
00D8AE 1 F0 03 beq SecondaryObject_CheckFlags
00D8B0 1 ; $D8AE: F0 03
00D8B0 1
00D8B0 1 4C 44 D9 jmp SecondaryObject_State86Path
00D8B3 1 ; $D8B0: 4C 44 D9
00D8B3 1
00D8B3 1 ; ----------------------------------------------------------------------------
00D8B3 1 ; When either $82 or $7F is nonzero, continue at the timer activation path.
00D8B3 1 ; ----------------------------------------------------------------------------
00D8B3 1
00D8B3 1 SecondaryObject_CheckFlags: ; $D8B3
00D8B3 1 A5 82 lda ActorActionComplete ; $D8B3: A5 82
00D8B5 1 D0 0C bne SecondaryObject_ActivateTimer
00D8B7 1 ; $D8B5: D0 0C
00D8B7 1
00D8B7 1 A5 7F lda SelectedStateCount ; $D8B7: A5 7F
00D8B9 1 D0 08 bne SecondaryObject_ActivateTimer
00D8BB 1 ; $D8B9: D0 08
00D8BB 1
00D8BB 1 ; ----------------------------------------------------------------------------
00D8BB 1 ; Run the helper at $DB18.
00D8BB 1 ;
00D8BB 1 ; A nonnegative result returns to the frame wait. A negative result transfers
00D8BB 1 ; to the later state path at $DA25.
00D8BB 1 ; ----------------------------------------------------------------------------
00D8BB 1
00D8BB 1 20 18 DB jsr TestCurrentObjectInput ; $D8BB: 20 18 DB
00D8BE 1 10 E9 bpl SecondaryObject_WaitFrame
00D8C0 1 ; $D8BE: 10 E9
00D8C0 1
00D8C0 1 4C 25 DA jmp SecondaryObject_NegativeResultPath
00D8C3 1 ; $D8C0: 4C 25 DA
00D8C3 1
00D8C3 1
00D8C3 1 ; ============================================================================
00D8C3 1 ; $D8C3-$D905
00D8C3 1 ; Secondary-object timer path.
00D8C3 1 ;
00D8C3 1 ; This path initializes the object's timer, waits for state conditions,
00D8C3 1 ; processes the object each frame, performs a collision/region check when the
00D8C3 1 ; timer expires, and dispatches to the appropriate result path.
00D8C3 1 ; ============================================================================
00D8C3 1
00D8C3 1 SecondaryObject_ActivateTimer: ; $D8C3
00D8C3 1 A9 01 lda #$01 ; $D8C3: A9 01
00D8C5 1 SecondaryObject_SetTimer:
00D8C5 1 A6 E1 ldx CurrentObjectIndex ; $D8C5: A6 E1
00D8C7 1 9D B1 05 sta $05B1,x ; $D8C7: 9D B1 05
00D8CA 1
00D8CA 1 ; ----------------------------------------------------------------------------
00D8CA 1 ; Wait for the next frame and derive the current object-relative index.
00D8CA 1 ; ----------------------------------------------------------------------------
00D8CA 1
00D8CA 1 SecondaryObject_TimerLoop: ; $D8CA
00D8CA 1 20 48 EB jsr SelectObjectEventBank1 ; $D8CA: 20 48 EB
00D8CD 1
00D8CD 1 20 68 DA jsr GetCurrentObjectStateIndex
00D8D0 1 ; $D8CD: 20 68 DA
00D8D0 1
00D8D0 1 ; ----------------------------------------------------------------------------
00D8D0 1 ; If the indexed state at $96,X is nonzero, continue with normal object
00D8D0 1 ; processing.
00D8D0 1 ; ----------------------------------------------------------------------------
00D8D0 1
00D8D0 1 B5 96 lda $96,x ; $D8D0: B5 96
00D8D2 1 D0 08 bne SecondaryObject_ProcessFrame
00D8D4 1 ; $D8D2: D0 08
00D8D4 1
00D8D4 1 ; ----------------------------------------------------------------------------
00D8D4 1 ; Otherwise, run the helper at $DB18.
00D8D4 1 ;
00D8D4 1 ; A nonnegative result continues normal processing. A negative result transfers
00D8D4 1 ; to the common negative-result path at $DA25.
00D8D4 1 ; ----------------------------------------------------------------------------
00D8D4 1
00D8D4 1 20 18 DB jsr TestCurrentObjectInput ; $D8D4: 20 18 DB
00D8D7 1 10 03 bpl SecondaryObject_ProcessFrame
00D8D9 1 ; $D8D7: 10 03
00D8D9 1
00D8D9 1 4C 25 DA jmp SecondaryObject_NegativeResultPath
00D8DC 1 ; $D8D9: 4C 25 DA
00D8DC 1
00D8DC 1 ; ----------------------------------------------------------------------------
00D8DC 1 ; Run the per-frame object helper.
00D8DC 1 ; ----------------------------------------------------------------------------
00D8DC 1
00D8DC 1 SecondaryObject_ProcessFrame: ; $D8DC
00D8DC 1 20 BC DA jsr CheckCurrentObjectSelector ; $D8DC: 20 BC DA
00D8DF 1
00D8DF 1 ; ----------------------------------------------------------------------------
00D8DF 1 ; Count down this object's timer at $05B1,X.
00D8DF 1 ;
00D8DF 1 ; Continue the frame loop until the timer reaches zero.
00D8DF 1 ; ----------------------------------------------------------------------------
00D8DF 1
00D8DF 1 A6 E1 ldx CurrentObjectIndex ; $D8DF: A6 E1
00D8E1 1
00D8E1 1 DE B1 05 dec $05B1,x ; $D8E1: DE B1 05
00D8E4 1 D0 E4 bne SecondaryObject_TimerLoop
00D8E6 1 ; $D8E4: D0 E4
00D8E6 1
00D8E6 1 ; ----------------------------------------------------------------------------
00D8E6 1 ; Timer expired. Run geometry/collision helpers.
00D8E6 1 ; ----------------------------------------------------------------------------
00D8E6 1
00D8E6 1 20 A5 E4 jsr SelectGeometryRecord_24 ; $D8E6: 20 A5 E4
00D8E9 1 20 5F E5 jsr ApplyCurrentObjectGeometry ; $D8E9: 20 5F E5
00D8EC 1
00D8EC 1 90 06 bcc SecondaryObject_NoCollision
00D8EE 1 ; $D8EC: 90 06
00D8EE 1
00D8EE 1 ; ----------------------------------------------------------------------------
00D8EE 1 ; Collision or region test succeeded.
00D8EE 1 ;
00D8EE 1 ; Select a delay and re-enter the object-processing path at $D8C5. This entry
00D8EE 1 ; reloads X from CurrentObjectIndex and stores the selected delay in $05B1,X.
00D8EE 1 ; ----------------------------------------------------------------------------
00D8EE 1
00D8EE 1 20 B8 DB jsr SelectSecondaryObjectDelay ; $D8EE: 20 B8 DB
00D8F1 1 4C C5 D8 jmp SecondaryObject_SetTimer
00D8F4 1 ; $D8F1: 4C C5 D8
00D8F4 1
00D8F4 1 ; ----------------------------------------------------------------------------
00D8F4 1 ; Collision or region test did not succeed.
00D8F4 1 ;
00D8F4 1 ; Decrement the indexed object state and process the resulting transition.
00D8F4 1 ; ----------------------------------------------------------------------------
00D8F4 1
00D8F4 1 SecondaryObject_NoCollision: ; $D8F4
00D8F4 1 20 68 DA jsr GetCurrentObjectStateIndex
00D8F7 1 ; $D8F4: 20 68 DA
00D8F7 1
00D8F7 1 DE 95 05 dec $0595,x ; $D8F7: DE 95 05
00D8FA 1
00D8FA 1 20 A4 DA jsr CountMatchingObjectStates ; $D8FA: 20 A4 DA
00D8FD 1 20 F7 DA jsr UpdateCurrentObjectSelectorState ; $D8FD: 20 F7 DA
00D900 1 20 EB DA jsr StoreCurrentObjectSelector ; $D900: 20 EB DA
00D903 1
00D903 1 4C 0C D9 jmp SecondaryObject_Continue
00D906 1 ; $D903: 4C 0C D9
00D906 1
00D906 1 ; ============================================================================
00D906 1 ; $D906-$D943
00D906 1 ; Retry object geometry processing, update indexed state, and select the next
00D906 1 ; secondary-object transition path.
00D906 1 ; ============================================================================
00D906 1
00D906 1 SecondaryObject_RetryGeometry: ; $D906
00D906 1 20 B8 DB jsr SelectSecondaryObjectDelay ; $D906: 20 B8 DB
00D909 1 20 41 EB jsr StoreObjectEventBankValue ; $D909: 20 41 EB
00D90C 1
00D90C 1 ; ----------------------------------------------------------------------------
00D90C 1 ; Run geometry/region helpers.
00D90C 1 ;
00D90C 1 ; If the region test returns carry set, select another delay and retry.
00D90C 1 ; ----------------------------------------------------------------------------
00D90C 1
00D90C 1 SecondaryObject_Continue: ; $D90C
00D90C 1 20 8F E4 jsr SelectGeometryRecord_34 ; $D90C: 20 8F E4
00D90F 1 20 5F E5 jsr ApplyCurrentObjectGeometry ; $D90F: 20 5F E5
00D912 1
00D912 1 B0 F2 bcs SecondaryObject_RetryGeometry
00D914 1 ; $D912: B0 F2
00D914 1
00D914 1 ; ----------------------------------------------------------------------------
00D914 1 ; Update object state, wait for the next frame, and derive the current
00D914 1 ; object-relative index.
00D914 1 ; ----------------------------------------------------------------------------
00D914 1
00D914 1 20 81 DA jsr UpdateCurrentObjectAnimation
00D917 1 ; $D914: 20 81 DA
00D917 1
00D917 1 SecondaryObject_StateLoop: ; $D917
00D917 1 20 48 EB jsr SelectObjectEventBank1 ; $D917: 20 48 EB
00D91A 1
00D91A 1 20 6D DA jsr MarkMatchingObjectState ; $D91A: 20 6D DA
00D91D 1
00D91D 1 ; ----------------------------------------------------------------------------
00D91D 1 ; If state $6E is nonzero, evaluate the current indexed object condition.
00D91D 1 ; A negative result branches to the transition path at $D941.
00D91D 1 ; ----------------------------------------------------------------------------
00D91D 1
00D91D 1 A5 6E lda ObjectTransitionState ; $D91D: A5 6E
00D91F 1 F0 0A beq SecondaryObject_CheckState6D
00D921 1 ; $D91F: F0 0A
00D921 1
00D921 1 20 5F DA jsr GetCurrentObjectSelector; $D921: 20 5F DA
00D924 1 30 1B bmi SecondaryObject_Transition
00D926 1 ; $D924: 30 1B
00D926 1
00D926 1 ; ----------------------------------------------------------------------------
00D926 1 ; Increment the indexed object-state byte at $96,X.
00D926 1 ; ----------------------------------------------------------------------------
00D926 1
00D926 1 20 68 DA jsr GetCurrentObjectStateIndex
00D929 1 ; $D926: 20 68 DA
00D929 1 F6 96 inc $96,x ; $D929: F6 96
00D92B 1
00D92B 1 ; ----------------------------------------------------------------------------
00D92B 1 ; State $6D immediately selects the transition path when nonzero.
00D92B 1 ; ----------------------------------------------------------------------------
00D92B 1
00D92B 1 SecondaryObject_CheckState6D: ; $D92B
00D92B 1 A5 6D lda SpecialSequenceState ; $D92B: A5 6D
00D92D 1 D0 12 bne SecondaryObject_Transition
00D92F 1 ; $D92D: D0 12
00D92F 1
00D92F 1 ; ----------------------------------------------------------------------------
00D92F 1 ; If both BaseMotionPhase and PendingStateTransition are zero, evaluate GetCurrentObjectSelector.
00D92F 1 ;
00D92F 1 ; A negative result selects the transition path.
00D92F 1 ; ----------------------------------------------------------------------------
00D92F 1
00D92F 1 A5 5D lda BaseMotionPhase ; $D92F: A5 5D
00D931 1 F0 09 beq SecondaryObject_CheckResult
00D933 1 ; $D931: F0 09
00D933 1
00D933 1 A5 60 lda PendingStateTransition ; $D933: A5 60
00D935 1 D0 05 bne SecondaryObject_CheckResult
00D937 1 ; $D935: D0 05
00D937 1
00D937 1 20 5F DA jsr GetCurrentObjectSelector; $D937: 20 5F DA
00D93A 1 30 05 bmi SecondaryObject_Transition
00D93C 1 ; $D93A: 30 05
00D93C 1
00D93C 1 ; ----------------------------------------------------------------------------
00D93C 1 ; Continue waiting while $DB18 returns a nonnegative result.
00D93C 1 ; ----------------------------------------------------------------------------
00D93C 1
00D93C 1 SecondaryObject_CheckResult: ; $D93C
00D93C 1 20 18 DB jsr TestCurrentObjectInput ; $D93C: 20 18 DB
00D93F 1 10 D6 bpl SecondaryObject_StateLoop
00D941 1 ; $D93F: 10 D6
00D941 1
00D941 1 ; ----------------------------------------------------------------------------
00D941 1 ; Transfer to the later transition handler.
00D941 1 ; ----------------------------------------------------------------------------
00D941 1
00D941 1 SecondaryObject_Transition: ; $D941
00D941 1 4C E6 D9 jmp SecondaryObject_TransitionHandler ; $D941: 4C E6 D9
00D944 1
00D944 1 ; ============================================================================
00D944 1 ; $D944-$D95F
00D944 1 ; State-86 path for the secondary-object handler.
00D944 1 ; ============================================================================
00D944 1
00D944 1 SecondaryObject_State86Path: ; $D944
00D944 1 A5 64 lda SecondarySequenceState ; $D944: A5 64
00D946 1 C9 02 cmp #$02 ; $D946: C9 02
00D948 1 F0 10 beq SecondaryObject_JumpToNegativeResult
00D94A 1 ; $D948: F0 10
00D94A 1
00D94A 1 ; ----------------------------------------------------------------------------
00D94A 1 ; Wait for the next frame.
00D94A 1 ; ----------------------------------------------------------------------------
00D94A 1
00D94A 1 SecondaryObject_State86Wait: ; $D94A
00D94A 1 20 48 EB jsr SelectObjectEventBank1 ; $D94A: 20 48 EB
00D94D 1
00D94D 1 ; ----------------------------------------------------------------------------
00D94D 1 ; If the sequence-state counter is nonzero, return to the timer path.
00D94D 1 ; ----------------------------------------------------------------------------
00D94D 1
00D94D 1 A5 A2 lda ObjectSequenceState ; $D94D: A5 A2
00D94F 1 D0 0C bne SecondaryObject_TimerPath
00D951 1 ; $D94F: D0 0C
00D951 1
00D951 1 ; ----------------------------------------------------------------------------
00D951 1 ; Continue waiting while BaseMotionPhase is zero.
00D951 1 ; ----------------------------------------------------------------------------
00D951 1
00D951 1 A5 5D lda BaseMotionPhase ; $D951: A5 5D
00D953 1 F0 F5 beq SecondaryObject_State86Wait
00D955 1 ; $D953: F0 F5
00D955 1
00D955 1 ; ----------------------------------------------------------------------------
00D955 1 ; Evaluate the current object result.
00D955 1 ;
00D955 1 ; A nonnegative result returns to the timer path. A negative result falls
00D955 1 ; through to a trampoline that jumps to the real handler at $DA25.
00D955 1 ; ----------------------------------------------------------------------------
00D955 1
00D955 1 20 5F DA jsr GetCurrentObjectSelector; $D955: 20 5F DA
00D958 1 10 03 bpl SecondaryObject_TimerPath
00D95A 1 ; $D958: 10 03
00D95A 1
00D95A 1 SecondaryObject_JumpToNegativeResult: ; $D95A
00D95A 1 4C 25 DA jmp SecondaryObject_NegativeResultPath
00D95D 1 ; $D95A: 4C 25 DA
00D95D 1
00D95D 1 ; ----------------------------------------------------------------------------
00D95D 1 ; Re-enter the timer initialization path.
00D95D 1 ; ----------------------------------------------------------------------------
00D95D 1
00D95D 1 SecondaryObject_TimerPath: ; $D95D
00D95D 1 4C C3 D8 jmp SecondaryObject_ActivateTimer
00D960 1 ; $D95D: 4C C3 D8
00D960 1
00D960 1 ; ============================================================================
00D960 1 ; $D960-$D966
00D960 1 ; Route according to the global action state.
00D960 1 ; ============================================================================
00D960 1
00D960 1 SecondaryObject_ActionStatePath: ; $D960
00D960 1 A5 9D lda CurrentActionState ; $D960: A5 9D
00D962 1 D0 33 bne SecondaryObject_ActionActive
00D964 1 ; $D962: D0 33
00D964 1
00D964 1 4C 85 D8 jmp UpdateSecondaryObjectState
00D967 1 ; $D964: 4C 85 D8
00D967 1
00D967 1 ; ============================================================================
00D967 1 ; $D967-$D990
00D967 1 ; Advance the indexed secondary-object state, run its update helpers, and
00D967 1 ; select the next path using the current event and object indices.
00D967 1 ; ============================================================================
00D967 1
00D967 1 SecondaryObject_AdvanceIndexedState: ; $D967
00D967 1 20 68 DA jsr GetCurrentObjectStateIndex
00D96A 1 ; $D967: 20 68 DA
00D96A 1
00D96A 1 ; ----------------------------------------------------------------------------
00D96A 1 ; Advance the indexed state byte at $0595,X.
00D96A 1 ; ----------------------------------------------------------------------------
00D96A 1
00D96A 1 FE 95 05 inc $0595,x ; $D96A: FE 95 05
00D96D 1
00D96D 1 ; ----------------------------------------------------------------------------
00D96D 1 ; Derive an object/event selector in Y.
00D96D 1 ;
00D96D 1 ; A selector value of eight transfers to the special path at $D9B3.
00D96D 1 ; ----------------------------------------------------------------------------
00D96D 1
00D96D 1 20 DC E3 jsr GetCurrentObjectSelectorAndState
00D970 1 ; $D96D: 20 DC E3
00D970 1
00D970 1 C0 08 cpy #$08 ; $D970: C0 08
00D972 1 F0 3F beq SecondaryObject_SelectorEight
00D974 1 ; $D972: F0 3F
00D974 1
00D974 1 ; ----------------------------------------------------------------------------
00D974 1 ; Run the normal indexed-object update helpers.
00D974 1 ; ----------------------------------------------------------------------------
00D974 1
00D974 1 20 A4 DA jsr CountMatchingObjectStates ; $D974: 20 A4 DA
00D977 1 20 F7 DA jsr UpdateCurrentObjectSelectorState ; $D977: 20 F7 DA
00D97A 1 20 EB DA jsr StoreCurrentObjectSelector ; $D97A: 20 EB DA
00D97D 1
00D97D 1 ; ----------------------------------------------------------------------------
00D97D 1 ; If state $6D is zero, return to the action-state dispatcher at $D960.
00D97D 1 ; ----------------------------------------------------------------------------
00D97D 1
00D97D 1 A5 6D lda SpecialSequenceState ; $D97D: A5 6D
00D97F 1 F0 DF beq SecondaryObject_ActionStatePath
00D981 1 ; $D97F: F0 DF
00D981 1
00D981 1 ; ----------------------------------------------------------------------------
00D981 1 ; Recalculate the event selector and convert it into an object-related index.
00D981 1 ;
00D981 1 ; Calculation:
00D981 1 ;
00D981 1 ; A = ((Y >> 1) + 4 - SpecialSequenceState) * 2
00D981 1 ; ----------------------------------------------------------------------------
00D981 1 SecondaryObject_RecalculateSelector:
00D981 1 20 DC E3 jsr GetCurrentObjectSelectorAndState
00D984 1 ; $D981: 20 DC E3
00D984 1
00D984 1 98 tya ; $D984: 98
00D985 1 4A lsr ; $D985: 4A
00D986 1
00D986 1 69 04 adc #$04 ; $D986: 69 04
00D988 1 E5 6D sbc SpecialSequenceState ; $D988: E5 6D
00D98A 1
00D98A 1 0A asl ; $D98A: 0A
00D98B 1
00D98B 1 ; ----------------------------------------------------------------------------
00D98B 1 ; Compare the calculated object offset against CurrentObjectIndex.
00D98B 1 ;
00D98B 1 ; If the calculated offset is below the current object index, branch to the
00D98B 1 ; transition handler at $D9E6. Otherwise, continue at $D997.
00D98B 1 ;
00D98B 1 ; The BCS at $D98F is effectively unconditional if the preceding BCC was not
00D98B 1 ; taken because CMP establishes carry.
00D98B 1 ; ----------------------------------------------------------------------------
00D98B 1
00D98B 1 C5 E1 cmp CurrentObjectIndex ; $D98B: C5 E1
00D98D 1 90 57 bcc SecondaryObject_TransitionHandler
00D98F 1 ; $D98D: 90 57
00D98F 1
00D98F 1 B0 06 bcs SecondaryObject_ActionActive
00D991 1 ; $D98F: B0 06
00D991 1
00D991 1 ; ============================================================================
00D991 1 ; $D991-$D9B2
00D991 1 ; Secondary-object delay retry and action-active paths.
00D991 1 ;
00D991 1 ; The retry path repeatedly selects a delay and performs a geometry test.
00D991 1 ; Once the test succeeds, the action-active path updates the object and waits
00D991 1 ; until another state condition selects either the normal loop or transition.
00D991 1 ; ============================================================================
00D991 1
00D991 1 SecondaryObject_RetryPath: ; $D991
00D991 1 20 B8 DB jsr SelectSecondaryObjectDelay ; $D991: 20 B8 DB
00D994 1 ; Select a delay value in A.
00D994 1
00D994 1 20 41 EB jsr StoreObjectEventBankValue ; $D994: 20 41 EB
00D997 1 ; Wait for the selected delay.
00D997 1
00D997 1 ; ----------------------------------------------------------------------------
00D997 1 ; Real entry for the action-active path.
00D997 1 ;
00D997 1 ; The BCS at $D98F branches here when the calculated object offset is greater
00D997 1 ; than or equal to CurrentObjectIndex.
00D997 1 ; ----------------------------------------------------------------------------
00D997 1
00D997 1 SecondaryObject_ActionActive: ; $D997
00D997 1 20 8F E4 jsr SelectGeometryRecord_34 ; $D997: 20 8F E4
00D99A 1 20 5F E5 jsr ApplyCurrentObjectGeometry ; $D99A: 20 5F E5
00D99D 1
00D99D 1 B0 F2 bcs SecondaryObject_RetryPath
00D99F 1 ; $D99D: B0 F2
00D99F 1
00D99F 1 ; ----------------------------------------------------------------------------
00D99F 1 ; Geometry test succeeded. Update the current object and wait for a frame.
00D99F 1 ; ----------------------------------------------------------------------------
00D99F 1
00D99F 1 20 81 DA jsr UpdateCurrentObjectAnimation
00D9A2 1 ; $D99F: 20 81 DA
00D9A2 1
00D9A2 1 SecondaryObject_ActionWait: ; $D9A2
00D9A2 1 20 48 EB jsr SelectObjectEventBank1 ; $D9A2: 20 48 EB
00D9A5 1
00D9A5 1 ; ----------------------------------------------------------------------------
00D9A5 1 ; If SpecialSequenceState is nonzero, return to the selector calculation at $D981.
00D9A5 1 ; ----------------------------------------------------------------------------
00D9A5 1
00D9A5 1 A5 6D lda SpecialSequenceState ; $D9A5: A5 6D
00D9A7 1 D0 D8 bne SecondaryObject_RecalculateSelector
00D9A9 1 ; $D9A7: D0 D8
00D9A9 1
00D9A9 1 ; ----------------------------------------------------------------------------
00D9A9 1 ; Run the per-frame object helper, then evaluate the result from $DB18.
00D9A9 1 ; ----------------------------------------------------------------------------
00D9A9 1
00D9A9 1 20 BC DA jsr CheckCurrentObjectSelector ; $D9A9: 20 BC DA
00D9AC 1
00D9AC 1 20 18 DB jsr TestCurrentObjectInput ; $D9AC: 20 18 DB
00D9AF 1 10 F1 bpl SecondaryObject_ActionWait
00D9B1 1 ; $D9AF: 10 F1
00D9B1 1
00D9B1 1 ; ----------------------------------------------------------------------------
00D9B1 1 ; A negative result transfers to the transition handler at $D9E6.
00D9B1 1 ; ----------------------------------------------------------------------------
00D9B1 1
00D9B1 1 30 33 bmi SecondaryObject_TransitionHandler
00D9B3 1 ; $D9B1: 30 33
00D9B3 1
00D9B3 1 ; ============================================================================
00D9B3 1 ; $D9B3-$D9E5
00D9B3 1 ; Handle selector value eight, update pending state, and retry the geometry
00D9B3 1 ; test until the secondary object can complete its transition.
00D9B3 1 ; ============================================================================
00D9B3 1
00D9B3 1 SecondaryObject_SelectorEight: ; $D9B3
00D9B3 1 20 F7 DA jsr UpdateCurrentObjectSelectorState ; $D9B3: 20 F7 DA
00D9B6 1 20 EB DA jsr StoreCurrentObjectSelector ; $D9B6: 20 EB DA
00D9B9 1
00D9B9 1 ; ----------------------------------------------------------------------------
00D9B9 1 ; When SecondarySequenceState has not reached three, increment PendingScoreIncrement.
00D9B9 1 ;
00D9B9 1 ; If CurrentActionState is zero, immediately apply the pending increment to the
00D9B9 1 ; counters/display and clear PendingScoreIncrement.
00D9B9 1 ; ----------------------------------------------------------------------------
00D9B9 1
00D9B9 1 A5 64 lda SecondarySequenceState ; $D9B9: A5 64
00D9BB 1 C9 03 cmp #$03 ; $D9BB: C9 03
00D9BD 1 F0 0D beq SecondaryObject_RunFrameHelper
00D9BF 1 ; $D9BD: F0 0D
00D9BF 1
00D9BF 1 E6 65 inc PendingScoreIncrement ; $D9BF: E6 65
00D9C1 1
00D9C1 1 A5 9D lda CurrentActionState ; $D9C1: A5 9D
00D9C3 1 D0 07 bne SecondaryObject_RunFrameHelper
00D9C5 1 ; $D9C3: D0 07
00D9C5 1
00D9C5 1 20 A6 CF jsr UpdateCountersAndDisplay
00D9C8 1 ; $D9C5: 20 A6 CF
00D9C8 1
00D9C8 1 A9 00 lda #$00 ; $D9C8: A9 00
00D9CA 1 85 65 sta PendingScoreIncrement ; $D9CA: 85 65
00D9CC 1
00D9CC 1 ; ----------------------------------------------------------------------------
00D9CC 1 ; Run the per-frame secondary-object helper and repeat the geometry test.
00D9CC 1 ; ----------------------------------------------------------------------------
00D9CC 1
00D9CC 1 SecondaryObject_RunFrameHelper: ; $D9CC
00D9CC 1 20 BC DA jsr CheckCurrentObjectSelector ; $D9CC: 20 BC DA
00D9CF 1
00D9CF 1 20 8F E4 jsr SelectGeometryRecord_34 ; $D9CF: 20 8F E4
00D9D2 1 20 5F E5 jsr ApplyCurrentObjectGeometry ; $D9D2: 20 5F E5
00D9D5 1
00D9D5 1 90 09 bcc SecondaryObject_FinishSelectorEight
00D9D7 1 ; $D9D5: 90 09
00D9D7 1
00D9D7 1 ; ----------------------------------------------------------------------------
00D9D7 1 ; Geometry test still blocks completion.
00D9D7 1 ;
00D9D7 1 ; Select a delay, wait, and retry from the per-frame helper at $D9CC.
00D9D7 1 ; ----------------------------------------------------------------------------
00D9D7 1
00D9D7 1 20 B8 DB jsr SelectSecondaryObjectDelay ; $D9D7: 20 B8 DB
00D9DA 1 20 41 EB jsr StoreObjectEventBankValue ; $D9DA: 20 41 EB
00D9DD 1
00D9DD 1 4C CC D9 jmp SecondaryObject_RunFrameHelper
00D9E0 1 ; $D9DD: 4C CC D9
00D9E0 1
00D9E0 1 ; ----------------------------------------------------------------------------
00D9E0 1 ; Geometry test completed. Update the object and leave through the common
00D9E0 1 ; engine exit.
00D9E0 1 ; ----------------------------------------------------------------------------
00D9E0 1
00D9E0 1 SecondaryObject_FinishSelectorEight: ; $D9E0
00D9E0 1 20 81 DA jsr UpdateCurrentObjectAnimation
00D9E3 1 ; $D9E0: 20 81 DA
00D9E3 1
00D9E3 1 4C 6A EB jmp CommonEngineExit ; $D9E3: 4C 6A EB
00D9E6 1
00D9E6 1 ; ============================================================================
00D9E6 1 ; $D9E6-$DA0E
00D9E6 1 ; Secondary-object transition handler.
00D9E6 1 ;
00D9E6 1 ; Entry:
00D9E6 1 ; X is restored or derived by GetCurrentObjectStateIndex.
00D9E6 1 ;
00D9E6 1 ; The handler advances the indexed object state. If that state becomes
00D9E6 1 ; nonzero, it transfers directly to the shared negative-result path at $DA25.
00D9E6 1 ; If the state wraps to zero, it loads a new inline position record and begins
00D9E6 1 ; a new object-processing cycle.
00D9E6 1 ; ============================================================================
00D9E6 1
00D9E6 1 SecondaryObject_TransitionHandler: ; $D9E6
00D9E6 1 20 68 DA jsr GetCurrentObjectStateIndex
00D9E9 1 ; $D9E6: 20 68 DA
00D9E9 1
00D9E9 1 ; ----------------------------------------------------------------------------
00D9E9 1 ; Advance the indexed state byte at $0595,X.
00D9E9 1 ;
00D9E9 1 ; A nonzero result transfers to the shared path at $DA25.
00D9E9 1 ; ----------------------------------------------------------------------------
00D9E9 1
00D9E9 1 FE 95 05 inc $0595,x ; $D9E9: FE 95 05
00D9EC 1 D0 37 bne SecondaryObject_NegativeResultPath
00D9EE 1 ; $D9EC: D0 37
00D9EE 1
00D9EE 1 ; ----------------------------------------------------------------------------
00D9EE 1 ; The indexed state wrapped from $FF to zero.
00D9EE 1 ;
00D9EE 1 ; Initialize object offset $06 with a new position record:
00D9EE 1 ;
00D9EE 1 ; $0509,$X = $00
00D9EE 1 ; $050A,$X = $01
00D9EE 1 ; $053A,$X = $00
00D9EE 1 ; $053B,$X = $F8
00D9EE 1 ; ----------------------------------------------------------------------------
00D9EE 1
00D9EE 1 20 A7 C9 jsr LoadObjectPositionInline
00D9F1 1 ; $D9EE: 20 A7 C9
00D9F1 1
00D9F1 1 06 .byte $06 ; $D9F1: object offset/metadata
00D9F2 1 00 01 00 F8 .byte $00,$01,$00,$F8 ; $D9F2-$D9F5: position fields
00D9F6 1
00D9F6 1 ; ----------------------------------------------------------------------------
00D9F6 1 ; Recalculate the indexed object state and advance $0595,X again.
00D9F6 1 ; ----------------------------------------------------------------------------
00D9F6 1
00D9F6 1 20 68 DA jsr GetCurrentObjectStateIndex
00D9F9 1 ; $D9F6: 20 68 DA
00D9F9 1
00D9F9 1 FE 95 05 inc $0595,x ; $D9F9: FE 95 05
00D9FC 1 85 95 sta $95 ; $D9FC: 85 95
00D9FE 1 D0 06 bne SecondaryObject_RunFrameHelper_DA06
00DA00 1 ; $D9FE: D0 06
00DA00 1
00DA00 1 ; ----------------------------------------------------------------------------
00DA00 1 ; If A is zero, select a delay and wait before continuing.
00DA00 1 ; ----------------------------------------------------------------------------
00DA00 1 SecondaryObject_SelectRetryDelay:
00DA00 1 20 B8 DB jsr SelectSecondaryObjectDelay ; $DA00: 20 B8 DB
00DA03 1 20 41 EB jsr StoreObjectEventBankValue ; $DA03: 20 41 EB
00DA06 1
00DA06 1 ; ----------------------------------------------------------------------------
00DA06 1 ; Run the per-frame helper, then begin another geometry/region test.
00DA06 1 ; ----------------------------------------------------------------------------
00DA06 1
00DA06 1 SecondaryObject_RunFrameHelper_DA06: ; $DA06
00DA06 1 20 BC DA jsr CheckCurrentObjectSelector ; $DA06: 20 BC DA
00DA09 1
00DA09 1 20 B0 E4 jsr UseFixedGeometryRecord54 ; $DA09: 20 B0 E4
00DA0C 1 20 5F E5 jsr ApplyCurrentObjectGeometry ; $DA0C: 20 5F E5
00DA0F 1
00DA0F 1 ; ============================================================================
00DA0F 1 ; $DA0F-$DA10
00DA0F 1 ; Complete the geometry retry path begun at $DA06.
00DA0F 1 ;
00DA0F 1 ; Carry set returns to $DA00, where a new delay is selected before retrying.
00DA0F 1 ; ============================================================================
00DA0F 1
00DA0F 1 B0 EF bcs SecondaryObject_SelectRetryDelay
00DA11 1 ; $DA0F: B0 EF
00DA11 1
00DA11 1 ; ============================================================================
00DA11 1 ; $DA11-$DA24
00DA11 1 ; Wait while the secondary object remains in an active motion/state phase.
00DA11 1 ; ============================================================================
00DA11 1
00DA11 1 SecondaryObject_WaitForState: ; $DA11
00DA11 1 20 48 EB jsr SelectObjectEventBank1 ; $DA11: 20 48 EB
00DA14 1 20 BC DA jsr CheckCurrentObjectSelector ; $DA14: 20 BC DA
00DA17 1
00DA17 1 ; ----------------------------------------------------------------------------
00DA17 1 ; SpecialSequenceState or ObjectTransitionState immediately selects the timer path at $DA25.
00DA17 1 ; ----------------------------------------------------------------------------
00DA17 1
00DA17 1 A5 6D lda SpecialSequenceState ; $DA17: A5 6D
00DA19 1 05 6E ora ObjectTransitionState ; $DA19: 05 6E
00DA1B 1 D0 08 bne SecondaryObject_NegativeResultPath
00DA1D 1 ; $DA1B: D0 08
00DA1D 1
00DA1D 1 ; ----------------------------------------------------------------------------
00DA1D 1 ; Continue waiting while BaseMotionPhase is zero.
00DA1D 1 ; ----------------------------------------------------------------------------
00DA1D 1
00DA1D 1 A5 5D lda BaseMotionPhase ; $DA1D: A5 5D
00DA1F 1 F0 F0 beq SecondaryObject_WaitForState
00DA21 1 ; $DA1F: F0 F0
00DA21 1
00DA21 1 ; ----------------------------------------------------------------------------
00DA21 1 ; Continue waiting while PendingStateTransition is nonzero.
00DA21 1 ; ----------------------------------------------------------------------------
00DA21 1
00DA21 1 A5 60 lda PendingStateTransition ; $DA21: A5 60
00DA23 1 D0 EC bne SecondaryObject_WaitForState
00DA25 1 ; $DA23: D0 EC
00DA25 1
00DA25 1 ; ============================================================================
00DA25 1 ; $DA25-$DA5E
00DA25 1 ; Shared secondary-object timer and transition path.
00DA25 1 ;
00DA25 1 ; This is the real destination used by several earlier jumps and branches.
00DA25 1 ; ============================================================================
00DA25 1
00DA25 1 SecondaryObject_NegativeResultPath: ; $DA25
00DA25 1 A6 E1 ldx CurrentObjectIndex ; $DA25: A6 E1
00DA27 1
00DA27 1 A9 01 lda #$01 ; $DA27: A9 01
00DA29 1 9D B1 05 sta $05B1,x ; $DA29: 9D B1 05
00DA2C 1
00DA2C 1 ; ----------------------------------------------------------------------------
00DA2C 1 ; Wait for a frame, process the object, and count down its timer.
00DA2C 1 ; ----------------------------------------------------------------------------
00DA2C 1
00DA2C 1 SecondaryObject_DA2C_TimerLoop: ; $DA2C
00DA2C 1 20 48 EB jsr SelectObjectEventBank1 ; $DA2C: 20 48 EB
00DA2F 1 20 BC DA jsr CheckCurrentObjectSelector ; $DA2F: 20 BC DA
00DA32 1
00DA32 1 A6 E1 ldx CurrentObjectIndex ; $DA32: A6 E1
00DA34 1
00DA34 1 DE B1 05 dec $05B1,x ; $DA34: DE B1 05
00DA37 1 D0 10 bne SecondaryObject_DA49_CheckSelector
00DA39 1 ; $DA37: D0 10
00DA39 1
00DA39 1 ; ----------------------------------------------------------------------------
00DA39 1 ; Timer expired. Run the alternate geometry test.
00DA39 1 ; ----------------------------------------------------------------------------
00DA39 1
00DA39 1 20 9A E4 jsr SelectGeometryRecord_28 ; $DA39: 20 9A E4
00DA3C 1 20 5F E5 jsr ApplyCurrentObjectGeometry ; $DA3C: 20 5F E5
00DA3F 1
00DA3F 1 90 1B bcc SecondaryObject_DA5C_ReturnToIndexedPath
00DA41 1 ; $DA3F: 90 1B
00DA41 1
00DA41 1 ; ----------------------------------------------------------------------------
00DA41 1 ; Geometry test remains active.
00DA41 1 ;
00DA41 1 ; Select a new timer value and store it into $05B1,X.
00DA41 1 ; ----------------------------------------------------------------------------
00DA41 1
00DA41 1 20 B8 DB jsr SelectSecondaryObjectDelay ; $DA41: 20 B8 DB
00DA44 1
00DA44 1 A6 E1 ldx CurrentObjectIndex ; $DA44: A6 E1
00DA46 1 9D B1 05 sta $05B1,x ; $DA46: 9D B1 05
00DA49 1
00DA49 1 ; ----------------------------------------------------------------------------
00DA49 1 ; Derive the current selector.
00DA49 1 ;
00DA49 1 ; Selector one, or a nonzero SpecialSequenceState, returns to the timer loop.
00DA49 1 ; ----------------------------------------------------------------------------
00DA49 1
00DA49 1 SecondaryObject_DA49_CheckSelector: ; $DA49
00DA49 1 20 DC E3 jsr GetCurrentObjectSelectorAndState
00DA4C 1 ; $DA49: 20 DC E3
00DA4C 1
00DA4C 1 C0 01 cpy #$01 ; $DA4C: C0 01
00DA4E 1 F0 DC beq SecondaryObject_DA2C_TimerLoop
00DA50 1 ; $DA4E: F0 DC
00DA50 1
00DA50 1 A5 6D lda SpecialSequenceState ; $DA50: A5 6D
00DA52 1 D0 D8 bne SecondaryObject_DA2C_TimerLoop
00DA54 1 ; $DA52: D0 D8
00DA54 1
00DA54 1 ; ----------------------------------------------------------------------------
00DA54 1 ; Continue the timer loop while $DB18 returns carry clear.
00DA54 1 ;
00DA54 1 ; Carry set returns to the timer initialization path at $D8C3.
00DA54 1 ; ----------------------------------------------------------------------------
00DA54 1
00DA54 1 20 18 DB jsr TestCurrentObjectInput ; $DA54: 20 18 DB
00DA57 1 90 D3 bcc SecondaryObject_DA2C_TimerLoop
00DA59 1 ; $DA57: 90 D3
00DA59 1
00DA59 1 4C C3 D8 jmp SecondaryObject_ActivateTimer
00DA5C 1 ; $DA59: 4C C3 D8
00DA5C 1
00DA5C 1 ; ----------------------------------------------------------------------------
00DA5C 1 ; The alternate geometry test completed.
00DA5C 1 ;
00DA5C 1 ; Return to the indexed-state path at $D967.
00DA5C 1 ; ----------------------------------------------------------------------------
00DA5C 1
00DA5C 1 SecondaryObject_DA5C_ReturnToIndexedPath: ; $DA5C
00DA5C 1 4C 67 D9 jmp SecondaryObject_AdvanceIndexedState
00DA5F 1 ; $DA5C: 4C 67 D9
00DA5F 1
00DA5F 1 ; ============================================================================
00DA5F 1 ; $DA5F-$DA67
00DA5F 1 ; Convert CurrentObjectIndex into a smaller selector and tail-call $E246.
00DA5F 1 ;
00DA5F 1 ; Calculation:
00DA5F 1 ;
00DA5F 1 ; Y = (CurrentObjectIndex >> 1) - 1 - !C
00DA5F 1 ;
00DA5F 1 ; The SBC intentionally uses carry left by LSR.
00DA5F 1 ; ============================================================================
00DA5F 1
00DA5F 1 ; ----------------------------------------------------------------------------
00DA5F 1 ; Contract:
00DA5F 1 ; Description: Implements Get Current Object Selector.
00DA5F 1 ; Entry: Registers: A; Memory: currentobjectindex
00DA5F 1 ; Returns/products: Registers/clobbers: A, Y; Flags: condition flags may carry result state
00DA5F 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00DA5F 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00DA5F 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00DA5F 1 ; comparison, load, or store path and are not a stable API product.
00DA5F 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 3.
00DA5F 1 ; ----------------------------------------------------------------------------
00DA5F 1 GetCurrentObjectSelector: ; $DA5F
00DA5F 1 A5 E1 lda CurrentObjectIndex ; $DA5F: A5 E1
00DA61 1 4A lsr ; $DA61: 4A
00DA62 1
00DA62 1 E9 01 sbc #$01 ; $DA62: E9 01
00DA64 1 A8 tay ; $DA64: A8
00DA65 1
00DA65 1 4C 46 E2 jmp FindObjectStateForSelector ; $DA65: 4C 46 E2
00DA68 1
00DA68 1 ; ============================================================================
00DA68 1 ; $DA68-$DA6C
00DA68 1 ; Convert CurrentObjectIndex into an object-state array index.
00DA68 1 ;
00DA68 1 ; Exit:
00DA68 1 ; A = CurrentObjectIndex >> 1
00DA68 1 ; X = CurrentObjectIndex >> 1
00DA68 1 ; ============================================================================
00DA68 1
00DA68 1 GetCurrentObjectStateIndex: ; $DA68
00DA68 1 A5 E1 lda CurrentObjectIndex ; $DA68: A5 E1
00DA6A 1 4A lsr ; $DA6A: 4A
00DA6B 1 AA tax ; $DA6B: AA
00DA6C 1
00DA6C 1 60 rts ; $DA6C: 60
00DA6D 1
00DA6D 1 ; ============================================================================
00DA6D 1 ; $DA6D-$DA80
00DA6D 1 ; Compare the current event selector against the object's derived selector.
00DA6D 1 ;
00DA6D 1 ; When they match, mark the corresponding zero-page object state at $95,X
00DA6D 1 ; as active by storing $01.
00DA6D 1 ; ============================================================================
00DA6D 1
00DA6D 1 ; ----------------------------------------------------------------------------
00DA6D 1 ; Contract:
00DA6D 1 ; Description: Implements Mark Matching Object State.
00DA6D 1 ; Entry: Registers: A, X, Y; Memory: mathtemp05
00DA6D 1 ; Returns/products: Registers/clobbers: A, X
00DA6D 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00DA6D 1 ; Memory effects: mathtemp05, $95
00DA6D 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00DA6D 1 ; comparison, load, or store path and are not a stable API product.
00DA6D 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00DA6D 1 ; ----------------------------------------------------------------------------
00DA6D 1 MarkMatchingObjectState: ; $DA6D
00DA6D 1 20 DC E3 jsr GetCurrentObjectSelectorAndState
00DA70 1 ; $DA6D: 20 DC E3
00DA70 1 ; Returns an event/object selector in X and Y.
00DA70 1
00DA70 1 8A txa ; $DA70: 8A
00DA71 1 38 sec ; $DA71: 38
00DA72 1 E9 06 sbc #$06 ; $DA72: E9 06
00DA74 1 85 05 sta MathTemp05 ; $DA74: 85 05
00DA76 1
00DA76 1 C4 05 cpy MathTemp05 ; $DA76: C4 05
00DA78 1 D0 06 bne MarkMatchingObjectState_Return
00DA7A 1 ; $DA78: D0 06
00DA7A 1
00DA7A 1 ; ----------------------------------------------------------------------------
00DA7A 1 ; The selectors match.
00DA7A 1 ;
00DA7A 1 ; Convert A to the corresponding indexed state slot and set $95,X to one.
00DA7A 1 ; ----------------------------------------------------------------------------
00DA7A 1
00DA7A 1 4A lsr ; $DA7A: 4A
00DA7B 1 AA tax ; $DA7B: AA
00DA7C 1
00DA7C 1 A9 01 lda #$01 ; $DA7C: A9 01
00DA7E 1 95 95 sta $95,x ; $DA7E: 95 95
00DA80 1
00DA80 1 MarkMatchingObjectState_Return: ; $DA80
00DA80 1 60 rts ; $DA80: 60
00DA81 1
00DA81 1 ; ============================================================================
00DA81 1 ; $DA81-$DA9B
00DA81 1 ; Update the current object's animation and sprite-state values.
00DA81 1 ;
00DA81 1 ; This routine:
00DA81 1 ; 1. Updates the object through $E6B7.
00DA81 1 ; 2. Derives an event selector through GetCurrentObjectSelectorAndState.
00DA81 1 ; 3. Converts Y and X to compact table indices.
00DA81 1 ; 4. Stores table-selected values into $03B0,X and $039B,X.
00DA81 1 ;
00DA81 1 ; The table loads intentionally use bases one byte before the visible tables:
00DA81 1 ;
00DA81 1 ; $DA9B,Y
00DA81 1 ; $DA9F,Y
00DA81 1 ; ============================================================================
00DA81 1
00DA81 1 UpdateCurrentObjectAnimation: ; $DA81
00DA81 1 A6 E1 ldx CurrentObjectIndex ; $DA81: A6 E1
00DA83 1 20 B7 E6 jsr ClearMovementTransforms ; $DA83: 20 B7 E6
00DA86 1
00DA86 1 20 DC E3 jsr GetCurrentObjectSelectorAndState
00DA89 1 ; $DA86: 20 DC E3
00DA89 1
00DA89 1 ; ----------------------------------------------------------------------------
00DA89 1 ; Convert the Y selector to a four-entry table index.
00DA89 1 ; ----------------------------------------------------------------------------
00DA89 1
00DA89 1 98 tya ; $DA89: 98
00DA8A 1 4A lsr ; $DA8A: 4A
00DA8B 1 A8 tay ; $DA8B: A8
00DA8C 1
00DA8C 1 ; ----------------------------------------------------------------------------
00DA8C 1 ; Convert the X selector to its sprite-array index.
00DA8C 1 ; ----------------------------------------------------------------------------
00DA8C 1
00DA8C 1 8A txa ; $DA8C: 8A
00DA8D 1 4A lsr ; $DA8D: 4A
00DA8E 1 AA tax ; $DA8E: AA
00DA8F 1
00DA8F 1 ; ----------------------------------------------------------------------------
00DA8F 1 ; Load the table-selected animation values.
00DA8F 1 ;
00DA8F 1 ; The first table access uses base $DA9B, where byte $DA9B is the preceding
00DA8F 1 ; RTS opcode. Expected Y values begin at one.
00DA8F 1 ; ----------------------------------------------------------------------------
00DA8F 1
00DA8F 1 B9 9B DA lda $DA9B,y ; $DA8F: B9 9B DA
00DA92 1 9D B0 03 sta $03B0,x ; $DA92: 9D B0 03
00DA95 1
00DA95 1 B9 9F DA lda $DA9F,y ; $DA95: B9 9F DA
00DA98 1 9D 9B 03 sta $039B,x ; $DA98: 9D 9B 03
00DA9B 1
00DA9B 1 60 rts ; $DA9B: 60
00DA9C 1
00DA9C 1 ; ============================================================================
00DA9C 1 ; $DA9C-$DAA3
00DA9C 1 ; Parallel four-byte animation lookup tables.
00DA9C 1 ;
00DA9C 1 ; Because the code uses one-byte-earlier bases, expected Y values are $01-$04:
00DA9C 1 ;
00DA9C 1 ; LDA $DA9B,Y:
00DA9C 1 ; Y=$01 -> $DA9C
00DA9C 1 ; Y=$04 -> $DA9F
00DA9C 1 ;
00DA9C 1 ; LDA $DA9F,Y:
00DA9C 1 ; Y=$01 -> $DAA0
00DA9C 1 ; Y=$04 -> $DAA3
00DA9C 1 ; ============================================================================
00DA9C 1
00DA9C 1 ObjectAnimationAttributeTable: ; $DA9C
00DA9C 1 1D 1D 1A 7A .byte $1D,$1D,$1A,$7A
00DAA0 1
00DAA0 1 ObjectAnimationFrameTable: ; $DAA0
00DAA0 1 53 56 4D 7A .byte $53,$56,$4D,$7A
00DAA4 1
00DAA4 1 ; ============================================================================
00DAA4 1 ; $DAA4-$DABB
00DAA4 1 ; Count matching object-state entries.
00DAA4 1 ;
00DAA4 1 ; The selector returned by GetCurrentObjectSelectorAndState is compared against the four entries at
00DAA4 1 ; $0598-$059B. Carry is set on return when at least two entries match.
00DAA4 1 ;
00DAA4 1 ; Return:
00DAA4 1 ; Y = number of matching entries
00DAA4 1 ; C = set when Y >= 2
00DAA4 1 ; ============================================================================
00DAA4 1
00DAA4 1 ; ----------------------------------------------------------------------------
00DAA4 1 ; Contract:
00DAA4 1 ; Description: Implements Count Matching Object States.
00DAA4 1 ; Entry: Registers: A, X, Y; Memory: $0598
00DAA4 1 ; Returns/products: Registers/clobbers: A, X, Y; Flags: condition flags may carry result state
00DAA4 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00DAA4 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00DAA4 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00DAA4 1 ; comparison, load, or store path and are not a stable API product.
00DAA4 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 2.
00DAA4 1 ; ----------------------------------------------------------------------------
00DAA4 1 CountMatchingObjectStates: ; $DAA4
00DAA4 1 20 DC E3 jsr GetCurrentObjectSelectorAndState
00DAA7 1 ; $DAA4: 20 DC E3
00DAA7 1
00DAA7 1 98 tya ; $DAA7: 98
00DAA8 1 30 2B bmi FinishSecondaryObject ; $DAA8: 30 2B
00DAAA 1
00DAAA 1 ; ----------------------------------------------------------------------------
00DAAA 1 ; Count entries in $0598-$059B that equal A.
00DAAA 1 ; ----------------------------------------------------------------------------
00DAAA 1
00DAAA 1 A0 00 ldy #$00 ; $DAAA: A0 00
00DAAC 1 A2 03 ldx #$03 ; $DAAC: A2 03
00DAAE 1
00DAAE 1 CountMatchingObjectStates_Loop: ; $DAAE
00DAAE 1 DD 98 05 cmp $0598,x ; $DAAE: DD 98 05
00DAB1 1 D0 01 bne CountMatchingObjectStates_Next
00DAB3 1 ; $DAB1: D0 01
00DAB3 1
00DAB3 1 C8 iny ; $DAB3: C8
00DAB4 1
00DAB4 1 CountMatchingObjectStates_Next: ; $DAB4
00DAB4 1 CA dex ; $DAB4: CA
00DAB5 1 10 F7 bpl CountMatchingObjectStates_Loop
00DAB7 1 ; $DAB5: 10 F7
00DAB7 1
00DAB7 1 C0 02 cpy #$02 ; $DAB7: C0 02
00DAB9 1 B0 08 bcs DisableCurrentObject ; $DAB9: B0 08
00DABB 1
00DABB 1 60 rts ; $DABB: 60
00DABC 1
00DABC 1 ; ============================================================================
00DABC 1 ; $DABC-$DAC2
00DABC 1 ; Check whether the selector returned by GetCurrentObjectSelectorAndState is negative.
00DABC 1 ;
00DABC 1 ; Return:
00DABC 1 ; N flag reflects the selector sign.
00DABC 1 ;
00DABC 1 ; A negative selector transfers to the common secondary-object finish path.
00DABC 1 ; ============================================================================
00DABC 1
00DABC 1 ; ----------------------------------------------------------------------------
00DABC 1 ; Contract:
00DABC 1 ; Description: Implements Check Current Object Selector.
00DABC 1 ; Entry: Registers: Y
00DABC 1 ; Returns/products: Registers/clobbers: A
00DABC 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00DABC 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00DABC 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00DABC 1 ; comparison, load, or store path and are not a stable API product.
00DABC 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 6.
00DABC 1 ; ----------------------------------------------------------------------------
00DABC 1 CheckCurrentObjectSelector: ; $DABC
00DABC 1 20 DC E3 jsr GetCurrentObjectSelectorAndState
00DABF 1 ; $DABC: 20 DC E3
00DABF 1
00DABF 1 98 tya ; $DABF: 98
00DAC0 1 30 13 bmi FinishSecondaryObject ; $DAC0: 30 13
00DAC2 1
00DAC2 1 60 rts ; $DAC2: 60
00DAC3 1
00DAC3 1 ; ============================================================================
00DAC3 1 ; $DAC3-$DAD4
00DAC3 1 ; Disable the current object and advance the associated state sequence.
00DAC3 1 ;
00DAC3 1 ; This path is entered when at least two object-state entries match.
00DAC3 1 ; ============================================================================
00DAC3 1
00DAC3 1 DisableCurrentObject: ; $DAC3
00DAC3 1 20 DC E3 jsr GetCurrentObjectSelectorAndState ; $DAC3: 20 DC E3
00DAC6 1
00DAC6 1 98 tya ; $DAC6: 98
00DAC7 1 4A lsr ; $DAC7: 4A
00DAC8 1 ; ----------------------------------------------------------------------------
00DAC8 1 ; Contract:
00DAC8 1 ; Description: Internal state-routing entry that stores A as the state selector.
00DAC8 1 ; Entry: A = state selector.
00DAC8 1 ; Returns/products: StateSelector updated; returns through parent routine flow.
00DAC8 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00DAC8 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00DAC8 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00DAC8 1 ; comparison, load, or store path and are not a stable API product.
00DAC8 1 ; Validation: Internal-entry contract; call sites: internal entry.
00DAC8 1 ; ----------------------------------------------------------------------------
00DAC8 1 StoreStateSelector:
00DAC8 1 85 72 sta StateSelector ; $DAC8: 85 72
00DACA 1
00DACA 1 20 68 DA jsr GetCurrentObjectStateIndex
00DACD 1 ; $DACA: 20 68 DA
00DACD 1
00DACD 1 A9 FF lda #$FF ; $DACD: A9 FF
00DACF 1 9D 95 05 sta $0595,x ; $DACF: 9D 95 05
00DAD2 1
00DAD2 1 20 E4 CC jsr AdvanceAlternateStateSequence
00DAD5 1 ; $DAD2: 20 E4 CC
00DAD5 1
00DAD5 1 ; ============================================================================
00DAD5 1 ; $DAD5-$DAEA
00DAD5 1 ; Finish the current secondary-object sequence.
00DAD5 1 ;
00DAD5 1 ; This path:
00DAD5 1 ; 1. Calls the engine helper at $E2D3.
00DAD5 1 ; 2. Waits $1E ticks.
00DAD5 1 ; 3. Sets the current object's animation fields to $7A.
00DAD5 1 ; 4. Leaves through the common engine exit.
00DAD5 1 ; ============================================================================
00DAD5 1
00DAD5 1 FinishSecondaryObject: ; $DAD5
00DAD5 1 20 D3 E2 jsr ClearCurrentObjectMovement ; $DAD5: 20 D3 E2
00DAD8 1
00DAD8 1 A9 1E lda #$1E ; $DAD8: A9 1E
00DADA 1 20 41 EB jsr StoreObjectEventBankValue ; $DADA: 20 41 EB
00DADD 1
00DADD 1 20 68 DA jsr GetCurrentObjectStateIndex
00DAE0 1 ; $DADD: 20 68 DA
00DAE0 1
00DAE0 1 A9 7A lda #$7A ; $DAE0: A9 7A
00DAE2 1 9D B0 03 sta $03B0,x ; $DAE2: 9D B0 03
00DAE5 1 9D 9B 03 sta $039B,x ; $DAE5: 9D 9B 03
00DAE8 1
00DAE8 1 4C 6A EB jmp CommonEngineExit ; $DAE8: 4C 6A EB
00DAEB 1
00DAEB 1 ; ============================================================================
00DAEB 1 ; $DAEB-$DAF6
00DAEB 1 ; Store the current selector in the object-state mirror array.
00DAEB 1 ;
00DAEB 1 ; When TrajectoryEvaluationEnabled is zero, GetCurrentObjectSelectorAndState returns a selector:
00DAEB 1 ;
00DAEB 1 ; X = destination index
00DAEB 1 ; Y = selector value
00DAEB 1 ;
00DAEB 1 ; The selector is stored at $9B,X.
00DAEB 1 ; ============================================================================
00DAEB 1
00DAEB 1 ; ----------------------------------------------------------------------------
00DAEB 1 ; Contract:
00DAEB 1 ; Description: Implements Store Current Object Selector.
00DAEB 1 ; Entry: Registers: A, Y; Memory: trajectoryevaluationenabled
00DAEB 1 ; Returns/products: Registers/clobbers: A, X
00DAEB 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00DAEB 1 ; Memory effects: $9b
00DAEB 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00DAEB 1 ; comparison, load, or store path and are not a stable API product.
00DAEB 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 3.
00DAEB 1 ; ----------------------------------------------------------------------------
00DAEB 1 StoreCurrentObjectSelector: ; $DAEB
00DAEB 1 A5 86 lda TrajectoryEvaluationEnabled ; $DAEB: A5 86
00DAED 1 D0 07 bne StoreCurrentObjectSelector_Return
00DAEF 1 ; $DAED: D0 07
00DAEF 1
00DAEF 1 20 DC E3 jsr GetCurrentObjectSelectorAndState ; $DAEF: 20 DC E3
00DAF2 1
00DAF2 1 AA tax ; $DAF2: AA
00DAF3 1 98 tya ; $DAF3: 98
00DAF4 1
00DAF4 1 95 9B sta $9B,x ; $DAF4: 95 9B
00DAF6 1
00DAF6 1 StoreCurrentObjectSelector_Return: ; $DAF6
00DAF6 1 60 rts ; $DAF6: 60
00DAF7 1
00DAF7 1 ; ============================================================================
00DAF7 1 ; $DAF7-$DB17
00DAF7 1 ; Compare the current selector against $9E and update the indexed object state.
00DAF7 1 ;
00DAF7 1 ; This routine can:
00DAF7 1 ;
00DAF7 1 ; - finish the current object sequence,
00DAF7 1 ; - disable an object and advance state,
00DAF7 1 ; - decrement $0595,X,
00DAF7 1 ; - or increment $0595,X.
00DAF7 1 ; ============================================================================
00DAF7 1
00DAF7 1 ; ----------------------------------------------------------------------------
00DAF7 1 ; Contract:
00DAF7 1 ; Description: Updates Current Object Selector State.
00DAF7 1 ; Entry: Registers: A, Y; Memory: $9e, objecttransitionstate
00DAF7 1 ; Returns/products: Registers/clobbers: A, Y; Flags: condition flags may carry result state
00DAF7 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00DAF7 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00DAF7 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00DAF7 1 ; comparison, load, or store path and are not a stable API product.
00DAF7 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 3.
00DAF7 1 ; ----------------------------------------------------------------------------
00DAF7 1 UpdateCurrentObjectSelectorState: ; $DAF7
00DAF7 1 20 DC E3 jsr GetCurrentObjectSelectorAndState ; $DAF7: 20 DC E3
00DAFA 1
00DAFA 1 98 tya ; $DAFA: 98
00DAFB 1 30 D8 bmi FinishSecondaryObject ; $DAFB: 30 D8
00DAFD 1
00DAFD 1 ; ----------------------------------------------------------------------------
00DAFD 1 ; Compare half of the selector against $9E.
00DAFD 1 ; ----------------------------------------------------------------------------
00DAFD 1
00DAFD 1 4A lsr ; $DAFD: 4A
00DAFE 1 C5 9E cmp $9E ; $DAFE: C5 9E
00DB00 1 D0 15 bne UpdateCurrentObjectSelectorState_Return
00DB02 1 ; $DB00: D0 15
00DB02 1
00DB02 1 ; ----------------------------------------------------------------------------
00DB02 1 ; If ObjectTransitionState is zero, branch directly into DisableCurrentObject after the
00DB02 1 ; selector-to-index conversion at $DAC3.
00DB02 1 ;
00DB02 1 ; The target $DAC8 stores the current A value into StateSelector.
00DB02 1 ; ----------------------------------------------------------------------------
00DB02 1
00DB02 1 A4 6E ldy ObjectTransitionState ; $DB02: A4 6E
00DB04 1 F0 C2 beq StoreStateSelector
00DB06 1 ; $DB04: F0 C2
00DB06 1
00DB06 1 ; ----------------------------------------------------------------------------
00DB06 1 ; Decrement the indexed object state and evaluate the current result.
00DB06 1 ; ----------------------------------------------------------------------------
00DB06 1
00DB06 1 20 68 DA jsr GetCurrentObjectStateIndex
00DB09 1 ; $DB06: 20 68 DA
00DB09 1
00DB09 1 DE 95 05 dec $0595,x ; $DB09: DE 95 05
00DB0C 1
00DB0C 1 20 5F DA jsr GetCurrentObjectSelector
00DB0F 1 ; $DB0C: 20 5F DA
00DB0F 1
00DB0F 1 10 B2 bpl DisableCurrentObject ; $DB0F: 10 B2
00DB11 1
00DB11 1 ; ----------------------------------------------------------------------------
00DB11 1 ; A negative selector result restores the indexed object-state value.
00DB11 1 ; ----------------------------------------------------------------------------
00DB11 1
00DB11 1 20 68 DA jsr GetCurrentObjectStateIndex
00DB14 1 ; $DB11: 20 68 DA
00DB14 1
00DB14 1 FE 95 05 inc $0595,x ; $DB14: FE 95 05
00DB17 1
00DB17 1 UpdateCurrentObjectSelectorState_Return: ; $DB17
00DB17 1 60 rts ; $DB17: 60
00DB18 1
00DB18 1
00DB18 1 ; ============================================================================
00DB18 1 ; $DB18-$DB2D
00DB18 1 ; Test the current input against a selector-specific mask.
00DB18 1 ;
00DB18 1 ; Return behavior:
00DB18 1 ;
00DB18 1 ; ActionSequenceCounter == 0:
00DB18 1 ; A = 0
00DB18 1 ; returns after ASL
00DB18 1 ;
00DB18 1 ; DerivedControl0 == 0:
00DB18 1 ; transfers directly to the next routine at $DB2E
00DB18 1 ;
00DB18 1 ; InputState1 & InputMaskTable[Y] == 0:
00DB18 1 ; A = 0
00DB18 1 ; returns after ASL
00DB18 1 ;
00DB18 1 ; InputState1 & InputMaskTable[Y] != 0:
00DB18 1 ; A = InputAux1 << 1
00DB18 1 ; returns with flags from ASL
00DB18 1 ;
00DB18 1 ; Callers commonly test the N or C flags produced by the final ASL.
00DB18 1 ; ============================================================================
00DB18 1
00DB18 1 ; ----------------------------------------------------------------------------
00DB18 1 ; Contract:
00DB18 1 ; Description: Implements Test Current Object Input.
00DB18 1 ; Entry: Registers: A; Memory: actionsequencecounter, derivedcontrol0, inputstate1, inputmasktable, inputaux1
00DB18 1 ; Returns/products: Registers/clobbers: A; Flags: condition flags may carry result state
00DB18 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00DB18 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00DB18 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00DB18 1 ; comparison, load, or store path and are not a stable API product.
00DB18 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 5.
00DB18 1 ; ----------------------------------------------------------------------------
00DB18 1 TestCurrentObjectInput: ; $DB18
00DB18 1 A5 7E lda ActionSequenceCounter ; $DB18: A5 7E
00DB1A 1 F0 10 beq TestCurrentObjectInput_Shift
00DB1C 1 ; $DB1A: F0 10
00DB1C 1
00DB1C 1 A5 0F lda DerivedControl0 ; $DB1C: A5 0F
00DB1E 1 F0 0E beq CurrentObjectInputFallback
00DB20 1 ; $DB1E: F0 0E
00DB20 1 ; Branches to $DB2E, the next routine entry.
00DB20 1
00DB20 1 ; ----------------------------------------------------------------------------
00DB20 1 ; Obtain the current object/event selector in Y.
00DB20 1 ; ----------------------------------------------------------------------------
00DB20 1
00DB20 1 20 DC E3 jsr GetCurrentObjectSelectorAndState ; $DB20: 20 DC E3
00DB23 1
00DB23 1 ; ----------------------------------------------------------------------------
00DB23 1 ; Test InputState1 against the selector-specific mask at $DBB0,Y.
00DB23 1 ; ----------------------------------------------------------------------------
00DB23 1
00DB23 1 A5 13 lda InputState1 ; $DB23: A5 13
00DB25 1 39 B0 DB and InputMaskTable,y ; $DB25: 39 B0 DB
00DB28 1
00DB28 1 F0 02 beq TestCurrentObjectInput_Shift
00DB2A 1 ; $DB28: F0 02
00DB2A 1
00DB2A 1 ; ----------------------------------------------------------------------------
00DB2A 1 ; Matching input was detected. Return InputAux1 shifted left once.
00DB2A 1 ; ----------------------------------------------------------------------------
00DB2A 1
00DB2A 1 A5 17 lda InputAux1 ; $DB2A: A5 17
00DB2C 1
00DB2C 1 TestCurrentObjectInput_Shift: ; $DB2C
00DB2C 1 0A asl ; $DB2C: 0A
00DB2D 1 60 rts ; $DB2D: 60
00DB2E 1
00DB2E 1 ; ============================================================================
00DB2E 1 ; $DB2E-$DB83
00DB2E 1 ; Resolve the current object's input/collision state.
00DB2E 1 ;
00DB2E 1 ; This routine combines:
00DB2E 1 ; - current object identity,
00DB2E 1 ; - object-state entries,
00DB2E 1 ; - animation state,
00DB2E 1 ; - current selector,
00DB2E 1 ; - movement state,
00DB2E 1 ; - coordinate comparisons,
00DB2E 1 ; - and the region test at $DB84.
00DB2E 1 ;
00DB2E 1 ; Return conventions:
00DB2E 1 ;
00DB2E 1 ; Carry set:
00DB2E 1 ; successful or active condition
00DB2E 1 ;
00DB2E 1 ; Carry clear, A = $00:
00DB2E 1 ; failed coordinate/region condition
00DB2E 1 ;
00DB2E 1 ; Carry clear, A = $80:
00DB2E 1 ; alternate inactive/result condition
00DB2E 1 ;
00DB2E 1 ; Carry clear, A preserved:
00DB2E 1 ; neutral state via $DB82
00DB2E 1 ; ============================================================================
00DB2E 1
00DB2E 1 CurrentObjectInputFallback: ; $DB2E
00DB2E 1 A6 E1 ldx CurrentObjectIndex ; $DB2E: A6 E1
00DB30 1
00DB30 1 ; ----------------------------------------------------------------------------
00DB30 1 ; Special-case object offset $08.
00DB30 1 ; ----------------------------------------------------------------------------
00DB30 1
00DB30 1 E0 08 cpx #$08 ; $DB30: E0 08
00DB32 1 D0 12 bne ResolveCurrentObjectSelector
00DB34 1 ; $DB32: D0 12
00DB34 1
00DB34 1 AD 9A 05 lda $059A ; $DB34: AD 9A 05
00DB37 1 10 0D bpl ResolveCurrentObjectSelector
00DB39 1 ; $DB37: 10 0D
00DB39 1
00DB39 1 AD B7 03 lda $03B7 ; $DB39: AD B7 03
00DB3C 1 C9 0D cmp #$0D ; $DB3C: C9 0D
00DB3E 1 D0 06 bne ResolveCurrentObjectSelector
00DB40 1 ; $DB3E: D0 06
00DB40 1
00DB40 1 ; ----------------------------------------------------------------------------
00DB40 1 ; When object $08 is inactive and frame $03B7 equals $0D, use a random result.
00DB40 1 ;
00DB40 1 ; A zero random result returns through the alternate result at $DB7E.
00DB40 1 ; ----------------------------------------------------------------------------
00DB40 1
00DB40 1 20 F5 E5 jsr AdvanceRandomState ; $DB40: 20 F5 E5
00DB43 1 A8 tay ; $DB43: A8
00DB44 1 F0 38 beq ResolveCurrentObject_AlternateResult
00DB46 1 ; $DB44: F0 38
00DB46 1
00DB46 1 ; ----------------------------------------------------------------------------
00DB46 1 ; Derive the current object/event selector.
00DB46 1 ; ----------------------------------------------------------------------------
00DB46 1
00DB46 1 ResolveCurrentObjectSelector: ; $DB46
00DB46 1 20 DC E3 jsr GetCurrentObjectSelectorAndState ; $DB46: 20 DC E3
00DB49 1
00DB49 1 98 tya ; $DB49: 98
00DB4A 1 4A lsr ; $DB4A: 4A
00DB4B 1
00DB4B 1 ; ----------------------------------------------------------------------------
00DB4B 1 ; If half the selector equals $BB, use the secondary region-test path.
00DB4B 1 ; ----------------------------------------------------------------------------
00DB4B 1
00DB4B 1 C5 BB cmp $BB ; $DB4B: C5 BB
00DB4D 1 F0 2A beq ResolveCurrentObject_SecondaryRegion
00DB4F 1 ; $DB4D: F0 2A
00DB4F 1
00DB4F 1 ; ----------------------------------------------------------------------------
00DB4F 1 ; BaseMotionPhase equal to zero returns through the neutral carry-clear path.
00DB4F 1 ; ----------------------------------------------------------------------------
00DB4F 1
00DB4F 1 A5 5D lda BaseMotionPhase ; $DB4F: A5 5D
00DB51 1 F0 2F beq ResolveCurrentObject_Neutral
00DB53 1 ; $DB51: F0 2F
00DB53 1
00DB53 1 ; ----------------------------------------------------------------------------
00DB53 1 ; BaseMotionEventCount equal to zero returns the alternate $80 result.
00DB53 1 ; ----------------------------------------------------------------------------
00DB53 1
00DB53 1 A5 5E lda BaseMotionEventCount ; $DB53: A5 5E
00DB55 1 F0 27 beq ResolveCurrentObject_AlternateResult
00DB57 1 ; $DB55: F0 27
00DB57 1
00DB57 1 ; ----------------------------------------------------------------------------
00DB57 1 ; A negative current-object selector returns through the neutral path.
00DB57 1 ; ----------------------------------------------------------------------------
00DB57 1
00DB57 1 20 5F DA jsr GetCurrentObjectSelector
00DB5A 1 ; $DB57: 20 5F DA
00DB5A 1
00DB5A 1 30 26 bmi ResolveCurrentObject_Neutral
00DB5C 1 ; $DB5A: 30 26
00DB5C 1
00DB5C 1 ; ----------------------------------------------------------------------------
00DB5C 1 ; Run the region test at $DB84.
00DB5C 1 ;
00DB5C 1 ; Carry clear selects the zero-result path at $DB75.
00DB5C 1 ; ----------------------------------------------------------------------------
00DB5C 1
00DB5C 1 20 84 DB jsr TestCurrentObjectRegion ; $DB5C: 20 84 DB
00DB5F 1 90 14 bcc ResolveCurrentObject_ZeroResult
00DB61 1 ; $DB5F: 90 14
00DB61 1
00DB61 1 ; ----------------------------------------------------------------------------
00DB61 1 ; Compare the current object's high X coordinate against a selector-indexed
00DB61 1 ; threshold table at $E021,Y.
00DB61 1 ; ----------------------------------------------------------------------------
00DB61 1
00DB61 1 20 DC E3 jsr GetCurrentObjectSelectorAndState ; $DB61: 20 DC E3
00DB64 1
00DB64 1 98 tya ; $DB64: 98
00DB65 1 4A lsr ; $DB65: 4A
00DB66 1 A8 tay ; $DB66: A8
00DB67 1
00DB67 1 BD 0A 05 lda $050A,x ; $DB67: BD 0A 05
00DB6A 1 D9 21 E0 cmp $E021,y ; $DB6A: D9 21 E0
00DB6D 1
00DB6D 1 ; ----------------------------------------------------------------------------
00DB6D 1 ; Convert comparison carry, selector range, and ADC carry into one final test.
00DB6D 1 ; ----------------------------------------------------------------------------
00DB6D 1
00DB6D 1 2A rol ; $DB6D: 2A
00DB6E 1
00DB6E 1 C0 03 cpy #$03 ; $DB6E: C0 03
00DB70 1 69 00 adc #$00 ; $DB70: 69 00
00DB72 1
00DB72 1 4A lsr ; $DB72: 4A
00DB73 1 90 09 bcc ResolveCurrentObject_AlternateResult
00DB75 1 ; $DB73: 90 09
00DB75 1
00DB75 1 ; ----------------------------------------------------------------------------
00DB75 1 ; Return carry clear with A = $00.
00DB75 1 ; ----------------------------------------------------------------------------
00DB75 1
00DB75 1 ResolveCurrentObject_ZeroResult: ; $DB75
00DB75 1 38 sec ; $DB75: 38
00DB76 1 A9 00 lda #$00 ; $DB76: A9 00
00DB78 1 60 rts ; $DB78: 60
00DB79 1 ; LDA preserves carry set, despite the path
00DB79 1 ; name. Callers may rely on both A and carry.
00DB79 1
00DB79 1 ; ----------------------------------------------------------------------------
00DB79 1 ; Secondary region-test path.
00DB79 1 ;
00DB79 1 ; Carry clear returns A = $00 with carry set through $DB75.
00DB79 1 ; Carry set falls through to the alternate $80 result.
00DB79 1 ; ----------------------------------------------------------------------------
00DB79 1
00DB79 1 ResolveCurrentObject_SecondaryRegion: ; $DB79
00DB79 1 20 84 DB jsr TestCurrentObjectRegion ; $DB79: 20 84 DB
00DB7C 1 90 F7 bcc ResolveCurrentObject_ZeroResult
00DB7E 1 ; $DB7C: 90 F7
00DB7E 1
00DB7E 1 ; ----------------------------------------------------------------------------
00DB7E 1 ; Return carry clear with A = $80.
00DB7E 1 ; ----------------------------------------------------------------------------
00DB7E 1
00DB7E 1 ResolveCurrentObject_AlternateResult: ; $DB7E
00DB7E 1 18 clc ; $DB7E: 18
00DB7F 1 A9 80 lda #$80 ; $DB7F: A9 80
00DB81 1 60 rts ; $DB81: 60
00DB82 1
00DB82 1 ; ----------------------------------------------------------------------------
00DB82 1 ; Neutral return with carry clear. A is preserved from the preceding test.
00DB82 1 ; ----------------------------------------------------------------------------
00DB82 1
00DB82 1 ResolveCurrentObject_Neutral: ; $DB82
00DB82 1 18 clc ; $DB82: 18
00DB83 1 60 rts ; $DB83: 60
00DB84 1
00DB84 1 ; ============================================================================
00DB84 1 ; $DB84-$DBAF
00DB84 1 ; Test whether another active object satisfies a selector and state condition
00DB84 1 ; relative to CurrentObjectIndex.
00DB84 1 ;
00DB84 1 ; Return:
00DB84 1 ; Carry is the primary Boolean result.
00DB84 1 ;
00DB84 1 ; C = 1:
00DB84 1 ; matching/active condition
00DB84 1 ;
00DB84 1 ; C = 0:
00DB84 1 ; no matching condition
00DB84 1 ;
00DB84 1 ; The final LSR converts bit zero of the calculated value into carry.
00DB84 1 ; ============================================================================
00DB84 1
00DB84 1 ; ----------------------------------------------------------------------------
00DB84 1 ; Contract:
00DB84 1 ; Description: Implements Test Current Object Region.
00DB84 1 ; Entry: Registers: A, X, Y; Memory: $0598, currentobjectindex, $056d
00DB84 1 ; Returns/products: Registers/clobbers: A, X, Y; Flags: condition flags may carry result state
00DB84 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00DB84 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00DB84 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00DB84 1 ; comparison, load, or store path and are not a stable API product.
00DB84 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 2.
00DB84 1 ; ----------------------------------------------------------------------------
00DB84 1 TestCurrentObjectRegion: ; $DB84
00DB84 1 20 DC E3 jsr GetCurrentObjectSelectorAndState ; $DB84: 20 DC E3
00DB87 1 ; Returns a selector in Y.
00DB87 1
00DB87 1 ; ----------------------------------------------------------------------------
00DB87 1 ; Convert the selector into a comparison value:
00DB87 1 ;
00DB87 1 ; A = ((Y >> 1) << 1) + 3
00DB87 1 ;
00DB87 1 ; The LSR/ASL pair clears bit zero before adding three.
00DB87 1 ; Carry from ASL is intentionally retained by ADC.
00DB87 1 ; ----------------------------------------------------------------------------
00DB87 1
00DB87 1 98 tya ; $DB87: 98
00DB88 1 4A lsr ; $DB88: 4A
00DB89 1 0A asl ; $DB89: 0A
00DB8A 1 69 03 adc #$03 ; $DB8A: 69 03
00DB8C 1
00DB8C 1 ; ----------------------------------------------------------------------------
00DB8C 1 ; Search the four state entries $0598-$059B.
00DB8C 1 ;
00DB8C 1 ; X starts at four, is decremented before each comparison, and stops when A is
00DB8C 1 ; greater than or equal to the indexed state value.
00DB8C 1 ; ----------------------------------------------------------------------------
00DB8C 1
00DB8C 1 A2 04 ldx #$04 ; $DB8C: A2 04
00DB8E 1
00DB8E 1 TestCurrentObjectRegion_Search: ; $DB8E
00DB8E 1 CA dex ; $DB8E: CA
00DB8F 1
00DB8F 1 DD 98 05 cmp $0598,x ; $DB8F: DD 98 05
00DB92 1 90 FA bcc TestCurrentObjectRegion_Search
00DB94 1 ; $DB92: 90 FA
00DB94 1
00DB94 1 ; ----------------------------------------------------------------------------
00DB94 1 ; Load the selected state entry into Y.
00DB94 1 ;
00DB94 1 ; Values of eight or greater return immediately. Carry remains set from
00DB94 1 ; CPY #$08 in that case.
00DB94 1 ; ----------------------------------------------------------------------------
00DB94 1
00DB94 1 BC 98 05 ldy $0598,x ; $DB94: BC 98 05
00DB97 1
00DB97 1 C0 08 cpy #$08 ; $DB97: C0 08
00DB99 1 B0 14 bcs TestCurrentObjectRegion_Return
00DB9B 1 ; $DB99: B0 14
00DB9B 1
00DB9B 1 ; ----------------------------------------------------------------------------
00DB9B 1 ; Convert the state-table index into an object offset:
00DB9B 1 ;
00DB9B 1 ; A = (X * 2) + 6
00DB9B 1 ;
00DB9B 1 ; If this offset is the current object, return immediately. Carry is set by
00DB9B 1 ; CMP on equality.
00DB9B 1 ; ----------------------------------------------------------------------------
00DB9B 1
00DB9B 1 8A txa ; $DB9B: 8A
00DB9C 1 0A asl ; $DB9C: 0A
00DB9D 1 69 06 adc #$06 ; $DB9D: 69 06
00DB9F 1
00DB9F 1 C5 E1 cmp CurrentObjectIndex ; $DB9F: C5 E1
00DBA1 1 F0 0C beq TestCurrentObjectRegion_Return
00DBA3 1 ; $DBA1: F0 0C
00DBA3 1
00DBA3 1 ; ----------------------------------------------------------------------------
00DBA3 1 ; Use the calculated object offset to inspect its state at $056D,X.
00DBA3 1 ; ----------------------------------------------------------------------------
00DBA3 1
00DBA3 1 AA tax ; $DBA3: AA
00DBA4 1
00DBA4 1 BD 6D 05 lda $056D,x ; $DBA4: BD 6D 05
00DBA7 1 F0 05 beq TestCurrentObjectRegion_Shift
00DBA9 1 ; $DBA7: F0 05
00DBA9 1
00DBA9 1 ; ----------------------------------------------------------------------------
00DBA9 1 ; For an active object, combine the selector comparison with carry.
00DBA9 1 ;
00DBA9 1 ; CPY #$06 establishes carry, ROL moves it into A, and ADC #$00 incorporates
00DBA9 1 ; the resulting carry state.
00DBA9 1 ; ----------------------------------------------------------------------------
00DBA9 1
00DBA9 1 C0 06 cpy #$06 ; $DBA9: C0 06
00DBAB 1 2A rol ; $DBAB: 2A
00DBAC 1 69 00 adc #$00 ; $DBAC: 69 00
00DBAE 1
00DBAE 1 ; ----------------------------------------------------------------------------
00DBAE 1 ; Return bit zero of A in carry.
00DBAE 1 ; ----------------------------------------------------------------------------
00DBAE 1
00DBAE 1 TestCurrentObjectRegion_Shift: ; $DBAE
00DBAE 1 4A lsr ; $DBAE: 4A
00DBAF 1
00DBAF 1 TestCurrentObjectRegion_Return: ; $DBAF
00DBAF 1 60 rts ; $DBAF: 60
00DBB0 1
00DBB0 1 ; ============================================================================
00DBB0 1 ; $DBB0-$DBB7
00DBB0 1 ; Selector-specific input-mask table.
00DBB0 1 ;
00DBB0 1 ; Used by TestCurrentObjectInput:
00DBB0 1 ;
00DBB0 1 ; jsr GetCurrentObjectSelectorAndState
00DBB0 1 ; lda InputState1
00DBB0 1 ; and InputMaskTable,y
00DBB0 1 ;
00DBB0 1 ; Y selects one of eight masks. Entries occur in identical pairs, suggesting
00DBB0 1 ; that adjacent selector values share the same accepted input bits.
00DBB0 1 ; ============================================================================
00DBB0 1
00DBB0 1 InputMaskTable: ; $DBB0
00DBB0 1 00 00 .byte $00,$00 ; Selectors $00-$01: no accepted input
00DBB2 1 05 05 .byte $05,$05 ; Selectors $02-$03: bits $01 and $04
00DBB4 1 0C 0C .byte $0C,$0C ; Selectors $04-$05: bits $04 and $08
00DBB6 1 06 06 .byte $06,$06 ; Selectors $06-$07: bits $02 and $04
00DBB8 1
00DBB8 1 ; ============================================================================
00DBB8 1 ; $DBB8-$DBF5
00DBB8 1 ; Update the current object's animation frame and return a six-tick delay.
00DBB8 1 ;
00DBB8 1 ; The routine derives one of eight animation ranges from the object's state at
00DBB8 1 ; $056D/$056E and an additional condition returned by $E6B7. When permitted,
00DBB8 1 ; it advances $039A,X and wraps or clamps the frame through two lookup tables.
00DBB8 1 ;
00DBB8 1 ; Return:
00DBB8 1 ; A = $06
00DBB8 1 ;
00DBB8 1 ; Carry from $E6B7 can skip the animation update entirely.
00DBB8 1 ; ============================================================================
00DBB8 1
00DBB8 1 ; ----------------------------------------------------------------------------
00DBB8 1 ; Contract:
00DBB8 1 ; Description: Implements Select Secondary Object Delay.
00DBB8 1 ; Entry: Registers: A, X; Memory: pendingaudioflags, currentobjectindex, $056e, $056d, $039a
00DBB8 1 ; Returns/products: Registers/clobbers: A, X, Y
00DBB8 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00DBB8 1 ; Memory effects: pendingaudioflags, $039a
00DBB8 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00DBB8 1 ; comparison, load, or store path and are not a stable API product.
00DBB8 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 7.
00DBB8 1 ; ----------------------------------------------------------------------------
00DBB8 1 SelectSecondaryObjectDelay: ; $DBB8
00DBB8 1 A5 FE lda PendingAudioFlags ; $DBB8: A5 FE
00DBBA 1 09 04 ora #$04 ; $DBBA: 09 04
00DBBC 1 85 FE sta PendingAudioFlags ; $DBBC: 85 FE
00DBBE 1
00DBBE 1 ; ----------------------------------------------------------------------------
00DBBE 1 ; Update or test the current object.
00DBBE 1 ;
00DBBE 1 ; Carry set skips directly to the fixed delay return.
00DBBE 1 ; ----------------------------------------------------------------------------
00DBBE 1
00DBBE 1 A6 E1 ldx CurrentObjectIndex ; $DBBE: A6 E1
00DBC0 1 20 B7 E6 jsr ClearMovementTransforms ; $DBC0: 20 B7 E6
00DBC3 1 B0 2E bcs SecondaryObjectDelay_Return
00DBC5 1 ; $DBC3: B0 2E
00DBC5 1
00DBC5 1 ; ----------------------------------------------------------------------------
00DBC5 1 ; Derive a compact animation-range selector from $056D,X and $056E,X.
00DBC5 1 ;
00DBC5 1 ; Bit flow:
00DBC5 1 ;
00DBC5 1 ; 1. ASL $056E,X places its high bit in carry.
00DBC5 1 ; 2. ROL A shifts that carry into $056D,X.
00DBC5 1 ; 3. A second ROL expands the selector before it is saved.
00DBC5 1 ; ----------------------------------------------------------------------------
00DBC5 1
00DBC5 1 A6 E1 ldx CurrentObjectIndex ; $DBC5: A6 E1
00DBC7 1
00DBC7 1 BD 6E 05 lda $056E,x ; $DBC7: BD 6E 05
00DBCA 1 0A asl ; $DBCA: 0A
00DBCB 1
00DBCB 1 BD 6D 05 lda $056D,x ; $DBCB: BD 6D 05
00DBCE 1 2A rol ; $DBCE: 2A
00DBCF 1 2A rol ; $DBCF: 2A
00DBD0 1
00DBD0 1 48 pha ; $DBD0: 48
00DBD1 1 ; Preserve the preliminary selector.
00DBD1 1
00DBD1 1 ; ----------------------------------------------------------------------------
00DBD1 1 ; Run the object helper again.
00DBD1 1 ;
00DBD1 1 ; The helper may update X and returns a condition in carry.
00DBD1 1 ; ----------------------------------------------------------------------------
00DBD1 1
00DBD1 1 20 B7 E6 jsr ClearMovementTransforms ; $DBD1: 20 B7 E6
00DBD4 1
00DBD4 1 68 pla ; $DBD4: 68
00DBD5 1 B0 1C bcs SecondaryObjectDelay_Return
00DBD7 1 ; $DBD5: B0 1C
00DBD7 1
00DBD7 1 ; ----------------------------------------------------------------------------
00DBD7 1 ; Incorporate whether X is at least $15 into the selector.
00DBD7 1 ;
00DBD7 1 ; CPX #$15 sets carry, and ROL shifts that condition into A.
00DBD7 1 ; ----------------------------------------------------------------------------
00DBD7 1
00DBD7 1 E0 15 cpx #$15 ; $DBD7: E0 15
00DBD9 1 2A rol ; $DBD9: 2A
00DBDA 1
00DBDA 1 29 07 and #$07 ; $DBDA: 29 07
00DBDC 1 A8 tay ; $DBDC: A8
00DBDD 1 ; Y selects one of eight animation ranges.
00DBDD 1
00DBDD 1 ; ----------------------------------------------------------------------------
00DBDD 1 ; Load the current frame and increment it.
00DBDD 1 ;
00DBDD 1 ; The original frame remains in A for the threshold comparisons.
00DBDD 1 ; ----------------------------------------------------------------------------
00DBDD 1
00DBDD 1 BD 9A 03 lda $039A,x ; $DBDD: BD 9A 03
00DBE0 1 FE 9A 03 inc $039A,x ; $DBE0: FE 9A 03
00DBE3 1
00DBE3 1 ; ----------------------------------------------------------------------------
00DBE3 1 ; Compare the original frame against the upper and lower bounds.
00DBE3 1 ;
00DBE3 1 ; The table bases intentionally overlap:
00DBE3 1 ;
00DBE3 1 ; SecondaryAnimationBaseTable,Y
00DBE3 1 ; SecondaryAnimationLimitTable,Y
00DBE3 1 ;
00DBE3 1 ; If the frame lies outside the permitted range, reset it to the base frame.
00DBE3 1 ; ----------------------------------------------------------------------------
00DBE3 1
00DBE3 1 D9 FE DB cmp SecondaryAnimationLimitTable,y
00DBE6 1 ; $DBE3: D9 FE DB
00DBE6 1 B0 05 bcs SecondaryObjectDelay_ResetFrame
00DBE8 1 ; $DBE6: B0 05
00DBE8 1
00DBE8 1 D9 F6 DB cmp SecondaryAnimationBaseTable,y
00DBEB 1 ; $DBE8: D9 F6 DB
00DBEB 1 B0 06 bcs SecondaryObjectDelay_Return
00DBED 1 ; $DBEB: B0 06
00DBED 1
00DBED 1 SecondaryObjectDelay_ResetFrame: ; $DBED
00DBED 1 B9 F6 DB lda SecondaryAnimationBaseTable,y
00DBF0 1 ; $DBED: B9 F6 DB
00DBF0 1 9D 9A 03 sta $039A,x ; $DBF0: 9D 9A 03
00DBF3 1
00DBF3 1 ; ----------------------------------------------------------------------------
00DBF3 1 ; Return a fixed six-tick delay.
00DBF3 1 ; ----------------------------------------------------------------------------
00DBF3 1
00DBF3 1 SecondaryObjectDelay_Return: ; $DBF3
00DBF3 1 A9 06 lda #$06 ; $DBF3: A9 06
00DBF5 1 60 rts ; $DBF5: 60
00DBF6 1
00DBF6 1 ; ============================================================================
00DBF6 1 ; $DBF6-$DC05
00DBF6 1 ; Parallel secondary-object animation tables.
00DBF6 1 ;
00DBF6 1 ; SelectSecondaryObjectDelay uses the same Y index with both tables:
00DBF6 1 ;
00DBF6 1 ; SecondaryAnimationBaseTable,Y
00DBF6 1 ; Base or reset animation frame.
00DBF6 1 ;
00DBF6 1 ; SecondaryAnimationLimitTable,Y
00DBF6 1 ; Upper animation-frame limit.
00DBF6 1 ;
00DBF6 1 ; The animation helper increments the current frame, then resets it to the
00DBF6 1 ; corresponding base frame whenever it falls below the base or reaches the
00DBF6 1 ; upper limit.
00DBF6 1 ; ============================================================================
00DBF6 1
00DBF6 1 ; ----------------------------------------------------------------------------
00DBF6 1 ; Base/reset animation frames.
00DBF6 1 ; ----------------------------------------------------------------------------
00DBF6 1
00DBF6 1 SecondaryAnimationBaseTable: ; $DBF6
00DBF6 1 4D 1A 50 1E .byte $4D,$1A,$50,$1E
00DBFA 1 56 27 53 23 .byte $56,$27,$53,$23
00DBFE 1
00DBFE 1 ; ----------------------------------------------------------------------------
00DBFE 1 ; Upper animation-frame limits.
00DBFE 1 ; ----------------------------------------------------------------------------
00DBFE 1
00DBFE 1 SecondaryAnimationLimitTable: ; $DBFE
00DBFE 1 4F 1C 52 20 .byte $4F,$1C,$52,$20
00DC02 1 58 29 55 25 .byte $58,$29,$55,$25
00DC06 1
00DC06 1
00DC06 1 ; ============================================================================
00DC06 1 ; $DC06-$DC28
00DC06 1 ; Test the current object's adjusted X and Y coordinate regions.
00DC06 1 ;
00DC06 1 ; Entry:
00DC06 1 ; X = ignored. The routine reloads X from CurrentObjectIndex.
00DC06 1 ; Y = coordinate-adjustment table index.
00DC06 1 ;
00DC06 1 ; Return:
00DC06 1 ; A contains the final comparison value.
00DC06 1 ;
00DC06 1 ; Carry set:
00DC06 1 ; The adjusted X coordinate is at least two, or the adjusted Y
00DC06 1 ; coordinate is at least two.
00DC06 1 ;
00DC06 1 ; Carry clear:
00DC06 1 ; Both adjusted coordinate values are below two.
00DC06 1 ;
00DC06 1 ; The low coordinate bytes are shifted only to place bit 7 into carry. That
00DC06 1 ; carry is then added to the corresponding high coordinate byte.
00DC06 1 ; ============================================================================
00DC06 1
00DC06 1 TestCurrentObjectCoordinateRegion: ; $DC06
00DC06 1 A6 E1 ldx CurrentObjectIndex ; $DC06: A6 E1
00DC08 1
00DC08 1 ; ----------------------------------------------------------------------------
00DC08 1 ; Test the adjusted horizontal coordinate.
00DC08 1 ;
00DC08 1 ; The horizontal high byte is adjusted using the table based at $DC2A,Y:
00DC08 1 ;
00DC08 1 ; adjustedX = $050A,X + Table_DC2A,Y + carry($0509,X << 1) + 1
00DC08 1 ; ----------------------------------------------------------------------------
00DC08 1
00DC08 1 BD 09 05 lda $0509,x ; $DC08: BD 09 05
00DC0B 1 0A asl ; $DC0B: 0A
00DC0C 1 ; Carry = bit 7 of the horizontal low byte.
00DC0C 1
00DC0C 1 BD 0A 05 lda $050A,x ; $DC0C: BD 0A 05
00DC0F 1 79 2A DC adc HorizontalAdjustmentTable,y
00DC12 1 ; $DC0F: 79 2A DC
00DC12 1
00DC12 1 18 clc ; $DC12: 18
00DC13 1 69 01 adc #$01 ; $DC13: 69 01
00DC15 1
00DC15 1 C9 02 cmp #$02 ; $DC15: C9 02
00DC17 1 B0 0F bcs TestCurrentObjectCoordinateRegion_Return
00DC19 1 ; $DC17: B0 0F
00DC19 1
00DC19 1 ; ----------------------------------------------------------------------------
00DC19 1 ; The adjusted horizontal coordinate is below two.
00DC19 1 ; Test the adjusted vertical coordinate.
00DC19 1 ;
00DC19 1 ; The vertical high byte is adjusted using the table based at $DC29,Y:
00DC19 1 ;
00DC19 1 ; adjustedY = $053B,X + Table_DC29,Y + carry($053A,X << 1) + 1
00DC19 1 ; ----------------------------------------------------------------------------
00DC19 1
00DC19 1 BD 3A 05 lda $053A,x ; $DC19: BD 3A 05
00DC1C 1 0A asl ; $DC1C: 0A
00DC1D 1 ; Carry = bit 7 of the vertical low byte.
00DC1D 1
00DC1D 1 BD 3B 05 lda $053B,x ; $DC1D: BD 3B 05
00DC20 1 79 29 DC adc VerticalAdjustmentTable,y
00DC23 1 ; $DC20: 79 29 DC
00DC23 1
00DC23 1 18 clc ; $DC23: 18
00DC24 1 69 01 adc #$01 ; $DC24: 69 01
00DC26 1
00DC26 1 C9 02 cmp #$02 ; $DC26: C9 02
00DC28 1
00DC28 1 TestCurrentObjectCoordinateRegion_Return: ; $DC28
00DC28 1 60 rts ; $DC28: 60
00DC29 1
00DC29 1 ; ============================================================================
00DC29 1 ; $DC29-$DC30
00DC29 1 ; Overlapping signed coordinate-adjustment tables.
00DC29 1 ;
00DC29 1 ; The routine accesses:
00DC29 1 ;
00DC29 1 ; VerticalAdjustmentTable,Y at $DC29
00DC29 1 ; HorizontalAdjustmentTable,Y at $DC2A
00DC29 1 ;
00DC29 1 ; The table index in Y is supplied by the caller.
00DC29 1 ; ============================================================================
00DC29 1
00DC29 1 VerticalAdjustmentTable: ; $DC29
00DC29 1 08 .byte $08
00DC2A 1
00DC2A 1 HorizontalAdjustmentTable: ; $DC2A
00DC2A 1 00 F8 00 08 .byte $00,$F8,$00,$08
00DC2E 1 00 F8 00 .byte $00,$F8,$00
00DC31 1
00DC31 1 ; ============================================================================
00DC31 1 ; $DC31-$DC87
00DC31 1 ; Initialize object-processing parameters, process a list of event slots,
00DC31 1 ; dispatch one command for each listed object, and leave through the common
00DC31 1 ; engine exit.
00DC31 1 ; ============================================================================
00DC31 1
00DC31 1 InitializeObjectEventSequence: ; $DC31
00DC31 1 A9 20 lda #$20 ; $DC31: A9 20
00DC33 1 20 41 EB jsr StoreObjectEventBankValue ; $DC33: 20 41 EB
00DC36 1
00DC36 1 ; ----------------------------------------------------------------------------
00DC36 1 ; Clear working object indices.
00DC36 1 ; ----------------------------------------------------------------------------
00DC36 1
00DC36 1 A9 00 lda #$00 ; $DC36: A9 00
00DC38 1 85 A4 sta $A4 ; $DC38: 85 A4
00DC3A 1 85 A9 sta $A9 ; $DC3A: 85 A9
00DC3C 1
00DC3C 1 ; ----------------------------------------------------------------------------
00DC3C 1 ; Initialize object-selection bounds.
00DC3C 1 ; ----------------------------------------------------------------------------
00DC3C 1
00DC3C 1 A9 04 lda #$04 ; $DC3C: A9 04
00DC3E 1 85 A8 sta $A8 ; $DC3E: 85 A8
00DC40 1
00DC40 1 A9 16 lda #$16 ; $DC40: A9 16
00DC42 1 85 A7 sta $A7 ; $DC42: 85 A7
00DC44 1
00DC44 1 ; ----------------------------------------------------------------------------
00DC44 1 ; Select initial values for $A6 and $A5.
00DC44 1 ;
00DC44 1 ; Defaults:
00DC44 1 ; Y = $14
00DC44 1 ; X = $10
00DC44 1 ;
00DC44 1 ; If RandomVerticalMotion is negative:
00DC44 1 ; Y = $12
00DC44 1 ;
00DC44 1 ; Otherwise, when RandomVerticalMotion is at least $1E and ObjectSelectionLowerBound is zero:
00DC44 1 ; X = $0E
00DC44 1 ; ----------------------------------------------------------------------------
00DC44 1
00DC44 1 A0 14 ldy #$14 ; $DC44: A0 14
00DC46 1 A2 10 ldx #$10 ; $DC46: A2 10
00DC48 1
00DC48 1 A5 90 lda RandomVerticalMotion ; $DC48: A5 90
00DC4A 1 10 04 bpl InitializeObjectEventSequence_CheckUpper
00DC4C 1 ; $DC4A: 10 04
00DC4C 1
00DC4C 1 A0 12 ldy #$12 ; $DC4C: A0 12
00DC4E 1 D0 0A bne InitializeObjectEventSequence_SaveBounds
00DC50 1 ; $DC4E: D0 0A
00DC50 1 ; Always taken because Y is nonzero.
00DC50 1
00DC50 1 InitializeObjectEventSequence_CheckUpper: ; $DC50
00DC50 1 C9 1E cmp #$1E ; $DC50: C9 1E
00DC52 1 30 06 bmi InitializeObjectEventSequence_SaveBounds
00DC54 1 ; $DC52: 30 06
00DC54 1
00DC54 1 A5 A5 lda ObjectSelectionLowerBound ; $DC54: A5 A5
00DC56 1 D0 02 bne InitializeObjectEventSequence_SaveBounds
00DC58 1 ; $DC56: D0 02
00DC58 1
00DC58 1 A2 0E ldx #$0E ; $DC58: A2 0E
00DC5A 1
00DC5A 1 InitializeObjectEventSequence_SaveBounds: ; $DC5A
00DC5A 1 84 A6 sty $A6 ; $DC5A: 84 A6
00DC5C 1 86 A5 stx ObjectSelectionLowerBound ; $DC5C: 86 A5
00DC5E 1
00DC5E 1 ; ----------------------------------------------------------------------------
00DC5E 1 ; Process event slots selected by the nine-byte table at $DC88.
00DC5E 1 ;
00DC5E 1 ; X begins at eight and counts down through zero. The table value is loaded
00DC5E 1 ; into Y and passed to $EB66.
00DC5E 1 ; ----------------------------------------------------------------------------
00DC5E 1
00DC5E 1 A2 08 ldx #$08 ; $DC5E: A2 08
00DC60 1
00DC60 1 InitializeObjectEventSequence_ProcessEvents: ; $DC60
00DC60 1 86 B8 stx $B8 ; $DC60: 86 B8
00DC62 1
00DC62 1 BC 88 DC ldy ObjectEventSlotTable,x ; $DC62: BC 88 DC
00DC65 1 20 66 EB jsr DispatchNextQueuedEvent ; $DC65: 20 66 EB
00DC68 1
00DC68 1 20 48 EB jsr SelectObjectEventBank1 ; $DC68: 20 48 EB
00DC6B 1
00DC6B 1 A6 B8 ldx $B8 ; $DC6B: A6 B8
00DC6D 1 CA dex ; $DC6D: CA
00DC6E 1 10 F0 bpl InitializeObjectEventSequence_ProcessEvents
00DC70 1 ; $DC6E: 10 F0
00DC70 1
00DC70 1 ; ----------------------------------------------------------------------------
00DC70 1 ; Dispatch a command for each object/event-table entry in reverse order.
00DC70 1 ; ----------------------------------------------------------------------------
00DC70 1
00DC70 1 A0 08 ldy #$08 ; $DC70: A0 08
00DC72 1
00DC72 1 InitializeObjectEventSequence_DispatchLoop: ; $DC72
00DC72 1 84 B8 sty $B8 ; $DC72: 84 B8
00DC74 1
00DC74 1 BE 88 DC ldx ObjectEventSlotTable,y ; $DC74: BE 88 DC
00DC77 1 20 9B E2 jsr DispatchInlineObjectCommand ; $DC77: 20 9B E2
00DC7A 1
00DC7A 1 ; Inline record consumed by $E29B.
00DC7A 1 ;
00DC7A 1 ; The stored address is $DD47, apparently the continuation/handler used
00DC7A 1 ; for each selected object. Its exact dispatch convention will be confirmed
00DC7A 1 ; when $E29B is decoded.
00DC7A 1 00 47 DD .byte $00,$47,$DD ; $DC7A-$DC7C
00DC7D 1
00DC7D 1 20 48 EB jsr SelectObjectEventBank1 ; $DC7D: 20 48 EB
00DC80 1
00DC80 1 A4 B8 ldy $B8 ; $DC80: A4 B8
00DC82 1 88 dey ; $DC82: 88
00DC83 1 10 ED bpl InitializeObjectEventSequence_DispatchLoop
00DC85 1 ; $DC83: 10 ED
00DC85 1
00DC85 1 ; ----------------------------------------------------------------------------
00DC85 1 ; Leave through the common engine exit.
00DC85 1 ; ----------------------------------------------------------------------------
00DC85 1
00DC85 1 4C 6A EB jmp CommonEngineExit ; $DC85: 4C 6A EB
00DC88 1
00DC88 1 ; ============================================================================
00DC88 1 ; $DC88-$DC90
00DC88 1 ; Object/event-slot lookup table.
00DC88 1 ;
00DC88 1 ; InitializeObjectEventSequence uses this table twice:
00DC88 1 ;
00DC88 1 ; 1. Each value is passed to $EB66 as an event-slot index.
00DC88 1 ; 2. Each value is loaded into X before dispatching the inline record
00DC88 1 ; through $E29B.
00DC88 1 ;
00DC88 1 ; The values are also valid even-numbered object-array offsets. Dividing each
00DC88 1 ; value by two gives the associated compact object-state index.
00DC88 1 ; ============================================================================
00DC88 1
00DC88 1 ObjectEventSlotTable: ; $DC88
00DC88 1 04 .byte $04 ; Object/event offset $04, compact index $02
00DC89 1 0E .byte $0E ; Object/event offset $0E, compact index $07
00DC8A 1 10 .byte $10 ; Object/event offset $10, compact index $08
00DC8B 1 12 .byte $12 ; Object/event offset $12, compact index $09
00DC8C 1 14 .byte $14 ; Object/event offset $14, compact index $0A
00DC8D 1 16 .byte $16 ; Object/event offset $16, compact index $0B
00DC8E 1 1E .byte $1E ; Object/event offset $1E, compact index $0F
00DC8F 1 20 .byte $20 ; Object/event offset $20, compact index $10
00DC90 1 22 .byte $22 ; Object/event offset $22, compact index $11
00DC91 1
00DC91 1 ; ============================================================================
00DC91 1 ; $DC91-$DCA0
00DC91 1 ; Wait until the current object's geometry or region test clears.
00DC91 1 ;
00DC91 1 ; The routine repeatedly:
00DC91 1 ;
00DC91 1 ; 1. Calls the setup helper at $E2DE.
00DC91 1 ; 2. Waits using the delay returned in A.
00DC91 1 ; 3. Prepares geometry arguments through $E4B8.
00DC91 1 ; 4. Tests the resulting region through $E55F.
00DC91 1 ;
00DC91 1 ; A carry-set result restarts the routine. Carry clear leaves through the
00DC91 1 ; common engine exit.
00DC91 1 ; ============================================================================
00DC91 1
00DC91 1 WaitForObjectRegionClear: ; $DC91
00DC91 1 20 DE E2 jsr UpdateCurrentObjectAnimationDelay ; $DC91: 20 DE E2
00DC94 1 ; Returns a delay value in A.
00DC94 1
00DC94 1 20 41 EB jsr StoreObjectEventBankValue ; $DC94: 20 41 EB
00DC97 1 ; Wait for the delay supplied in A.
00DC97 1
00DC97 1 WaitForObjectRegionClear_Test:
00DC97 1 20 B8 E4 jsr SelectGeometryRecordFromObject ; $DC97: 20 B8 E4
00DC9A 1 ; Prepare the geometry/region arguments.
00DC9A 1
00DC9A 1 20 5F E5 jsr ApplyCurrentObjectGeometry ; $DC9A: 20 5F E5
00DC9D 1 ; Test the prepared region.
00DC9D 1
00DC9D 1 B0 F2 bcs WaitForObjectRegionClear
00DC9F 1 ; $DC9D: B0 F2
00DC9F 1
00DC9F 1 4C 6A EB jmp CommonEngineExit ; $DC9F: 4C 6A EB
00DCA2 1
00DCA2 1 ; ============================================================================
00DCA2 1 ; $DCA2-$DCB9
00DCA2 1 ; Dispatch an inline command for six entries from ObjectEventSlotTable.
00DCA2 1 ;
00DCA2 1 ; The routine processes table indices five through zero:
00DCA2 1 ;
00DCA2 1 ; Y=$05 -> object/event offset $16
00DCA2 1 ; Y=$04 -> object/event offset $14
00DCA2 1 ; Y=$03 -> object/event offset $12
00DCA2 1 ; Y=$02 -> object/event offset $10
00DCA2 1 ; Y=$01 -> object/event offset $0E
00DCA2 1 ; Y=$00 -> object/event offset $04
00DCA2 1 ;
00DCA2 1 ; For each entry:
00DCA2 1 ; 1. Save the table index in $B8.
00DCA2 1 ; 2. Load the object/event offset into X.
00DCA2 1 ; 3. Dispatch the inline record through $E29B.
00DCA2 1 ; 4. Wait for the next frame.
00DCA2 1 ; ============================================================================
00DCA2 1
00DCA2 1 DispatchSixObjectEvents: ; $DCA2
00DCA2 1 A0 05 ldy #$05 ; $DCA2: A0 05
00DCA4 1
00DCA4 1 DispatchSixObjectEvents_Loop: ; $DCA4
00DCA4 1 84 B8 sty $B8 ; $DCA4: 84 B8
00DCA6 1
00DCA6 1 BE 88 DC ldx ObjectEventSlotTable,y ; $DCA6: BE 88 DC
00DCA9 1
00DCA9 1 20 9B E2 jsr DispatchInlineObjectCommand ; $DCA9: 20 9B E2
00DCAC 1
00DCAC 1 ; Inline record consumed by $E29B.
00DCAC 1 ;
00DCAC 1 ; The record contains a leading zero byte followed by address $DC96.
00DCAC 1 ; The address points inside WaitForObjectRegionClear:
00DCAC 1 ;
00DCAC 1 ; $DC94: JSR $EB41
00DCAC 1 ; $DC97: JSR $E4B8
00DCAC 1 ;
00DCAC 1 ; A stored address of $DC96 is one byte before the entry at $DC97,
00DCAC 1 ; suggesting an RTS-style dispatch to $DC97.
00DCAC 1 00 .byte $00 ; $DCAC
00DCAD 1 96 DC .word WaitForObjectRegionClear_Test - 1
00DCAF 1 ; $DCAD-$DCAE: $DC96
00DCAF 1
00DCAF 1 20 48 EB jsr SelectObjectEventBank1 ; $DCAF: 20 48 EB
00DCB2 1
00DCB2 1 A4 B8 ldy $B8 ; $DCB2: A4 B8
00DCB4 1 88 dey ; $DCB4: 88
00DCB5 1
00DCB5 1 D0 ED bne DispatchSixObjectEvents_Loop
00DCB7 1 ; $DCB5: D0 ED
00DCB7 1
00DCB7 1 ; ----------------------------------------------------------------------------
00DCB7 1 ; Leave through the common engine exit.
00DCB7 1 ;
00DCB7 1 ; Because the loop uses BNE rather than BPL, processing stops after Y is
00DCB7 1 ; decremented from one to zero. The table entry at index zero is therefore not
00DCB7 1 ; dispatched by this loop. The actual processed indices are five through one.
00DCB7 1 ; ----------------------------------------------------------------------------
00DCB7 1
00DCB7 1 4C 6A EB jmp CommonEngineExit ; $DCB7: 4C 6A EB
00DCBA 1
00DCBA 1 ; ============================================================================
00DCBA 1 ; $DCBA-$DCDF
00DCBA 1 ; Select and initialize an active object or event slot.
00DCBA 1 ;
00DCBA 1 ; The routine does nothing if $A4 already contains a nonzero object offset.
00DCBA 1 ; Otherwise, it checks the base object state and searches for a usable
00DCBA 1 ; selector. On success, it stores the selected offset in $A4 and clears the
00DCBA 1 ; corresponding zero-page state byte at $A4,X.
00DCBA 1 ; ============================================================================
00DCBA 1
00DCBA 1 ; ----------------------------------------------------------------------------
00DCBA 1 ; Contract:
00DCBA 1 ; Description: Implements Select Active Object.
00DCBA 1 ; Entry: Registers: A, X; Memory: $a4, $056c
00DCBA 1 ; Returns/products: Registers/clobbers: A, X
00DCBA 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00DCBA 1 ; Memory effects: $a4
00DCBA 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00DCBA 1 ; comparison, load, or store path and are not a stable API product.
00DCBA 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00DCBA 1 ; ----------------------------------------------------------------------------
00DCBA 1 SelectActiveObject: ; $DCBA
00DCBA 1 A5 A4 lda $A4 ; $DCBA: A5 A4
00DCBC 1 D0 21 bne SelectActiveObject_Return
00DCBE 1 ; $DCBC: D0 21
00DCBE 1
00DCBE 1 ; ----------------------------------------------------------------------------
00DCBE 1 ; When the base object's high state at $056C is negative after comparison with
00DCBE 1 ; three, use the alternate selector helper at $DF45.
00DCBE 1 ; ----------------------------------------------------------------------------
00DCBE 1
00DCBE 1 AD 6C 05 lda $056C ; $DCBE: AD 6C 05
00DCC1 1 C9 03 cmp #$03 ; $DCC1: C9 03
00DCC3 1 30 13 bmi SelectActiveObject_Alternate
00DCC5 1 ; $DCC3: 30 13
00DCC5 1
00DCC5 1 ; ----------------------------------------------------------------------------
00DCC5 1 ; Obtain a candidate selector through $DF08.
00DCC5 1 ;
00DCC5 1 ; Values seven or greater are rejected.
00DCC5 1 ; ----------------------------------------------------------------------------
00DCC5 1
00DCC5 1 20 08 DF jsr TestCurrentObjectGeometry ; $DCC5: 20 08 DF
00DCC8 1
00DCC8 1 C9 07 cmp #$07 ; $DCC8: C9 07
00DCCA 1 B0 13 bcs SelectActiveObject_Return
00DCCC 1 ; $DCCA: B0 13
00DCCC 1
00DCCC 1 ; ----------------------------------------------------------------------------
00DCCC 1 ; Convert the candidate selector into an object offset.
00DCCC 1 ;
00DCCC 1 ; GetCurrentObjectSelectorAndState returns:
00DCCC 1 ; X = selected object offset
00DCCC 1 ; Y = related selector value
00DCCC 1 ; ----------------------------------------------------------------------------
00DCCC 1
00DCCC 1 SelectActiveObject_Save: ; $DCCC
00DCCC 1 20 DC E3 jsr GetCurrentObjectSelectorAndState ; $DCCC: 20 DC E3
00DCCF 1
00DCCF 1 86 A4 stx $A4 ; $DCCF: 86 A4
00DCD1 1
00DCD1 1 ; ----------------------------------------------------------------------------
00DCD1 1 ; Clear the selected zero-page object-state entry.
00DCD1 1 ;
00DCD1 1 ; X is explicitly changed to zero, so STX $A4,X stores zero at address $A4.
00DCD1 1 ; This is distinct from clearing the variable at zero-page address $A4.
00DCD1 1 ; ----------------------------------------------------------------------------
00DCD1 1
00DCD1 1 A2 00 ldx #$00 ; $DCD1: A2 00
00DCD3 1 96 A4 stx $A4,y ; $DCD3: 96 A4
00DCD5 1
00DCD5 1 4C 48 DD jmp ContinueObjectProcessing; $DCD5: 4C 48 DD
00DCD8 1
00DCD8 1 ; ----------------------------------------------------------------------------
00DCD8 1 ; Alternate selection path.
00DCD8 1 ;
00DCD8 1 ; Continue requesting a selector until the returned value is at least eight.
00DCD8 1 ; The successful value remains in A while GetCurrentObjectSelectorAndState derives the selected object.
00DCD8 1 ; ----------------------------------------------------------------------------
00DCD8 1
00DCD8 1 SelectActiveObject_Alternate: ; $DCD8
00DCD8 1 20 45 DF jsr CalculateCurrentObjectGeometry ; $DCD8: 20 45 DF
00DCDB 1
00DCDB 1 C9 08 cmp #$08 ; $DCDB: C9 08
00DCDD 1 90 ED bcc SelectActiveObject_Save ; $DCDD: 90 ED
00DCDF 1
00DCDF 1 SelectActiveObject_Return: ; $DCDF
00DCDF 1 60 rts ; $DCDF: 60
00DCE0 1
00DCE0 1 ; ============================================================================
00DCE0 1 ; $DCE0-$DD20
00DCE0 1 ; Initialize the selected object's state, run geometry tests, and select one
00DCE0 1 ; of two shared continuation paths.
00DCE0 1 ;
00DCE0 1 ; Entry:
00DCE0 1 ; X = selected object offset
00DCE0 1 ;
00DCE0 1 ; The routine saves the incoming object offset, derives its compact state
00DCE0 1 ; index, stores the original offset into $0595,X, then executes a sequence of
00DCE0 1 ; object and geometry helpers.
00DCE0 1 ; ============================================================================
00DCE0 1
00DCE0 1 ProcessSelectedObject: ; $DCE0
00DCE0 1 8A txa ; $DCE0: 8A
00DCE1 1 A8 tay ; $DCE1: A8
00DCE2 1 ; Preserve the incoming object offset in Y.
00DCE2 1
00DCE2 1 20 68 DA jsr GetCurrentObjectStateIndex
00DCE5 1 ; $DCE2: 20 68 DA
00DCE5 1 ; X = CurrentObjectIndex >> 1.
00DCE5 1
00DCE5 1 98 tya ; $DCE5: 98
00DCE6 1 9D 95 05 sta $0595,x ; $DCE6: 9D 95 05
00DCE9 1 ; Save the selected object offset.
00DCE9 1
00DCE9 1 ; ----------------------------------------------------------------------------
00DCE9 1 ; Re-enter the object-selector routine.
00DCE9 1 ;
00DCE9 1 ; Because $A4 is now nonzero, SelectActiveObject returns immediately.
00DCE9 1 ; ----------------------------------------------------------------------------
00DCE9 1
00DCE9 1 20 BA DC jsr SelectActiveObject ; $DCE9: 20 BA DC
00DCEC 1
00DCEC 1 ; ----------------------------------------------------------------------------
00DCEC 1 ; Prepare and evaluate the selected object's geometry.
00DCEC 1 ; ----------------------------------------------------------------------------
00DCEC 1 ProcessSelectedObject_Geometry:
00DCEC 1 20 74 E4 jsr SelectGeometryRecord_Default ; $DCEC: 20 74 E4
00DCEF 1 20 C2 E4 jsr LoadGeometryRecord ; $DCEF: 20 C2 E4
00DCF2 1 20 DB E4 jsr CalculateCurrentGeometryDifference ; $DCF2: 20 DB E4
00DCF5 1 20 02 E5 jsr EvaluateGeometryDifference ; $DCF5: 20 02 E5
00DCF8 1
00DCF8 1 C9 08 cmp #$08 ; $DCF8: C9 08
00DCFA 1 B0 0B bcs ProcessSelectedObject_LargeResult
00DCFC 1 ; $DCFA: B0 0B
00DCFC 1
00DCFC 1 ; ----------------------------------------------------------------------------
00DCFC 1 ; For values below eight, preserve A while obtaining the current selector.
00DCFC 1 ;
00DCFC 1 ; GetCurrentObjectSelectorAndState returns X and Y. STX $A4,Y stores X into a selector-dependent
00DCFC 1 ; zero-page state slot.
00DCFC 1 ; ----------------------------------------------------------------------------
00DCFC 1
00DCFC 1 48 pha ; $DCFC: 48
00DCFD 1
00DCFD 1 20 DC E3 jsr GetCurrentObjectSelectorAndState ; $DCFD: 20 DC E3
00DD00 1
00DD00 1 96 A4 stx $A4,y ; $DD00: 96 A4
00DD02 1
00DD02 1 68 pla ; $DD02: 68
00DD03 1
00DD03 1 C9 03 cmp #$03 ; $DD03: C9 03
00DD05 1 90 0E bcc ProcessSelectedObject_SmallResult
00DD07 1 ; $DD05: 90 0E
00DD07 1
00DD07 1 ; ----------------------------------------------------------------------------
00DD07 1 ; Handle values three or greater, or any original result at least eight.
00DD07 1 ; ----------------------------------------------------------------------------
00DD07 1
00DD07 1 ProcessSelectedObject_LargeResult: ; $DD07
00DD07 1 A5 C6 lda $C6 ; $DD07: A5 C6
00DD09 1
00DD09 1 20 13 E5 jsr BuildGeometryVector ; $DD09: 20 13 E5
00DD0C 1 20 28 E5 jsr StoreCurrentObjectMovement ; $DD0C: 20 28 E5
00DD0F 1 20 DE E2 jsr UpdateCurrentObjectAnimationDelay ; $DD0F: 20 DE E2
00DD12 1
00DD12 1 4C 4A DD jmp ContinueObjectProcessingWithDelay
00DD15 1 ; $DD12: 4C 4A DD
00DD15 1
00DD15 1 ; ----------------------------------------------------------------------------
00DD15 1 ; Handle result values zero through two.
00DD15 1 ; ----------------------------------------------------------------------------
00DD15 1
00DD15 1 ProcessSelectedObject_SmallResult: ; $DD15
00DD15 1 20 48 E5 jsr StoreGeometryInCurrentObject ; $DD15: 20 48 E5
00DD18 1 20 D3 E2 jsr ClearCurrentObjectMovement ; $DD18: 20 D3 E2
00DD1B 1 20 D4 DF jsr UpdateCurrentObjectDisplayState ; $DD1B: 20 D4 DF
00DD1E 1
00DD1E 1 4C 48 DD jmp ContinueObjectProcessing
00DD21 1 ; $DD1E: 4C 48 DD
00DD21 1
00DD21 1 ; ============================================================================
00DD21 1 ; $DD21-$DD4C
00DD21 1 ; Find an available object-state slot or continue processing the current
00DD21 1 ; selected object.
00DD21 1 ;
00DD21 1 ; The routine searches zero-page state entries $A4-$A7 when the current object
00DD21 1 ; offset is below $18. If an empty entry is found, the current object is moved
00DD21 1 ; into that slot and processing restarts at the geometry setup path at $DCEC.
00DD21 1 ;
00DD21 1 ; Otherwise, the routine performs a short delay and continues with the shared
00DD21 1 ; object-processing path beginning at $DD4D.
00DD21 1 ; ============================================================================
00DD21 1
00DD21 1 FindAvailableObjectSlot: ; $DD21
00DD21 1 A6 E1 ldx CurrentObjectIndex ; $DD21: A6 E1
00DD23 1
00DD23 1 E0 18 cpx #$18 ; $DD23: E0 18
00DD25 1 B0 09 bcs CheckSavedObjectOffset ; $DD25: B0 09
00DD27 1
00DD27 1 ; ----------------------------------------------------------------------------
00DD27 1 ; Search zero-page entries $A4-$A7 for an empty slot.
00DD27 1 ;
00DD27 1 ; X begins at four and is decremented before looping, so the tested addresses
00DD27 1 ; are:
00DD27 1 ;
00DD27 1 ; $A8 initially through indexed addressing at X=$04
00DD27 1 ; then $A7, $A6, and $A5 as X counts down
00DD27 1 ;
00DD27 1 ; The loop intentionally stops before repeating with X=$00.
00DD27 1 ; ----------------------------------------------------------------------------
00DD27 1
00DD27 1 A2 04 ldx #$04 ; $DD27: A2 04
00DD29 1
00DD29 1 FindAvailableObjectSlot_Search: ; $DD29
00DD29 1 B5 A4 lda $A4,x ; $DD29: B5 A4
00DD2B 1 F0 0F beq AssignObjectToSlot ; $DD2B: F0 0F
00DD2D 1
00DD2D 1 CA dex ; $DD2D: CA
00DD2E 1 D0 F9 bne FindAvailableObjectSlot_Search
00DD30 1 ; $DD2E: D0 F9
00DD30 1
00DD30 1 ; ----------------------------------------------------------------------------
00DD30 1 ; No empty slot was found, or the current object offset is at least $18.
00DD30 1 ;
00DD30 1 ; If the saved object offset at $A9 equals CurrentObjectIndex, branch forward
00DD30 1 ; to the special path at HandleSavedObject
00DD30 1 ; ----------------------------------------------------------------------------
00DD30 1
00DD30 1 CheckSavedObjectOffset: ; $DD30
00DD30 1 A5 A9 lda $A9 ; $DD30: A5 A9
00DD32 1 C5 E1 cmp CurrentObjectIndex ; $DD32: C5 E1
00DD34 1 F0 4C beq ObjectSelection_CheckActive ; $DD34: F0 4C
00DD36 1
00DD36 1 ; ----------------------------------------------------------------------------
00DD36 1 ; Run the object helper and continue at the common delay path.
00DD36 1 ; ----------------------------------------------------------------------------
00DD36 1
00DD36 1 20 D3 E2 jsr ClearCurrentObjectMovement ; $DD36: 20 D3 E2
00DD39 1
00DD39 1 4C 48 DD jmp ContinueObjectProcessing
00DD3C 1 ; $DD39: 4C 48 DD
00DD3C 1
00DD3C 1 ; ----------------------------------------------------------------------------
00DD3C 1 ; An empty zero-page object slot was found.
00DD3C 1 ;
00DD3C 1 ; Preserve the slot index in Y, derive the compact current-object state index,
00DD3C 1 ; and store the slot index into $0595,X.
00DD3C 1 ; ----------------------------------------------------------------------------
00DD3C 1
00DD3C 1 AssignObjectToSlot: ; $DD3C
00DD3C 1 8A txa ; $DD3C: 8A
00DD3D 1 A8 tay ; $DD3D: A8
00DD3E 1 ; Y = available zero-page slot index.
00DD3E 1
00DD3E 1 20 68 DA jsr GetCurrentObjectStateIndex
00DD41 1 ; $DD3E: 20 68 DA
00DD41 1
00DD41 1 98 tya ; $DD41: 98
00DD42 1 9D 95 05 sta $0595,x ; $DD42: 9D 95 05
00DD45 1
00DD45 1 ; ----------------------------------------------------------------------------
00DD45 1 ; Restart selected-object processing at the geometry setup entry.
00DD45 1 ; ----------------------------------------------------------------------------
00DD45 1
00DD45 1 4C EC DC jmp ProcessSelectedObject_Geometry
00DD48 1 ; $DD45: 4C EC DC
00DD48 1
00DD48 1 ; ============================================================================
00DD48 1 ; $DD48-$DD4C
00DD48 1 ; Shared continuation used by several earlier object-processing paths.
00DD48 1 ;
00DD48 1 ; Entry at $DD48 loads a six-tick delay.
00DD48 1 ; Entry at ContinueObjectProcessingWithDelay uses the delay already present in A.
00DD48 1 ; ============================================================================
00DD48 1
00DD48 1 ContinueObjectProcessing: ; $DD48
00DD48 1 A9 06 lda #$06 ; $DD48: A9 06
00DD4A 1
00DD4A 1 ContinueObjectProcessingWithDelay: ; $DD4A
00DD4A 1 20 41 EB jsr StoreObjectEventBankValue ; $DD4A: 20 41 EB
00DD4D 1
00DD4D 1 ; ============================================================================
00DD4D 1 ; $DD4D-$DD77
00DD4D 1 ; Shared object-selection and routing path.
00DD4D 1 ;
00DD4D 1 ; This path checks whether CurrentObjectIndex is already assigned to one of
00DD4D 1 ; the zero-page object slots at $A4-$A8. It then evaluates global state and
00DD4D 1 ; routes to the appropriate object-processing branch.
00DD4D 1 ; ============================================================================
00DD4D 1
00DD4D 1 ObjectSelectionSharedPath: ; $DD4D
00DD4D 1 A5 E1 lda CurrentObjectIndex ; $DD4D: A5 E1
00DD4F 1
00DD4F 1 ; ----------------------------------------------------------------------------
00DD4F 1 ; Search the five zero-page object slots $A8 through $A4.
00DD4F 1 ;
00DD4F 1 ; X begins at four:
00DD4F 1 ;
00DD4F 1 ; X=$04 -> $A8
00DD4F 1 ; X=$03 -> $A7
00DD4F 1 ; X=$02 -> $A6
00DD4F 1 ; X=$01 -> $A5
00DD4F 1 ; X=$00 -> $A4
00DD4F 1 ;
00DD4F 1 ; If a slot matches CurrentObjectIndex, restart selected-object processing at
00DD4F 1 ; $DCE0 with the matching slot index still in X.
00DD4F 1 ; ----------------------------------------------------------------------------
00DD4F 1
00DD4F 1 A2 04 ldx #$04 ; $DD4F: A2 04
00DD51 1
00DD51 1 ObjectSelection_SearchSlots: ; $DD51
00DD51 1 D5 A4 cmp $A4,x ; $DD51: D5 A4
00DD53 1 F0 8B beq ProcessSelectedObject ; $DD53: F0 8B
00DD55 1
00DD55 1 CA dex ; $DD55: CA
00DD56 1 D0 F9 bne ObjectSelection_SearchSlots
00DD58 1 ; $DD56: D0 F9
00DD58 1
00DD58 1 ; ----------------------------------------------------------------------------
00DD58 1 ; If BaseMotionEventCount or SpecialSequenceState is nonzero, continue at the shared state path
00DD58 1 ; beginning at $DD78.
00DD58 1 ; ----------------------------------------------------------------------------
00DD58 1
00DD58 1 A6 5E ldx BaseMotionEventCount ; $DD58: A6 5E
00DD5A 1 D0 1C bne ObjectSelection_NoSavedObject
00DD5C 1 ; $DD5A: D0 1C
00DD5C 1
00DD5C 1 A6 6D ldx SpecialSequenceState ; $DD5C: A6 6D
00DD5E 1 D0 18 bne ObjectSelection_NoSavedObject
00DD60 1 ; $DD5E: D0 18
00DD60 1
00DD60 1 ; ----------------------------------------------------------------------------
00DD60 1 ; Run the geometry/collision test at $CBEA.
00DD60 1 ;
00DD60 1 ; Carry clear continues locally. Carry set transfers to the alternate path at
00DD60 1 ; $DED8.
00DD60 1 ; ----------------------------------------------------------------------------
00DD60 1
00DD60 1 20 EA CB jsr TestCurrentObjectCollision ; $DD60: 20 EA CB
00DD63 1 90 03 bcc ObjectSelection_CheckCurrent
00DD65 1 ; $DD63: 90 03
00DD65 1
00DD65 1 4C D8 DE jmp ObjectRouting_ReverseMovement ; $DD65: 4C D8 DE
00DD68 1
00DD68 1 ; ----------------------------------------------------------------------------
00DD68 1 ; Compare CurrentObjectIndex against the primary and saved object offsets.
00DD68 1 ; ----------------------------------------------------------------------------
00DD68 1
00DD68 1 ObjectSelection_CheckCurrent: ; $DD68
00DD68 1 A6 E1 ldx CurrentObjectIndex ; $DD68: A6 E1
00DD6A 1
00DD6A 1 E4 A4 cpx $A4 ; $DD6A: E4 A4
00DD6C 1 F0 71 beq ObjectRouting_CheckBaseState ; $DD6C: F0 71
00DD6E 1
00DD6E 1 E4 A9 cpx $A9 ; $DD6E: E4 A9
00DD70 1 F0 10 beq ObjectSelection_CheckActive
00DD72 1 ; $DD70: F0 10
00DD72 1
00DD72 1 ; ----------------------------------------------------------------------------
00DD72 1 ; If no saved object exists, branch forward to $DDC8.
00DD72 1 ;
00DD72 1 ; Otherwise, restart the available-slot search at $DD21.
00DD72 1 ; ----------------------------------------------------------------------------
00DD72 1
00DD72 1 A5 A9 lda $A9 ; $DD72: A5 A9
00DD74 1 F0 52 beq ObjectRoutingPath ; $DD74: F0 52
00DD76 1
00DD76 1 D0 A9 bne FindAvailableObjectSlot ; $DD76: D0 A9
00DD78 1 ; Always taken when A is nonzero.
00DD78 1
00DD78 1 ; ============================================================================
00DD78 1 ; $DD78-$DD8E
00DD78 1 ; Exit path followed by the shared object-selection continuation.
00DD78 1 ; ============================================================================
00DD78 1
00DD78 1 ObjectSelection_NoSavedObject: ; $DD78
00DD78 1 20 D3 E2 jsr ClearCurrentObjectMovement ; $DD78: 20 D3 E2
00DD7B 1 4C 6A EB jmp CommonEngineExit ; $DD7B: 4C 6A EB
00DD7E 1
00DD7E 1 ; ----------------------------------------------------------------------------
00DD7E 1 ; Continue according to the flags returned by the preceding shared helper.
00DD7E 1 ;
00DD7E 1 ; These branches go backward into previously decoded code:
00DD7E 1 ;
00DD7E 1 ; Z set -> assign the current object to an available slot at $DD3C
00DD7E 1 ; C clear -> restart the slot-selection routine at $DD21
00DD7E 1 ; ----------------------------------------------------------------------------
00DD7E 1
00DD7E 1 ObjectSelection_StatePath: ; $DD7E
00DD7E 1 F0 BC beq AssignObjectToSlot ; $DD7E: F0 BC
00DD80 1 ObjectSelection_RestartSlots:
00DD80 1 90 9F bcc FindAvailableObjectSlot ; $DD80: 90 9F
00DD82 1
00DD82 1 ; ----------------------------------------------------------------------------
00DD82 1 ; Check whether an object is already active in $A4.
00DD82 1 ;
00DD82 1 ; This is also the target of the BEQ at $DD34:
00DD82 1 ;
00DD82 1 ; $DD34: F0 4C -> $DD82
00DD82 1 ; ----------------------------------------------------------------------------
00DD82 1
00DD82 1 ObjectSelection_CheckActive: ; $DD82
00DD82 1 A6 A4 ldx $A4 ; $DD82: A6 A4
00DD84 1 D0 09 bne ProcessSavedObjectGeometry
00DD86 1 ; $DD84: D0 09
00DD86 1
00DD86 1 ; ----------------------------------------------------------------------------
00DD86 1 ; No active object is stored in $A4.
00DD86 1 ;
00DD86 1 ; X is zero here, so clear $A9, then assign CurrentObjectIndex to $A4.
00DD86 1 ; ----------------------------------------------------------------------------
00DD86 1
00DD86 1 86 A9 stx $A9 ; $DD86: 86 A9
00DD88 1
00DD88 1 HandleSavedObject: ; $DD88
00DD88 1 A6 E1 ldx CurrentObjectIndex ; $DD88: A6 E1
00DD8A 1 86 A4 stx $A4 ; $DD8A: 86 A4
00DD8C 1
00DD8C 1 4C 48 DD jmp ContinueObjectProcessing
00DD8F 1 ; $DD8C: 4C 48 DD
00DD8F 1
00DD8F 1 ; ============================================================================
00DD8F 1 ; $DD8F-$DDC7
00DD8F 1 ; Build and test a geometry region around the active object.
00DD8F 1 ;
00DD8F 1 ; Entry:
00DD8F 1 ; X = active object offset loaded from $A4
00DD8F 1 ;
00DD8F 1 ; The object's coordinate is copied into the geometry arguments at $B2-$B5.
00DD8F 1 ; The vertical high byte is increased by five before the geometry test.
00DD8F 1 ; ============================================================================
00DD8F 1
00DD8F 1 ProcessSavedObjectGeometry: ; $DD8F
00DD8F 1 BD 09 05 lda $0509,x ; $DD8F: BD 09 05
00DD92 1 85 B2 sta $B2 ; $DD92: 85 B2
00DD94 1
00DD94 1 BD 0A 05 lda $050A,x ; $DD94: BD 0A 05
00DD97 1 85 B3 sta $B3 ; $DD97: 85 B3
00DD99 1
00DD99 1 BD 3A 05 lda $053A,x ; $DD99: BD 3A 05
00DD9C 1 85 B4 sta $B4 ; $DD9C: 85 B4
00DD9E 1
00DD9E 1 BD 3B 05 lda $053B,x ; $DD9E: BD 3B 05
00DDA1 1 18 clc ; $DDA1: 18
00DDA2 1 69 05 adc #$05 ; $DDA2: 69 05
00DDA4 1 85 B5 sta $B5 ; $DDA4: 85 B5
00DDA6 1
00DDA6 1 ; ----------------------------------------------------------------------------
00DDA6 1 ; Adjust the geometry arguments and perform the region test.
00DDA6 1 ; ----------------------------------------------------------------------------
00DDA6 1
00DDA6 1 20 FB DE jsr SelectObjectGeometrySize ; $DDA6: 20 FB DE
00DDA9 1 20 62 E5 jsr EvaluateLoadedCurrentObjectGeometry ; $DDA9: 20 62 E5
00DDAC 1
00DDAC 1 90 06 bcc ProcessSavedObjectAnimation
00DDAE 1 ; $DDAC: 90 06
00DDAE 1
00DDAE 1 ; ----------------------------------------------------------------------------
00DDAE 1 ; Region test remains active.
00DDAE 1 ;
00DDAE 1 ; Run the setup helper and continue using the delay returned in A.
00DDAE 1 ; ----------------------------------------------------------------------------
00DDAE 1
00DDAE 1 20 DE E2 jsr UpdateCurrentObjectAnimationDelay ; $DDAE: 20 DE E2
00DDB1 1
00DDB1 1 4C 4A DD jmp ContinueObjectProcessingWithDelay
00DDB4 1 ; $DDB1: 4C 4A DD
00DDB4 1
00DDB4 1 ; ----------------------------------------------------------------------------
00DDB4 1 ; Region test cleared.
00DDB4 1 ;
00DDB4 1 ; Set the current object's animation frame to $67. Compact object indices
00DDB4 1 ; below $0C also receive attribute/state value $43.
00DDB4 1 ; ----------------------------------------------------------------------------
00DDB4 1
00DDB4 1 ProcessSavedObjectAnimation: ; $DDB4
00DDB4 1 20 68 DA jsr GetCurrentObjectStateIndex
00DDB7 1 ; $DDB4: 20 68 DA
00DDB7 1
00DDB7 1 A9 67 lda #$67 ; $DDB7: A9 67
00DDB9 1 9D 9B 03 sta $039B,x ; $DDB9: 9D 9B 03
00DDBC 1
00DDBC 1 E0 0C cpx #$0C ; $DDBC: E0 0C
00DDBE 1 B0 05 bcs ProcessSavedObjectAnimation_Done
00DDC0 1 ; $DDBE: B0 05
00DDC0 1
00DDC0 1 A9 43 lda #$43 ; $DDC0: A9 43
00DDC2 1 9D B0 03 sta $03B0,x ; $DDC2: 9D B0 03
00DDC5 1
00DDC5 1 ProcessSavedObjectAnimation_Done: ; $DDC5
00DDC5 1 4C 48 DD jmp ContinueObjectProcessing
00DDC8 1 ; $DDC5: 4C 48 DD
00DDC8 1
00DDC8 1 ; ============================================================================
00DDC8 1 ; $DDC8-$DE54
00DDC8 1 ; Route the current object through slot selection, state checks, animation
00DDC8 1 ; setup, collision tests, and common continuation paths.
00DDC8 1 ; ============================================================================
00DDC8 1
00DDC8 1 ObjectRoutingPath: ; $DDC8
00DDC8 1 A0 16 ldy #$16 ; $DDC8: A0 16
00DDCA 1
00DDCA 1 ; ----------------------------------------------------------------------------
00DDCA 1 ; Object offsets above $16 skip directly to the main state check at $DDDF.
00DDCA 1 ; ----------------------------------------------------------------------------
00DDCA 1
00DDCA 1 C4 E1 cpy CurrentObjectIndex ; $DDCA: C4 E1
00DDCC 1 90 11 bcc ObjectRouting_CheckBaseState
00DDCE 1 ; $DDCC: 90 11
00DDCE 1
00DDCE 1 ; ----------------------------------------------------------------------------
00DDCE 1 ; Search zero-page object slots $A8 through $A5.
00DDCE 1 ;
00DDCE 1 ; An empty slot branches backward to ObjectSelection_StatePath at $DD7E.
00DDCE 1 ; ----------------------------------------------------------------------------
00DDCE 1
00DDCE 1 A2 04 ldx #$04 ; $DDCE: A2 04
00DDD0 1
00DDD0 1 ObjectRouting_SearchSlots: ; $DDD0
00DDD0 1 B5 A4 lda $A4,x ; $DDD0: B5 A4
00DDD2 1 F0 AA beq ObjectSelection_StatePath
00DDD4 1 ; $DDD2: F0 AA
00DDD4 1
00DDD4 1 CA dex ; $DDD4: CA
00DDD5 1 D0 F9 bne ObjectRouting_SearchSlots
00DDD7 1 ; $DDD5: D0 F9
00DDD7 1
00DDD7 1 ; ----------------------------------------------------------------------------
00DDD7 1 ; Compare the limit value $16 against the active and saved object offsets.
00DDD7 1 ;
00DDD7 1 ; If Y is below either offset, branch backward to the BCC at $DD80, which
00DDD7 1 ; restarts the available-slot routine at $DD21.
00DDD7 1 ; ----------------------------------------------------------------------------
00DDD7 1
00DDD7 1 C4 A4 cpy $A4 ; $DDD7: C4 A4
00DDD9 1 90 A5 bcc ObjectSelection_RestartSlots
00DDDB 1 ; $DDD9: 90 A5
00DDDB 1
00DDDB 1 C4 A9 cpy $A9 ; $DDDB: C4 A9
00DDDD 1 90 A1 bcc ObjectSelection_RestartSlots
00DDDF 1 ; $DDDD: 90 A1
00DDDF 1
00DDDF 1 ; ============================================================================
00DDDF 1 ; $DDDF
00DDDF 1 ; Main state and candidate-selection path.
00DDDF 1 ; ============================================================================
00DDDF 1
00DDDF 1 ObjectRouting_CheckBaseState: ; $DDDF
00DDDF 1 AD 6C 05 lda $056C ; $DDDF: AD 6C 05
00DDE2 1 C9 03 cmp #$03 ; $DDE2: C9 03
00DDE4 1 10 6F bpl ObjectRouting_BaseStateAtLeast3
00DDE6 1 ; $DDE4: 10 6F
00DDE6 1 ; Target $DE55.
00DDE6 1
00DDE6 1 ; ----------------------------------------------------------------------------
00DDE6 1 ; Obtain a candidate through $DF45.
00DDE6 1 ; ----------------------------------------------------------------------------
00DDE6 1
00DDE6 1 20 45 DF jsr CalculateCurrentObjectGeometry ; $DDE6: 20 45 DF
00DDE9 1
00DDE9 1 C9 18 cmp #$18 ; $DDE9: C9 18
00DDEB 1 B0 08 bcs ObjectRouting_CheckCandidate8
00DDED 1 ; $DDEB: B0 08
00DDED 1
00DDED 1 ; ----------------------------------------------------------------------------
00DDED 1 ; For candidates below $18, distinguish current object offsets below or above
00DDED 1 ; $18 before applying the candidate-$08 threshold.
00DDED 1 ; ----------------------------------------------------------------------------
00DDED 1
00DDED 1 A6 E1 ldx CurrentObjectIndex ; $DDED: A6 E1
00DDEF 1 E0 18 cpx #$18 ; $DDEF: E0 18
00DDF1 1 B0 04 bcs ObjectRouting_CompareCurrent
00DDF3 1 ; $DDF1: B0 04
00DDF3 1
00DDF3 1 C9 08 cmp #$08 ; $DDF3: C9 08
00DDF5 1
00DDF5 1 ObjectRouting_CheckCandidate8: ; $DDF5
00DDF5 1 B0 78 bcs ObjectRouting_LargeCandidate
00DDF7 1 ; $DDF5: B0 78
00DDF7 1 ; Target $DE6F.
00DDF7 1
00DDF7 1 ; ----------------------------------------------------------------------------
00DDF7 1 ; Candidate is below the active threshold.
00DDF7 1 ;
00DDF7 1 ; If CurrentObjectIndex differs from $A4, run the alternate path at $DE4D.
00DDF7 1 ; ----------------------------------------------------------------------------
00DDF7 1
00DDF7 1 ObjectRouting_CompareCurrent: ; $DDF7
00DDF7 1 A6 E1 ldx CurrentObjectIndex ; $DDF7: A6 E1
00DDF9 1 E4 A4 cpx $A4 ; $DDF9: E4 A4
00DDFB 1 D0 50 bne ObjectRouting_Alternate ; $DDFB: D0 50
00DDFD 1
00DDFD 1 C9 02 cmp #$02 ; $DDFD: C9 02
00DDFF 1 B0 77 bcs ObjectRouting_ApplyCoordinateSetup
00DE01 1 ; $DDFF: B0 77
00DE01 1 ; Target $DE78.
00DE01 1
00DE01 1 ; ----------------------------------------------------------------------------
00DE01 1 ; Configure animation values for candidate values zero or one.
00DE01 1 ; ----------------------------------------------------------------------------
00DE01 1
00DE01 1 20 68 DA jsr GetCurrentObjectStateIndex
00DE04 1 ; $DE01: 20 68 DA
00DE04 1
00DE04 1 A9 3E lda #$3E ; $DE04: A9 3E
00DE06 1 AC 6C 05 ldy $056C ; $DE06: AC 6C 05
00DE09 1 F0 0B beq ObjectRouting_UseFrame60
00DE0B 1 ; $DE09: F0 0B
00DE0B 1
00DE0B 1 A9 43 lda #$43 ; $DE0B: A9 43
00DE0D 1
00DE0D 1 88 dey ; $DE0D: 88
00DE0E 1 D0 06 bne ObjectRouting_UseFrame60
00DE10 1 ; $DE0E: D0 06
00DE10 1
00DE10 1 A9 41 lda #$41 ; $DE10: A9 41
00DE12 1 A0 5E ldy #$5E ; $DE12: A0 5E
00DE14 1 D0 02 bne ObjectRouting_SaveFrames
00DE16 1 ; $DE14: D0 02
00DE16 1
00DE16 1 ObjectRouting_UseFrame60: ; $DE16
00DE16 1 A0 60 ldy #$60 ; $DE16: A0 60
00DE18 1
00DE18 1 ObjectRouting_SaveFrames: ; $DE18
00DE18 1 E0 0C cpx #$0C ; $DE18: E0 0C
00DE1A 1 B0 03 bcs ObjectRouting_SaveMainFrame
00DE1C 1 ; $DE1A: B0 03
00DE1C 1
00DE1C 1 9D B0 03 sta $03B0,x ; $DE1C: 9D B0 03
00DE1F 1
00DE1F 1 ObjectRouting_SaveMainFrame: ; $DE1F
00DE1F 1 98 tya ; $DE1F: 98
00DE20 1 9D 9B 03 sta $039B,x ; $DE20: 9D 9B 03
00DE23 1
00DE23 1 ; ----------------------------------------------------------------------------
00DE23 1 ; Run the base-object merge/comparison helper.
00DE23 1 ;
00DE23 1 ; Failure returns a one-tick delay through the shared path at $DD4A.
00DE23 1 ; ----------------------------------------------------------------------------
00DE23 1
00DE23 1 A6 E1 ldx CurrentObjectIndex ; $DE23: A6 E1
00DE25 1 20 C0 C9 jsr TryMergeObjectIntoBase ; $DE25: 20 C0 C9
00DE28 1
00DE28 1 F0 05 beq ObjectRouting_MergeSucceeded
00DE2A 1 ; $DE28: F0 05
00DE2A 1
00DE2A 1 A9 01 lda #$01 ; $DE2A: A9 01
00DE2C 1 4C 4A DD jmp ContinueObjectProcessingWithDelay
00DE2F 1 ; $DE2C: 4C 4A DD
00DE2F 1
00DE2F 1 ; ----------------------------------------------------------------------------
00DE2F 1 ; Merge succeeded. Advance engine and motion state.
00DE2F 1 ; ----------------------------------------------------------------------------
00DE2F 1
00DE2F 1 ObjectRouting_MergeSucceeded: ; $DE2F
00DE2F 1 20 D3 E2 jsr ClearCurrentObjectMovement ; $DE2F: 20 D3 E2
00DE32 1 20 E6 E3 jsr InitializeBaseObjectFromCurrent ; $DE32: 20 E6 E3
00DE35 1
00DE35 1 E6 5E inc BaseMotionEventCount ; $DE35: E6 5E
00DE37 1
00DE37 1 A9 20 lda #$20 ; $DE37: A9 20
00DE39 1 85 FE sta PendingAudioFlags ; $DE39: 85 FE
00DE3B 1
00DE3B 1 A5 5D lda BaseMotionPhase ; $DE3B: A5 5D
00DE3D 1 D0 03 bne ObjectRouting_TestRegion
00DE3F 1 ; $DE3D: D0 03
00DE3F 1
00DE3F 1 20 5A E3 jsr ProcessCompactObjectState_FindAlternate ; $DE3F: 20 5A E3
00DE42 1
00DE42 1 ; ----------------------------------------------------------------------------
00DE42 1 ; Test the current object's region.
00DE42 1 ;
00DE42 1 ; Carry set routes to $DED8. Carry clear enters the engine path at $E037.
00DE42 1 ; ----------------------------------------------------------------------------
00DE42 1
00DE42 1 ObjectRouting_TestRegion: ; $DE42
00DE42 1 20 EA CB jsr TestCurrentObjectCollision ; $DE42: 20 EA CB
00DE45 1 90 03 bcc ObjectRouting_EnterEngine
00DE47 1 ; $DE45: 90 03
00DE47 1
00DE47 1 4C D8 DE jmp ObjectRouting_ReverseMovement ; $DE47: 4C D8 DE
00DE4A 1
00DE4A 1 ObjectRouting_EnterEngine: ; $DE4A
00DE4A 1 4C 37 E0 jmp ObjectStateDispatch ; $DE4A: 4C 37 E0
00DE4D 1
00DE4D 1 ; ----------------------------------------------------------------------------
00DE4D 1 ; CurrentObjectIndex differs from $A4.
00DE4D 1 ;
00DE4D 1 ; Run the helper at $DEEF and return a one-tick delay through the shared path.
00DE4D 1 ; ----------------------------------------------------------------------------
00DE4D 1
00DE4D 1 ObjectRouting_Alternate: ; $DE4D
00DE4D 1 20 EF DE jsr AssignCurrentObjectSlot ; $DE4D: 20 EF DE
00DE50 1
00DE50 1 A9 01 lda #$01 ; $DE50: A9 01
00DE52 1 4C 4A DD jmp ContinueObjectProcessingWithDelay
00DE55 1 ; $DE52: 4C 4A DD
00DE55 1
00DE55 1 ; ============================================================================
00DE55 1 ; $DE55-$DE83
00DE55 1 ; Handle base state $056C >= 3.
00DE55 1 ;
00DE55 1 ; The routine obtains a candidate value from $DF08 and chooses between a
00DE55 1 ; coordinate-based setup path and the candidate-state path at $DE84.
00DE55 1 ; ============================================================================
00DE55 1
00DE55 1 ObjectRouting_BaseStateAtLeast3: ; $DE55
00DE55 1 20 08 DF jsr TestCurrentObjectGeometry ; $DE55: 20 08 DF
00DE58 1
00DE58 1 C9 07 cmp #$07 ; $DE58: C9 07
00DE5A 1 90 28 bcc ObjectRouting_CandidateBelow7
00DE5C 1 ; $DE5A: 90 28
00DE5C 1 ; Target $DE84.
00DE5C 1
00DE5C 1 ; ----------------------------------------------------------------------------
00DE5C 1 ; Candidate is at least seven.
00DE5C 1 ;
00DE5C 1 ; For object offsets below $18, use the coordinate setup path directly.
00DE5C 1 ; For offsets at least $18, candidate values below $18 return to $DE84.
00DE5C 1 ; ----------------------------------------------------------------------------
00DE5C 1
00DE5C 1 A6 E1 ldx CurrentObjectIndex ; $DE5C: A6 E1
00DE5E 1 E0 18 cpx #$18 ; $DE5E: E0 18
00DE60 1 90 04 bcc ObjectRouting_SetupCoordinates
00DE62 1 ; $DE60: 90 04
00DE62 1
00DE62 1 C9 18 cmp #$18 ; $DE62: C9 18
00DE64 1 90 1E bcc ObjectRouting_CandidateBelow7
00DE66 1 ; $DE64: 90 1E
00DE66 1
00DE66 1 ; ----------------------------------------------------------------------------
00DE66 1 ; Build geometry/coordinate arguments.
00DE66 1 ;
00DE66 1 ; $B5 begins at zero. $DEFB adjusts or derives the geometry values and returns
00DE66 1 ; a value in A, which is saved in $B3.
00DE66 1 ; ----------------------------------------------------------------------------
00DE66 1
00DE66 1 ObjectRouting_SetupCoordinates: ; $DE66
00DE66 1 A9 00 lda #$00 ; $DE66: A9 00
00DE68 1 85 B5 sta $B5 ; $DE68: 85 B5
00DE6A 1
00DE6A 1 20 FB DE jsr SelectObjectGeometrySize ; $DE6A: 20 FB DE
00DE6D 1 85 B3 sta $B3 ; $DE6D: 85 B3
00DE6F 1
00DE6F 1 ; ----------------------------------------------------------------------------
00DE6F 1 ; If $A4 equals CurrentObjectIndex, clear $A4.
00DE6F 1 ; ----------------------------------------------------------------------------
00DE6F 1 ObjectRouting_LargeCandidate:
00DE6F 1 38 sec ; $DE6F: 38
00DE70 1
00DE70 1 A5 A4 lda $A4 ; $DE70: A5 A4
00DE72 1 E5 E1 sbc CurrentObjectIndex ; $DE72: E5 E1
00DE74 1 D0 02 bne ObjectRouting_ApplyCoordinateSetup
00DE76 1 ; $DE74: D0 02
00DE76 1
00DE76 1 85 A4 sta $A4 ; $DE76: 85 A4
00DE78 1 ; A is zero on equality.
00DE78 1
00DE78 1 ; ----------------------------------------------------------------------------
00DE78 1 ; Apply the geometry setup, select a delay, and continue through $DD4A.
00DE78 1 ; ----------------------------------------------------------------------------
00DE78 1
00DE78 1 ObjectRouting_ApplyCoordinateSetup: ; $DE78
00DE78 1 20 19 E5 jsr BuildGeometryVectorFromArguments ; $DE78: 20 19 E5
00DE7B 1 20 28 E5 jsr StoreCurrentObjectMovement ; $DE7B: 20 28 E5
00DE7E 1 20 DE E2 jsr UpdateCurrentObjectAnimationDelay ; $DE7E: 20 DE E2
00DE81 1
00DE81 1 4C 4A DD jmp ContinueObjectProcessingWithDelay
00DE84 1 ; $DE81: 4C 4A DD
00DE84 1
00DE84 1 ; ============================================================================
00DE84 1 ; $DE84-$DEC7
00DE84 1 ; Handle candidate values below the high-state routing threshold.
00DE84 1 ; ============================================================================
00DE84 1
00DE84 1 ObjectRouting_CandidateBelow7: ; $DE84
00DE84 1 C9 02 cmp #$02 ; $DE84: C9 02
00DE86 1 90 40 bcc ObjectRouting_CandidateBelow2
00DE88 1 ; $DE86: 90 40
00DE88 1 ; Target $DEC8.
00DE88 1
00DE88 1 ; ----------------------------------------------------------------------------
00DE88 1 ; Candidate is at least two.
00DE88 1 ;
00DE88 1 ; CurrentObjectIndex must match either $A4 or $A9. Otherwise, return to the
00DE88 1 ; alternate path at $DE4D.
00DE88 1 ; ----------------------------------------------------------------------------
00DE88 1
00DE88 1 A6 E1 ldx CurrentObjectIndex ; $DE88: A6 E1
00DE8A 1
00DE8A 1 E4 A4 cpx $A4 ; $DE8A: E4 A4
00DE8C 1 F0 04 beq ObjectRouting_SetCandidateAnimation
00DE8E 1 ; $DE8C: F0 04
00DE8E 1
00DE8E 1 E4 A9 cpx $A9 ; $DE8E: E4 A9
00DE90 1 D0 BB bne ObjectRouting_Alternate ; $DE90: D0 BB
00DE92 1
00DE92 1 ; ----------------------------------------------------------------------------
00DE92 1 ; Assign animation frame $5E and an attribute/state value of $41 or $42.
00DE92 1 ; ----------------------------------------------------------------------------
00DE92 1
00DE92 1 ObjectRouting_SetCandidateAnimation: ; $DE92
00DE92 1 20 68 DA jsr GetCurrentObjectStateIndex
00DE95 1 ; $DE92: 20 68 DA
00DE95 1
00DE95 1 A9 5E lda #$5E ; $DE95: A9 5E
00DE97 1 9D 9B 03 sta $039B,x ; $DE97: 9D 9B 03
00DE9A 1
00DE9A 1 E0 0C cpx #$0C ; $DE9A: E0 0C
00DE9C 1 B0 0C bcs ObjectRouting_UpdateCandidate
00DE9E 1 ; $DE9C: B0 0C
00DE9E 1
00DE9E 1 A9 41 lda #$41 ; $DE9E: A9 41
00DEA0 1
00DEA0 1 DD B0 03 cmp $03B0,x ; $DEA0: DD B0 03
00DEA3 1 D0 02 bne ObjectRouting_SaveCandidateAttribute
00DEA5 1 ; $DEA3: D0 02
00DEA5 1
00DEA5 1 A9 42 lda #$42 ; $DEA5: A9 42
00DEA7 1
00DEA7 1 ObjectRouting_SaveCandidateAttribute: ; $DEA7
00DEA7 1 9D B0 03 sta $03B0,x ; $DEA7: 9D B0 03
00DEAA 1
00DEAA 1 ; ----------------------------------------------------------------------------
00DEAA 1 ; Update the current object and attempt the base-object merge.
00DEAA 1 ; ----------------------------------------------------------------------------
00DEAA 1
00DEAA 1 ObjectRouting_UpdateCandidate: ; $DEAA
00DEAA 1 A6 E1 ldx CurrentObjectIndex ; $DEAA: A6 E1
00DEAC 1 20 B7 E6 jsr ClearMovementTransforms ; $DEAC: 20 B7 E6
00DEAF 1
00DEAF 1 A6 E1 ldx CurrentObjectIndex ; $DEAF: A6 E1
00DEB1 1 20 C0 C9 jsr TryMergeObjectIntoBase ; $DEB1: 20 C0 C9
00DEB4 1
00DEB4 1 F0 1F beq ObjectRouting_MergeComplete
00DEB6 1 ; $DEB4: F0 1F
00DEB6 1 ; Target $DED5.
00DEB6 1
00DEB6 1 ; ----------------------------------------------------------------------------
00DEB6 1 ; Merge did not complete.
00DEB6 1 ;
00DEB6 1 ; Rebuild geometry arguments and return through the shared continuation.
00DEB6 1 ; ----------------------------------------------------------------------------
00DEB6 1
00DEB6 1 A9 00 lda #$00 ; $DEB6: A9 00
00DEB8 1 85 B5 sta $B5 ; $DEB8: 85 B5
00DEBA 1
00DEBA 1 20 FB DE jsr SelectObjectGeometrySize ; $DEBA: 20 FB DE
00DEBD 1 85 B3 sta $B3 ; $DEBD: 85 B3
00DEBF 1
00DEBF 1 20 19 E5 jsr BuildGeometryVectorFromArguments ; $DEBF: 20 19 E5
00DEC2 1 20 28 E5 jsr StoreCurrentObjectMovement ; $DEC2: 20 28 E5
00DEC5 1
00DEC5 1 4C 48 DD jmp ContinueObjectProcessing
00DEC8 1 ; $DEC5: 4C 48 DD
00DEC8 1
00DEC8 1 ; ============================================================================
00DEC8 1 ; $DEC8-$DED7
00DEC8 1 ; Candidate values zero or one.
00DEC8 1 ; ============================================================================
00DEC8 1
00DEC8 1 ObjectRouting_CandidateBelow2: ; $DEC8
00DEC8 1 20 D3 E2 jsr ClearCurrentObjectMovement ; $DEC8: 20 D3 E2
00DECB 1
00DECB 1 20 C0 C9 jsr TryMergeObjectIntoBase ; $DECB: 20 C0 C9
00DECE 1 F0 05 beq ObjectRouting_MergeComplete
00DED0 1 ; $DECE: F0 05
00DED0 1
00DED0 1 A9 01 lda #$01 ; $DED0: A9 01
00DED2 1 4C 4A DD jmp ContinueObjectProcessingWithDelay
00DED5 1 ; $DED2: 4C 4A DD
00DED5 1
00DED5 1 ; ----------------------------------------------------------------------------
00DED5 1 ; Merge completed. Re-enter the success path at $DE2F.
00DED5 1 ; ----------------------------------------------------------------------------
00DED5 1
00DED5 1 ObjectRouting_MergeComplete: ; $DED5
00DED5 1 4C 2F DE jmp ObjectRouting_MergeSucceeded
00DED8 1 ; $DED5: 4C 2F DE
00DED8 1
00DED8 1 ; ============================================================================
00DED8 1 ; $DED8-$DEEE
00DED8 1 ; Region/collision response path.
00DED8 1 ;
00DED8 1 ; Negate the current object's horizontal and vertical high movement values and
00DED8 1 ; store the results in $056D,X/$056E,X.
00DED8 1 ; ============================================================================
00DED8 1
00DED8 1 ObjectRouting_ReverseMovement: ; $DED8
00DED8 1 A6 E1 ldx CurrentObjectIndex ; $DED8: A6 E1
00DEDA 1
00DEDA 1 A9 00 lda #$00 ; $DEDA: A9 00
00DEDC 1 38 sec ; $DEDC: 38
00DEDD 1 FD 0A 05 sbc $050A,x ; $DEDD: FD 0A 05
00DEE0 1 9D 6D 05 sta $056D,x ; $DEE0: 9D 6D 05
00DEE3 1
00DEE3 1 A9 00 lda #$00 ; $DEE3: A9 00
00DEE5 1 38 sec ; $DEE5: 38
00DEE6 1 FD 3B 05 sbc $053B,x ; $DEE6: FD 3B 05
00DEE9 1 9D 6E 05 sta $056E,x ; $DEE9: 9D 6E 05
00DEEC 1
00DEEC 1 4C 48 DD jmp ContinueObjectProcessing
00DEEF 1 ; $DEEC: 4C 48 DD
00DEEF 1
00DEEF 1 ; ============================================================================
00DEEF 1 ; $DEEF-$DEFA
00DEEF 1 ; Assign CurrentObjectIndex to the active or saved object slot.
00DEEF 1 ;
00DEEF 1 ; If $A4 is zero:
00DEEF 1 ; Store CurrentObjectIndex in $A4.
00DEEF 1 ;
00DEEF 1 ; If $A4 is nonzero:
00DEEF 1 ; Store CurrentObjectIndex in $A9.
00DEEF 1 ;
00DEEF 1 ; Return:
00DEEF 1 ; X = CurrentObjectIndex
00DEEF 1 ; ============================================================================
00DEEF 1
00DEEF 1 ; ----------------------------------------------------------------------------
00DEEF 1 ; Contract:
00DEEF 1 ; Description: Implements Assign Current Object Slot.
00DEEF 1 ; Entry: Registers: X; Memory: currentobjectindex, $a4
00DEEF 1 ; Returns/products: Registers/clobbers: A, X
00DEEF 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00DEEF 1 ; Memory effects: $a4
00DEEF 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00DEEF 1 ; comparison, load, or store path and are not a stable API product.
00DEEF 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00DEEF 1 ; ----------------------------------------------------------------------------
00DEEF 1 AssignCurrentObjectSlot: ; $DEEF
00DEEF 1 A6 E1 ldx CurrentObjectIndex ; $DEEF: A6 E1
00DEF1 1
00DEF1 1 A5 A4 lda $A4 ; $DEF1: A5 A4
00DEF3 1 D0 03 bne AssignCurrentObjectToSavedSlot
00DEF5 1 ; $DEF3: D0 03
00DEF5 1
00DEF5 1 ; ----------------------------------------------------------------------------
00DEF5 1 ; No active object is assigned. Store the current object in the primary slot.
00DEF5 1 ; ----------------------------------------------------------------------------
00DEF5 1
00DEF5 1 86 A4 stx $A4 ; $DEF5: 86 A4
00DEF7 1 60 rts ; $DEF7: 60
00DEF8 1
00DEF8 1 ; ----------------------------------------------------------------------------
00DEF8 1 ; The primary slot is occupied. Store the current object in the saved slot.
00DEF8 1 ; ----------------------------------------------------------------------------
00DEF8 1
00DEF8 1 AssignCurrentObjectToSavedSlot: ; $DEF8
00DEF8 1 86 A9 stx $A9 ; $DEF8: 86 A9
00DEFA 1 60 rts ; $DEFA: 60
00DEFB 1
00DEFB 1 ; ============================================================================
00DEFB 1 ; $DEFB-$DF07
00DEFB 1 ; Select a geometry or object-size parameter from CurrentObjectIndex.
00DEFB 1 ;
00DEFB 1 ; Return:
00DEFB 1 ; A = selected parameter
00DEFB 1 ; $C6 = selected parameter
00DEFB 1 ;
00DEFB 1 ; CurrentObjectIndex below $18:
00DEFB 1 ; parameter = $08
00DEFB 1 ;
00DEFB 1 ; CurrentObjectIndex at least $18:
00DEFB 1 ; parameter = $03
00DEFB 1 ; ============================================================================
00DEFB 1
00DEFB 1 ; ----------------------------------------------------------------------------
00DEFB 1 ; Contract:
00DEFB 1 ; Description: Implements Select Object Geometry Size.
00DEFB 1 ; Entry: Registers: A, X; Memory: currentobjectindex
00DEFB 1 ; Returns/products: Registers/clobbers: A, X
00DEFB 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00DEFB 1 ; Memory effects: $c6
00DEFB 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00DEFB 1 ; comparison, load, or store path and are not a stable API product.
00DEFB 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 3.
00DEFB 1 ; ----------------------------------------------------------------------------
00DEFB 1 SelectObjectGeometrySize: ; $DEFB
00DEFB 1 A6 E1 ldx CurrentObjectIndex ; $DEFB: A6 E1
00DEFD 1
00DEFD 1 A9 03 lda #$03 ; $DEFD: A9 03
00DEFF 1
00DEFF 1 E0 18 cpx #$18 ; $DEFF: E0 18
00DF01 1 B0 02 bcs SelectObjectGeometrySize_Save
00DF03 1 ; $DF01: B0 02
00DF03 1
00DF03 1 A9 08 lda #$08 ; $DF03: A9 08
00DF05 1
00DF05 1 SelectObjectGeometrySize_Save: ; $DF05
00DF05 1 85 C6 sta $C6 ; $DF05: 85 C6
00DF07 1 60 rts ; $DF07: 60
00DF08 1
00DF08 1 ; ============================================================================
00DF08 1 ; $DF08-$DF11
00DF08 1 ; Configure geometry arguments for the current object and run the region test.
00DF08 1 ;
00DF08 1 ; Return:
00DF08 1 ; A and processor flags are returned directly from $E502.
00DF08 1 ;
00DF08 1 ; Call sequence:
00DF08 1 ; $DF12 Select and copy the relevant object coordinates into $B2-$B5.
00DF08 1 ; $E4DB Process or normalize the geometry arguments.
00DF08 1 ; $E502 Perform the final geometry/region test.
00DF08 1 ; ============================================================================
00DF08 1
00DF08 1 ; ----------------------------------------------------------------------------
00DF08 1 ; Contract:
00DF08 1 ; Description: Implements Test Current Object Geometry.
00DF08 1 ; Entry: No register input inferred
00DF08 1 ; Returns/products: No direct product inferred
00DF08 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00DF08 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00DF08 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00DF08 1 ; comparison, load, or store path and are not a stable API product.
00DF08 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 2.
00DF08 1 ; ----------------------------------------------------------------------------
00DF08 1 TestCurrentObjectGeometry: ; $DF08
00DF08 1 20 12 DF jsr SetupCurrentObjectGeometry
00DF0B 1 ; $DF08: 20 12 DF
00DF0B 1
00DF0B 1 20 DB E4 jsr CalculateCurrentGeometryDifference ; $DF0B: 20 DB E4
00DF0E 1 20 02 E5 jsr EvaluateGeometryDifference ; $DF0E: 20 02 E5
00DF11 1
00DF11 1 60 rts ; $DF11: 60
00DF12 1
00DF12 1 ; ============================================================================
00DF12 1 ; $DF12-$DF26
00DF12 1 ; Copy saved base coordinates into the geometry argument structure.
00DF12 1 ;
00DF12 1 ; The original ROM deliberately uses absolute addressing for zero-page
00DF12 1 ; locations $53-$56. Raw bytes are used here to prevent CA65 from shortening
00DF12 1 ; these instructions to zero-page addressing.
00DF12 1 ; ============================================================================
00DF12 1
00DF12 1 SetupCurrentObjectGeometry: ; $DF12
00DF12 1 AD 53 00 .byte $AD,$53,$00 ; $DF12: LDA $0053
00DF15 1 85 B2 sta $B2 ; $DF15: 85 B2
00DF17 1
00DF17 1 AD 54 00 .byte $AD,$54,$00 ; $DF17: LDA $0054
00DF1A 1 85 B3 sta $B3 ; $DF1A: 85 B3
00DF1C 1
00DF1C 1 AD 55 00 .byte $AD,$55,$00 ; $DF1C: LDA $0055
00DF1F 1 85 B4 sta $B4 ; $DF1F: 85 B4
00DF21 1
00DF21 1 AD 56 00 .byte $AD,$56,$00 ; $DF21: LDA $0056
00DF24 1 85 B5 sta $B5 ; $DF24: 85 B5
00DF26 1
00DF26 1 60 rts ; $DF26: 60
00DF27 1
00DF27 1 ; ============================================================================
00DF27 1 ; $DF27-$DF3B
00DF27 1 ; Copy the base object's live coordinates into the geometry arguments.
00DF27 1 ;
00DF27 1 ; Source:
00DF27 1 ; $0509/$050A = base horizontal coordinate
00DF27 1 ; $053A/$053B = base vertical coordinate
00DF27 1 ;
00DF27 1 ; Destination:
00DF27 1 ; $B2/$B3 = geometry horizontal coordinate
00DF27 1 ; $B4/$B5 = geometry vertical coordinate
00DF27 1 ; ============================================================================
00DF27 1
00DF27 1 ; ----------------------------------------------------------------------------
00DF27 1 ; Contract:
00DF27 1 ; Description: Implements Setup Base Object Geometry.
00DF27 1 ; Entry: Registers: A; Memory: $0509, $050a, $053a, $053b
00DF27 1 ; Returns/products: Registers/clobbers: A
00DF27 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00DF27 1 ; Memory effects: $b2, $b3, $b4, $b5
00DF27 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00DF27 1 ; comparison, load, or store path and are not a stable API product.
00DF27 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00DF27 1 ; ----------------------------------------------------------------------------
00DF27 1 SetupBaseObjectGeometry: ; $DF27
00DF27 1 AD 09 05 lda $0509 ; $DF27: AD 09 05
00DF2A 1 85 B2 sta $B2 ; $DF2A: 85 B2
00DF2C 1
00DF2C 1 AD 0A 05 lda $050A ; $DF2C: AD 0A 05
00DF2F 1 85 B3 sta $B3 ; $DF2F: 85 B3
00DF31 1
00DF31 1 AD 3A 05 lda $053A ; $DF31: AD 3A 05
00DF34 1 85 B4 sta $B4 ; $DF34: 85 B4
00DF36 1
00DF36 1 AD 3B 05 lda $053B ; $DF36: AD 3B 05
00DF39 1 85 B5 sta $B5 ; $DF39: 85 B5
00DF3B 1
00DF3B 1 60 rts ; $DF3B: 60
00DF3C 1
00DF3C 1 ; ============================================================================
00DF3C 1 ; $DF3C-$DF44
00DF3C 1 ; Prepare geometry using the base object's live coordinates, process the
00DF3C 1 ; geometry arguments, and return the resulting high coordinate in X.
00DF3C 1 ;
00DF3C 1 ; Return:
00DF3C 1 ; X = $AF
00DF3C 1 ;
00DF3C 1 ; A and Y retain whatever values were left by $E4DB.
00DF3C 1 ; Processor flags reflect LDX $AF.
00DF3C 1 ; ============================================================================
00DF3C 1
00DF3C 1 PrepareBaseObjectGeometry: ; $DF3C
00DF3C 1 20 27 DF jsr SetupBaseObjectGeometry ; $DF3C: 20 27 DF
00DF3F 1 20 DB E4 jsr CalculateCurrentGeometryDifference ; $DF3F: 20 DB E4
00DF42 1
00DF42 1 A6 AF ldx CalculatedCoordinateHigh ; $DF42: A6 AF
00DF44 1 60 rts ; $DF44: 60
00DF45 1
00DF45 1 ; ============================================================================
00DF45 1 ; $DF45-$DF91
00DF45 1 ; Calculate geometry and movement arguments for the current object.
00DF45 1 ;
00DF45 1 ; This routine:
00DF45 1 ; 1. Selects an object-size parameter in $C6.
00DF45 1 ; 2. Prepares the base object's geometry.
00DF45 1 ; 3. Saves a geometry result in $D4/$D5.
00DF45 1 ; 4. Copies base movement values into $D6/$D7.
00DF45 1 ; 5. Calls the signed-vector helper at $E877.
00DF45 1 ; 6. Selects and installs final geometry arguments.
00DF45 1 ; 7. Tail-calls the geometry-processing helper at $E502.
00DF45 1 ; ============================================================================
00DF45 1
00DF45 1 ; ----------------------------------------------------------------------------
00DF45 1 ; Contract:
00DF45 1 ; Description: Calculates Current Object Geometry.
00DF45 1 ; Entry: Registers: A, X, Y; Memory: $0508, $0539, $c6, $d4
00DF45 1 ; Returns/products: Registers/clobbers: A, X, Y
00DF45 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00DF45 1 ; Memory effects: $d4, $d5, $d6, $d7, $b5, $b3
00DF45 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00DF45 1 ; comparison, load, or store path and are not a stable API product.
00DF45 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 2.
00DF45 1 ; ----------------------------------------------------------------------------
00DF45 1 CalculateCurrentObjectGeometry: ; $DF45
00DF45 1 20 FB DE jsr SelectObjectGeometrySize
00DF48 1 ; $DF45: 20 FB DE
00DF48 1
00DF48 1 20 3C DF jsr PrepareBaseObjectGeometry
00DF4B 1 ; $DF48: 20 3C DF
00DF4B 1
00DF4B 1 ; ----------------------------------------------------------------------------
00DF4B 1 ; Save the geometry result.
00DF4B 1 ;
00DF4B 1 ; PrepareBaseObjectGeometry returns:
00DF4B 1 ; X = geometry high/result byte from $AF
00DF4B 1 ; A = result left by $E4DB
00DF4B 1 ; ----------------------------------------------------------------------------
00DF4B 1
00DF4B 1 86 D4 stx $D4 ; $DF4B: 86 D4
00DF4D 1 85 D5 sta $D5 ; $DF4D: 85 D5
00DF4F 1
00DF4F 1 ; ----------------------------------------------------------------------------
00DF4F 1 ; Save the base movement values.
00DF4F 1 ; ----------------------------------------------------------------------------
00DF4F 1
00DF4F 1 AE 08 05 ldx $0508 ; $DF4F: AE 08 05
00DF52 1 86 D6 stx $D6 ; $DF52: 86 D6
00DF54 1
00DF54 1 AC 39 05 ldy $0539 ; $DF54: AC 39 05
00DF57 1 84 D7 sty $D7 ; $DF57: 84 D7
00DF59 1
00DF59 1 ; ----------------------------------------------------------------------------
00DF59 1 ; Run the signed-vector helper.
00DF59 1 ;
00DF59 1 ; The helper returns a signed result in A/Y. A is copied to X so its sign can
00DF59 1 ; select the next path.
00DF59 1 ; ----------------------------------------------------------------------------
00DF59 1
00DF59 1 20 77 E8 jsr NormalizeSignedVector ; $DF59: 20 77 E8
00DF5C 1
00DF5C 1 AA tax ; $DF5C: AA
00DF5D 1 10 1B bpl CalculateCurrentObjectGeometry_Nonnegative
00DF5F 1 ; $DF5D: 10 1B
00DF5F 1
00DF5F 1 ; ----------------------------------------------------------------------------
00DF5F 1 ; Negative-result path.
00DF5F 1 ;
00DF5F 1 ; Convert Y to its magnitude when negative, then compare it with the selected
00DF5F 1 ; object-size parameter at $C6.
00DF5F 1 ; ----------------------------------------------------------------------------
00DF5F 1
00DF5F 1 98 tya ; $DF5F: 98
00DF60 1 10 05 bpl CalculateCurrentObjectGeometry_CompareMagnitude
00DF62 1 ; $DF60: 10 05
00DF62 1
00DF62 1 49 FF eor #$FF ; $DF62: 49 FF
00DF64 1 38 sec ; $DF64: 38
00DF65 1 69 00 adc #$00 ; $DF65: 69 00
00DF67 1 ; With carry set, forms two's-complement
00DF67 1 ; magnitude: (~A) + 1.
00DF67 1
00DF67 1 CalculateCurrentObjectGeometry_CompareMagnitude: ; $DF67
00DF67 1 C5 C6 cmp $C6 ; $DF67: C5 C6
00DF69 1 B0 15 bcs CalculateCurrentObjectGeometry_Clamp
00DF6B 1 ; $DF69: B0 15
00DF6B 1
00DF6B 1 ; ----------------------------------------------------------------------------
00DF6B 1 ; Magnitude is below the selected object size.
00DF6B 1 ;
00DF6B 1 ; Use:
00DF6B 1 ; X = $C6
00DF6B 1 ; $B5 = Y
00DF6B 1 ; $B3 = $D4
00DF6B 1 ;
00DF6B 1 ; Then enter the geometry helper at $E502.
00DF6B 1 ; ----------------------------------------------------------------------------
00DF6B 1
00DF6B 1 A6 C6 ldx $C6 ; $DF6B: A6 C6
00DF6D 1
00DF6D 1 98 tya ; $DF6D: 98
00DF6E 1 85 B5 sta $B5 ; $DF6E: 85 B5
00DF70 1
00DF70 1 20 A5 E8 jsr RunEightRoundTransform ; $DF70: 20 A5 E8
00DF73 1
00DF73 1 A5 D4 lda $D4 ; $DF73: A5 D4
00DF75 1 85 B3 sta $B3 ; $DF75: 85 B3
00DF77 1
00DF77 1 CalculateCurrentObjectGeometry_RunTest: ; $DF77
00DF77 1 4C 02 E5 jmp EvaluateGeometryDifference ; $DF77: 4C 02 E5
00DF7A 1
00DF7A 1 ; ----------------------------------------------------------------------------
00DF7A 1 ; Nonnegative-result path.
00DF7A 1 ;
00DF7A 1 ; Initialize X from the selected object-size parameter and A to zero.
00DF7A 1 ; The unconditional BEQ continues at the shared argument-store path.
00DF7A 1 ; ----------------------------------------------------------------------------
00DF7A 1
00DF7A 1 CalculateCurrentObjectGeometry_Nonnegative: ; $DF7A
00DF7A 1 A6 C6 ldx $C6 ; $DF7A: A6 C6
00DF7C 1
00DF7C 1 A9 00 lda #$00 ; $DF7C: A9 00
00DF7E 1 F0 0C beq CalculateCurrentObjectGeometry_SaveArguments
00DF80 1 ; $DF7E: F0 0C
00DF80 1
00DF80 1 ; ----------------------------------------------------------------------------
00DF80 1 ; Clamp or normalize the selected object-size value.
00DF80 1 ;
00DF80 1 ; If Y is at least $80, invert $C6 and add the incoming carry.
00DF80 1 ; X is cleared before storing the resulting arguments.
00DF80 1 ; ----------------------------------------------------------------------------
00DF80 1
00DF80 1 CalculateCurrentObjectGeometry_Clamp: ; $DF80
00DF80 1 A5 C6 lda $C6 ; $DF80: A5 C6
00DF82 1
00DF82 1 C0 80 cpy #$80 ; $DF82: C0 80
00DF84 1 90 04 bcc CalculateCurrentObjectGeometry_ClearX
00DF86 1 ; $DF84: 90 04
00DF86 1
00DF86 1 49 FF eor #$FF ; $DF86: 49 FF
00DF88 1 69 00 adc #$00 ; $DF88: 69 00
00DF8A 1
00DF8A 1 CalculateCurrentObjectGeometry_ClearX: ; $DF8A
00DF8A 1 A2 00 ldx #$00 ; $DF8A: A2 00
00DF8C 1
00DF8C 1 CalculateCurrentObjectGeometry_SaveArguments: ; $DF8C
00DF8C 1 85 B5 sta $B5 ; $DF8C: 85 B5
00DF8E 1 86 B3 stx $B3 ; $DF8E: 86 B3
00DF90 1
00DF90 1 F0 E5 beq CalculateCurrentObjectGeometry_RunTest
00DF92 1 ; $DF90: F0 E5
00DF92 1 ; Branches to $DF77 when the stored A value
00DF92 1 ; is zero.
00DF92 1
00DF92 1 ; ============================================================================
00DF92 1 ; $DF92-$DFA6
00DF92 1 ; Transform X and Y independently, then add their two-byte results.
00DF92 1 ;
00DF92 1 ; Entry:
00DF92 1 ; X = first signed input
00DF92 1 ; Y = second signed input
00DF92 1 ;
00DF92 1 ; Exit:
00DF92 1 ; A/Y = combined two-byte result
00DF92 1 ;
00DF92 1 ; The helper at $DFA7 returns:
00DF92 1 ; A = low/result byte
00DF92 1 ; X = high/result byte
00DF92 1 ; ============================================================================
00DF92 1
00DF92 1 AddTransformedSignedValues: ; $DF92
00DF92 1 8A txa ; $DF92: 8A
00DF93 1 20 A7 DF jsr TransformSignedValue ; $DF93: 20 A7 DF
00DF96 1
00DF96 1 86 06 stx $06 ; $DF96: 86 06
00DF98 1 85 05 sta MathTemp05 ; $DF98: 85 05
00DF9A 1
00DF9A 1 98 tya ; $DF9A: 98
00DF9B 1 20 A7 DF jsr TransformSignedValue ; $DF9B: 20 A7 DF
00DF9E 1
00DF9E 1 ; ----------------------------------------------------------------------------
00DF9E 1 ; Add the two transformed results:
00DF9E 1 ;
00DF9E 1 ; second high + first high -> Y
00DF9E 1 ; second low + first low -> A
00DF9E 1 ; ----------------------------------------------------------------------------
00DF9E 1
00DF9E 1 48 pha ; $DF9E: 48
00DF9F 1
00DF9F 1 8A txa ; $DF9F: 8A
00DFA0 1 65 06 adc $06 ; $DFA0: 65 06
00DFA2 1 A8 tay ; $DFA2: A8
00DFA3 1
00DFA3 1 68 pla ; $DFA3: 68
00DFA4 1 65 05 adc MathTemp05 ; $DFA4: 65 05
00DFA6 1
00DFA6 1 60 rts ; $DFA6: 60
00DFA7 1
00DFA7 1 ; ============================================================================
00DFA7 1 ; $DFA7-$DFC3
00DFA7 1 ; Convert a signed byte to its magnitude, then perform an eight-step
00DFA7 1 ; shift-and-add transformation.
00DFA7 1 ;
00DFA7 1 ; Entry:
00DFA7 1 ; A = signed input byte
00DFA7 1 ;
00DFA7 1 ; Exit:
00DFA7 1 ; A = transformed low byte
00DFA7 1 ; X = transformed high/working byte from $28
00DFA7 1 ;
00DFA7 1 ; Working values:
00DFA7 1 ; $28 = shifting multiplier/result byte
00DFA7 1 ; $2B = absolute input value
00DFA7 1 ; ============================================================================
00DFA7 1
00DFA7 1 ; ----------------------------------------------------------------------------
00DFA7 1 ; Contract:
00DFA7 1 ; Description: Implements Transform Signed Value.
00DFA7 1 ; Entry: Registers: A, X; Memory: $2b, $28
00DFA7 1 ; Returns/products: Registers/clobbers: A, X
00DFA7 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00DFA7 1 ; Memory effects: $28, $2b
00DFA7 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00DFA7 1 ; comparison, load, or store path and are not a stable API product.
00DFA7 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 2.
00DFA7 1 ; ----------------------------------------------------------------------------
00DFA7 1 TransformSignedValue: ; $DFA7
00DFA7 1 10 05 bpl TransformSignedValue_HaveMagnitude
00DFA9 1 ; $DFA7: 10 05
00DFA9 1
00DFA9 1 49 FF eor #$FF ; $DFA9: 49 FF
00DFAB 1 18 clc ; $DFAB: 18
00DFAC 1 69 01 adc #$01 ; $DFAC: 69 01
00DFAE 1
00DFAE 1 TransformSignedValue_HaveMagnitude: ; $DFAE
00DFAE 1 85 28 sta $28 ; $DFAE: 85 28
00DFB0 1 85 2B sta $2B ; $DFB0: 85 2B
00DFB2 1
00DFB2 1 A9 00 lda #$00 ; $DFB2: A9 00
00DFB4 1 A2 07 ldx #$07 ; $DFB4: A2 07
00DFB6 1
00DFB6 1 ; ----------------------------------------------------------------------------
00DFB6 1 ; Repeatedly shift $28 right through A.
00DFB6 1 ;
00DFB6 1 ; Whenever carry is set, add the original magnitude from $2B.
00DFB6 1 ; ----------------------------------------------------------------------------
00DFB6 1
00DFB6 1 TransformSignedValue_Loop: ; $DFB6
00DFB6 1 4A lsr ; $DFB6: 4A
00DFB7 1 66 28 ror $28 ; $DFB7: 66 28
00DFB9 1
00DFB9 1 90 03 bcc TransformSignedValue_Next
00DFBB 1 ; $DFB9: 90 03
00DFBB 1
00DFBB 1 18 clc ; $DFBB: 18
00DFBC 1 65 2B adc $2B ; $DFBC: 65 2B
00DFBE 1
00DFBE 1 TransformSignedValue_Next: ; $DFBE
00DFBE 1 CA dex ; $DFBE: CA
00DFBF 1 D0 F5 bne TransformSignedValue_Loop
00DFC1 1 ; $DFBF: D0 F5
00DFC1 1
00DFC1 1 A6 28 ldx $28 ; $DFC1: A6 28
00DFC3 1 60 rts ; $DFC3: 60
00DFC4 1
00DFC4 1 ; ============================================================================
00DFC4 1 ; $DFC4-$DFD3
00DFC4 1 ; Signed coordinate-offset table.
00DFC4 1 ;
00DFC4 1 ; Eight two-byte entries are present. Interpreted as little-endian signed
00DFC4 1 ; 16-bit values:
00DFC4 1 ;
00DFC4 1 ; $F800, $0800, $F800, $0000,
00DFC4 1 ; $00F9, $0007, $00F9, $FE00
00DFC4 1 ;
00DFC4 1 ; Several later routines index this region through nearby or overlapping base
00DFC4 1 ; addresses, so preserving the raw byte layout is safest.
00DFC4 1 ; ============================================================================
00DFC4 1
00DFC4 1 SignedCoordinateOffsetTable: ; $DFC4
00DFC4 1 00 F8 .byte $00,$F8 ; $F800
00DFC6 1 00 08 .byte $00,$08 ; $0800
00DFC8 1 00 F8 .byte $00,$F8 ; $F800
00DFCA 1 00 00 .byte $00,$00 ; $0000
00DFCC 1 F9 00 .byte $F9,$00 ; $00F9
00DFCE 1 07 00 .byte $07,$00 ; $0007
00DFD0 1 F9 00 .byte $F9,$00 ; $00F9
00DFD2 1 00 FE .byte $00,$FE ; $FE00
00DFD4 1
00DFD4 1 ; ============================================================================
00DFD4 1 ; $DFD4-$DFEA
00DFD4 1 ; Update the current object's animation values from the selector returned by
00DFD4 1 ; GetCurrentObjectSelectorAndState.
00DFD4 1 ;
00DFD4 1 ; The selector returned in X chooses an attribute from the four-byte table
00DFD4 1 ; immediately following the routine.
00DFD4 1 ; ============================================================================
00DFD4 1
00DFD4 1 ; ----------------------------------------------------------------------------
00DFD4 1 ; Contract:
00DFD4 1 ; Description: Updates Current Object Display State.
00DFD4 1 ; Entry: Registers: A, X; Memory: $dfea, currentobjectindex
00DFD4 1 ; Returns/products: Registers/clobbers: A, X
00DFD4 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00DFD4 1 ; Memory effects: $03b0, $039b
00DFD4 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00DFD4 1 ; comparison, load, or store path and are not a stable API product.
00DFD4 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00DFD4 1 ; ----------------------------------------------------------------------------
00DFD4 1 UpdateCurrentObjectDisplayState: ; $DFD4
00DFD4 1 20 DC E3 jsr GetCurrentObjectSelectorAndState ; $DFD4: 20 DC E3
00DFD7 1
00DFD7 1 ; ----------------------------------------------------------------------------
00DFD7 1 ; Convert the returned object/event offset into a compact sprite-array index.
00DFD7 1 ; ----------------------------------------------------------------------------
00DFD7 1
00DFD7 1 8A txa ; $DFD7: 8A
00DFD8 1 4A lsr ; $DFD8: 4A
00DFD9 1 AA tax ; $DFD9: AA
00DFDA 1
00DFDA 1 ; ----------------------------------------------------------------------------
00DFDA 1 ; Load the selector-dependent animation attribute.
00DFDA 1 ;
00DFDA 1 ; Y is returned by GetCurrentObjectSelectorAndState and selects one of the table entries at $DFEB.
00DFDA 1 ; ----------------------------------------------------------------------------
00DFDA 1
00DFDA 1 B9 EA DF lda $DFEA,y ; $DFDA: B9 EA DF
00DFDD 1 ; Original indexed base is $DFEA, one byte
00DFDD 1 ; before the visible table.
00DFDD 1
00DFDD 1 9D B0 03 sta $03B0,x ; $DFDD: 9D B0 03
00DFE0 1
00DFE0 1 A9 5A lda #$5A ; $DFE0: A9 5A
00DFE2 1 9D 9B 03 sta $039B,x ; $DFE2: 9D 9B 03
00DFE5 1
00DFE5 1 ; ----------------------------------------------------------------------------
00DFE5 1 ; Update the current object and return.
00DFE5 1 ; ----------------------------------------------------------------------------
00DFE5 1
00DFE5 1 A6 E1 ldx CurrentObjectIndex ; $DFE5: A6 E1
00DFE7 1 20 B7 E6 jsr ClearMovementTransforms ; $DFE7: 20 B7 E6
00DFEA 1
00DFEA 1 60 rts ; $DFEA: 60
00DFEB 1
00DFEB 1 ; ============================================================================
00DFEB 1 ; $DFEB-$DFEE
00DFEB 1 ; Object-display attribute table.
00DFEB 1 ;
00DFEB 1 ; The load at $DFDA intentionally uses base $DFEA. Expected Y values are
00DFEB 1 ; therefore $01-$04:
00DFEB 1 ;
00DFEB 1 ; Y=$01 -> $DFEB
00DFEB 1 ; Y=$02 -> $DFEC
00DFEB 1 ; Y=$03 -> $DFED
00DFEB 1 ; Y=$04 -> $DFEE
00DFEB 1 ; ============================================================================
00DFEB 1
00DFEB 1 ObjectDisplayAttributeTable: ; $DFEB
00DFEB 1 2A 3D 3D 13 .byte $2A,$3D,$3D,$13
00DFEF 1
00DFEF 1 ; ============================================================================
00DFEF 1 ; $DFEF-$E01C
00DFEF 1 ; Assign a state value to the current object, perform a geometry test, and
00DFEF 1 ; either restart the test or finish the object transition.
00DFEF 1 ;
00DFEF 1 ; Multiple entry points select state values one through five in Y.
00DFEF 1 ; ============================================================================
00DFEF 1
00DFEF 1 SetCurrentObjectState1: ; $DFEF
00DFEF 1 A0 01 ldy #$01 ; $DFEF: A0 01
00DFF1 1 D0 0E bne SetCurrentObjectState ; $DFF1: D0 0E
00DFF3 1
00DFF3 1 SetCurrentObjectState2: ; $DFF3
00DFF3 1 A0 02 ldy #$02 ; $DFF3: A0 02
00DFF5 1 D0 0A bne SetCurrentObjectState ; $DFF5: D0 0A
00DFF7 1
00DFF7 1 SetCurrentObjectState3: ; $DFF7
00DFF7 1 A0 03 ldy #$03 ; $DFF7: A0 03
00DFF9 1 D0 06 bne SetCurrentObjectState ; $DFF9: D0 06
00DFFB 1
00DFFB 1 SetCurrentObjectState4: ; $DFFB
00DFFB 1 A0 04 ldy #$04 ; $DFFB: A0 04
00DFFD 1 D0 02 bne SetCurrentObjectState ; $DFFD: D0 02
00DFFF 1
00DFFF 1 SetCurrentObjectState5: ; $DFFF
00DFFF 1 A0 05 ldy #$05 ; $DFFF: A0 05
00E001 1
00E001 1 ; ----------------------------------------------------------------------------
00E001 1 ; Store the selected state in $0595 using the compact current-object index.
00E001 1 ; ----------------------------------------------------------------------------
00E001 1
00E001 1 SetCurrentObjectState: ; $E001
00E001 1 A5 E1 lda CurrentObjectIndex ; $E001: A5 E1
00E003 1 4A lsr ; $E003: 4A
00E004 1 AA tax ; $E004: AA
00E005 1
00E005 1 98 tya ; $E005: 98
00E006 1 9D 95 05 sta $0595,x ; $E006: 9D 95 05
00E009 1
00E009 1 ; ----------------------------------------------------------------------------
00E009 1 ; Prepare and test the current object's geometry.
00E009 1 ; ----------------------------------------------------------------------------
00E009 1
00E009 1 SetCurrentObjectState_Retry: ; $E009
00E009 1 20 74 E4 jsr SelectGeometryRecord_Default ; $E009: 20 74 E4
00E00C 1 20 5F E5 jsr ApplyCurrentObjectGeometry ; $E00C: 20 5F E5
00E00F 1
00E00F 1 90 06 bcc SetCurrentObjectState_Finish
00E011 1 ; $E00F: 90 06
00E011 1
00E011 1 ; ----------------------------------------------------------------------------
00E011 1 ; Geometry remains active. Run the helper at $E313 and retry.
00E011 1 ; ----------------------------------------------------------------------------
00E011 1
00E011 1 20 13 E3 jsr UpdateCurrentObjectAnimationAndWait ; $E011: 20 13 E3
00E014 1
00E014 1 4C 09 E0 jmp SetCurrentObjectState_Retry
00E017 1 ; $E014: 4C 09 E0
00E017 1
00E017 1 ; ----------------------------------------------------------------------------
00E017 1 ; Geometry cleared. Update display state and leave through the common exit.
00E017 1 ; ----------------------------------------------------------------------------
00E017 1
00E017 1 SetCurrentObjectState_Finish: ; $E017
00E017 1 20 D4 DF jsr UpdateCurrentObjectDisplayState
00E01A 1 ; $E017: 20 D4 DF
00E01A 1
00E01A 1 4C 6A EB jmp CommonEngineExit ; $E01A: 4C 6A EB
00E01D 1
00E01D 1 ; ============================================================================
00E01D 1 ; $E01D-$E036
00E01D 1 ; Lookup data used by the following object-state routines.
00E01D 1 ;
00E01D 1 ; Several later routines reference addresses inside this region, including
00E01D 1 ; $E021 and $E027. Preserve the exact raw layout until all references have
00E01D 1 ; been fully characterized.
00E01D 1 ; ============================================================================
00E01D 1
00E01D 1 ObjectStateLookupData: ; $E01D
00E01D 1 02 06 08 04 .byte $02,$06,$08,$04
00E021 1 ObjectStateThresholdTable:
00E021 1 02 05 FD FB .byte $02,$05,$FD,$FB
00E025 1 05 FD .byte $05,$FD
00E027 1 ObjectStateResultTable:
00E027 1 F9 00 .byte $F9,$00
00E029 1 00 FF 04 04 .byte $00,$FF,$04,$04
00E02D 1 02 04 06 06 .byte $02,$04,$06,$06
00E031 1 04 06 08 06 .byte $04,$06,$08,$06
00E035 1 08 08 .byte $08,$08
00E037 1
00E037 1 ; ============================================================================
00E037 1 ; $E037-$E08A
00E037 1 ; Evaluate global object state, select an active object, initialize its timer,
00E037 1 ; and wait for either input or timer expiration.
00E037 1 ;
00E037 1 ; Several conditions transfer directly to the next major path at $E08B.
00E037 1 ; ============================================================================
00E037 1
00E037 1 ObjectStateDispatch: ; $E037
00E037 1 A5 60 lda PendingStateTransition ; $E037: A5 60
00E039 1 D0 50 bne ObjectStateDispatch_NextPath
00E03B 1 ; $E039: D0 50
00E03B 1
00E03B 1 ; ----------------------------------------------------------------------------
00E03B 1 ; Search or validate the current object state.
00E03B 1 ;
00E03B 1 ; Carry set from $E1CE skips the three setup helpers and continues at $E049.
00E03B 1 ; ----------------------------------------------------------------------------
00E03B 1
00E03B 1 20 CE E1 jsr TestObjectGeometryFourTimes ; $E03B: 20 CE E1
00E03E 1 B0 09 bcs ObjectStateDispatch_CheckCandidate
00E040 1 ; $E03E: B0 09
00E040 1
00E040 1 ; ----------------------------------------------------------------------------
00E040 1 ; Contract:
00E040 1 ; Description: Internal dispatcher entry for the current object-state selection.
00E040 1 ; Entry: Current object and selector state initialized.
00E040 1 ; Returns/products: Dispatches selected state; products follow selected path.
00E040 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E040 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00E040 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E040 1 ; comparison, load, or store path and are not a stable API product.
00E040 1 ; Validation: Internal-entry contract; call sites: internal entry.
00E040 1 ; ----------------------------------------------------------------------------
00E040 1 ProcessObjectStateSelection:
00E040 1 20 47 E3 jsr ProcessCompactObjectState ; $E040: 20 47 E3
00E043 1 20 6A E3 jsr ProcessCompactObjectState_TestSelector ; $E043: 20 6A E3
00E046 1 20 31 E3 jsr FindAndQueueSelectedState ; $E046: 20 31 E3
00E049 1
00E049 1 ; ----------------------------------------------------------------------------
00E049 1 ; Run the next selection test.
00E049 1 ;
00E049 1 ; Carry set transfers to the next major state path at $E08B.
00E049 1 ; ----------------------------------------------------------------------------
00E049 1
00E049 1 ObjectStateDispatch_CheckCandidate: ; $E049
00E049 1 20 E7 E1 jsr FindEligibleObjectState ; $E049: 20 E7 E1
00E04C 1 B0 3D bcs ObjectStateDispatch_NextPath
00E04E 1 ; $E04C: B0 3D
00E04E 1
00E04E 1 ; ----------------------------------------------------------------------------
00E04E 1 ; When ObjectTransitionState is nonzero, validate the object-state selector.
00E04E 1 ; ----------------------------------------------------------------------------
00E04E 1
00E04E 1 A5 6E lda ObjectTransitionState ; $E04E: A5 6E
00E050 1 F0 0D beq ObjectStateDispatch_InitializeObject
00E052 1 ; $E050: F0 0D
00E052 1
00E052 1 A6 C3 ldx $C3 ; $E052: A6 C3
00E054 1
00E054 1 BD 98 05 lda $0598,x ; $E054: BD 98 05
00E057 1 4A lsr ; $E057: 4A
00E058 1 A8 tay ; $E058: A8
00E059 1 C8 iny ; $E059: C8
00E05A 1
00E05A 1 20 46 E2 jsr FindObjectStateForSelector ; $E05A: 20 46 E2
00E05D 1 30 2C bmi ObjectStateDispatch_NextPath
00E05F 1 ; $E05D: 30 2C
00E05F 1
00E05F 1 ; ----------------------------------------------------------------------------
00E05F 1 ; Initialize the selected object's compact state.
00E05F 1 ;
00E05F 1 ; GetCurrentObjectStateIndex derives X from CurrentObjectIndex. The entry indexed by $C3 is
00E05F 1 ; complemented and stored in $0595,X.
00E05F 1 ; ----------------------------------------------------------------------------
00E05F 1
00E05F 1 ObjectStateDispatch_InitializeObject: ; $E05F
00E05F 1 20 68 DA jsr GetCurrentObjectStateIndex
00E062 1 ; $E05F: 20 68 DA
00E062 1
00E062 1 A5 C3 lda $C3 ; $E062: A5 C3
00E064 1 49 FF eor #$FF ; $E064: 49 FF
00E066 1 9D 95 05 sta $0595,x ; $E066: 9D 95 05
00E069 1
00E069 1 A9 00 lda #$00 ; $E069: A9 00
00E06B 1 85 9E sta $9E ; $E06B: 85 9E
00E06D 1
00E06D 1 ; ----------------------------------------------------------------------------
00E06D 1 ; Initialize the current object's timer to one.
00E06D 1 ;
00E06D 1 ; This is also the restart point after $E222 returns a nonzero result.
00E06D 1 ; ----------------------------------------------------------------------------
00E06D 1
00E06D 1 ObjectStateDispatch_SetTimer: ; $E06D
00E06D 1 A9 01 lda #$01 ; $E06D: A9 01
00E06F 1
00E06F 1 ObjectStateDispatch_StoreTimer: ; $E06F
00E06F 1 A6 E1 ldx CurrentObjectIndex ; $E06F: A6 E1
00E071 1 9D B1 05 sta $05B1,x ; $E071: 9D B1 05
00E074 1
00E074 1 ; ----------------------------------------------------------------------------
00E074 1 ; Wait for a frame and monitor the high two bits of InputAux2.
00E074 1 ; ----------------------------------------------------------------------------
00E074 1
00E074 1 ObjectStateDispatch_TimerLoop: ; $E074
00E074 1 20 48 EB jsr SelectObjectEventBank1 ; $E074: 20 48 EB
00E077 1
00E077 1 A5 18 lda InputAux2 ; $E077: A5 18
00E079 1 29 C0 and #$C0 ; $E079: 29 C0
00E07B 1 D0 0C bne ObjectStateDispatch_InputActive
00E07D 1 ; $E07B: D0 0C
00E07D 1
00E07D 1 ; ----------------------------------------------------------------------------
00E07D 1 ; No relevant input. Count the current object's timer down.
00E07D 1 ; ----------------------------------------------------------------------------
00E07D 1
00E07D 1 A6 E1 ldx CurrentObjectIndex ; $E07D: A6 E1
00E07F 1
00E07F 1 DE B1 05 dec $05B1,x ; $E07F: DE B1 05
00E082 1 D0 F0 bne ObjectStateDispatch_TimerLoop
00E084 1 ; $E082: D0 F0
00E084 1
00E084 1 ; ----------------------------------------------------------------------------
00E084 1 ; The timer expired. Run $E222.
00E084 1 ;
00E084 1 ; A nonzero result restarts the timer using the value currently in A.
00E084 1 ; A zero result falls through to $E089, but BNE is not taken there either,
00E084 1 ; allowing execution to continue at the next path at $E08B.
00E084 1 ; ----------------------------------------------------------------------------
00E084 1
00E084 1 20 22 E2 jsr ProcessSelectedObjectState ; $E084: 20 22 E2
00E087 1 D0 E6 bne ObjectStateDispatch_StoreTimer
00E089 1 ; $E087: D0 E6
00E089 1
00E089 1 ObjectStateDispatch_InputActive: ; $E089
00E089 1 D0 7C bne ObjectStateDispatch_ForwardPath
00E08B 1 ; $E089: D0 7C
00E08B 1 ; When reached from $E07B, branches to $E107.
00E08B 1 ; When reached after zero from $E222, falls
00E08B 1 ; through to $E08B.
00E08B 1
00E08B 1 ; ============================================================================
00E08B 1 ; $E08B-$E106
00E08B 1 ; Scan active object-state entries, evaluate their position and state tables,
00E08B 1 ; then wait for the next eligible input or state transition.
00E08B 1 ; ============================================================================
00E08B 1
00E08B 1 ObjectStateDispatch_NextPath: ; $E08B
00E08B 1 A6 E1 ldx CurrentObjectIndex ; $E08B: A6 E1
00E08D 1
00E08D 1 E0 04 cpx #$04 ; $E08D: E0 04
00E08F 1 D0 65 bne ObjectStateDispatch_WaitLoop
00E091 1 ; $E08F: D0 65
00E091 1
00E091 1 ; ----------------------------------------------------------------------------
00E091 1 ; Special setup for object offset $04.
00E091 1 ; ----------------------------------------------------------------------------
00E091 1
00E091 1 A9 12 lda #$12 ; $E091: A9 12
00E093 1 8D B2 03 sta $03B2 ; $E093: 8D B2 03
00E096 1
00E096 1 D0 5E bne ObjectStateDispatch_WaitLoop
00E098 1 ; $E096: D0 5E
00E098 1 ; Always taken because A is nonzero.
00E098 1
00E098 1 ; ============================================================================
00E098 1 ; $E098
00E098 1 ; Select the initial object-state table index.
00E098 1 ; ============================================================================
00E098 1
00E098 1 ObjectStateDispatch_SelectStart: ; $E098
00E098 1 A2 02 ldx #$02 ; $E098: A2 02
00E09A 1
00E09A 1 E4 64 cpx SecondarySequenceState ; $E09A: E4 64
00E09C 1 D0 07 bne ObjectStateDispatch_AdvanceIndex
00E09E 1 ; $E09C: D0 07
00E09E 1
00E09E 1 A5 BC lda $BC ; $E09E: A5 BC
00E0A0 1 D0 03 bne ObjectStateDispatch_AdvanceIndex
00E0A2 1 ; $E0A0: D0 03
00E0A2 1
00E0A2 1 ; ----------------------------------------------------------------------------
00E0A2 1 ; When SecondarySequenceState equals two and $BC is zero, use $BC as the initial index and
00E0A2 1 ; increment it for the next pass.
00E0A2 1 ; ----------------------------------------------------------------------------
00E0A2 1
00E0A2 1 AA tax ; $E0A2: AA
00E0A3 1 ; A is zero, so X becomes zero.
00E0A3 1
00E0A3 1 E6 BC inc $BC ; $E0A3: E6 BC
00E0A5 1
00E0A5 1 ObjectStateDispatch_AdvanceIndex: ; $E0A5
00E0A5 1 E8 inx ; $E0A5: E8
00E0A6 1 86 C3 stx $C3 ; $E0A6: 86 C3
00E0A8 1
00E0A8 1 ; ============================================================================
00E0A8 1 ; $E0A8
00E0A8 1 ; Search object-state entries beginning at index $C3.
00E0A8 1 ; ============================================================================
00E0A8 1
00E0A8 1 ObjectStateDispatch_Search: ; $E0A8
00E0A8 1 A6 C3 ldx $C3 ; $E0A8: A6 C3
00E0AA 1
00E0AA 1 BD 98 05 lda $0598,x ; $E0AA: BD 98 05
00E0AD 1 30 43 bmi ObjectStateDispatch_NextEntry
00E0AF 1 ; $E0AD: 30 43
00E0AF 1
00E0AF 1 ; ----------------------------------------------------------------------------
00E0AF 1 ; Load the corresponding compact state from zero-page $95-$98.
00E0AF 1 ; ----------------------------------------------------------------------------
00E0AF 1
00E0AF 1 B4 95 ldy $95,x ; $E0AF: B4 95
00E0B1 1 D0 04 bne ObjectStateDispatch_TestState
00E0B3 1 ; $E0B1: D0 04
00E0B3 1
00E0B3 1 ; ----------------------------------------------------------------------------
00E0B3 1 ; A zero compact state derives a value from the table index.
00E0B3 1 ;
00E0B3 1 ; A nonzero doubled X branches to the forward transition at
00E0B3 1 ; ObjectStateDispatch_ForwardTransition
00E0B3 1 ; ----------------------------------------------------------------------------
00E0B3 1
00E0B3 1 8A txa ; $E0B3: 8A
00E0B4 1 0A asl ; $E0B4: 0A
00E0B5 1 D0 5D bne ObjectStateDispatch_ForwardTransition
00E0B7 1 ; $E0B5: D0 5D
00E0B7 1
00E0B7 1 ; ----------------------------------------------------------------------------
00E0B7 1 ; Shift the compact state and reject entries whose low bit was clear.
00E0B7 1 ; ----------------------------------------------------------------------------
00E0B7 1
00E0B7 1 ObjectStateDispatch_TestState: ; $E0B7
00E0B7 1 4A lsr ; $E0B7: 4A
00E0B8 1 90 38 bcc ObjectStateDispatch_NextEntry
00E0BA 1 ; $E0B8: 90 38
00E0BA 1
00E0BA 1 85 C2 sta $C2 ; $E0BA: 85 C2
00E0BC 1 A8 tay ; $E0BC: A8
00E0BD 1 C8 iny ; $E0BD: C8
00E0BE 1
00E0BE 1 ; ----------------------------------------------------------------------------
00E0BE 1 ; Test the selected state using the helper at $E246.
00E0BE 1 ; ----------------------------------------------------------------------------
00E0BE 1
00E0BE 1 20 46 E2 jsr FindObjectStateForSelector ; $E0BE: 20 46 E2
00E0C1 1 10 09 bpl ObjectStateDispatch_CompareTables
00E0C3 1 ; $E0C1: 10 09
00E0C3 1
00E0C3 1 ; ----------------------------------------------------------------------------
00E0C3 1 ; A negative result is ignored while ObjectTransitionState is nonzero.
00E0C3 1 ;
00E0C3 1 ; Otherwise, increment A and transfer to the forward transition at
00E0C3 1 ; ObjectStateDispatch_ForwardTransition
00E0C3 1 ; ----------------------------------------------------------------------------
00E0C3 1
00E0C3 1 A4 6E ldy ObjectTransitionState ; $E0C3: A4 6E
00E0C5 1 D0 2B bne ObjectStateDispatch_NextEntry
00E0C7 1 ; $E0C5: D0 2B
00E0C7 1
00E0C7 1 18 clc ; $E0C7: 18
00E0C8 1 69 01 adc #$01 ; $E0C8: 69 01
00E0CA 1 D0 48 bne ObjectStateDispatch_ForwardTransition
00E0CC 1 ; $E0CA: D0 48
00E0CC 1
00E0CC 1 ; ============================================================================
00E0CC 1 ; $E0CC
00E0CC 1 ; Compare the selected object's high coordinate against overlapping lookup
00E0CC 1 ; tables at $E021, $E024, and $E027.
00E0CC 1 ; ============================================================================
00E0CC 1
00E0CC 1 ObjectStateDispatch_CompareTables: ; $E0CC
00E0CC 1 A4 C2 ldy $C2 ; $E0CC: A4 C2
00E0CE 1
00E0CE 1 A5 C3 lda $C3 ; $E0CE: A5 C3
00E0D0 1 0A asl ; $E0D0: 0A
00E0D1 1 AA tax ; $E0D1: AA
00E0D2 1
00E0D2 1 ; ----------------------------------------------------------------------------
00E0D2 1 ; Signed/bitwise first comparison.
00E0D2 1 ; ----------------------------------------------------------------------------
00E0D2 1
00E0D2 1 BD 10 05 lda $0510,x ; $E0D2: BD 10 05
00E0D5 1
00E0D5 1 F9 24 E0 sbc $E024,y ; $E0D5: F9 24 E0
00E0D8 1 59 27 E0 eor $E027,y ; $E0D8: 59 27 E0
00E0DB 1
00E0DB 1 10 15 bpl ObjectStateDispatch_NextEntry
00E0DD 1 ; $E0DB: 10 15
00E0DD 1
00E0DD 1 ; ----------------------------------------------------------------------------
00E0DD 1 ; Second comparison against the table beginning at $E021.
00E0DD 1 ;
00E0DD 1 ; ROL incorporates the comparison carry into Y.
00E0DD 1 ; ----------------------------------------------------------------------------
00E0DD 1
00E0DD 1 BD 10 05 lda $0510,x ; $E0DD: BD 10 05
00E0E0 1 D9 21 E0 cmp $E021,y ; $E0E0: D9 21 E0
00E0E3 1
00E0E3 1 98 tya ; $E0E3: 98
00E0E4 1 2A rol ; $E0E4: 2A
00E0E5 1 A8 tay ; $E0E5: A8
00E0E6 1
00E0E6 1 ; ----------------------------------------------------------------------------
00E0E6 1 ; Combine the indexed activity byte at $0573,X with the comparison result.
00E0E6 1 ; ----------------------------------------------------------------------------
00E0E6 1
00E0E6 1 BD 73 05 lda $0573,x ; $E0E6: BD 73 05
00E0E9 1 0A asl ; $E0E9: 0A
00E0EA 1
00E0EA 1 98 tya ; $E0EA: 98
00E0EB 1 2A rol ; $E0EB: 2A
00E0EC 1 A8 tay ; $E0EC: A8
00E0ED 1
00E0ED 1 B9 27 E0 lda $E027,y ; $E0ED: B9 27 E0
00E0F0 1 D0 22 bne ObjectStateDispatch_ForwardTransition
00E0F2 1 ; $E0F0: D0 22
00E0F2 1
00E0F2 1 ; ----------------------------------------------------------------------------
00E0F2 1 ; Reject this entry and continue searching backward.
00E0F2 1 ; ----------------------------------------------------------------------------
00E0F2 1
00E0F2 1 ObjectStateDispatch_NextEntry: ; $E0F2
00E0F2 1 C6 C3 dec $C3 ; $E0F2: C6 C3
00E0F4 1 10 B2 bpl ObjectStateDispatch_Search
00E0F6 1 ; $E0F4: 10 B2
00E0F6 1
00E0F6 1 ; ============================================================================
00E0F6 1 ; $E0F6
00E0F6 1 ; Wait until the global state and input conditions permit another scan.
00E0F6 1 ; ============================================================================
00E0F6 1
00E0F6 1 ObjectStateDispatch_WaitLoop: ; $E0F6
00E0F6 1 20 48 EB jsr SelectObjectEventBank1 ; $E0F6: 20 48 EB
00E0F9 1
00E0F9 1 A5 60 lda PendingStateTransition ; $E0F9: A5 60
00E0FB 1 D0 F9 bne ObjectStateDispatch_WaitLoop
00E0FD 1 ; $E0FB: D0 F9
00E0FD 1
00E0FD 1 ; ----------------------------------------------------------------------------
00E0FD 1 ; If $10 is zero, restart object-state selection at $E098.
00E0FD 1 ; ----------------------------------------------------------------------------
00E0FD 1
00E0FD 1 A5 10 lda $10 ; $E0FD: A5 10
00E0FF 1 F0 97 beq ObjectStateDispatch_SelectStart
00E101 1 ; $E0FF: F0 97
00E101 1
00E101 1 ; ----------------------------------------------------------------------------
00E101 1 ; Otherwise, wait until either of the high two bits in InputAux2 becomes set.
00E101 1 ; ----------------------------------------------------------------------------
00E101 1
00E101 1 A5 18 lda InputAux2 ; $E101: A5 18
00E103 1 29 C0 and #$C0 ; $E103: 29 C0
00E105 1 F0 EF beq ObjectStateDispatch_WaitLoop
00E107 1 ; $E105: F0 EF
00E107 1
00E107 1
00E107 1 ; ============================================================================
00E107 1 ; $E107-$E16B
00E107 1 ; Convert input state into an object-state selection, process event slot $1D,
00E107 1 ; assign the selected state to an object, and either retry geometry processing
00E107 1 ; or return to the main object-state dispatch loop.
00E107 1 ; ============================================================================
00E107 1
00E107 1 ObjectStateDispatch_ForwardPath: ; $E107
00E107 1 A2 FF ldx #$FF ; $E107: A2 FF
00E109 1
00E109 1 ; ----------------------------------------------------------------------------
00E109 1 ; Derive a compact index from InputState2.
00E109 1 ;
00E109 1 ; InputState2 is ORed with $F0, then shifted right until a zero bit reaches
00E109 1 ; carry. X begins at $FF and is incremented before each shift.
00E109 1 ; ----------------------------------------------------------------------------
00E109 1
00E109 1 A5 14 lda InputState2 ; $E109: A5 14
00E10B 1 09 F0 ora #$F0 ; $E10B: 09 F0
00E10D 1
00E10D 1 ObjectStateDispatch_FindInputIndex: ; $E10D
00E10D 1 E8 inx ; $E10D: E8
00E10E 1 4A lsr ; $E10E: 4A
00E10F 1 90 FC bcc ObjectStateDispatch_FindInputIndex
00E111 1 ; $E10F: 90 FC
00E111 1
00E111 1 ; ----------------------------------------------------------------------------
00E111 1 ; Use the resulting X index to select a byte from the lookup data beginning at
00E111 1 ; $E01D.
00E111 1 ; ----------------------------------------------------------------------------
00E111 1
00E111 1 BD 1D E0 lda $E01D,x ; $E111: BD 1D E0
00E114 1 ObjectStateDispatch_ForwardTransition:
00E114 1 48 pha ; $E114: 48
00E115 1
00E115 1 ; ----------------------------------------------------------------------------
00E115 1 ; Process event slot $1D and run two engine helpers.
00E115 1 ; ----------------------------------------------------------------------------
00E115 1
00E115 1 A0 1D ldy #$1D ; $E115: A0 1D
00E117 1 20 66 EB jsr DispatchNextQueuedEvent ; $E117: 20 66 EB
00E11A 1
00E11A 1 20 D3 E2 jsr ClearCurrentObjectMovement ; $E11A: 20 D3 E2
00E11D 1 20 E6 E3 jsr InitializeBaseObjectFromCurrent ; $E11D: 20 E6 E3
00E120 1
00E120 1 ; ----------------------------------------------------------------------------
00E120 1 ; Restore the selected lookup value and divide it by two.
00E120 1 ; Store the resulting compact state in $C2.
00E120 1 ; ----------------------------------------------------------------------------
00E120 1
00E120 1 68 pla ; $E120: 68
00E121 1 4A lsr ; $E121: 4A
00E122 1 85 C2 sta $C2 ; $E122: 85 C2
00E124 1
00E124 1 ; ----------------------------------------------------------------------------
00E124 1 ; Obtain the current object/event selector.
00E124 1 ; ----------------------------------------------------------------------------
00E124 1
00E124 1 20 DC E3 jsr GetCurrentObjectSelectorAndState ; $E124: 20 DC E3
00E127 1
00E127 1 A5 C2 lda $C2 ; $E127: A5 C2
00E129 1
00E129 1 ; ----------------------------------------------------------------------------
00E129 1 ; Adjust $BB for two special selector/state combinations:
00E129 1 ;
00E129 1 ; Y = $02 and A = $04 -> $BB = $01
00E129 1 ; Y = $04 and A = $02 -> $BB = $03
00E129 1 ; ----------------------------------------------------------------------------
00E129 1
00E129 1 C0 02 cpy #$02 ; $E129: C0 02
00E12B 1 D0 08 bne ObjectStateDispatch_CheckSelector4
00E12D 1 ; $E12B: D0 08
00E12D 1
00E12D 1 C9 04 cmp #$04 ; $E12D: C9 04
00E12F 1 D0 04 bne ObjectStateDispatch_CheckSelector4
00E131 1 ; $E12F: D0 04
00E131 1
00E131 1 A2 01 ldx #$01 ; $E131: A2 01
00E133 1 86 BB stx $BB ; $E133: 86 BB
00E135 1
00E135 1 ObjectStateDispatch_CheckSelector4: ; $E135
00E135 1 C0 04 cpy #$04 ; $E135: C0 04
00E137 1 D0 08 bne ObjectStateDispatch_AssignState
00E139 1 ; $E137: D0 08
00E139 1
00E139 1 C9 02 cmp #$02 ; $E139: C9 02
00E13B 1 D0 04 bne ObjectStateDispatch_AssignState
00E13D 1 ; $E13B: D0 04
00E13D 1
00E13D 1 A2 03 ldx #$03 ; $E13D: A2 03
00E13F 1 86 BB stx $BB ; $E13F: 86 BB
00E141 1
00E141 1 ; ----------------------------------------------------------------------------
00E141 1 ; Select the target object through $E25E.
00E141 1 ;
00E141 1 ; The helper returns an object offset in Y.
00E141 1 ; ----------------------------------------------------------------------------
00E141 1
00E141 1 ObjectStateDispatch_AssignState: ; $E141
00E141 1 20 5E E2 jsr FindNearestCandidateObject ; $E141: 20 5E E2
00E144 1
00E144 1 ; ----------------------------------------------------------------------------
00E144 1 ; Convert the object offset in Y into a compact object-state index and store
00E144 1 ; the selected state from $C2 into $0595,X.
00E144 1 ; ----------------------------------------------------------------------------
00E144 1
00E144 1 98 tya ; $E144: 98
00E145 1 4A lsr ; $E145: 4A
00E146 1 AA tax ; $E146: AA
00E147 1
00E147 1 A5 C2 lda $C2 ; $E147: A5 C2
00E149 1 9D 95 05 sta $0595,x ; $E149: 9D 95 05
00E14C 1
00E14C 1 ; ----------------------------------------------------------------------------
00E14C 1 ; Compare the selected object offset in Y against CurrentObjectIndex.
00E14C 1 ;
00E14C 1 ; If they differ, continue at the next path at $E16C.
00E14C 1 ; ----------------------------------------------------------------------------
00E14C 1
00E14C 1 C4 E1 cpy CurrentObjectIndex ; $E14C: C4 E1
00E14E 1 D0 1C bne ObjectStateDispatch_DifferentObject
00E150 1 ; $E14E: D0 1C
00E150 1
00E150 1 ; ----------------------------------------------------------------------------
00E150 1 ; The selected object is the current object.
00E150 1 ;
00E150 1 ; Prepare and test its geometry. Carry set runs $E313 and retries the test.
00E150 1 ; ----------------------------------------------------------------------------
00E150 1
00E150 1 ObjectStateDispatch_TestSelectedObject: ; $E150
00E150 1 20 74 E4 jsr SelectGeometryRecord_Default ; $E150: 20 74 E4
00E153 1 20 5F E5 jsr ApplyCurrentObjectGeometry ; $E153: 20 5F E5
00E156 1
00E156 1 90 06 bcc ObjectStateDispatch_SelectedObjectClear
00E158 1 ; $E156: 90 06
00E158 1
00E158 1 20 13 E3 jsr UpdateCurrentObjectAnimationAndWait ; $E158: 20 13 E3
00E15B 1 4C 50 E1 jmp ObjectStateDispatch_TestSelectedObject
00E15E 1 ; $E15B: 4C 50 E1
00E15E 1
00E15E 1 ; ----------------------------------------------------------------------------
00E15E 1 ; Geometry cleared.
00E15E 1 ;
00E15E 1 ; Update the current object's display state, derive its selector, save that
00E15E 1 ; selector in $9E, run the engine helper, and return to the setup path at
00E15E 1 ; $E040.
00E15E 1 ; ----------------------------------------------------------------------------
00E15E 1
00E15E 1 ObjectStateDispatch_SelectedObjectClear: ; $E15E
00E15E 1 20 D4 DF jsr UpdateCurrentObjectDisplayState
00E161 1 ; $E15E: 20 D4 DF
00E161 1
00E161 1 20 DC E3 jsr GetCurrentObjectSelectorAndState ; $E161: 20 DC E3
00E164 1 84 9E sty $9E ; $E164: 84 9E
00E166 1
00E166 1 20 E6 E3 jsr InitializeBaseObjectFromCurrent ; $E166: 20 E6 E3
00E169 1
00E169 1 4C 40 E0 jmp ProcessObjectStateSelection ; $E169: 4C 40 E0
00E16C 1
00E16C 1 ; ============================================================================
00E16C 1 ; $E16C-$E1CD
00E16C 1 ; Process the selected object's event, update its animation, wait, and leave
00E16C 1 ; through the common engine exit.
00E16C 1 ;
00E16C 1 ; Entry:
00E16C 1 ; Y = selected object/event offset returned by $E25E
00E16C 1 ; $C2 = selected compact state
00E16C 1 ; ============================================================================
00E16C 1
00E16C 1 ObjectStateDispatch_DifferentObject: ; $E16C
00E16C 1 84 C4 sty $C4 ; $E16C: 84 C4
00E16E 1
00E16E 1 ; ----------------------------------------------------------------------------
00E16E 1 ; Process the selected object's event slot and wait ten ticks.
00E16E 1 ; ----------------------------------------------------------------------------
00E16E 1
00E16E 1 20 66 EB jsr DispatchNextQueuedEvent ; $E16E: 20 66 EB
00E171 1
00E171 1 A9 0A lda #$0A ; $E171: A9 0A
00E173 1 20 41 EB jsr StoreObjectEventBankValue ; $E173: 20 41 EB
00E176 1
00E176 1 ; ----------------------------------------------------------------------------
00E176 1 ; Dispatch the selected object through $E29B.
00E176 1 ;
00E176 1 ; X is restored from $C4. The inline record contains a leading zero byte and
00E176 1 ; stored address $E3AB. The exact dispatch convention will be confirmed when
00E176 1 ; $E29B and $E3AB are decoded.
00E176 1 ; ----------------------------------------------------------------------------
00E176 1
00E176 1 A6 C4 ldx $C4 ; $E176: A6 C4
00E178 1 20 9B E2 jsr DispatchInlineObjectCommand ; $E178: 20 9B E2
00E17B 1
00E17B 1 00 AB E3 .byte $00,$AB,$E3 ; $E17B-$E17D
00E17E 1
00E17E 1 ; ----------------------------------------------------------------------------
00E17E 1 ; Run the shared engine update, then clear $9E.
00E17E 1 ; ----------------------------------------------------------------------------
00E17E 1
00E17E 1 20 E6 E3 jsr InitializeBaseObjectFromCurrent ; $E17E: 20 E6 E3
00E181 1
00E181 1 A9 00 lda #$00 ; $E181: A9 00
00E183 1 85 9E sta $9E ; $E183: 85 9E
00E185 1
00E185 1 ; ----------------------------------------------------------------------------
00E185 1 ; Object offset $04 uses a short alternate exit at $E1C6.
00E185 1 ; ----------------------------------------------------------------------------
00E185 1
00E185 1 A6 E1 ldx CurrentObjectIndex ; $E185: A6 E1
00E187 1 E0 04 cpx #$04 ; $E187: E0 04
00E189 1 F0 3B beq ObjectStateDispatch_Object04
00E18B 1 ; $E189: F0 3B
00E18B 1
00E18B 1 ; ----------------------------------------------------------------------------
00E18B 1 ; Select an animation attribute according to $C2 and the sign of the current
00E18B 1 ; object's high horizontal coordinate.
00E18B 1 ;
00E18B 1 ; The table access intentionally uses base $DFCD.
00E18B 1 ; ----------------------------------------------------------------------------
00E18B 1
00E18B 1 A6 E1 ldx CurrentObjectIndex ; $E18B: A6 E1
00E18D 1
00E18D 1 A4 C2 ldy $C2 ; $E18D: A4 C2
00E18F 1 B9 CD DF lda $DFCD,y ; $E18F: B9 CD DF
00E192 1
00E192 1 A0 3F ldy #$3F ; $E192: A0 3F
00E194 1
00E194 1 DD 0A 05 cmp $050A,x ; $E194: DD 0A 05
00E197 1 10 02 bpl ObjectStateDispatch_SaveFirstFrame
00E199 1 ; $E197: 10 02
00E199 1
00E199 1 A0 40 ldy #$40 ; $E199: A0 40
00E19B 1
00E19B 1 ; ----------------------------------------------------------------------------
00E19B 1 ; Convert CurrentObjectIndex to the compact sprite-array index.
00E19B 1 ; ----------------------------------------------------------------------------
00E19B 1
00E19B 1 ObjectStateDispatch_SaveFirstFrame: ; $E19B
00E19B 1 A5 E1 lda CurrentObjectIndex ; $E19B: A5 E1
00E19D 1 4A lsr ; $E19D: 4A
00E19E 1 AA tax ; $E19E: AA
00E19F 1
00E19F 1 ; ----------------------------------------------------------------------------
00E19F 1 ; Compact indices below $0C receive the selected attribute $3F/$40.
00E19F 1 ; ----------------------------------------------------------------------------
00E19F 1
00E19F 1 E0 0C cpx #$0C ; $E19F: E0 0C
00E1A1 1 B0 04 bcs ObjectStateDispatch_SaveFrame5F
00E1A3 1 ; $E1A1: B0 04
00E1A3 1
00E1A3 1 98 tya ; $E1A3: 98
00E1A4 1 9D B0 03 sta $03B0,x ; $E1A4: 9D B0 03
00E1A7 1
00E1A7 1 ObjectStateDispatch_SaveFrame5F: ; $E1A7
00E1A7 1 A9 5F lda #$5F ; $E1A7: A9 5F
00E1A9 1 9D 9B 03 sta $039B,x ; $E1A9: 9D 9B 03
00E1AC 1
00E1AC 1 ; ----------------------------------------------------------------------------
00E1AC 1 ; Hold this animation for $3C ticks.
00E1AC 1 ; ----------------------------------------------------------------------------
00E1AC 1
00E1AC 1 A9 3C lda #$3C ; $E1AC: A9 3C
00E1AE 1 20 41 EB jsr StoreObjectEventBankValue ; $E1AE: 20 41 EB
00E1B1 1
00E1B1 1 ; ----------------------------------------------------------------------------
00E1B1 1 ; Replace the animation with frame $67. Compact indices below $0C also receive
00E1B1 1 ; attribute $2F.
00E1B1 1 ; ----------------------------------------------------------------------------
00E1B1 1
00E1B1 1 A5 E1 lda CurrentObjectIndex ; $E1B1: A5 E1
00E1B3 1 4A lsr ; $E1B3: 4A
00E1B4 1 AA tax ; $E1B4: AA
00E1B5 1
00E1B5 1 E0 0C cpx #$0C ; $E1B5: E0 0C
00E1B7 1 B0 05 bcs ObjectStateDispatch_SaveFrame67
00E1B9 1 ; $E1B7: B0 05
00E1B9 1
00E1B9 1 A9 2F lda #$2F ; $E1B9: A9 2F
00E1BB 1 9D B0 03 sta $03B0,x ; $E1BB: 9D B0 03
00E1BE 1
00E1BE 1 ObjectStateDispatch_SaveFrame67: ; $E1BE
00E1BE 1 A9 67 lda #$67 ; $E1BE: A9 67
00E1C0 1 9D 9B 03 sta $039B,x ; $E1C0: 9D 9B 03
00E1C3 1
00E1C3 1 4C 6A EB jmp CommonEngineExit ; $E1C3: 4C 6A EB
00E1C6 1
00E1C6 1 ; ----------------------------------------------------------------------------
00E1C6 1 ; Special exit for object offset $04.
00E1C6 1 ; ----------------------------------------------------------------------------
00E1C6 1
00E1C6 1 ObjectStateDispatch_Object04: ; $E1C6
00E1C6 1 A9 13 lda #$13 ; $E1C6: A9 13
00E1C8 1 8D B2 03 sta $03B2 ; $E1C8: 8D B2 03
00E1CB 1
00E1CB 1 4C 6A EB jmp CommonEngineExit ; $E1CB: 4C 6A EB
00E1CE 1
00E1CE 1 ; ============================================================================
00E1CE 1 ; $E1CE-$E1E6
00E1CE 1 ; Repeat the geometry test while its result is at least two.
00E1CE 1 ;
00E1CE 1 ; The loop permits up to four geometry-test attempts.
00E1CE 1 ;
00E1CE 1 ; Return:
00E1CE 1 ; A < $02, or the four-attempt counter expired.
00E1CE 1 ; ============================================================================
00E1CE 1
00E1CE 1 ; ----------------------------------------------------------------------------
00E1CE 1 ; Contract:
00E1CE 1 ; Description: Implements Test Object Geometry Four Times.
00E1CE 1 ; Entry: Registers: A, Y
00E1CE 1 ; Returns/products: Registers/clobbers: Y
00E1CE 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E1CE 1 ; Memory effects: $c2
00E1CE 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E1CE 1 ; comparison, load, or store path and are not a stable API product.
00E1CE 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E1CE 1 ; ----------------------------------------------------------------------------
00E1CE 1 TestObjectGeometryFourTimes: ; $E1CE
00E1CE 1 A0 04 ldy #$04 ; $E1CE: A0 04
00E1D0 1 84 C2 sty $C2 ; $E1D0: 84 C2
00E1D2 1
00E1D2 1 TestObjectGeometryFourTimes_Loop: ; $E1D2
00E1D2 1 20 74 E4 jsr SelectGeometryRecord_Default ; $E1D2: 20 74 E4
00E1D5 1 20 C2 E4 jsr LoadGeometryRecord ; $E1D5: 20 C2 E4
00E1D8 1 20 DB E4 jsr CalculateCurrentGeometryDifference ; $E1D8: 20 DB E4
00E1DB 1 20 02 E5 jsr EvaluateGeometryDifference ; $E1DB: 20 02 E5
00E1DE 1
00E1DE 1 C9 02 cmp #$02 ; $E1DE: C9 02
00E1E0 1 90 04 bcc TestObjectGeometryFourTimes_Return
00E1E2 1 ; $E1E0: 90 04
00E1E2 1
00E1E2 1 C6 C2 dec $C2 ; $E1E2: C6 C2
00E1E4 1 D0 EC bne TestObjectGeometryFourTimes_Loop
00E1E6 1 ; $E1E4: D0 EC
00E1E6 1
00E1E6 1 TestObjectGeometryFourTimes_Return: ; $E1E6
00E1E6 1 60 rts ; $E1E6: 60
00E1E7 1
00E1E7 1 ; ============================================================================
00E1E7 1 ; $E1E7-$E200
00E1E7 1 ; Search object-state entries $0598-$059B for an eligible geometry result.
00E1E7 1 ;
00E1E7 1 ; The routine scans indices three through zero. An entry is eligible when:
00E1E7 1 ;
00E1E7 1 ; 1. Its state byte is nonnegative.
00E1E7 1 ; 2. Bit zero of the state byte is set.
00E1E7 1 ; 3. Its geometry-test result is at least $0C.
00E1E7 1 ;
00E1E7 1 ; Return:
00E1E7 1 ; C = clear when a qualifying entry is found
00E1E7 1 ; C = set when no entry qualifies
00E1E7 1 ;
00E1E7 1 ; $C3 = qualifying index, or $FF after the search is exhausted
00E1E7 1 ; ============================================================================
00E1E7 1
00E1E7 1 ; ----------------------------------------------------------------------------
00E1E7 1 ; Contract:
00E1E7 1 ; Description: Implements Find Eligible Object State.
00E1E7 1 ; Entry: Registers: A, Y; Memory: $0598, $c3
00E1E7 1 ; Returns/products: Registers/clobbers: A, Y
00E1E7 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E1E7 1 ; Memory effects: $c3
00E1E7 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E1E7 1 ; comparison, load, or store path and are not a stable API product.
00E1E7 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E1E7 1 ; ----------------------------------------------------------------------------
00E1E7 1 FindEligibleObjectState: ; $E1E7
00E1E7 1 A0 03 ldy #$03 ; $E1E7: A0 03
00E1E9 1
00E1E9 1 ; ----------------------------------------------------------------------------
00E1E9 1 ; Save the current table index.
00E1E9 1 ; ----------------------------------------------------------------------------
00E1E9 1
00E1E9 1 FindEligibleObjectState_Loop: ; $E1E9
00E1E9 1 84 C3 sty $C3 ; $E1E9: 84 C3
00E1EB 1
00E1EB 1 ; ----------------------------------------------------------------------------
00E1EB 1 ; Reject inactive entries whose state byte is negative.
00E1EB 1 ; ----------------------------------------------------------------------------
00E1EB 1
00E1EB 1 B9 98 05 lda $0598,y ; $E1EB: B9 98 05
00E1EE 1 30 0A bmi FindEligibleObjectState_Next
00E1F0 1 ; $E1EE: 30 0A
00E1F0 1
00E1F0 1 ; ----------------------------------------------------------------------------
00E1F0 1 ; Shift the state byte and reject entries whose low bit was clear.
00E1F0 1 ; ----------------------------------------------------------------------------
00E1F0 1
00E1F0 1 4A lsr ; $E1F0: 4A
00E1F1 1 90 07 bcc FindEligibleObjectState_Next
00E1F3 1 ; $E1F1: 90 07
00E1F3 1
00E1F3 1 ; ----------------------------------------------------------------------------
00E1F3 1 ; Test the geometry associated with the current state-table index.
00E1F3 1 ;
00E1F3 1 ; Results below $0C qualify and return immediately with carry clear from
00E1F3 1 ; CMP #$0C. Results at least $0C continue searching.
00E1F3 1 ; ----------------------------------------------------------------------------
00E1F3 1
00E1F3 1 20 01 E2 jsr TestIndexedObjectGeometry
00E1F6 1 ; $E1F3: 20 01 E2
00E1F6 1
00E1F6 1 C9 0C cmp #$0C ; $E1F6: C9 0C
00E1F8 1 90 06 bcc FindEligibleObjectState_Return
00E1FA 1 ; $E1F8: 90 06
00E1FA 1
00E1FA 1 ; ----------------------------------------------------------------------------
00E1FA 1 ; Continue with the preceding state-table index.
00E1FA 1 ; ----------------------------------------------------------------------------
00E1FA 1
00E1FA 1 FindEligibleObjectState_Next: ; $E1FA
00E1FA 1 A4 C3 ldy $C3 ; $E1FA: A4 C3
00E1FC 1 88 dey ; $E1FC: 88
00E1FD 1 10 EA bpl FindEligibleObjectState_Loop
00E1FF 1 ; $E1FD: 10 EA
00E1FF 1
00E1FF 1 ; ----------------------------------------------------------------------------
00E1FF 1 ; No entry qualified. Return carry set.
00E1FF 1 ; ----------------------------------------------------------------------------
00E1FF 1
00E1FF 1 38 sec ; $E1FF: 38
00E200 1
00E200 1 FindEligibleObjectState_Return: ; $E200
00E200 1 60 rts ; $E200: 60
00E201 1
00E201 1 ; ============================================================================
00E201 1 ; $E201-$E221
00E201 1 ; Copy coordinates for the state-table entry selected in $C3 into the geometry
00E201 1 ; arguments, process them, and test the resulting region.
00E201 1 ;
00E201 1 ; Entry:
00E201 1 ; $C3 = compact object/state index
00E201 1 ;
00E201 1 ; Return:
00E201 1 ; A = result returned by $E502
00E201 1 ; Flags from CMP #$03
00E201 1 ; ============================================================================
00E201 1
00E201 1 TestIndexedObjectGeometry: ; $E201
00E201 1 A5 C3 lda $C3 ; $E201: A5 C3
00E203 1 0A asl ; $E203: 0A
00E204 1 A8 tay ; $E204: A8
00E205 1 ; Convert compact index to object-array offset.
00E205 1
00E205 1 ; ----------------------------------------------------------------------------
00E205 1 ; Copy the selected object's horizontal coordinate.
00E205 1 ; ----------------------------------------------------------------------------
00E205 1
00E205 1 B9 0F 05 lda $050F,y ; $E205: B9 0F 05
00E208 1 85 B2 sta $B2 ; $E208: 85 B2
00E20A 1
00E20A 1 B9 10 05 lda $0510,y ; $E20A: B9 10 05
00E20D 1 85 B3 sta $B3 ; $E20D: 85 B3
00E20F 1
00E20F 1 ; ----------------------------------------------------------------------------
00E20F 1 ; Copy the selected object's vertical coordinate.
00E20F 1 ; ----------------------------------------------------------------------------
00E20F 1
00E20F 1 B9 40 05 lda $0540,y ; $E20F: B9 40 05
00E212 1 85 B4 sta $B4 ; $E212: 85 B4
00E214 1
00E214 1 B9 41 05 lda $0541,y ; $E214: B9 41 05
00E217 1 85 B5 sta $B5 ; $E217: 85 B5
00E219 1
00E219 1 ; ----------------------------------------------------------------------------
00E219 1 ; Process the coordinates and perform the final geometry test.
00E219 1 ; ----------------------------------------------------------------------------
00E219 1
00E219 1 20 DB E4 jsr CalculateCurrentGeometryDifference ; $E219: 20 DB E4
00E21C 1 20 02 E5 jsr EvaluateGeometryDifference ; $E21C: 20 02 E5
00E21F 1
00E21F 1 C9 03 cmp #$03 ; $E21F: C9 03
00E221 1 60 rts ; $E221: 60
00E222 1
00E222 1 ; ============================================================================
00E222 1 ; $E222-$E245
00E222 1 ; Derive an object-state index, test its geometry, and route according to the
00E222 1 ; result.
00E222 1 ;
00E222 1 ; Return behavior:
00E222 1 ; This helper does not return directly. Both paths tail-jump elsewhere.
00E222 1 ; ============================================================================
00E222 1
00E222 1 ; ----------------------------------------------------------------------------
00E222 1 ; Contract:
00E222 1 ; Description: Processes Selected Object State.
00E222 1 ; Entry: Registers: A, Y
00E222 1 ; Returns/products: Registers/clobbers: A
00E222 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E222 1 ; Memory effects: $c3
00E222 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E222 1 ; comparison, load, or store path and are not a stable API product.
00E222 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E222 1 ; ----------------------------------------------------------------------------
00E222 1 ProcessSelectedObjectState: ; $E222
00E222 1 20 DC E3 jsr GetCurrentObjectSelectorAndState ; $E222: 20 DC E3
00E225 1
00E225 1 ; ----------------------------------------------------------------------------
00E225 1 ; Complement the selector returned in Y and save it in $C3.
00E225 1 ; ----------------------------------------------------------------------------
00E225 1
00E225 1 98 tya ; $E225: 98
00E226 1 49 FF eor #$FF ; $E226: 49 FF
00E228 1 85 C3 sta $C3 ; $E228: 85 C3
00E22A 1
00E22A 1 ; ----------------------------------------------------------------------------
00E22A 1 ; Test the geometry for the selected entry.
00E22A 1 ;
00E22A 1 ; TestIndexedObjectGeometry returns flags from CMP #$03.
00E22A 1 ; Carry clear means the result is below three.
00E22A 1 ; ----------------------------------------------------------------------------
00E22A 1
00E22A 1 20 01 E2 jsr TestIndexedObjectGeometry
00E22D 1 ; $E22A: 20 01 E2
00E22D 1
00E22D 1 90 0B bcc ProcessSelectedObjectState_Clear
00E22F 1 ; $E22D: 90 0B
00E22F 1
00E22F 1 ; ----------------------------------------------------------------------------
00E22F 1 ; Geometry result is at least three.
00E22F 1 ;
00E22F 1 ; Configure value $0F, apply the geometry helpers, and jump to $E2DE.
00E22F 1 ; ----------------------------------------------------------------------------
00E22F 1
00E22F 1 A9 0F lda #$0F ; $E22F: A9 0F
00E231 1
00E231 1 20 13 E5 jsr BuildGeometryVector ; $E231: 20 13 E5
00E234 1 20 28 E5 jsr StoreCurrentObjectMovement ; $E234: 20 28 E5
00E237 1
00E237 1 4C DE E2 jmp UpdateCurrentObjectAnimationDelay ; $E237: 4C DE E2
00E23A 1
00E23A 1 ; ----------------------------------------------------------------------------
00E23A 1 ; Geometry result is below three.
00E23A 1 ;
00E23A 1 ; Run the state-update helpers, then return to the object-state dispatch path
00E23A 1 ; at $E08B.
00E23A 1 ; ----------------------------------------------------------------------------
00E23A 1
00E23A 1 ProcessSelectedObjectState_Clear: ; $E23A
00E23A 1 20 D3 E2 jsr ClearCurrentObjectMovement ; $E23A: 20 D3 E2
00E23D 1 20 E6 E3 jsr InitializeBaseObjectFromCurrent ; $E23D: 20 E6 E3
00E240 1 20 84 E3 jsr ProcessCompactObjectState_Validate ; $E240: 20 84 E3
00E243 1
00E243 1 4C 8B E0 jmp ObjectStateDispatch_NextPath
00E246 1 ; $E243: 4C 8B E0
00E246 1
00E246 1 ; ============================================================================
00E246 1 ; $E246-$E25D
00E246 1 ; Search the object-state entries at $0598-$059B using a caller-supplied
00E246 1 ; selector in Y.
00E246 1 ;
00E246 1 ; Entry:
00E246 1 ; Y = one-based selector value
00E246 1 ;
00E246 1 ; Exit:
00E246 1 ; X = selected state-table index, normally $00-$03
00E246 1 ; Y = adjusted selector value
00E246 1 ;
00E246 1 ; If $0598 is zero, the routine returns immediately without performing the
00E246 1 ; search.
00E246 1 ;
00E246 1 ; The comparison intentionally uses base address $0597,X. Since X begins at
00E246 1 ; four and is decremented after unsuccessful comparisons, the effective
00E246 1 ; entries are $059B, $059A, $0599, and $0598.
00E246 1 ; ============================================================================
00E246 1
00E246 1 ; ----------------------------------------------------------------------------
00E246 1 ; Contract:
00E246 1 ; Description: Implements Find Object State For Selector.
00E246 1 ; Entry: Registers: A, X, Y; Memory: $0598, $0597
00E246 1 ; Returns/products: Registers/clobbers: A, X, Y; Flags: condition flags may carry result state
00E246 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E246 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00E246 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E246 1 ; comparison, load, or store path and are not a stable API product.
00E246 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 2.
00E246 1 ; ----------------------------------------------------------------------------
00E246 1 FindObjectStateForSelector: ; $E246
00E246 1 AD 98 05 lda $0598 ; $E246: AD 98 05
00E249 1 F0 12 beq FindObjectStateForSelector_Return
00E24B 1 ; $E249: F0 12
00E24B 1
00E24B 1 ; ----------------------------------------------------------------------------
00E24B 1 ; Convert the one-based selector in Y into an odd comparison value:
00E24B 1 ;
00E24B 1 ; A = ((Y - 1) * 2) + 1
00E24B 1 ;
00E24B 1 ; Y itself remains decremented by one.
00E24B 1 ; ----------------------------------------------------------------------------
00E24B 1
00E24B 1 88 dey ; $E24B: 88
00E24C 1
00E24C 1 98 tya ; $E24C: 98
00E24D 1 0A asl ; $E24D: 0A
00E24E 1 69 01 adc #$01 ; $E24E: 69 01
00E250 1
00E250 1 ; ----------------------------------------------------------------------------
00E250 1 ; Search the four state entries in reverse order.
00E250 1 ;
00E250 1 ; The indexed base is deliberately one byte before $0598:
00E250 1 ;
00E250 1 ; X=$04 -> $059B
00E250 1 ; X=$03 -> $059A
00E250 1 ; X=$02 -> $0599
00E250 1 ; X=$01 -> $0598
00E250 1 ; ----------------------------------------------------------------------------
00E250 1
00E250 1 A2 04 ldx #$04 ; $E250: A2 04
00E252 1
00E252 1 FindObjectStateForSelector_Search: ; $E252
00E252 1 DD 97 05 cmp $0597,x ; $E252: DD 97 05
00E255 1 90 03 bcc FindObjectStateForSelector_Previous
00E257 1 ; $E255: 90 03
00E257 1
00E257 1 ; ----------------------------------------------------------------------------
00E257 1 ; The current table value is not greater than A.
00E257 1 ;
00E257 1 ; Decrement Y once more. If it becomes negative, return immediately.
00E257 1 ; Otherwise, keep the current X.
00E257 1 ; ----------------------------------------------------------------------------
00E257 1
00E257 1 88 dey ; $E257: 88
00E258 1 30 03 bmi FindObjectStateForSelector_Return
00E25A 1 ; $E258: 30 03
00E25A 1
00E25A 1 ; ----------------------------------------------------------------------------
00E25A 1 ; Continue searching the preceding table entry.
00E25A 1 ; ----------------------------------------------------------------------------
00E25A 1
00E25A 1 FindObjectStateForSelector_Previous: ; $E25A
00E25A 1 CA dex ; $E25A: CA
00E25B 1 D0 F5 bne FindObjectStateForSelector_Search
00E25D 1 ; $E25B: D0 F5
00E25D 1
00E25D 1 FindObjectStateForSelector_Return: ; $E25D
00E25D 1 60 rts ; $E25D: 60
00E25E 1
00E25E 1 ; ============================================================================
00E25E 1 ; $E25E-$E294
00E25E 1 ; Find the nearest candidate object from a six-entry object-offset table.
00E25E 1 ;
00E25E 1 ; Entry:
00E25E 1 ; $C2 = index selecting a signed coordinate adjustment from the overlapping
00E25E 1 ; tables at $DFCA and $DFCB
00E25E 1 ;
00E25E 1 ; Exit:
00E25E 1 ; X = selected candidate-table index, $00-$05
00E25E 1 ; Y = selected object offset:
00E25E 1 ; $04, $0E, $10, $12, $14, or $16
00E25E 1 ;
00E25E 1 ; Working values:
00E25E 1 ; $06 = smallest distance found, initialized to $FF
00E25E 1 ; $05 = candidate-table index associated with that distance
00E25E 1 ; $41 = current candidate-table index
00E25E 1 ; ============================================================================
00E25E 1
00E25E 1 ; ----------------------------------------------------------------------------
00E25E 1 ; Contract:
00E25E 1 ; Description: Implements Find Nearest Candidate Object.
00E25E 1 ; Entry: Registers: A, X; Memory: $c2, $050a, $dfcb, $053b, $dfca, $06, $41
00E25E 1 ; Returns/products: Registers/clobbers: A, X, Y
00E25E 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E25E 1 ; Memory effects: $06, $41, mathtemp05
00E25E 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E25E 1 ; comparison, load, or store path and are not a stable API product.
00E25E 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E25E 1 ; ----------------------------------------------------------------------------
00E25E 1 FindNearestCandidateObject: ; $E25E
00E25E 1 A9 FF lda #$FF ; $E25E: A9 FF
00E260 1 85 06 sta $06 ; $E260: 85 06
00E262 1 ; Initialize best distance to the maximum.
00E262 1
00E262 1 A2 05 ldx #$05 ; $E262: A2 05
00E264 1
00E264 1 ; ----------------------------------------------------------------------------
00E264 1 ; Save the current candidate-table index.
00E264 1 ; ----------------------------------------------------------------------------
00E264 1
00E264 1 FindNearestCandidateObject_Loop: ; $E264
00E264 1 86 41 stx $41 ; $E264: 86 41
00E266 1
00E266 1 ; ----------------------------------------------------------------------------
00E266 1 ; Load the candidate object offset into Y.
00E266 1 ; ----------------------------------------------------------------------------
00E266 1
00E266 1 BC 95 E2 ldy CandidateObjectOffsetTable,x
00E269 1 ; $E266: BC 95 E2
00E269 1
00E269 1 ; ----------------------------------------------------------------------------
00E269 1 ; Load the signed coordinate-adjustment index.
00E269 1 ; ----------------------------------------------------------------------------
00E269 1
00E269 1 A6 C2 ldx $C2 ; $E269: A6 C2
00E26B 1
00E26B 1 ; ----------------------------------------------------------------------------
00E26B 1 ; Calculate the adjusted horizontal high coordinate:
00E26B 1 ;
00E26B 1 ; candidateXHi + $DFCB,X
00E26B 1 ;
00E26B 1 ; The result is preserved on the stack.
00E26B 1 ; ----------------------------------------------------------------------------
00E26B 1
00E26B 1 18 clc ; $E26B: 18
00E26C 1
00E26C 1 B9 0A 05 lda $050A,y ; $E26C: B9 0A 05
00E26F 1 7D CB DF adc $DFCB,x ; $E26F: 7D CB DF
00E272 1
00E272 1 48 pha ; $E272: 48
00E273 1
00E273 1 ; ----------------------------------------------------------------------------
00E273 1 ; Calculate the adjusted vertical high coordinate:
00E273 1 ;
00E273 1 ; candidateYHi + $DFCA,X
00E273 1 ;
00E273 1 ; The result is passed to $E80B in Y.
00E273 1 ; ----------------------------------------------------------------------------
00E273 1
00E273 1 18 clc ; $E273: 18
00E274 1
00E274 1 B9 3B 05 lda $053B,y ; $E274: B9 3B 05
00E277 1 7D CA DF adc $DFCA,x ; $E277: 7D CA DF
00E27A 1
00E27A 1 A8 tay ; $E27A: A8
00E27B 1
00E27B 1 ; ----------------------------------------------------------------------------
00E27B 1 ; Restore the adjusted horizontal value into X and calculate a distance or
00E27B 1 ; magnitude through $E80B.
00E27B 1 ; ----------------------------------------------------------------------------
00E27B 1
00E27B 1 68 pla ; $E27B: 68
00E27C 1 AA tax ; $E27C: AA
00E27D 1
00E27D 1 20 0B E8 jsr CalculateVectorMagnitude ; $E27D: 20 0B E8
00E280 1
00E280 1 ; ----------------------------------------------------------------------------
00E280 1 ; Keep this candidate only when its returned distance in A is lower than the
00E280 1 ; current best distance in $06.
00E280 1 ; ----------------------------------------------------------------------------
00E280 1
00E280 1 C5 06 cmp $06 ; $E280: C5 06
00E282 1 B0 06 bcs FindNearestCandidateObject_Next
00E284 1 ; $E282: B0 06
00E284 1
00E284 1 85 06 sta $06 ; $E284: 85 06
00E286 1
00E286 1 A5 41 lda $41 ; $E286: A5 41
00E288 1 85 05 sta MathTemp05 ; $E288: 85 05
00E28A 1 ; Save the winning candidate-table index.
00E28A 1
00E28A 1 ; ----------------------------------------------------------------------------
00E28A 1 ; Continue through all six candidate entries, from index five down to zero.
00E28A 1 ; ----------------------------------------------------------------------------
00E28A 1
00E28A 1 FindNearestCandidateObject_Next: ; $E28A
00E28A 1 A6 41 ldx $41 ; $E28A: A6 41
00E28C 1 CA dex ; $E28C: CA
00E28D 1 10 D5 bpl FindNearestCandidateObject_Loop
00E28F 1 ; $E28D: 10 D5
00E28F 1
00E28F 1 ; ----------------------------------------------------------------------------
00E28F 1 ; Return the winning candidate-table index in X and its object offset in Y.
00E28F 1 ; ----------------------------------------------------------------------------
00E28F 1
00E28F 1 A6 05 ldx MathTemp05 ; $E28F: A6 05
00E291 1 BC 95 E2 ldy CandidateObjectOffsetTable,x
00E294 1 ; $E291: BC 95 E2
00E294 1
00E294 1 60 rts ; $E294: 60
00E295 1
00E295 1 ; ============================================================================
00E295 1 ; $E295-$E29A
00E295 1 ; Candidate object offsets searched by FindNearestCandidateObject.
00E295 1 ;
00E295 1 ; The values are even object-array offsets. Their compact indices are obtained
00E295 1 ; by dividing by two.
00E295 1 ; ============================================================================
00E295 1
00E295 1 CandidateObjectOffsetTable: ; $E295
00E295 1 04 .byte $04 ; Compact index $02
00E296 1 0E .byte $0E ; Compact index $07
00E297 1 10 .byte $10 ; Compact index $08
00E298 1 12 .byte $12 ; Compact index $09
00E299 1 14 .byte $14 ; Compact index $0A
00E29A 1 16 .byte $16 ; Compact index $0B
00E29B 1
00E29B 1 ; ============================================================================
00E29B 1 ; $E29B-$E2A4
00E29B 1 ; Dispatch an inline command for a caller-supplied object offset.
00E29B 1 ;
00E29B 1 ; Entry:
00E29B 1 ; X = object or event offset
00E29B 1 ;
00E29B 1 ; Inline caller data:
00E29B 1 ; The bytes immediately following the caller's JSR are interpreted by
00E29B 1 ; $E99A. Existing call sites provide records such as:
00E29B 1 ;
00E29B 1 ; .byte $00
00E29B 1 ; .word HandlerAddress - 1
00E29B 1 ;
00E29B 1 ; Operation:
00E29B 1 ; 1. Preserve X in zero-page $06.
00E29B 1 ; 2. Call $E99A to locate or decode the caller's inline data.
00E29B 1 ; 3. Restore X.
00E29B 1 ; 4. Tail-call the command dispatcher at $EB0D.
00E29B 1 ;
00E29B 1 ; The jump to $EB0D enters three bytes after the normal QueueInlineObjectEvent entry, which
00E29B 1 ; suggests $E99A has already completed the inline-record setup normally
00E29B 1 ; performed by QueueInlineObjectEvent.
00E29B 1 ; ============================================================================
00E29B 1
00E29B 1 ; ----------------------------------------------------------------------------
00E29B 1 ; Contract:
00E29B 1 ; Description: Implements Dispatch Inline Object Command.
00E29B 1 ; Entry: Registers: X; Memory: $06
00E29B 1 ; Returns/products: Registers/clobbers: X
00E29B 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E29B 1 ; Memory effects: $06
00E29B 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E29B 1 ; comparison, load, or store path and are not a stable API product.
00E29B 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 3.
00E29B 1 ; ----------------------------------------------------------------------------
00E29B 1 DispatchInlineObjectCommand: ; $E29B
00E29B 1 86 06 stx $06 ; $E29B: 86 06
00E29D 1 ; Preserve the caller-supplied object offset.
00E29D 1
00E29D 1 20 9A E9 jsr DecodeInlineParameters ; $E29D: 20 9A E9
00E2A0 1 ; Decode or locate the inline record following
00E2A0 1 ; the caller's JSR.
00E2A0 1
00E2A0 1 A6 06 ldx $06 ; $E2A0: A6 06
00E2A2 1 ; Restore the object offset.
00E2A2 1
00E2A2 1 4C 0D EB jmp QueueDecodedObjectEvent ; $E2A2: 4C 0D EB
00E2A5 1 ; Tail-call the command dispatcher after its
00E2A5 1 ; normal inline-record setup entry.
00E2A5 1
00E2A5 1 ; ============================================================================
00E2A5 1 ; $E2A5-$E2D2
00E2A5 1 ; Calculate scaled coordinate differences between the base object and the
00E2A5 1 ; object selected by X.
00E2A5 1 ;
00E2A5 1 ; Entry:
00E2A5 1 ; X = object-array offset
00E2A5 1 ;
00E2A5 1 ; Exit:
00E2A5 1 ; A = scaled horizontal high/result byte
00E2A5 1 ; Y = scaled vertical high/result byte
00E2A5 1 ;
00E2A5 1 ; Working values:
00E2A5 1 ; $AE = horizontal low difference
00E2A5 1 ; $B0 = vertical low difference
00E2A5 1 ;
00E2A5 1 ; Both signed 16-bit differences are shifted left twice across their low and
00E2A5 1 ; high bytes. The low result bytes remain in $AE and $B0.
00E2A5 1 ; ============================================================================
00E2A5 1
00E2A5 1 CalculateObjectCoordinateDifference: ; $E2A5
00E2A5 1 38 sec ; $E2A5: 38
00E2A6 1
00E2A6 1 ; ----------------------------------------------------------------------------
00E2A6 1 ; Calculate the signed vertical difference:
00E2A6 1 ;
00E2A6 1 ; baseY - objectY
00E2A6 1 ;
00E2A6 1 ; Low byte:
00E2A6 1 ; $053A - $053A,X
00E2A6 1 ;
00E2A6 1 ; High byte:
00E2A6 1 ; $053B - $053B,X
00E2A6 1 ; ----------------------------------------------------------------------------
00E2A6 1
00E2A6 1 AD 3A 05 lda $053A ; $E2A6: AD 3A 05
00E2A9 1 FD 3A 05 sbc $053A,x ; $E2A9: FD 3A 05
00E2AC 1 85 B0 sta $B0 ; $E2AC: 85 B0
00E2AE 1
00E2AE 1 AD 3B 05 lda $053B ; $E2AE: AD 3B 05
00E2B1 1 FD 3B 05 sbc $053B,x ; $E2B1: FD 3B 05
00E2B4 1
00E2B4 1 ; ----------------------------------------------------------------------------
00E2B4 1 ; Multiply the signed vertical difference by four.
00E2B4 1 ;
00E2B4 1 ; First shift:
00E2B4 1 ; ASL $B0
00E2B4 1 ; ROL A
00E2B4 1 ;
00E2B4 1 ; Second shift:
00E2B4 1 ; ASL $B0
00E2B4 1 ; ADC #$00
00E2B4 1 ;
00E2B4 1 ; The second ADC incorporates carry from the low-byte shift into the high byte.
00E2B4 1 ; ----------------------------------------------------------------------------
00E2B4 1
00E2B4 1 06 B0 asl $B0 ; $E2B4: 06 B0
00E2B6 1 2A rol ; $E2B6: 2A
00E2B7 1
00E2B7 1 06 B0 asl $B0 ; $E2B7: 06 B0
00E2B9 1 69 00 adc #$00 ; $E2B9: 69 00
00E2BB 1
00E2BB 1 A8 tay ; $E2BB: A8
00E2BC 1 ; Y = scaled vertical high/result byte.
00E2BC 1
00E2BC 1 ; ----------------------------------------------------------------------------
00E2BC 1 ; Calculate the signed horizontal difference:
00E2BC 1 ;
00E2BC 1 ; baseX - objectX
00E2BC 1 ;
00E2BC 1 ; Low byte:
00E2BC 1 ; $0509 - $0509,X
00E2BC 1 ;
00E2BC 1 ; High byte:
00E2BC 1 ; $050A - $050A,X
00E2BC 1 ; ----------------------------------------------------------------------------
00E2BC 1
00E2BC 1 38 sec ; $E2BC: 38
00E2BD 1
00E2BD 1 AD 09 05 lda $0509 ; $E2BD: AD 09 05
00E2C0 1 FD 09 05 sbc $0509,x ; $E2C0: FD 09 05
00E2C3 1 85 AE sta CalculatedCoordinateLow ; $E2C3: 85 AE
00E2C5 1
00E2C5 1 AD 0A 05 lda $050A ; $E2C5: AD 0A 05
00E2C8 1 FD 0A 05 sbc $050A,x ; $E2C8: FD 0A 05
00E2CB 1
00E2CB 1 ; ----------------------------------------------------------------------------
00E2CB 1 ; Multiply the signed horizontal difference by four.
00E2CB 1 ; ----------------------------------------------------------------------------
00E2CB 1
00E2CB 1 06 AE asl CalculatedCoordinateLow ; $E2CB: 06 AE
00E2CD 1 2A rol ; $E2CD: 2A
00E2CE 1
00E2CE 1 06 AE asl CalculatedCoordinateLow ; $E2CE: 06 AE
00E2D0 1 69 00 adc #$00 ; $E2D0: 69 00
00E2D2 1
00E2D2 1 60 rts ; $E2D2: 60
00E2D3 1
00E2D3 1 ; ============================================================================
00E2D3 1 ; $E2D3-$E2DF
00E2D3 1 ; Clear the current object's two movement or velocity state bytes.
00E2D3 1 ;
00E2D3 1 ; Entry:
00E2D3 1 ; CurrentObjectIndex = object-array offset
00E2D3 1 ;
00E2D3 1 ; Exit:
00E2D3 1 ; A = $00
00E2D3 1 ; X = CurrentObjectIndex
00E2D3 1 ; Z = set
00E2D3 1 ;
00E2D3 1 ; Modified object fields:
00E2D3 1 ; $056D,X = $00
00E2D3 1 ; $056E,X = $00
00E2D3 1 ; ============================================================================
00E2D3 1
00E2D3 1 ; ----------------------------------------------------------------------------
00E2D3 1 ; Contract:
00E2D3 1 ; Description: Clears or resets Current Object Movement.
00E2D3 1 ; Entry: Registers: A; Memory: currentobjectindex
00E2D3 1 ; Returns/products: Registers/clobbers: A, X
00E2D3 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E2D3 1 ; Memory effects: $056d, $056e
00E2D3 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E2D3 1 ; comparison, load, or store path and are not a stable API product.
00E2D3 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 8.
00E2D3 1 ; ----------------------------------------------------------------------------
00E2D3 1 ClearCurrentObjectMovement: ; $E2D3
00E2D3 1 A6 E1 ldx CurrentObjectIndex ; $E2D3: A6 E1
00E2D5 1
00E2D5 1 A9 00 lda #$00 ; $E2D5: A9 00
00E2D7 1 9D 6D 05 sta $056D,x ; $E2D7: 9D 6D 05
00E2DA 1 9D 6E 05 sta $056E,x ; $E2DA: 9D 6E 05
00E2DD 1
00E2DD 1 60 rts ; $E2DD: 60
00E2DE 1
00E2DE 1 ; ============================================================================
00E2DE 1 ; $E2DE-$E312
00E2DE 1 ; Update the current object's animation frame and return a delay selected from
00E2DE 1 ; a table.
00E2DE 1 ;
00E2DE 1 ; Entry:
00E2DE 1 ; CurrentObjectIndex = object-array offset
00E2DE 1 ;
00E2DE 1 ; Return:
00E2DE 1 ; A = selector-specific delay from $E329,Y
00E2DE 1 ;
00E2DE 1 ; If either call to $E6B7 returns carry set:
00E2DE 1 ; A = $06
00E2DE 1 ; ============================================================================
00E2DE 1
00E2DE 1 ; ----------------------------------------------------------------------------
00E2DE 1 ; Contract:
00E2DE 1 ; Description: Updates Current Object Animation Delay.
00E2DE 1 ; Entry: Registers: A, X; Memory: currentobjectindex, $056e, $056d, $039a
00E2DE 1 ; Returns/products: Registers/clobbers: A, X, Y
00E2DE 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E2DE 1 ; Memory effects: $039a
00E2DE 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E2DE 1 ; comparison, load, or store path and are not a stable API product.
00E2DE 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 4.
00E2DE 1 ; ----------------------------------------------------------------------------
00E2DE 1 UpdateCurrentObjectAnimationDelay: ; $E2DE
00E2DE 1 A6 E1 ldx CurrentObjectIndex ; $E2DE: A6 E1
00E2E0 1
00E2E0 1 ; ----------------------------------------------------------------------------
00E2E0 1 ; Derive a preliminary three-bit animation selector from the current object's
00E2E0 1 ; state bytes at $056D/$056E.
00E2E0 1 ;
00E2E0 1 ; Bit flow:
00E2E0 1 ;
00E2E0 1 ; ASL $056E,X puts its high bit in carry.
00E2E0 1 ; ROL $056D,X shifts that carry into A.
00E2E0 1 ; A second ROL expands the selector.
00E2E0 1 ; ----------------------------------------------------------------------------
00E2E0 1
00E2E0 1 BD 6E 05 lda $056E,x ; $E2E0: BD 6E 05
00E2E3 1 0A asl ; $E2E3: 0A
00E2E4 1
00E2E4 1 BD 6D 05 lda $056D,x ; $E2E4: BD 6D 05
00E2E7 1 2A rol ; $E2E7: 2A
00E2E8 1 2A rol ; $E2E8: 2A
00E2E9 1
00E2E9 1 48 pha ; $E2E9: 48
00E2EA 1 ; Preserve the preliminary selector.
00E2EA 1
00E2EA 1 ; ----------------------------------------------------------------------------
00E2EA 1 ; Update or test the current object through $E6B7.
00E2EA 1 ; ----------------------------------------------------------------------------
00E2EA 1
00E2EA 1 20 B7 E6 jsr ClearMovementTransforms ; $E2EA: 20 B7 E6
00E2ED 1
00E2ED 1 68 pla ; $E2ED: 68
00E2EE 1 B0 20 bcs UpdateCurrentObjectAnimationDelay_Default
00E2F0 1 ; $E2EE: B0 20
00E2F0 1
00E2F0 1 ; ----------------------------------------------------------------------------
00E2F0 1 ; Incorporate whether X is at least $15 into the selector.
00E2F0 1 ;
00E2F0 1 ; CPX sets carry, then ROL shifts that condition into A.
00E2F0 1 ; ----------------------------------------------------------------------------
00E2F0 1
00E2F0 1 E0 15 cpx #$15 ; $E2F0: E0 15
00E2F2 1 2A rol ; $E2F2: 2A
00E2F3 1
00E2F3 1 29 07 and #$07 ; $E2F3: 29 07
00E2F5 1 A8 tay ; $E2F5: A8
00E2F6 1 ; Y selects one of eight animation ranges.
00E2F6 1
00E2F6 1 ; ----------------------------------------------------------------------------
00E2F6 1 ; Increment the current frame while preserving its original value in A for
00E2F6 1 ; the range comparisons.
00E2F6 1 ; ----------------------------------------------------------------------------
00E2F6 1
00E2F6 1 BD 9A 03 lda $039A,x ; $E2F6: BD 9A 03
00E2F9 1 FE 9A 03 inc $039A,x ; $E2F9: FE 9A 03
00E2FC 1
00E2FC 1 ; ----------------------------------------------------------------------------
00E2FC 1 ; If the original frame is at or beyond its upper limit, reset it to the base
00E2FC 1 ; frame.
00E2FC 1 ;
00E2FC 1 ; If it is between the base and upper limit, keep the incremented frame.
00E2FC 1 ;
00E2FC 1 ; If it is below the base frame, reset it to the base frame.
00E2FC 1 ; ----------------------------------------------------------------------------
00E2FC 1
00E2FC 1 D9 21 E3 cmp CurrentObjectAnimationLimitTable,y
00E2FF 1 ; $E2FC: D9 21 E3
00E2FF 1 B0 05 bcs UpdateCurrentObjectAnimationDelay_Reset
00E301 1 ; $E2FF: B0 05
00E301 1
00E301 1 D9 19 E3 cmp CurrentObjectAnimationBaseTable,y
00E304 1 ; $E301: D9 19 E3
00E304 1 B0 06 bcs UpdateCurrentObjectAnimationDelay_LoadDelay
00E306 1 ; $E304: B0 06
00E306 1
00E306 1 UpdateCurrentObjectAnimationDelay_Reset: ; $E306
00E306 1 B9 19 E3 lda CurrentObjectAnimationBaseTable,y
00E309 1 ; $E306: B9 19 E3
00E309 1 9D 9A 03 sta $039A,x ; $E309: 9D 9A 03
00E30C 1
00E30C 1 ; ----------------------------------------------------------------------------
00E30C 1 ; Return the delay associated with this animation range.
00E30C 1 ; ----------------------------------------------------------------------------
00E30C 1
00E30C 1 UpdateCurrentObjectAnimationDelay_LoadDelay: ; $E30C
00E30C 1 B9 29 E3 lda CurrentObjectAnimationDelayTable,y
00E30F 1 ; $E30C: B9 29 E3
00E30F 1 60 rts ; $E30F: 60
00E310 1
00E310 1 ; ----------------------------------------------------------------------------
00E310 1 ; Carry-set fallback from $E6B7.
00E310 1 ; ----------------------------------------------------------------------------
00E310 1
00E310 1 UpdateCurrentObjectAnimationDelay_Default: ; $E310
00E310 1 A9 06 lda #$06 ; $E310: A9 06
00E312 1 60 rts ; $E312: 60
00E313 1
00E313 1 ; ============================================================================
00E313 1 ; $E313-$E318
00E313 1 ; Update the current object's animation and immediately wait for the returned
00E313 1 ; delay.
00E313 1 ;
00E313 1 ; This is a compact wrapper around UpdateCurrentObjectAnimationDelay and
00E313 1 ; $EB41.
00E313 1 ; ============================================================================
00E313 1
00E313 1 ; ----------------------------------------------------------------------------
00E313 1 ; Contract:
00E313 1 ; Description: Updates Current Object Animation And Wait.
00E313 1 ; Entry: No register input inferred
00E313 1 ; Returns/products: No direct product inferred
00E313 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E313 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00E313 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E313 1 ; comparison, load, or store path and are not a stable API product.
00E313 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 2.
00E313 1 ; ----------------------------------------------------------------------------
00E313 1 UpdateCurrentObjectAnimationAndWait: ; $E313
00E313 1 20 DE E2 jsr UpdateCurrentObjectAnimationDelay
00E316 1 ; $E313: 20 DE E2
00E316 1
00E316 1 4C 41 EB jmp StoreObjectEventBankValue ; $E316: 4C 41 EB
00E319 1 ; Tail-call the delay helper.
00E319 1
00E319 1 ; ============================================================================
00E319 1 ; $E319-$E320
00E319 1 ; Base/reset frames for the eight current-object animation ranges.
00E319 1 ; ============================================================================
00E319 1
00E319 1 CurrentObjectAnimationBaseTable: ; $E319
00E319 1 61 32 64 35 .byte $61,$32,$64,$35
00E31D 1 5C 3B 5C 38 .byte $5C,$3B,$5C,$38
00E321 1
00E321 1 ; ============================================================================
00E321 1 ; $E321-$E328
00E321 1 ; Exclusive upper frame limits for the eight animation ranges.
00E321 1 ; ============================================================================
00E321 1
00E321 1 CurrentObjectAnimationLimitTable: ; $E321
00E321 1 63 34 66 37 .byte $63,$34,$66,$37
00E325 1 5D 3D 5D 3A .byte $5D,$3D,$5D,$3A
00E329 1
00E329 1 ; ============================================================================
00E329 1 ; $E329-$E330
00E329 1 ; Delay values associated with the eight animation ranges.
00E329 1 ; ============================================================================
00E329 1
00E329 1 CurrentObjectAnimationDelayTable: ; $E329
00E329 1 06 06 06 06 .byte $06,$06,$06,$06
00E32D 1 09 06 09 06 .byte $09,$06,$09,$06
00E331 1
00E331 1 ; ============================================================================
00E331 1 ; $E331-$E346
00E331 1 ; Find an object-state entry equal to twice the selected compact state.
00E331 1 ;
00E331 1 ; Entry:
00E331 1 ; $C2 = compact state value
00E331 1 ;
00E331 1 ; Search:
00E331 1 ; $059B, $059A, $0599, $0598
00E331 1 ;
00E331 1 ; If a matching entry is found:
00E331 1 ; 1. Copy $C2 to StateSelector.
00E331 1 ; 2. Call the state-marker helper at $CD2E.
00E331 1 ;
00E331 1 ; If no entry matches:
00E331 1 ; Return without changing StateSelector.
00E331 1 ;
00E331 1 ; Exit:
00E331 1 ; X = matching object-state index, or $FF if no match was found
00E331 1 ; ============================================================================
00E331 1
00E331 1 ; ----------------------------------------------------------------------------
00E331 1 ; Contract:
00E331 1 ; Description: Implements Find And Queue Selected State.
00E331 1 ; Entry: Registers: A, X; Memory: $c2, $0598
00E331 1 ; Returns/products: Registers/clobbers: A, X; Flags: condition flags may carry result state
00E331 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E331 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00E331 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E331 1 ; comparison, load, or store path and are not a stable API product.
00E331 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E331 1 ; ----------------------------------------------------------------------------
00E331 1 FindAndQueueSelectedState: ; $E331
00E331 1 A2 03 ldx #$03 ; $E331: A2 03
00E333 1
00E333 1 ; ----------------------------------------------------------------------------
00E333 1 ; Double the compact state value.
00E333 1 ;
00E333 1 ; The loop branches back to the CMP at $E336, not to LDA/ASL. The doubled
00E333 1 ; value therefore remains in A for all four comparisons.
00E333 1 ; ----------------------------------------------------------------------------
00E333 1
00E333 1 A5 C2 lda $C2 ; $E333: A5 C2
00E335 1 0A asl ; $E335: 0A
00E336 1
00E336 1 FindAndQueueSelectedState_Search: ; $E336
00E336 1 DD 98 05 cmp $0598,x ; $E336: DD 98 05
00E339 1 F0 04 beq FindAndQueueSelectedState_Found
00E33B 1 ; $E339: F0 04
00E33B 1
00E33B 1 CA dex ; $E33B: CA
00E33C 1 10 F8 bpl FindAndQueueSelectedState_Search
00E33E 1 ; $E33C: 10 F8
00E33E 1
00E33E 1 ; ----------------------------------------------------------------------------
00E33E 1 ; No matching state entry was found.
00E33E 1 ; ----------------------------------------------------------------------------
00E33E 1
00E33E 1 60 rts ; $E33E: 60
00E33F 1
00E33F 1 ; ----------------------------------------------------------------------------
00E33F 1 ; Matching entry found.
00E33F 1 ;
00E33F 1 ; Restore the undoubled state value from $C2, save it in StateSelector, and
00E33F 1 ; invoke the state-marker helper at $CD2E.
00E33F 1 ; ----------------------------------------------------------------------------
00E33F 1
00E33F 1 FindAndQueueSelectedState_Found: ; $E33F
00E33F 1 A5 C2 lda $C2 ; $E33F: A5 C2
00E341 1 85 72 sta StateSelector ; $E341: 85 72
00E343 1
00E343 1 20 2E CD jsr QueueSelectedStateMarker ; $E343: 20 2E CD
00E346 1
00E346 1 60 rts ; $E346: 60
00E347 1
00E347 1 ; ============================================================================
00E347 1 ; $E347-$E3AB
00E347 1 ; Validate and consume the compact object-state selected in $C2.
00E347 1 ;
00E347 1 ; The routine inspects the corresponding entries in $0598-$059B and $95-$98,
00E347 1 ; may search for an alternate state, updates PendingScoreIncrement, marks an object
00E347 1 ; state inactive, and advances the alternate state sequence.
00E347 1 ;
00E347 1 ; Entry:
00E347 1 ; $C2 = compact object-state index
00E347 1 ; ============================================================================
00E347 1
00E347 1 ; ----------------------------------------------------------------------------
00E347 1 ; Contract:
00E347 1 ; Description: Processes Compact Object State.
00E347 1 ; Entry: Registers: A, X, Y; Memory: $c2, $0598, $95, objecttransitionstate, secondarysequencestate, $c3
00E347 1 ; Returns/products: Registers/clobbers: A, X, Y
00E347 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E347 1 ; Memory effects: $c3, $c2, $96, $97, $98, pendingscoreincrement
00E347 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E347 1 ; comparison, load, or store path and are not a stable API product.
00E347 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E347 1 ; ----------------------------------------------------------------------------
00E347 1 ProcessCompactObjectState: ; $E347
00E347 1 A6 C2 ldx $C2 ; $E347: A6 C2
00E349 1
00E349 1 ; ----------------------------------------------------------------------------
00E349 1 ; Compact state values of four or greater are rejected.
00E349 1 ; ----------------------------------------------------------------------------
00E349 1
00E349 1 E0 04 cpx #$04 ; $E349: E0 04
00E34B 1 B0 5E bcs ProcessCompactObjectState_Return
00E34D 1 ; $E34B: B0 5E
00E34D 1
00E34D 1 ; ----------------------------------------------------------------------------
00E34D 1 ; Reject inactive state-table entries.
00E34D 1 ; ----------------------------------------------------------------------------
00E34D 1
00E34D 1 BD 98 05 lda $0598,x ; $E34D: BD 98 05
00E350 1 30 59 bmi ProcessCompactObjectState_Return
00E352 1 ; $E350: 30 59
00E352 1
00E352 1 ; ----------------------------------------------------------------------------
00E352 1 ; Reject entries whose corresponding zero-page state at $95-$98 is nonzero.
00E352 1 ; ----------------------------------------------------------------------------
00E352 1
00E352 1 B5 95 lda $95,x ; $E352: B5 95
00E354 1 D0 55 bne ProcessCompactObjectState_Return
00E356 1 ; $E354: D0 55
00E356 1
00E356 1 ; ----------------------------------------------------------------------------
00E356 1 ; Preserve the selected compact index.
00E356 1 ;
00E356 1 ; Index zero uses the shared PendingScoreIncrement path at $E380.
00E356 1 ; ----------------------------------------------------------------------------
00E356 1
00E356 1 86 C3 stx $C3 ; $E356: 86 C3
00E358 1 F0 26 beq ProcessCompactObjectState_SavePending
00E35A 1 ; $E358: F0 26
00E35A 1
00E35A 1 ; ============================================================================
00E35A 1 ; $E35A
00E35A 1 ; Search for an alternate state entry.
00E35A 1 ; ============================================================================
00E35A 1
00E35A 1 ; ----------------------------------------------------------------------------
00E35A 1 ; Contract:
00E35A 1 ; Description: Processes Compact Object State Find Alternate.
00E35A 1 ; Entry: Registers: A, X, Y; Memory: $c2, objecttransitionstate, secondarysequencestate, $c3, $0598
00E35A 1 ; Returns/products: Registers/clobbers: A, X, Y
00E35A 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E35A 1 ; Memory effects: $c2, $c3, $96, $97, $98, pendingscoreincrement
00E35A 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E35A 1 ; comparison, load, or store path and are not a stable API product.
00E35A 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E35A 1 ; ----------------------------------------------------------------------------
00E35A 1 ProcessCompactObjectState_FindAlternate: ; $E35A
00E35A 1 A9 04 lda #$04 ; $E35A: A9 04
00E35C 1 85 C2 sta $C2 ; $E35C: 85 C2
00E35E 1
00E35E 1 A9 00 lda #$00 ; $E35E: A9 00
00E360 1 85 C3 sta $C3 ; $E360: 85 C3
00E362 1
00E362 1 85 96 sta $96 ; $E362: 85 96
00E364 1 85 97 sta $97 ; $E364: 85 97
00E366 1 85 98 sta $98 ; $E366: 85 98
00E368 1
00E368 1 ; ----------------------------------------------------------------------------
00E368 1 ; A is zero, so this branch is always taken to the state comparison at $E379.
00E368 1 ;
00E368 1 ; The entry at $E36A is also called directly by earlier code.
00E368 1 ; ----------------------------------------------------------------------------
00E368 1
00E368 1 F0 0F beq ProcessCompactObjectState_CompareState64
00E36A 1 ; $E368: F0 0F
00E36A 1
00E36A 1 ; ============================================================================
00E36A 1 ; $E36A
00E36A 1 ; Alternate entry used by the main object-state dispatcher.
00E36A 1 ;
00E36A 1 ; Test whether the selector derived from $C2 has a valid matching object state.
00E36A 1 ; ============================================================================
00E36A 1
00E36A 1 ; ----------------------------------------------------------------------------
00E36A 1 ; Contract:
00E36A 1 ; Description: Processes Compact Object State Test Selector.
00E36A 1 ; Entry: Registers: A, X, Y; Memory: $c2, objecttransitionstate, secondarysequencestate, $c3, $0598
00E36A 1 ; Returns/products: Registers/clobbers: A, X, Y
00E36A 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E36A 1 ; Memory effects: $c3, pendingscoreincrement, $c2, $0598, stateselector
00E36A 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E36A 1 ; comparison, load, or store path and are not a stable API product.
00E36A 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E36A 1 ; ----------------------------------------------------------------------------
00E36A 1 ProcessCompactObjectState_TestSelector: ; $E36A
00E36A 1 A4 C2 ldy $C2 ; $E36A: A4 C2
00E36C 1 88 dey ; $E36C: 88
00E36D 1 84 C3 sty $C3 ; $E36D: 84 C3
00E36F 1 C8 iny ; $E36F: C8
00E370 1
00E370 1 20 46 E2 jsr FindObjectStateForSelector
00E373 1 ; $E370: 20 46 E2
00E373 1
00E373 1 10 36 bpl ProcessCompactObjectState_Return
00E375 1 ; $E373: 10 36
00E375 1
00E375 1 A5 6E lda ObjectTransitionState ; $E375: A5 6E
00E377 1 D0 32 bne ProcessCompactObjectState_Return
00E379 1 ; $E377: D0 32
00E379 1
00E379 1 ; ----------------------------------------------------------------------------
00E379 1 ; Compare SecondarySequenceState against two.
00E379 1 ;
00E379 1 ; The subtraction result becomes the value stored in PendingScoreIncrement.
00E379 1 ; ----------------------------------------------------------------------------
00E379 1
00E379 1 ProcessCompactObjectState_CompareState64: ; $E379
00E379 1 38 sec ; $E379: 38
00E37A 1
00E37A 1 A5 64 lda SecondarySequenceState ; $E37A: A5 64
00E37C 1 E9 02 sbc #$02 ; $E37C: E9 02
00E37E 1 D0 1D bne ProcessCompactObjectState_Consume
00E380 1 ; $E37E: D0 1D
00E380 1
00E380 1 ; ----------------------------------------------------------------------------
00E380 1 ; Store the subtraction result in PendingScoreIncrement.
00E380 1 ;
00E380 1 ; Entry from $E358 uses A from LDA $95,X, which is known to be zero.
00E380 1 ; Therefore both paths normally store zero.
00E380 1 ; ----------------------------------------------------------------------------
00E380 1
00E380 1 ProcessCompactObjectState_SavePending: ; $E380
00E380 1 85 65 sta PendingScoreIncrement ; $E380: 85 65
00E382 1 F0 19 beq ProcessCompactObjectState_Consume
00E384 1 ; $E382: F0 19
00E384 1
00E384 1 ; ============================================================================
00E384 1 ; $E384
00E384 1 ; Validate the selected state when ObjectTransitionState is nonzero.
00E384 1 ;
00E384 1 ; This entry is also called independently from $E240.
00E384 1 ; ============================================================================
00E384 1
00E384 1 ; ----------------------------------------------------------------------------
00E384 1 ; Contract:
00E384 1 ; Description: Processes Compact Object State Validate.
00E384 1 ; Entry: Registers: A, X, Y; Memory: objecttransitionstate, $c3, $0598, $c2
00E384 1 ; Returns/products: Registers/clobbers: A, X, Y
00E384 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E384 1 ; Memory effects: $c2, $0598, stateselector
00E384 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E384 1 ; comparison, load, or store path and are not a stable API product.
00E384 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E384 1 ; ----------------------------------------------------------------------------
00E384 1 ProcessCompactObjectState_Validate: ; $E384
00E384 1 A5 6E lda ObjectTransitionState ; $E384: A5 6E
00E386 1 F0 09 beq ProcessCompactObjectState_LoadEntry
00E388 1 ; $E386: F0 09
00E388 1
00E388 1 A5 C3 lda $C3 ; $E388: A5 C3
00E38A 1 A8 tay ; $E38A: A8
00E38B 1 C8 iny ; $E38B: C8
00E38C 1
00E38C 1 20 46 E2 jsr FindObjectStateForSelector
00E38F 1 ; $E38C: 20 46 E2
00E38F 1
00E38F 1 30 1A bmi ProcessCompactObjectState_Return
00E391 1 ; $E38F: 30 1A
00E391 1
00E391 1 ; ----------------------------------------------------------------------------
00E391 1 ; Load the selected state entry, divide it by two, and save the compact result
00E391 1 ; in $C2.
00E391 1 ; ----------------------------------------------------------------------------
00E391 1
00E391 1 ProcessCompactObjectState_LoadEntry: ; $E391
00E391 1 A6 C3 ldx $C3 ; $E391: A6 C3
00E393 1
00E393 1 BD 98 05 lda $0598,x ; $E393: BD 98 05
00E396 1 4A lsr ; $E396: 4A
00E397 1 85 C2 sta $C2 ; $E397: 85 C2
00E399 1
00E399 1 ; ----------------------------------------------------------------------------
00E399 1 ; If the original state byte was even, carry is clear and processing branches
00E399 1 ; backward to the found path in FindAndQueueSelectedState at $E33F.
00E399 1 ; ----------------------------------------------------------------------------
00E399 1
00E399 1 90 A4 bcc FindAndQueueSelectedState_Found
00E39B 1 ; $E399: 90 A4
00E39B 1
00E39B 1 ; ----------------------------------------------------------------------------
00E39B 1 ; Odd state values increment the compact state before being consumed.
00E39B 1 ; ----------------------------------------------------------------------------
00E39B 1
00E39B 1 E6 C2 inc $C2 ; $E39B: E6 C2
00E39D 1
00E39D 1 ; ============================================================================
00E39D 1 ; $E39D
00E39D 1 ; Mark the selected object-state entry inactive and advance the state sequence.
00E39D 1 ; ============================================================================
00E39D 1
00E39D 1 ProcessCompactObjectState_Consume: ; $E39D
00E39D 1 A6 C3 ldx $C3 ; $E39D: A6 C3
00E39F 1
00E39F 1 A9 FF lda #$FF ; $E39F: A9 FF
00E3A1 1 9D 98 05 sta $0598,x ; $E3A1: 9D 98 05
00E3A4 1
00E3A4 1 A6 C2 ldx $C2 ; $E3A4: A6 C2
00E3A6 1 86 72 stx StateSelector ; $E3A6: 86 72
00E3A8 1
00E3A8 1 20 E4 CC jsr AdvanceAlternateStateSequence
00E3AB 1 ; $E3A8: 20 E4 CC
00E3AB 1 ; Advance the alternate state sequence.
00E3AB 1
00E3AB 1 ProcessCompactObjectState_Return: ; $E3AB
00E3AB 1 60 rts ; $E3AB: 60
00E3AC 1
00E3AC 1 ; ============================================================================
00E3AC 1 ; $E3AC-$E3DB
00E3AC 1 ; Run the selected object's geometry and animation transition.
00E3AC 1 ;
00E3AC 1 ; The routine:
00E3AC 1 ; 1. Initializes geometry or object state through $E59D.
00E3AC 1 ; 2. Repeats the geometry test until it clears.
00E3AC 1 ; 3. Updates the current object's display state.
00E3AC 1 ; 4. Waits until the test at $E57E returns carry clear.
00E3AC 1 ; 5. Resets shared state and returns to the main object dispatcher.
00E3AC 1 ; ============================================================================
00E3AC 1
00E3AC 1 RunSelectedObjectTransition: ; $E3AC
00E3AC 1 20 9D E5 jsr InitializeSharedObjectMotion ; $E3AC: 20 9D E5
00E3AF 1
00E3AF 1 ; ----------------------------------------------------------------------------
00E3AF 1 ; Prepare and test the current object's geometry.
00E3AF 1 ;
00E3AF 1 ; Carry set runs the animation-and-wait helper at $E313, then retries from
00E3AF 1 ; $E3AF. Carry clear continues with display-state processing.
00E3AF 1 ; ----------------------------------------------------------------------------
00E3AF 1
00E3AF 1 RunSelectedObjectTransition_TestGeometry: ; $E3AF
00E3AF 1 20 74 E4 jsr SelectGeometryRecord_Default ; $E3AF: 20 74 E4
00E3B2 1 20 5F E5 jsr ApplyCurrentObjectGeometry ; $E3B2: 20 5F E5
00E3B5 1
00E3B5 1 90 06 bcc RunSelectedObjectTransition_GeometryClear
00E3B7 1 ; $E3B5: 90 06
00E3B7 1
00E3B7 1 20 13 E3 jsr UpdateCurrentObjectAnimationAndWait
00E3BA 1 ; $E3B7: 20 13 E3
00E3BA 1
00E3BA 1 4C AF E3 jmp RunSelectedObjectTransition_TestGeometry
00E3BD 1 ; $E3BA: 4C AF E3
00E3BD 1
00E3BD 1 ; ----------------------------------------------------------------------------
00E3BD 1 ; Geometry cleared. Update the current object's display state.
00E3BD 1 ; ----------------------------------------------------------------------------
00E3BD 1
00E3BD 1 RunSelectedObjectTransition_GeometryClear: ; $E3BD
00E3BD 1 20 D4 DF jsr UpdateCurrentObjectDisplayState
00E3C0 1 ; $E3BD: 20 D4 DF
00E3C0 1
00E3C0 1 ; ----------------------------------------------------------------------------
00E3C0 1 ; Wait three ticks, then test the condition at $E57E.
00E3C0 1 ;
00E3C0 1 ; Carry set repeats the delay and test. Carry clear completes the transition.
00E3C0 1 ; ----------------------------------------------------------------------------
00E3C0 1
00E3C0 1 RunSelectedObjectTransition_WaitLoop: ; $E3C0
00E3C0 1 A9 03 lda #$03 ; $E3C0: A9 03
00E3C2 1 20 41 EB jsr StoreObjectEventBankValue ; $E3C2: 20 41 EB
00E3C5 1
00E3C5 1 20 7E E5 jsr ApplyBaseObjectGeometry ; $E3C5: 20 7E E5
00E3C8 1 B0 F6 bcs RunSelectedObjectTransition_WaitLoop
00E3CA 1 ; $E3C8: B0 F6
00E3CA 1
00E3CA 1 ; ----------------------------------------------------------------------------
00E3CA 1 ; Set the shared engine flags and clear the selector remapping state.
00E3CA 1 ; ----------------------------------------------------------------------------
00E3CA 1
00E3CA 1 A9 20 lda #$20 ; $E3CA: A9 20
00E3CC 1 85 FE sta PendingAudioFlags ; $E3CC: 85 FE
00E3CE 1
00E3CE 1 A9 00 lda #$00 ; $E3CE: A9 00
00E3D0 1 85 BB sta $BB ; $E3D0: 85 BB
00E3D2 1
00E3D2 1 ; ----------------------------------------------------------------------------
00E3D2 1 ; Derive the current selector through GetCurrentObjectSelectorAndState and save
00E3D2 1 ; it to both $9E and $C2.
00E3D2 1 ; ----------------------------------------------------------------------------
00E3D2 1
00E3D2 1 20 DC E3 jsr GetCurrentObjectSelectorAndState
00E3D5 1 ; $E3D2: 20 DC E3
00E3D5 1
00E3D5 1 84 9E sty $9E ; $E3D5: 84 9E
00E3D7 1 84 C2 sty $C2 ; $E3D7: 84 C2
00E3D9 1
00E3D9 1 ; ----------------------------------------------------------------------------
00E3D9 1 ; Return to the main object-state dispatcher setup at $E040.
00E3D9 1 ; ----------------------------------------------------------------------------
00E3D9 1
00E3D9 1 4C 40 E0 jmp ProcessObjectStateSelection ; $E3D9: 4C 40 E0
00E3DC 1
00E3DC 1 ; ============================================================================
00E3DC 1 ; $E3DC-$E3E5
00E3DC 1 ; Derive the compact state index and saved selector for CurrentObjectIndex.
00E3DC 1 ;
00E3DC 1 ; Exit:
00E3DC 1 ; X = CurrentObjectIndex
00E3DC 1 ; Y = $0595[CurrentObjectIndex / 2]
00E3DC 1 ; A = CurrentObjectIndex / 2
00E3DC 1 ;
00E3DC 1 ; The final LDX restores the full object-array offset in X while leaving the
00E3DC 1 ; compact index in A and the saved selector in Y.
00E3DC 1 ; ============================================================================
00E3DC 1
00E3DC 1 ; ----------------------------------------------------------------------------
00E3DC 1 ; Contract:
00E3DC 1 ; Description: Implements Get Current Object Selector And State.
00E3DC 1 ; Entry: Registers: A; Memory: currentobjectindex, $0595
00E3DC 1 ; Returns/products: Registers/clobbers: A, X, Y; Flags: condition flags may carry result state
00E3DC 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E3DC 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00E3DC 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E3DC 1 ; comparison, load, or store path and are not a stable API product.
00E3DC 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 13.
00E3DC 1 ; ----------------------------------------------------------------------------
00E3DC 1 GetCurrentObjectSelectorAndState: ; $E3DC
00E3DC 1 A5 E1 lda CurrentObjectIndex ; $E3DC: A5 E1
00E3DE 1 4A lsr ; $E3DE: 4A
00E3DF 1 AA tax ; $E3DF: AA
00E3E0 1
00E3E0 1 BC 95 05 ldy $0595,x ; $E3E0: BC 95 05
00E3E3 1
00E3E3 1 A6 E1 ldx CurrentObjectIndex ; $E3E3: A6 E1
00E3E5 1 60 rts ; $E3E5: 60
00E3E6 1
00E3E6 1 ; ============================================================================
00E3E6 1 ; $E3E6-$E412
00E3E6 1 ; Copy the current object's position into the base-object position fields,
00E3E6 1 ; initialize the base object's motion state, clear its auxiliary fields, and
00E3E6 1 ; save the result in BaseMotionActive.
00E3E6 1 ;
00E3E6 1 ; Entry:
00E3E6 1 ; CurrentObjectIndex = source object-array offset
00E3E6 1 ;
00E3E6 1 ; Exit:
00E3E6 1 ; A = value returned by ClearBaseAccelerationFields
00E3E6 1 ; X = CurrentObjectIndex
00E3E6 1 ; BaseMotionActive = returned value
00E3E6 1 ; ============================================================================
00E3E6 1
00E3E6 1 ; ----------------------------------------------------------------------------
00E3E6 1 ; Contract:
00E3E6 1 ; Description: Initializes Base Object From Current.
00E3E6 1 ; Entry: Registers: A; Memory: currentobjectindex, $0509, $050a, $053a, $053b
00E3E6 1 ; Returns/products: Registers/clobbers: A, X
00E3E6 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E3E6 1 ; Memory effects: $0509, $050a, $053a, $053b, $056b, $056c, basemotionactive
00E3E6 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E3E6 1 ; comparison, load, or store path and are not a stable API product.
00E3E6 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 6.
00E3E6 1 ; ----------------------------------------------------------------------------
00E3E6 1 InitializeBaseObjectFromCurrent: ; $E3E6
00E3E6 1 A6 E1 ldx CurrentObjectIndex ; $E3E6: A6 E1
00E3E8 1
00E3E8 1 ; ----------------------------------------------------------------------------
00E3E8 1 ; Copy the current object's horizontal coordinate to the base object.
00E3E8 1 ; ----------------------------------------------------------------------------
00E3E8 1
00E3E8 1 ; ----------------------------------------------------------------------------
00E3E8 1 ; Contract:
00E3E8 1 ; Description: Internal position-copy entry with X already loaded.
00E3E8 1 ; Entry: X = current object array offset.
00E3E8 1 ; Returns/products: Base object position fields updated.
00E3E8 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E3E8 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00E3E8 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E3E8 1 ; comparison, load, or store path and are not a stable API product.
00E3E8 1 ; Validation: Internal-entry contract; call sites: internal entry.
00E3E8 1 ; ----------------------------------------------------------------------------
00E3E8 1 CopyCurrentObjectPositionToBaseAfterIndex:
00E3E8 1 BD 09 05 lda $0509,x ; $E3E8: BD 09 05
00E3EB 1 8D 09 05 sta $0509 ; $E3EB: 8D 09 05
00E3EE 1
00E3EE 1 BD 0A 05 lda $050A,x ; $E3EE: BD 0A 05
00E3F1 1 8D 0A 05 sta $050A ; $E3F1: 8D 0A 05
00E3F4 1
00E3F4 1 ; ----------------------------------------------------------------------------
00E3F4 1 ; Copy the current object's vertical coordinate to the base object.
00E3F4 1 ; ----------------------------------------------------------------------------
00E3F4 1
00E3F4 1 BD 3A 05 lda $053A,x ; $E3F4: BD 3A 05
00E3F7 1 8D 3A 05 sta $053A ; $E3F7: 8D 3A 05
00E3FA 1
00E3FA 1 BD 3B 05 lda $053B,x ; $E3FA: BD 3B 05
00E3FD 1 8D 3B 05 sta $053B ; $E3FD: 8D 3B 05
00E400 1
00E400 1 ; ----------------------------------------------------------------------------
00E400 1 ; Initialize the base object's movement/state pair.
00E400 1 ; ----------------------------------------------------------------------------
00E400 1
00E400 1 A9 00 lda #$00 ; $E400: A9 00
00E402 1 8D 6B 05 sta $056B ; $E402: 8D 6B 05
00E405 1
00E405 1 A9 01 lda #$01 ; $E405: A9 01
00E407 1 8D 6C 05 sta $056C ; $E407: 8D 6C 05
00E40A 1
00E40A 1 ; ----------------------------------------------------------------------------
00E40A 1 ; Clear the base object's position/motion fields.
00E40A 1 ;
00E40A 1 ; These calls use the earlier helpers at $C94F and ClearBaseAccelerationFields
00E40A 1 ; ----------------------------------------------------------------------------
00E40A 1
00E40A 1 20 4F C9 jsr ClearBasePositionFields ; $E40A: 20 4F C9
00E40D 1 20 43 C9 jsr ClearBaseAccelerationFields ; $E40D: 20 43 C9
00E410 1
00E410 1 ; ----------------------------------------------------------------------------
00E410 1 ; Save the result from ClearBaseAccelerationFields as the active-motion state.
00E410 1 ; ----------------------------------------------------------------------------
00E410 1
00E410 1 85 5C sta BaseMotionActive ; $E410: 85 5C
00E412 1
00E412 1 60 rts ; $E412: 60
00E413 1
00E413 1 ; ============================================================================
00E413 1 ; $E413-$E432
00E413 1 ; Geometry parameter data, first 32 bytes.
00E413 1 ;
00E413 1 ; Keep this region as raw bytes. Later routines use calculated and overlapping
00E413 1 ; offsets into the larger data structure.
00E413 1 ; ============================================================================
00E413 1
00E413 1 GeometryParameterData: ; $E413
00E413 1 D0 05 00 00 .byte $D0,$05,$00,$00,$00,$02,$30,$08
00E417 1 00 02 30 08
00E41B 1 20 F9 C0 00 .byte $20,$F9,$C0,$00,$00,$00,$40,$F7
00E41F 1 00 00 40 F7
00E423 1 00 FE 00 FC .byte $00,$FE,$00,$FC,$00,$02,$00,$04
00E427 1 00 02 00 04
00E42B 1 80 06 00 00 .byte $80,$06,$00,$00,$D0,$00,$50,$08
00E42F 1 D0 00 50 08
00E433 1 GeometryParameterData_Block2: ; $E433
00E433 1 40 F8 C0 00 .byte $40,$F8,$C0,$00,$00,$00,$40,$F7
00E437 1 00 00 40 F7
00E43B 1 00 08 00 00 .byte $00,$08,$00,$00,$00,$00,$00,$08
00E43F 1 00 00 00 08
00E443 1 00 F8 00 00 .byte $00,$F8,$00,$00,$00,$00,$00,$F8
00E447 1 00 00 00 F8
00E44B 1 00 07 80 00 .byte $00,$07,$80,$00,$00,$FF,$00,$08
00E44F 1 00 FF 00 08
00E453 1 GeometryParameterData_Block3: ; $E453
00E453 1 80 F8 80 FF .byte $80,$F8,$80,$FF,$00,$03,$00,$F5
00E457 1 00 03 00 F5
00E45B 1 A0 06 60 01 .byte $A0,$06,$60,$01,$40,$FE,$C0,$06
00E45F 1 40 FE C0 06
00E463 1 40 F9 60 FE .byte $40,$F9,$60,$FE,$80,$06,$80,$FE
00E467 1 80 06 80 FE
00E46B 1
00E46B 1 ; ============================================================================
00E46B 1 ; $E46B-$E473
00E46B 1 ; Convert the current object's saved selector into a four-byte geometry-record
00E46B 1 ; offset.
00E46B 1 ;
00E46B 1 ; GetCurrentObjectSelectorAndState returns the saved selector in Y.
00E46B 1 ;
00E46B 1 ; Exit:
00E46B 1 ; Y = (saved selector - 1) * 4
00E46B 1 ; ============================================================================
00E46B 1
00E46B 1 GetCurrentGeometryRecordOffset: ; $E46B
00E46B 1 20 DC E3 jsr GetCurrentObjectSelectorAndState
00E46E 1 ; $E46B: 20 DC E3
00E46E 1
00E46E 1 88 dey ; $E46E: 88
00E46F 1 98 tya ; $E46F: 98
00E470 1
00E470 1 0A asl ; $E470: 0A
00E471 1 0A asl ; $E471: 0A
00E472 1
00E472 1 A8 tay ; $E472: A8
00E473 1 60 rts ; $E473: 60
00E474 1
00E474 1 ; ============================================================================
00E474 1 ; $E474-$E4B7
00E474 1 ; Geometry-record selection helpers.
00E474 1 ;
00E474 1 ; Each entry selects:
00E474 1 ;
00E474 1 ; Y = offset into the geometry data beginning at GeometryParameterData
00E474 1 ; A = geometry parameter stored in $C6
00E474 1 ;
00E474 1 ; The entries at $E474 and $E481 preserve parameters $0F and $05 by branching
00E474 1 ; directly to STA $C6 at $E4B5.
00E474 1 ;
00E474 1 ; The remaining entries merge at $E4B2, convert their calculated offset from
00E474 1 ; A to Y, and use the default geometry parameter $07.
00E474 1 ; ============================================================================
00E474 1
00E474 1 ; ----------------------------------------------------------------------------
00E474 1 ; Contract:
00E474 1 ; Description: Implements Select Geometry Record Default.
00E474 1 ; Entry: Registers: A, Y
00E474 1 ; Returns/products: Registers/clobbers: A, Y
00E474 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E474 1 ; Memory effects: $c6
00E474 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E474 1 ; comparison, load, or store path and are not a stable API product.
00E474 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 5.
00E474 1 ; ----------------------------------------------------------------------------
00E474 1 SelectGeometryRecord_Default: ; $E474
00E474 1 20 DC E3 jsr GetCurrentObjectSelectorAndState
00E477 1 ; $E474: 20 DC E3
00E477 1
00E477 1 98 tya ; $E477: 98
00E478 1 0A asl ; $E478: 0A
00E479 1 0A asl ; $E479: 0A
00E47A 1
00E47A 1 69 14 adc #$14 ; $E47A: 69 14
00E47C 1 A8 tay ; $E47C: A8
00E47D 1
00E47D 1 A9 0F lda #$0F ; $E47D: A9 0F
00E47F 1 D0 34 bne StoreGeometryParameter ; $E47F: D0 34
00E481 1 ; Always taken.
00E481 1 ; Target $E4B5.
00E481 1
00E481 1 ; ----------------------------------------------------------------------------
00E481 1 ; Select from the geometry-record group beginning at offset $44.
00E481 1 ;
00E481 1 ; Return:
00E481 1 ; Y = (($selector << 1) & $0C) + $44
00E481 1 ; $C6 = $05
00E481 1 ; ----------------------------------------------------------------------------
00E481 1
00E481 1 ; ----------------------------------------------------------------------------
00E481 1 ; Contract:
00E481 1 ; Description: Implements Select Geometry Record 4 4.
00E481 1 ; Entry: Registers: A, Y
00E481 1 ; Returns/products: Registers/clobbers: A, Y
00E481 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E481 1 ; Memory effects: $c6
00E481 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E481 1 ; comparison, load, or store path and are not a stable API product.
00E481 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E481 1 ; ----------------------------------------------------------------------------
00E481 1 SelectGeometryRecord_44: ; $E481
00E481 1 20 DC E3 jsr GetCurrentObjectSelectorAndState
00E484 1 ; $E481: 20 DC E3
00E484 1
00E484 1 98 tya ; $E484: 98
00E485 1 0A asl ; $E485: 0A
00E486 1 29 0C and #$0C ; $E486: 29 0C
00E488 1
00E488 1 69 44 adc #$44 ; $E488: 69 44
00E48A 1 A8 tay ; $E48A: A8
00E48B 1
00E48B 1 A9 05 lda #$05 ; $E48B: A9 05
00E48D 1 D0 26 bne StoreGeometryParameter ; $E48D: D0 26
00E48F 1 ; Always taken.
00E48F 1 ; Target $E4B5.
00E48F 1
00E48F 1 ; ----------------------------------------------------------------------------
00E48F 1 ; Select from the geometry-record group beginning at offset $34.
00E48F 1 ;
00E48F 1 ; Return:
00E48F 1 ; Y = (($selector << 1) & $1C) + $34
00E48F 1 ; $C6 = $07
00E48F 1 ; ----------------------------------------------------------------------------
00E48F 1
00E48F 1 ; ----------------------------------------------------------------------------
00E48F 1 ; Contract:
00E48F 1 ; Description: Implements Select Geometry Record 3 4.
00E48F 1 ; Entry: Registers: A, Y
00E48F 1 ; Returns/products: Registers/clobbers: A, Y
00E48F 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E48F 1 ; Memory effects: $c6
00E48F 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E48F 1 ; comparison, load, or store path and are not a stable API product.
00E48F 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 3.
00E48F 1 ; ----------------------------------------------------------------------------
00E48F 1 SelectGeometryRecord_34: ; $E48F
00E48F 1 20 DC E3 jsr GetCurrentObjectSelectorAndState
00E492 1 ; $E48F: 20 DC E3
00E492 1
00E492 1 98 tya ; $E492: 98
00E493 1 0A asl ; $E493: 0A
00E494 1 29 1C and #$1C ; $E494: 29 1C
00E496 1
00E496 1 69 34 adc #$34 ; $E496: 69 34
00E498 1 D0 18 bne UseGeometryRecordOffset ; $E498: D0 18
00E49A 1 ; Target $E4B2.
00E49A 1
00E49A 1 ; ----------------------------------------------------------------------------
00E49A 1 ; Select from the geometry-record group beginning at offset $28.
00E49A 1 ;
00E49A 1 ; Return:
00E49A 1 ; Y = (($selector << 1) & $0C) + $28
00E49A 1 ; $C6 = $07
00E49A 1 ; ----------------------------------------------------------------------------
00E49A 1
00E49A 1 ; ----------------------------------------------------------------------------
00E49A 1 ; Contract:
00E49A 1 ; Description: Implements Select Geometry Record 2 8.
00E49A 1 ; Entry: Registers: A, Y
00E49A 1 ; Returns/products: Registers/clobbers: A, Y
00E49A 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E49A 1 ; Memory effects: $c6
00E49A 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E49A 1 ; comparison, load, or store path and are not a stable API product.
00E49A 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E49A 1 ; ----------------------------------------------------------------------------
00E49A 1 SelectGeometryRecord_28: ; $E49A
00E49A 1 20 DC E3 jsr GetCurrentObjectSelectorAndState
00E49D 1 ; $E49A: 20 DC E3
00E49D 1
00E49D 1 98 tya ; $E49D: 98
00E49E 1 0A asl ; $E49E: 0A
00E49F 1 29 0C and #$0C ; $E49F: 29 0C
00E4A1 1
00E4A1 1 69 28 adc #$28 ; $E4A1: 69 28
00E4A3 1 D0 0D bne UseGeometryRecordOffset ; $E4A3: D0 0D
00E4A5 1 ; Target $E4B2.
00E4A5 1
00E4A5 1 ; ----------------------------------------------------------------------------
00E4A5 1 ; Select from the geometry-record group beginning at offset $24.
00E4A5 1 ;
00E4A5 1 ; If the calculation produces zero, substitute fixed offset $54.
00E4A5 1 ;
00E4A5 1 ; Return:
00E4A5 1 ; Y = calculated offset or $54
00E4A5 1 ; $C6 = $07
00E4A5 1 ; ----------------------------------------------------------------------------
00E4A5 1
00E4A5 1 ; ----------------------------------------------------------------------------
00E4A5 1 ; Contract:
00E4A5 1 ; Description: Implements Select Geometry Record 2 4.
00E4A5 1 ; Entry: Registers: A, Y
00E4A5 1 ; Returns/products: Registers/clobbers: A, Y
00E4A5 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E4A5 1 ; Memory effects: $c6
00E4A5 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E4A5 1 ; comparison, load, or store path and are not a stable API product.
00E4A5 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E4A5 1 ; ----------------------------------------------------------------------------
00E4A5 1 SelectGeometryRecord_24: ; $E4A5
00E4A5 1 20 DC E3 jsr GetCurrentObjectSelectorAndState
00E4A8 1 ; $E4A5: 20 DC E3
00E4A8 1
00E4A8 1 98 tya ; $E4A8: 98
00E4A9 1 0A asl ; $E4A9: 0A
00E4AA 1 29 0C and #$0C ; $E4AA: 29 0C
00E4AC 1
00E4AC 1 69 24 adc #$24 ; $E4AC: 69 24
00E4AE 1 D0 02 bne UseGeometryRecordOffset ; $E4AE: D0 02
00E4B0 1 ; Target $E4B2.
00E4B0 1
00E4B0 1 ; ----------------------------------------------------------------------------
00E4B0 1 ; Contract:
00E4B0 1 ; Description: Internal geometry-selector path using fixed record offset $54.
00E4B0 1 ; Entry: No additional register input beyond parent selector state.
00E4B0 1 ; Returns/products: Y receives record offset; shared geometry parameter set.
00E4B0 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E4B0 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00E4B0 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E4B0 1 ; comparison, load, or store path and are not a stable API product.
00E4B0 1 ; Validation: Internal-entry contract; call sites: internal entry.
00E4B0 1 ; ----------------------------------------------------------------------------
00E4B0 1 UseFixedGeometryRecord54:
00E4B0 1 A9 54 lda #$54 ; $E4B0: A9 54
00E4B2 1
00E4B2 1 ; ----------------------------------------------------------------------------
00E4B2 1 ; Convert the selected geometry-record offset from A to Y.
00E4B2 1 ; ----------------------------------------------------------------------------
00E4B2 1
00E4B2 1 UseGeometryRecordOffset: ; $E4B2
00E4B2 1 A8 tay ; $E4B2: A8
00E4B3 1
00E4B3 1 A9 07 lda #$07 ; $E4B3: A9 07
00E4B5 1
00E4B5 1 ; ----------------------------------------------------------------------------
00E4B5 1 ; Shared parameter store.
00E4B5 1 ;
00E4B5 1 ; The branches from $E47F and $E48D enter directly here, preserving their
00E4B5 1 ; respective values $0F and $05.
00E4B5 1 ; ----------------------------------------------------------------------------
00E4B5 1
00E4B5 1 StoreGeometryParameter: ; $E4B5
00E4B5 1 85 C6 sta $C6 ; $E4B5: 85 C6
00E4B7 1
00E4B7 1 60 rts ; $E4B7: 60
00E4B8 1
00E4B8 1 ; ============================================================================
00E4B8 1 ; $E4B8-$E4C1
00E4B8 1 ; Select a geometry record directly from CurrentObjectIndex.
00E4B8 1 ;
00E4B8 1 ; Return:
00E4B8 1 ; Y = (CurrentObjectIndex * 2) + $F4
00E4B8 1 ; $C6 = $0F
00E4B8 1 ;
00E4B8 1 ; The BNE branches backward directly to STA $C6 at $E4B5.
00E4B8 1 ; ============================================================================
00E4B8 1
00E4B8 1 ; ----------------------------------------------------------------------------
00E4B8 1 ; Contract:
00E4B8 1 ; Description: Implements Select Geometry Record From Object.
00E4B8 1 ; Entry: Registers: A; Memory: currentobjectindex, GeometryParameterData, $e414, $e415, $e416
00E4B8 1 ; Returns/products: Registers/clobbers: A, Y
00E4B8 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E4B8 1 ; Memory effects: $b2, $b3, $b4, $b5
00E4B8 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E4B8 1 ; comparison, load, or store path and are not a stable API product.
00E4B8 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E4B8 1 ; ----------------------------------------------------------------------------
00E4B8 1 SelectGeometryRecordFromObject: ; $E4B8
00E4B8 1 A5 E1 lda CurrentObjectIndex ; $E4B8: A5 E1
00E4BA 1 0A asl ; $E4BA: 0A
00E4BB 1
00E4BB 1 69 F4 adc #$F4 ; $E4BB: 69 F4
00E4BD 1 A8 tay ; $E4BD: A8
00E4BE 1
00E4BE 1 A9 0F lda #$0F ; $E4BE: A9 0F
00E4C0 1 D0 F3 bne StoreGeometryParameter ; $E4C0: D0 F3
00E4C2 1 ; Always taken.
00E4C2 1 ; Target $E4B5.
00E4C2 1
00E4C2 1 ; ============================================================================
00E4C2 1 ; $E4C2-$E4D6
00E4C2 1 ; Load a four-byte geometry record into $B2-$B5.
00E4C2 1 ;
00E4C2 1 ; Entry:
00E4C2 1 ; Y = byte offset into the geometry data beginning at GeometryParameterData
00E4C2 1 ;
00E4C2 1 ; Exit:
00E4C2 1 ; $B2 = byte at $E413+Y
00E4C2 1 ; $B3 = byte at $E414+Y
00E4C2 1 ; $B4 = byte at $E415+Y
00E4C2 1 ; $B5 = byte at $E416+Y
00E4C2 1 ;
00E4C2 1 ; Literal addresses are used because the geometry data was decoded as several
00E4C2 1 ; smaller source blocks.
00E4C2 1 ; ============================================================================
00E4C2 1
00E4C2 1 ; ----------------------------------------------------------------------------
00E4C2 1 ; Contract:
00E4C2 1 ; Description: Implements Load Geometry Record.
00E4C2 1 ; Entry: Registers: A; Memory: GeometryParameterData, $e414, $e415, $e416
00E4C2 1 ; Returns/products: Registers/clobbers: A
00E4C2 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E4C2 1 ; Memory effects: $b2, $b3, $b4, $b5
00E4C2 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E4C2 1 ; comparison, load, or store path and are not a stable API product.
00E4C2 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 6.
00E4C2 1 ; ----------------------------------------------------------------------------
00E4C2 1 LoadGeometryRecord: ; $E4C2
00E4C2 1 B9 13 E4 lda GeometryParameterData,y ; $E4C2: B9 13 E4
00E4C5 1 85 B2 sta $B2 ; $E4C5: 85 B2
00E4C7 1
00E4C7 1 B9 14 E4 lda GeometryParameterData+1,y ; $E4C7: B9 14 E4
00E4CA 1 85 B3 sta $B3 ; $E4CA: 85 B3
00E4CC 1
00E4CC 1 B9 15 E4 lda GeometryParameterData+2,y ; $E4CC: B9 15 E4
00E4CF 1 85 B4 sta $B4 ; $E4CF: 85 B4
00E4D1 1
00E4D1 1 B9 16 E4 lda GeometryParameterData+3,y ; $E4D1: B9 16 E4
00E4D4 1 85 B5 sta $B5 ; $E4D4: 85 B5
00E4D6 1
00E4D6 1 60 rts ; $E4D6: 60
00E4D7 1
00E4D7 1 ; ============================================================================
00E4D7 1 ; $E4D7-$E501
00E4D7 1 ; Calculate doubled signed coordinate differences between geometry arguments
00E4D7 1 ; $B2-$B5 and an object position.
00E4D7 1 ;
00E4D7 1 ; Two entry points select the object:
00E4D7 1 ;
00E4D7 1 ; $E4D7: compare against the base object at array offset $00
00E4D7 1 ; $E4DB: compare against CurrentObjectIndex
00E4D7 1 ;
00E4D7 1 ; Results:
00E4D7 1 ; $AE/$AF = doubled horizontal difference
00E4D7 1 ; $B0/$B1 = doubled vertical difference
00E4D7 1 ; ============================================================================
00E4D7 1
00E4D7 1 CalculateBaseGeometryDifference: ; $E4D7
00E4D7 1 A2 00 ldx #$00 ; $E4D7: A2 00
00E4D9 1 F0 02 beq CalculateGeometryDifference
00E4DB 1 ; $E4D9: F0 02
00E4DB 1 ; Always taken because X is zero.
00E4DB 1
00E4DB 1 ; ----------------------------------------------------------------------------
00E4DB 1 ; Contract:
00E4DB 1 ; Description: Calculates Current Geometry Difference.
00E4DB 1 ; Entry: Registers: A; Memory: currentobjectindex, $b2, $0509, $b3, $050a, $b4, $053a, $b5
00E4DB 1 ; Returns/products: Registers/clobbers: A, X
00E4DB 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E4DB 1 ; Memory effects: calculatedcoordinatelow, calculatedcoordinatehigh, $b0, $b1
00E4DB 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E4DB 1 ; comparison, load, or store path and are not a stable API product.
00E4DB 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 5.
00E4DB 1 ; ----------------------------------------------------------------------------
00E4DB 1 CalculateCurrentGeometryDifference: ; $E4DB
00E4DB 1 A6 E1 ldx CurrentObjectIndex ; $E4DB: A6 E1
00E4DD 1
00E4DD 1 ; ----------------------------------------------------------------------------
00E4DD 1 ; Calculate the signed horizontal difference:
00E4DD 1 ;
00E4DD 1 ; ($B2/$B3) - ($0509/$050A,X)
00E4DD 1 ;
00E4DD 1 ; Then multiply the 16-bit result by two.
00E4DD 1 ; ----------------------------------------------------------------------------
00E4DD 1
00E4DD 1 ; ----------------------------------------------------------------------------
00E4DD 1 ; Contract:
00E4DD 1 ; Description: Calculates Geometry Difference.
00E4DD 1 ; Entry: Registers: A; Memory: $b2, $0509, $b3, $050a, $b4, $053a, $b5, $053b
00E4DD 1 ; Returns/products: Registers/clobbers: A
00E4DD 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E4DD 1 ; Memory effects: calculatedcoordinatelow, calculatedcoordinatehigh, $b0, $b1
00E4DD 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E4DD 1 ; comparison, load, or store path and are not a stable API product.
00E4DD 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E4DD 1 ; ----------------------------------------------------------------------------
00E4DD 1 CalculateGeometryDifference: ; $E4DD
00E4DD 1 38 sec ; $E4DD: 38
00E4DE 1
00E4DE 1 A5 B2 lda $B2 ; $E4DE: A5 B2
00E4E0 1 FD 09 05 sbc $0509,x ; $E4E0: FD 09 05
00E4E3 1 85 AE sta CalculatedCoordinateLow ; $E4E3: 85 AE
00E4E5 1
00E4E5 1 A5 B3 lda $B3 ; $E4E5: A5 B3
00E4E7 1 FD 0A 05 sbc $050A,x ; $E4E7: FD 0A 05
00E4EA 1
00E4EA 1 06 AE asl CalculatedCoordinateLow ; $E4EA: 06 AE
00E4EC 1 2A rol ; $E4EC: 2A
00E4ED 1 85 AF sta CalculatedCoordinateHigh ; $E4ED: 85 AF
00E4EF 1
00E4EF 1 ; ----------------------------------------------------------------------------
00E4EF 1 ; Calculate the signed vertical difference:
00E4EF 1 ;
00E4EF 1 ; ($B4/$B5) - ($053A/$053B,X)
00E4EF 1 ;
00E4EF 1 ; Then multiply the 16-bit result by two.
00E4EF 1 ; ----------------------------------------------------------------------------
00E4EF 1
00E4EF 1 38 sec ; $E4EF: 38
00E4F0 1
00E4F0 1 A5 B4 lda $B4 ; $E4F0: A5 B4
00E4F2 1 FD 3A 05 sbc $053A,x ; $E4F2: FD 3A 05
00E4F5 1 85 B0 sta $B0 ; $E4F5: 85 B0
00E4F7 1
00E4F7 1 A5 B5 lda $B5 ; $E4F7: A5 B5
00E4F9 1 FD 3B 05 sbc $053B,x ; $E4F9: FD 3B 05
00E4FC 1
00E4FC 1 06 B0 asl $B0 ; $E4FC: 06 B0
00E4FE 1 2A rol ; $E4FE: 2A
00E4FF 1 85 B1 sta $B1 ; $E4FF: 85 B1
00E501 1
00E501 1 60 rts ; $E501: 60
00E502 1
00E502 1 ; ============================================================================
00E502 1 ; $E502-$E512
00E502 1 ; Normalize or measure the signed coordinate difference in $AE-$B1.
00E502 1 ;
00E502 1 ; The high bytes are adjusted upward when the corresponding low signed value
00E502 1 ; is negative, then passed to the vector or distance helper at $E80B.
00E502 1 ;
00E502 1 ; Entry:
00E502 1 ; $AE/$AF = signed horizontal difference
00E502 1 ; $B0/$B1 = signed vertical difference
00E502 1 ;
00E502 1 ; Exit:
00E502 1 ; Returned directly from $E80B
00E502 1 ; ============================================================================
00E502 1
00E502 1 ; ----------------------------------------------------------------------------
00E502 1 ; Contract:
00E502 1 ; Description: Implements Evaluate Geometry Difference.
00E502 1 ; Entry: Registers: X, Y; Memory: calculatedcoordinatehigh, calculatedcoordinatelow, $b1, $b0
00E502 1 ; Returns/products: Registers/clobbers: A, X, Y
00E502 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E502 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00E502 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E502 1 ; comparison, load, or store path and are not a stable API product.
00E502 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 5.
00E502 1 ; ----------------------------------------------------------------------------
00E502 1 EvaluateGeometryDifference: ; $E502
00E502 1 A6 AF ldx CalculatedCoordinateHigh ; $E502: A6 AF
00E504 1
00E504 1 A5 AE lda CalculatedCoordinateLow ; $E504: A5 AE
00E506 1 10 01 bpl EvaluateGeometryDifference_HorizontalReady
00E508 1 ; $E506: 10 01
00E508 1
00E508 1 E8 inx ; $E508: E8
00E509 1
00E509 1 EvaluateGeometryDifference_HorizontalReady: ; $E509
00E509 1 A4 B1 ldy $B1 ; $E509: A4 B1
00E50B 1
00E50B 1 A5 B0 lda $B0 ; $E50B: A5 B0
00E50D 1 10 01 bpl EvaluateGeometryDifference_VerticalReady
00E50F 1 ; $E50D: 10 01
00E50F 1
00E50F 1 C8 iny ; $E50F: C8
00E510 1
00E510 1 EvaluateGeometryDifference_VerticalReady: ; $E510
00E510 1 4C 0B E8 jmp CalculateVectorMagnitude ; $E510: 4C 0B E8
00E513 1
00E513 1 ; ============================================================================
00E513 1 ; $E513-$E527
00E513 1 ; Convert geometry parameter bytes into a signed vector.
00E513 1 ;
00E513 1 ; Entry:
00E513 1 ; A = horizontal parameter
00E513 1 ; $B5 = vertical parameter or zero
00E513 1 ; $AF/$B1 = signed coordinate-difference high bytes
00E513 1 ;
00E513 1 ; Operation:
00E513 1 ; 1. Save A in $B3.
00E513 1 ; 2. Clear $B5.
00E513 1 ; 3. Copy $B3/$B5 into $D6/$D7.
00E513 1 ; 4. Pass X=$AF and Y=$B1 to $E828.
00E513 1 ;
00E513 1 ; Exit:
00E513 1 ; Returned directly from $E828
00E513 1 ; ============================================================================
00E513 1
00E513 1 ; ----------------------------------------------------------------------------
00E513 1 ; Contract:
00E513 1 ; Description: Implements Build Geometry Vector.
00E513 1 ; Entry: Registers: A; Memory: $b3, $b5, calculatedcoordinatehigh, $b1
00E513 1 ; Returns/products: Registers/clobbers: A, X, Y
00E513 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E513 1 ; Memory effects: $b3, $b5, $d6, $d7
00E513 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E513 1 ; comparison, load, or store path and are not a stable API product.
00E513 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 5.
00E513 1 ; ----------------------------------------------------------------------------
00E513 1 BuildGeometryVector: ; $E513
00E513 1 85 B3 sta $B3 ; $E513: 85 B3
00E515 1
00E515 1 A9 00 lda #$00 ; $E515: A9 00
00E517 1 85 B5 sta $B5 ; $E517: 85 B5
00E519 1
00E519 1 ; ----------------------------------------------------------------------------
00E519 1 ; Alternate entry used when $B3 and $B5 are already initialized.
00E519 1 ; ----------------------------------------------------------------------------
00E519 1
00E519 1 ; ----------------------------------------------------------------------------
00E519 1 ; Contract:
00E519 1 ; Description: Implements Build Geometry Vector From Arguments.
00E519 1 ; Entry: Registers: A; Memory: $b3, $b5, calculatedcoordinatehigh, $b1
00E519 1 ; Returns/products: Registers/clobbers: A, X, Y
00E519 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E519 1 ; Memory effects: $d6, $d7
00E519 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E519 1 ; comparison, load, or store path and are not a stable API product.
00E519 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 2.
00E519 1 ; ----------------------------------------------------------------------------
00E519 1 BuildGeometryVectorFromArguments: ; $E519
00E519 1 A5 B3 lda $B3 ; $E519: A5 B3
00E51B 1 85 D6 sta $D6 ; $E51B: 85 D6
00E51D 1
00E51D 1 A5 B5 lda $B5 ; $E51D: A5 B5
00E51F 1 85 D7 sta $D7 ; $E51F: 85 D7
00E521 1
00E521 1 A6 AF ldx CalculatedCoordinateHigh ; $E521: A6 AF
00E523 1 A4 B1 ldy $B1 ; $E523: A4 B1
00E525 1
00E525 1 4C 28 E8 jmp CalculateSignedVectorFromResult ; $E525: 4C 28 E8
00E528 1
00E528 1 ; ============================================================================
00E528 1 ; $E528-$E532
00E528 1 ; Store a calculated movement vector into the current object.
00E528 1 ;
00E528 1 ; Entry:
00E528 1 ; A = horizontal movement low/result byte
00E528 1 ; Y = vertical movement low/result byte
00E528 1 ;
00E528 1 ; Exit:
00E528 1 ; X = CurrentObjectIndex
00E528 1 ;
00E528 1 ; Modified fields:
00E528 1 ; $056D,X = A
00E528 1 ; $056E,X = Y
00E528 1 ; ============================================================================
00E528 1
00E528 1 ; ----------------------------------------------------------------------------
00E528 1 ; Contract:
00E528 1 ; Description: Implements Store Current Object Movement.
00E528 1 ; Entry: Registers: A, Y; Memory: currentobjectindex
00E528 1 ; Returns/products: Registers/clobbers: A, X
00E528 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E528 1 ; Memory effects: $056d, $056e
00E528 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E528 1 ; comparison, load, or store path and are not a stable API product.
00E528 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 4.
00E528 1 ; ----------------------------------------------------------------------------
00E528 1 StoreCurrentObjectMovement: ; $E528
00E528 1 AA tax ; $E528: AA
00E529 1 ; Temporarily preserve A in X.
00E529 1
00E529 1 A6 E1 ldx CurrentObjectIndex ; $E529: A6 E1
00E52B 1
00E52B 1 9D 6D 05 sta $056D,x ; $E52B: 9D 6D 05
00E52E 1
00E52E 1 98 tya ; $E52E: 98
00E52F 1 9D 6E 05 sta $056E,x ; $E52F: 9D 6E 05
00E532 1
00E532 1 60 rts ; $E532: 60
00E533 1
00E533 1 ; ============================================================================
00E533 1 ; $E533-$E547
00E533 1 ; Store a calculated position in the base object and clear its movement fields.
00E533 1 ;
00E533 1 ; Entry:
00E533 1 ; A = horizontal low/result byte
00E533 1 ; Y = vertical low/result byte
00E533 1 ;
00E533 1 ; Modified fields:
00E533 1 ; $0508 = A
00E533 1 ; $0539 = Y
00E533 1 ;
00E533 1 ; $056A = $00
00E533 1 ; $0507 = $00
00E533 1 ; $0538 = $00
00E533 1 ; $0569 = $00
00E533 1 ;
00E533 1 ; Exit:
00E533 1 ; A = $00
00E533 1 ; ============================================================================
00E533 1
00E533 1 StoreBaseObjectPositionAndClearMovement: ; $E533
00E533 1 8D 08 05 sta $0508 ; $E533: 8D 08 05
00E536 1 8C 39 05 sty $0539 ; $E536: 8C 39 05
00E539 1
00E539 1 ; ----------------------------------------------------------------------------
00E539 1 ; Clear the remaining base-object movement components.
00E539 1 ; ----------------------------------------------------------------------------
00E539 1
00E539 1 A9 00 lda #$00 ; $E539: A9 00
00E53B 1
00E53B 1 8D 6A 05 sta $056A ; $E53B: 8D 6A 05
00E53E 1 8D 07 05 sta $0507 ; $E53E: 8D 07 05
00E541 1 8D 38 05 sta $0538 ; $E541: 8D 38 05
00E544 1 8D 69 05 sta $0569 ; $E544: 8D 69 05
00E547 1
00E547 1 60 rts ; $E547: 60
00E548 1
00E548 1 ; ============================================================================
00E548 1 ; $E548-$E54E
00E548 1 ; Begin copying geometry arguments into the current object's coordinates.
00E548 1 ; ============================================================================
00E548 1
00E548 1 ; ----------------------------------------------------------------------------
00E548 1 ; Contract:
00E548 1 ; Description: Implements Store Geometry In Current Object.
00E548 1 ; Entry: Registers: A; Memory: currentobjectindex, $b2, $b3, $b4, $b5
00E548 1 ; Returns/products: Registers/clobbers: A, X
00E548 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E548 1 ; Memory effects: $0509, $050a, $053a, $053b
00E548 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E548 1 ; comparison, load, or store path and are not a stable API product.
00E548 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E548 1 ; ----------------------------------------------------------------------------
00E548 1 StoreGeometryInCurrentObject: ; $E548
00E548 1 A6 E1 ldx CurrentObjectIndex ; $E548: A6 E1
00E54A 1
00E54A 1 A5 B2 lda $B2 ; $E54A: A5 B2
00E54C 1 9D 09 05 sta $0509,x ; $E54C: 9D 09 05
00E54F 1
00E54F 1 ; ============================================================================
00E54F 1 ; $E54F-$E561
00E54F 1 ; Complete the copy of geometry arguments $B2-$B5 into the current object's
00E54F 1 ; coordinate fields.
00E54F 1 ;
00E54F 1 ; Entry:
00E54F 1 ; X = CurrentObjectIndex, loaded by the preceding code at $E548
00E54F 1 ;
00E54F 1 ; Geometry source:
00E54F 1 ; $B2 = horizontal low byte
00E54F 1 ; $B3 = horizontal high byte
00E54F 1 ; $B4 = vertical low byte
00E54F 1 ; $B5 = vertical high byte
00E54F 1 ;
00E54F 1 ; Object destination:
00E54F 1 ; $0509,X/$050A,X = horizontal coordinate
00E54F 1 ; $053A,X/$053B,X = vertical coordinate
00E54F 1 ; ============================================================================
00E54F 1
00E54F 1 A5 B3 lda $B3 ; $E54F: A5 B3
00E551 1 9D 0A 05 sta $050A,x ; $E551: 9D 0A 05
00E554 1
00E554 1 A5 B4 lda $B4 ; $E554: A5 B4
00E556 1 9D 3A 05 sta $053A,x ; $E556: 9D 3A 05
00E559 1
00E559 1 A5 B5 lda $B5 ; $E559: A5 B5
00E55B 1 9D 3B 05 sta $053B,x ; $E55B: 9D 3B 05
00E55E 1
00E55E 1 60 rts ; $E55E: 60
00E55F 1
00E55F 1 ; ============================================================================
00E55F 1 ; $E55F-$E57D
00E55F 1 ; Load the selected geometry record, compare it with the current object, and
00E55F 1 ; either apply a calculated movement vector or copy the geometry directly into
00E55F 1 ; the current object's position.
00E55F 1 ;
00E55F 1 ; Entry:
00E55F 1 ; Y = geometry-record offset
00E55F 1 ; $C6 = geometry/vector parameter
00E55F 1 ;
00E55F 1 ; Return:
00E55F 1 ; C = set when the geometry result is at least $02
00E55F 1 ; C = clear when the geometry result is below $02
00E55F 1 ; ============================================================================
00E55F 1
00E55F 1 ; ----------------------------------------------------------------------------
00E55F 1 ; Contract:
00E55F 1 ; Description: Implements Apply Current Object Geometry.
00E55F 1 ; Entry: Registers: A; Memory: $c6
00E55F 1 ; Returns/products: Registers/clobbers: A; Flags: condition flags may carry result state
00E55F 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E55F 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00E55F 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E55F 1 ; comparison, load, or store path and are not a stable API product.
00E55F 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 11.
00E55F 1 ; ----------------------------------------------------------------------------
00E55F 1 ApplyCurrentObjectGeometry: ; $E55F
00E55F 1 20 C2 E4 jsr LoadGeometryRecord ; $E55F: 20 C2 E4
00E562 1
00E562 1 ; ----------------------------------------------------------------------------
00E562 1 ; Calculate and evaluate the difference between the loaded geometry record
00E562 1 ; and the current object.
00E562 1 ; ----------------------------------------------------------------------------
00E562 1 EvaluateLoadedCurrentObjectGeometry:
00E562 1 20 DB E4 jsr CalculateCurrentGeometryDifference
00E565 1 ; $E562: 20 DB E4
00E565 1
00E565 1 20 02 E5 jsr EvaluateGeometryDifference
00E568 1 ; $E565: 20 02 E5
00E568 1
00E568 1 C9 02 cmp #$02 ; $E568: C9 02
00E56A 1 90 0A bcc ApplyCurrentObjectGeometry_CopyPosition
00E56C 1 ; $E56A: 90 0A
00E56C 1
00E56C 1 ; ----------------------------------------------------------------------------
00E56C 1 ; Geometry result is at least two.
00E56C 1 ;
00E56C 1 ; Use the selected parameter in $C6 to build a movement vector and store it in
00E56C 1 ; the current object's movement fields.
00E56C 1 ; ----------------------------------------------------------------------------
00E56C 1
00E56C 1 A5 C6 lda $C6 ; $E56C: A5 C6
00E56E 1
00E56E 1 20 13 E5 jsr BuildGeometryVector ; $E56E: 20 13 E5
00E571 1 20 28 E5 jsr StoreCurrentObjectMovement
00E574 1 ; $E571: 20 28 E5
00E574 1
00E574 1 38 sec ; $E574: 38
00E575 1 60 rts ; $E575: 60
00E576 1
00E576 1 ; ----------------------------------------------------------------------------
00E576 1 ; Geometry result is below two.
00E576 1 ;
00E576 1 ; Copy the loaded geometry record directly into the current object's position,
00E576 1 ; clear the object's movement fields, and return carry clear.
00E576 1 ; ----------------------------------------------------------------------------
00E576 1
00E576 1 ApplyCurrentObjectGeometry_CopyPosition: ; $E576
00E576 1 20 48 E5 jsr StoreGeometryInCurrentObject
00E579 1 ; $E576: 20 48 E5
00E579 1
00E579 1 20 D3 E2 jsr ClearCurrentObjectMovement
00E57C 1 ; $E579: 20 D3 E2
00E57C 1
00E57C 1 18 clc ; $E57C: 18
00E57D 1 60 rts ; $E57D: 60
00E57E 1
00E57E 1 ; ============================================================================
00E57E 1 ; $E57E-$E59C
00E57E 1 ; Select a geometry record from the current object's saved selector, compare
00E57E 1 ; it with the base object, and either update the base object's movement or
00E57E 1 ; initialize the base object from the current object.
00E57E 1 ;
00E57E 1 ; Entry:
00E57E 1 ; CurrentObjectIndex selects the current object.
00E57E 1 ;
00E57E 1 ; Return:
00E57E 1 ; C = set when the geometry result is at least $02
00E57E 1 ; C = clear when the geometry result is below $02
00E57E 1 ; ============================================================================
00E57E 1
00E57E 1 ; ----------------------------------------------------------------------------
00E57E 1 ; Contract:
00E57E 1 ; Description: Implements Apply Base Object Geometry.
00E57E 1 ; Entry: Registers: A; Memory: $c5
00E57E 1 ; Returns/products: Registers/clobbers: A; Flags: condition flags may carry result state
00E57E 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E57E 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00E57E 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E57E 1 ; comparison, load, or store path and are not a stable API product.
00E57E 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E57E 1 ; ----------------------------------------------------------------------------
00E57E 1 ApplyBaseObjectGeometry: ; $E57E
00E57E 1 20 6B E4 jsr GetCurrentGeometryRecordOffset
00E581 1 ; $E57E: 20 6B E4
00E581 1
00E581 1 20 C2 E4 jsr LoadGeometryRecord ; $E581: 20 C2 E4
00E584 1
00E584 1 ; ----------------------------------------------------------------------------
00E584 1 ; Calculate and evaluate the difference between the loaded geometry record
00E584 1 ; and the base object at array offset zero.
00E584 1 ; ----------------------------------------------------------------------------
00E584 1
00E584 1 20 D7 E4 jsr CalculateBaseGeometryDifference
00E587 1 ; $E584: 20 D7 E4
00E587 1
00E587 1 20 02 E5 jsr EvaluateGeometryDifference
00E58A 1 ; $E587: 20 02 E5
00E58A 1
00E58A 1 C9 02 cmp #$02 ; $E58A: C9 02
00E58C 1 90 0A bcc ApplyBaseObjectGeometry_CopyCurrent
00E58E 1 ; $E58C: 90 0A
00E58E 1
00E58E 1 ; ----------------------------------------------------------------------------
00E58E 1 ; Geometry result is at least two.
00E58E 1 ;
00E58E 1 ; Build a vector using the parameter in $C5, then store the result in the base
00E58E 1 ; object's position/movement fields.
00E58E 1 ; ----------------------------------------------------------------------------
00E58E 1
00E58E 1 A5 C5 lda $C5 ; $E58E: A5 C5
00E590 1
00E590 1 20 13 E5 jsr BuildGeometryVector ; $E590: 20 13 E5
00E593 1 20 33 E5 jsr StoreBaseObjectPositionAndClearMovement
00E596 1 ; $E593: 20 33 E5
00E596 1
00E596 1 38 sec ; $E596: 38
00E597 1 60 rts ; $E597: 60
00E598 1
00E598 1 ; ----------------------------------------------------------------------------
00E598 1 ; Geometry result is below two.
00E598 1 ;
00E598 1 ; Initialize the base object from the current object and return carry clear.
00E598 1 ; ----------------------------------------------------------------------------
00E598 1
00E598 1 ApplyBaseObjectGeometry_CopyCurrent: ; $E598
00E598 1 20 E6 E3 jsr InitializeBaseObjectFromCurrent
00E59B 1 ; $E598: 20 E6 E3
00E59B 1
00E59B 1 18 clc ; $E59B: 18
00E59C 1 60 rts ; $E59C: 60
00E59D 1
00E59D 1 ; ============================================================================
00E59D 1 ; $E59D-$E5CE
00E59D 1 ; Evaluate both current-object and base-object geometry, calculate a bounded
00E59D 1 ; shared vector parameter, apply that vector to the base object, and activate
00E59D 1 ; motion.
00E59D 1 ;
00E59D 1 ; This routine combines the geometry results from two separate record
00E59D 1 ; selections:
00E59D 1 ;
00E59D 1 ; 1. Selector-dependent record chosen by $E474.
00E59D 1 ; 2. Current-selector record chosen by $E46B.
00E59D 1 ; ============================================================================
00E59D 1
00E59D 1 ; ----------------------------------------------------------------------------
00E59D 1 ; Contract:
00E59D 1 ; Description: Initializes Shared Object Motion.
00E59D 1 ; Entry: Registers: A
00E59D 1 ; Returns/products: Registers/clobbers: A, X, Y
00E59D 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E59D 1 ; Memory effects: $c5
00E59D 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E59D 1 ; comparison, load, or store path and are not a stable API product.
00E59D 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E59D 1 ; ----------------------------------------------------------------------------
00E59D 1 InitializeSharedObjectMotion: ; $E59D
00E59D 1 20 74 E4 jsr SelectGeometryRecord_Default
00E5A0 1 ; $E59D: 20 74 E4
00E5A0 1
00E5A0 1 20 C2 E4 jsr LoadGeometryRecord ; $E5A0: 20 C2 E4
00E5A3 1
00E5A3 1 20 DB E4 jsr CalculateCurrentGeometryDifference
00E5A6 1 ; $E5A3: 20 DB E4
00E5A6 1
00E5A6 1 20 02 E5 jsr EvaluateGeometryDifference
00E5A9 1 ; $E5A6: 20 02 E5
00E5A9 1
00E5A9 1 48 pha ; $E5A9: 48
00E5AA 1 ; Preserve the current-object geometry result.
00E5AA 1
00E5AA 1 ; ----------------------------------------------------------------------------
00E5AA 1 ; Select and evaluate the corresponding geometry relative to the base object.
00E5AA 1 ; ----------------------------------------------------------------------------
00E5AA 1
00E5AA 1 20 6B E4 jsr GetCurrentGeometryRecordOffset
00E5AD 1 ; $E5AA: 20 6B E4
00E5AD 1
00E5AD 1 20 C2 E4 jsr LoadGeometryRecord ; $E5AD: 20 C2 E4
00E5B0 1
00E5B0 1 20 D7 E4 jsr CalculateBaseGeometryDifference
00E5B3 1 ; $E5B0: 20 D7 E4
00E5B3 1
00E5B3 1 20 02 E5 jsr EvaluateGeometryDifference
00E5B6 1 ; $E5B3: 20 02 E5
00E5B6 1
00E5B6 1 AA tax ; $E5B6: AA
00E5B7 1 ; X = base-object geometry result.
00E5B7 1
00E5B7 1 68 pla ; $E5B7: 68
00E5B8 1 A8 tay ; $E5B8: A8
00E5B9 1 ; Y = current-object geometry result.
00E5B9 1
00E5B9 1 ; ----------------------------------------------------------------------------
00E5B9 1 ; Call the math helper at $E965 with:
00E5B9 1 ;
00E5B9 1 ; A = $0F
00E5B9 1 ; X = base-object result
00E5B9 1 ; Y = current-object result
00E5B9 1 ;
00E5B9 1 ; Clamp its returned value to a maximum of $19.
00E5B9 1 ; ----------------------------------------------------------------------------
00E5B9 1
00E5B9 1 A9 0F lda #$0F ; $E5B9: A9 0F
00E5BB 1 20 65 E9 jsr CalculateScaledRatio ; $E5BB: 20 65 E9
00E5BE 1
00E5BE 1 C9 19 cmp #$19 ; $E5BE: C9 19
00E5C0 1 90 02 bcc InitializeSharedObjectMotion_Save
00E5C2 1 ; $E5C0: 90 02
00E5C2 1
00E5C2 1 A9 19 lda #$19 ; $E5C2: A9 19
00E5C4 1
00E5C4 1 InitializeSharedObjectMotion_Save: ; $E5C4
00E5C4 1 85 C5 sta $C5 ; $E5C4: 85 C5
00E5C6 1
00E5C6 1 ; ----------------------------------------------------------------------------
00E5C6 1 ; Build and store the resulting vector in the base object.
00E5C6 1 ; ----------------------------------------------------------------------------
00E5C6 1
00E5C6 1 20 13 E5 jsr BuildGeometryVector ; $E5C6: 20 13 E5
00E5C9 1
00E5C9 1 20 33 E5 jsr StoreBaseObjectPositionAndClearMovement
00E5CC 1 ; $E5C9: 20 33 E5
00E5CC 1
00E5CC 1 ; ----------------------------------------------------------------------------
00E5CC 1 ; Mark base motion active.
00E5CC 1 ; ----------------------------------------------------------------------------
00E5CC 1
00E5CC 1 E6 5C inc BaseMotionActive ; $E5CC: E6 5C
00E5CE 1
00E5CE 1 60 rts ; $E5CE: 60
00E5CF 1
00E5CF 1 ; ============================================================================
00E5CF 1 ; $E5CF-$E5F3
00E5CF 1 ; Build a short PPU/display queue entry in the buffer at $0300.
00E5CF 1 ;
00E5CF 1 ; The routine:
00E5CF 1 ; 1. Calls $EA3E with A=$22, X=$A8, Y=$03, and carry set.
00E5CF 1 ; 2. Saves the returned buffer index from X in $05.
00E5CF 1 ; 3. Writes three copies of tile/value $25 into $0300,X.
00E5CF 1 ; 4. Uses bit zero of ModeFlags to select one of two final buffer positions.
00E5CF 1 ; 5. Writes tile/value $AE at that selected position.
00E5CF 1 ;
00E5CF 1 ; The exact semantics of $EA3E are not yet decoded, but it appears to prepare
00E5CF 1 ; or reserve a display/PPU queue entry and return its starting index in X.
00E5CF 1 ; ============================================================================
00E5CF 1
00E5CF 1 ; ----------------------------------------------------------------------------
00E5CF 1 ; Contract:
00E5CF 1 ; Description: Queues Mode Indicator Tiles.
00E5CF 1 ; Entry: Registers: A, X, Y; Memory: modeflags, $05
00E5CF 1 ; Returns/products: Registers/clobbers: A, X, Y
00E5CF 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E5CF 1 ; Memory effects: $05, $0300
00E5CF 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E5CF 1 ; comparison, load, or store path and are not a stable API product.
00E5CF 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E5CF 1 ; ----------------------------------------------------------------------------
00E5CF 1 QueueModeIndicatorTiles: ; $E5CF
00E5CF 1 A9 22 lda #$22 ; $E5CF: A9 22
00E5D1 1 ; Display/PPU destination parameter.
00E5D1 1
00E5D1 1 A2 A8 ldx #$A8 ; $E5D1: A2 A8
00E5D3 1 ; Tile, address, or queue parameter.
00E5D3 1
00E5D3 1 A0 03 ldy #$03 ; $E5D3: A0 03
00E5D5 1 ; Record length or field count.
00E5D5 1
00E5D5 1 38 sec ; $E5D5: 38
00E5D6 1 ; Carry is an input to $EA3E.
00E5D6 1
00E5D6 1 20 3E EA jsr AllocateDisplayBufferRecord ; $E5D6: 20 3E EA
00E5D9 1 ; Prepare the queue entry.
00E5D9 1 ; Returns a buffer index in X.
00E5D9 1
00E5D9 1 ; ----------------------------------------------------------------------------
00E5D9 1 ; Preserve the returned buffer index.
00E5D9 1 ; ----------------------------------------------------------------------------
00E5D9 1
00E5D9 1 86 05 stx $05 ; $E5D9: 86 05
00E5DB 1
00E5DB 1 ; ----------------------------------------------------------------------------
00E5DB 1 ; Write three copies of $25 into consecutive bytes of the $0300 buffer.
00E5DB 1 ;
00E5DB 1 ; The loop writes:
00E5DB 1 ;
00E5DB 1 ; $0300,X = $25
00E5DB 1 ; $0301,X = $25
00E5DB 1 ; $0302,X = $25
00E5DB 1 ; ----------------------------------------------------------------------------
00E5DB 1
00E5DB 1 A0 03 ldy #$03 ; $E5DB: A0 03
00E5DD 1 A9 25 lda #$25 ; $E5DD: A9 25
00E5DF 1
00E5DF 1 QueueModeIndicatorTiles_Fill: ; $E5DF
00E5DF 1 9D 00 03 sta $0300,x ; $E5DF: 9D 00 03
00E5E2 1 E8 inx ; $E5E2: E8
00E5E3 1
00E5E3 1 88 dey ; $E5E3: 88
00E5E4 1 D0 F9 bne QueueModeIndicatorTiles_Fill
00E5E6 1 ; $E5E4: D0 F9
00E5E6 1
00E5E6 1 ; ----------------------------------------------------------------------------
00E5E6 1 ; Select the final marker position according to bit zero of ModeFlags.
00E5E6 1 ;
00E5E6 1 ; Selected offset:
00E5E6 1 ;
00E5E6 1 ; X = saved buffer index + ((ModeFlags & $01) * 2)
00E5E6 1 ; ----------------------------------------------------------------------------
00E5E6 1
00E5E6 1 A5 40 lda ModeFlags ; $E5E6: A5 40
00E5E8 1 29 01 and #$01 ; $E5E8: 29 01
00E5EA 1 0A asl ; $E5EA: 0A
00E5EB 1
00E5EB 1 65 05 adc $05 ; $E5EB: 65 05
00E5ED 1 ; Carry is clear after ASL because the input
00E5ED 1 ; can only be zero or one.
00E5ED 1
00E5ED 1 AA tax ; $E5ED: AA
00E5EE 1
00E5EE 1 ; ----------------------------------------------------------------------------
00E5EE 1 ; Write marker tile/value $AE into the selected buffer position.
00E5EE 1 ; ----------------------------------------------------------------------------
00E5EE 1
00E5EE 1 A9 AE lda #$AE ; $E5EE: A9 AE
00E5F0 1 9D 00 03 sta $0300,x ; $E5F0: 9D 00 03
00E5F3 1
00E5F3 1 60 rts ; $E5F3: 60
00E5F4 1
00E5F4 1 ; ============================================================================
00E5F4 1 ; $E5F4
00E5F4 1 ; Standalone return entry.
00E5F4 1 ;
00E5F4 1 ; No decoded branch currently targets this byte, but it is a valid one-byte
00E5F4 1 ; routine/alternate return immediately before the random-number generator.
00E5F4 1 ; ============================================================================
00E5F4 1
00E5F4 1 Return_E5F4: ; $E5F4
00E5F4 1 60 rts ; $E5F4: 60
00E5F5 1
00E5F5 1 ; ============================================================================
00E5F5 1 ; $E5F5-$E610
00E5F5 1 ; Advance the 16-bit pseudo-random state by eight rounds.
00E5F5 1 ;
00E5F5 1 ; Random state:
00E5F5 1 ; $19 = low/output byte
00E5F5 1 ; $1A = high/feedback byte
00E5F5 1 ;
00E5F5 1 ; Working state:
00E5F5 1 ; $DC = eight-round loop counter
00E5F5 1 ;
00E5F5 1 ; Return:
00E5F5 1 ; A = updated $19
00E5F5 1 ;
00E5F5 1 ; The routine shifts the combined random state right. When the shifted-out bit
00E5F5 1 ; is clear, feedback masks $88 and $10 are XORed into $1A and $19.
00E5F5 1 ; ============================================================================
00E5F5 1
00E5F5 1 ; ----------------------------------------------------------------------------
00E5F5 1 ; Contract:
00E5F5 1 ; Description: Implements Advance Random State.
00E5F5 1 ; Entry: Registers: A; Memory: randomstatelo, randomstatehi
00E5F5 1 ; Returns/products: Registers/clobbers: A
00E5F5 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E5F5 1 ; Memory effects: $dc, randomstatehi, randomstatelo
00E5F5 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E5F5 1 ; comparison, load, or store path and are not a stable API product.
00E5F5 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 21.
00E5F5 1 ; ----------------------------------------------------------------------------
00E5F5 1 AdvanceRandomState: ; $E5F5
00E5F5 1 A9 08 lda #$08 ; $E5F5: A9 08
00E5F7 1 85 DC sta $DC ; $E5F7: 85 DC
00E5F9 1
00E5F9 1 ; ----------------------------------------------------------------------------
00E5F9 1 ; Load the low random-state byte once at the start of each round.
00E5F9 1 ; ----------------------------------------------------------------------------
00E5F9 1
00E5F9 1 AdvanceRandomState_Loop: ; $E5F9
00E5F9 1 A5 19 lda RandomStateLo ; $E5F9: A5 19
00E5FB 1
00E5FB 1 ; ----------------------------------------------------------------------------
00E5FB 1 ; Shift the combined 16-bit state right:
00E5FB 1 ;
00E5FB 1 ; LSR $1A shifts the high byte and places its old bit zero in carry.
00E5FB 1 ; ROR A shifts that carry into bit seven of the low byte.
00E5FB 1 ;
00E5FB 1 ; Carry after ROR contains the former bit zero of $19.
00E5FB 1 ; ----------------------------------------------------------------------------
00E5FB 1
00E5FB 1 46 1A lsr RandomStateHi ; $E5FB: 46 1A
00E5FD 1 6A ror ; $E5FD: 6A
00E5FE 1
00E5FE 1 ; ----------------------------------------------------------------------------
00E5FE 1 ; If the shifted-out low bit was one, store the shifted low byte directly.
00E5FE 1 ; ----------------------------------------------------------------------------
00E5FE 1
00E5FE 1 B0 0A bcs AdvanceRandomState_SaveLow
00E600 1 ; $E5FE: B0 0A
00E600 1
00E600 1 ; ----------------------------------------------------------------------------
00E600 1 ; The shifted-out low bit was zero.
00E600 1 ;
00E600 1 ; Apply feedback masks to both bytes:
00E600 1 ;
00E600 1 ; $1A ^= $88
00E600 1 ; A ^= $10
00E600 1 ;
00E600 1 ; A is preserved on the stack while $1A is updated.
00E600 1 ; ----------------------------------------------------------------------------
00E600 1
00E600 1 48 pha ; $E600: 48
00E601 1
00E601 1 A5 1A lda RandomStateHi ; $E601: A5 1A
00E603 1 49 88 eor #$88 ; $E603: 49 88
00E605 1 85 1A sta RandomStateHi ; $E605: 85 1A
00E607 1
00E607 1 68 pla ; $E607: 68
00E608 1 49 10 eor #$10 ; $E608: 49 10
00E60A 1
00E60A 1 ; ----------------------------------------------------------------------------
00E60A 1 ; Save the updated low byte and continue for eight total rounds.
00E60A 1 ; ----------------------------------------------------------------------------
00E60A 1
00E60A 1 AdvanceRandomState_SaveLow: ; $E60A
00E60A 1 85 19 sta RandomStateLo ; $E60A: 85 19
00E60C 1
00E60C 1 C6 DC dec $DC ; $E60C: C6 DC
00E60E 1 D0 E9 bne AdvanceRandomState_Loop ; $E60E: D0 E9
00E610 1
00E610 1 60 rts ; $E610: 60
00E611 1
00E611 1 ; ============================================================================
00E611 1 ; $E611-$E63D
00E611 1 ; Multiply an 8-bit value by a signed 16-bit value using eight rounds of
00E611 1 ; conditional addition and arithmetic right shifting.
00E611 1 ;
00E611 1 ; Entry:
00E611 1 ; A = 8-bit multiplier
00E611 1 ; Y = multiplicand low byte
00E611 1 ; X = multiplicand high byte
00E611 1 ;
00E611 1 ; Working storage:
00E611 1 ; $28 = shifting multiplier
00E611 1 ; $2B/$2C = signed 16-bit multiplicand
00E611 1 ; $29/$2A = signed 16-bit accumulator/result
00E611 1 ;
00E611 1 ; Exit:
00E611 1 ; Y = result low byte
00E611 1 ; X = result high byte
00E611 1 ;
00E611 1 ; The accumulator is arithmetically shifted right after every round. This
00E611 1 ; produces a fixed-point scaled result rather than the full 24-bit product.
00E611 1 ; ============================================================================
00E611 1
00E611 1 MultiplyByteBySignedWord: ; $E611
00E611 1 84 2B sty $2B ; $E611: 84 2B
00E613 1 ; Save multiplicand low byte.
00E613 1
00E613 1 86 2C stx $2C ; $E613: 86 2C
00E615 1 ; Save multiplicand high byte.
00E615 1
00E615 1 85 28 sta $28 ; $E615: 85 28
00E617 1 ; Save the 8-bit multiplier.
00E617 1
00E617 1 ; ----------------------------------------------------------------------------
00E617 1 ; Clear the signed 16-bit accumulator.
00E617 1 ; ----------------------------------------------------------------------------
00E617 1
00E617 1 A9 00 lda #$00 ; $E617: A9 00
00E619 1 85 29 sta $29 ; $E619: 85 29
00E61B 1 ; Accumulator low byte.
00E61B 1
00E61B 1 85 2A sta $2A ; $E61B: 85 2A
00E61D 1 ; Accumulator high byte.
00E61D 1
00E61D 1 ; ----------------------------------------------------------------------------
00E61D 1 ; Process all eight multiplier bits.
00E61D 1 ; ----------------------------------------------------------------------------
00E61D 1
00E61D 1 A2 08 ldx #$08 ; $E61D: A2 08
00E61F 1
00E61F 1 MultiplyByteBySignedWord_Loop: ; $E61F
00E61F 1 66 28 ror $28 ; $E61F: 66 28
00E621 1 ; Shift the next multiplier bit into carry.
00E621 1
00E621 1 90 0D bcc MultiplyByteBySignedWord_Shift
00E623 1 ; $E621: 90 0D
00E623 1
00E623 1 ; ----------------------------------------------------------------------------
00E623 1 ; The current multiplier bit is one.
00E623 1 ;
00E623 1 ; Add the signed 16-bit multiplicand to the accumulator.
00E623 1 ; ----------------------------------------------------------------------------
00E623 1
00E623 1 18 clc ; $E623: 18
00E624 1
00E624 1 A5 29 lda $29 ; $E624: A5 29
00E626 1 65 2B adc $2B ; $E626: 65 2B
00E628 1 85 29 sta $29 ; $E628: 85 29
00E62A 1
00E62A 1 A5 2A lda $2A ; $E62A: A5 2A
00E62C 1 65 2C adc $2C ; $E62C: 65 2C
00E62E 1 85 2A sta $2A ; $E62E: 85 2A
00E630 1
00E630 1 ; ----------------------------------------------------------------------------
00E630 1 ; Arithmetically shift the signed accumulator right by one bit.
00E630 1 ;
00E630 1 ; CMP #$80 copies the sign bit of the high accumulator byte into carry:
00E630 1 ;
00E630 1 ; $2A >= $80 -> carry set
00E630 1 ; $2A < $80 -> carry clear
00E630 1 ;
00E630 1 ; ROR $2A therefore preserves the sign bit. ROR $29 completes the signed
00E630 1 ; 16-bit right shift.
00E630 1 ; ----------------------------------------------------------------------------
00E630 1
00E630 1 MultiplyByteBySignedWord_Shift: ; $E630
00E630 1 C9 80 cmp #$80 ; $E630: C9 80
00E632 1
00E632 1 66 2A ror $2A ; $E632: 66 2A
00E634 1 66 29 ror $29 ; $E634: 66 29
00E636 1
00E636 1 ; ----------------------------------------------------------------------------
00E636 1 ; Continue until all eight multiplier bits have been processed.
00E636 1 ; ----------------------------------------------------------------------------
00E636 1
00E636 1 CA dex ; $E636: CA
00E637 1 D0 E6 bne MultiplyByteBySignedWord_Loop
00E639 1 ; $E637: D0 E6
00E639 1
00E639 1 ; ----------------------------------------------------------------------------
00E639 1 ; Return the signed 16-bit result in Y:X.
00E639 1 ; ----------------------------------------------------------------------------
00E639 1
00E639 1 A4 29 ldy $29 ; $E639: A4 29
00E63B 1 A6 2A ldx $2A ; $E63B: A6 2A
00E63D 1
00E63D 1 60 rts ; $E63D: 60
00E63E 1
00E63E 1 ; ============================================================================
00E63E 1 ; $E63E-$E672
00E63E 1 ; Perform an eight-round restoring division or normalization operation.
00E63E 1 ;
00E63E 1 ; Entry:
00E63E 1 ; Y = initial low working byte
00E63E 1 ; A = initial high working byte
00E63E 1 ; $2D/$2E = 16-bit divisor or comparison value
00E63E 1 ; $28 = quotient/result shift register
00E63E 1 ;
00E63E 1 ; Working values:
00E63E 1 ; $29/$2A = 16-bit partial remainder
00E63E 1 ;
00E63E 1 ; Exit:
00E63E 1 ; A = quotient/result byte from $28
00E63E 1 ; X = adjustment or status value
00E63E 1 ;
00E63E 1 ; Failure/overflow:
00E63E 1 ; A = $00
00E63E 1 ;
00E63E 1 ; The exact numeric interpretation should remain provisional until all callers
00E63E 1 ; are analyzed, but the implementation follows a restoring-division pattern.
00E63E 1 ; ============================================================================
00E63E 1
00E63E 1 ; ----------------------------------------------------------------------------
00E63E 1 ; Contract:
00E63E 1 ; Description: Implements Divide Or Normalize Word.
00E63E 1 ; Entry: Registers: A, X, Y; Memory: $29, $2d, $2a, $2e
00E63E 1 ; Returns/products: Registers/clobbers: A, X, Y
00E63E 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E63E 1 ; Memory effects: $29, $2a
00E63E 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E63E 1 ; comparison, load, or store path and are not a stable API product.
00E63E 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 2.
00E63E 1 ; ----------------------------------------------------------------------------
00E63E 1 DivideOrNormalizeWord: ; $E63E
00E63E 1 84 29 sty $29 ; $E63E: 84 29
00E640 1 85 2A sta $2A ; $E640: 85 2A
00E642 1
00E642 1 A2 08 ldx #$08 ; $E642: A2 08
00E644 1 ; Process eight output bits.
00E644 1
00E644 1 ; ----------------------------------------------------------------------------
00E644 1 ; Add the divisor to the current partial remainder.
00E644 1 ; ----------------------------------------------------------------------------
00E644 1
00E644 1 DivideOrNormalizeWord_Loop: ; $E644
00E644 1 18 clc ; $E644: 18
00E645 1
00E645 1 A5 29 lda $29 ; $E645: A5 29
00E647 1 65 2D adc $2D ; $E647: 65 2D
00E649 1 A8 tay ; $E649: A8
00E64A 1
00E64A 1 A5 2A lda $2A ; $E64A: A5 2A
00E64C 1 65 2E adc $2E ; $E64C: 65 2E
00E64E 1
00E64E 1 ; ----------------------------------------------------------------------------
00E64E 1 ; If the addition overflowed, retain the previous partial remainder.
00E64E 1 ;
00E64E 1 ; Otherwise, save the candidate remainder from A:Y.
00E64E 1 ; ----------------------------------------------------------------------------
00E64E 1 DivideOrNormalizeWord_CheckCarry: ; $E64E
00E64E 1 90 04 bcc DivideOrNormalizeWord_Shift
00E650 1 ; $E64E: 90 04
00E650 1
00E650 1 84 29 sty $29 ; $E650: 84 29
00E652 1 85 2A sta $2A ; $E652: 85 2A
00E654 1
00E654 1 ; ----------------------------------------------------------------------------
00E654 1 ; Shift the quotient/result and partial remainder left.
00E654 1 ; ----------------------------------------------------------------------------
00E654 1
00E654 1 DivideOrNormalizeWord_Shift: ; $E654
00E654 1 26 28 rol $28 ; $E654: 26 28
00E656 1
00E656 1 06 29 asl $29 ; $E656: 06 29
00E658 1 26 2A rol $2A ; $E658: 26 2A
00E65A 1
00E65A 1 B0 14 bcs DivideOrNormalizeWord_Overflow
00E65C 1 ; $E65A: B0 14
00E65C 1
00E65C 1 ; ----------------------------------------------------------------------------
00E65C 1 ; Subtract the divisor to prepare the next candidate remainder.
00E65C 1 ; ----------------------------------------------------------------------------
00E65C 1
00E65C 1 38 sec ; $E65C: 38
00E65D 1
00E65D 1 A5 29 lda $29 ; $E65D: A5 29
00E65F 1 E5 2D sbc $2D ; $E65F: E5 2D
00E661 1 A8 tay ; $E661: A8
00E662 1
00E662 1 A5 2A lda $2A ; $E662: A5 2A
00E664 1 E5 2E sbc $2E ; $E664: E5 2E
00E666 1
00E666 1 CA dex ; $E666: CA
00E667 1 D0 E5 bne DivideOrNormalizeWord_CheckCarry
00E669 1 ; $E667: D0 E5
00E669 1 ; Continue from the quotient/remainder shift.
00E669 1
00E669 1 ; ----------------------------------------------------------------------------
00E669 1 ; Return the quotient/result byte.
00E669 1 ;
00E669 1 ; X is adjusted according to carry from the final subtraction.
00E669 1 ; ----------------------------------------------------------------------------
00E669 1
00E669 1 A5 28 lda $28 ; $E669: A5 28
00E66B 1
00E66B 1 CA dex ; $E66B: CA
00E66C 1 B0 01 bcs DivideOrNormalizeWord_Return
00E66E 1 ; $E66C: B0 01
00E66E 1
00E66E 1 CA dex ; $E66E: CA
00E66F 1
00E66F 1 DivideOrNormalizeWord_Return: ; $E66F
00E66F 1 60 rts ; $E66F: 60
00E670 1
00E670 1 ; ----------------------------------------------------------------------------
00E670 1 ; Overflow path.
00E670 1 ; ----------------------------------------------------------------------------
00E670 1
00E670 1 DivideOrNormalizeWord_Overflow: ; $E670
00E670 1 A9 00 lda #$00 ; $E670: A9 00
00E672 1 60 rts ; $E672: 60
00E673 1
00E673 1 ; ============================================================================
00E673 1 ; $E673-$E6C0
00E673 1 ; Build transformed movement/vector components from object state.
00E673 1 ;
00E673 1 ; Three entry paths are present:
00E673 1 ;
00E673 1 ; $E673 uses movement values at $056D/$056E.
00E673 1 ; $E695 uses movement values at $056B/$056C.
00E673 1 ; $E6B7 clears all four transformed results.
00E673 1 ;
00E673 1 ; Results:
00E673 1 ; $31/$32 = first transformed 16-bit component
00E673 1 ; $2F/$30 = second transformed 16-bit component
00E673 1 ;
00E673 1 ; The transformation helper is MultiplyByteBySignedWord at $E611.
00E673 1 ; ============================================================================
00E673 1
00E673 1 ; ----------------------------------------------------------------------------
00E673 1 ; Contract:
00E673 1 ; Description: Implements Build Current Movement Transforms.
00E673 1 ; Entry: Registers: A, X, Y; Memory: $056d, $056e, $cf, $d1, $056b, $056c
00E673 1 ; Returns/products: Registers/clobbers: A, X, Y
00E673 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E673 1 ; Memory effects: $31, selectionvalue0, $2f, $30, $32
00E673 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E673 1 ; comparison, load, or store path and are not a stable API product.
00E673 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E673 1 ; ----------------------------------------------------------------------------
00E673 1 BuildCurrentMovementTransforms: ; $E673
00E673 1 AC 6D 05 ldy $056D ; $E673: AC 6D 05
00E676 1 AE 6E 05 ldx $056E ; $E676: AE 6E 05
00E679 1
00E679 1 A5 CF lda $CF ; $E679: A5 CF
00E67B 1 20 11 E6 jsr MultiplyByteBySignedWord
00E67E 1 ; $E67B: 20 11 E6
00E67E 1
00E67E 1 84 31 sty $31 ; $E67E: 84 31
00E680 1 86 32 stx SelectionValue0 ; $E680: 86 32
00E682 1
00E682 1 AC 6D 05 ldy $056D ; $E682: AC 6D 05
00E685 1 AE 6E 05 ldx $056E ; $E685: AE 6E 05
00E688 1
00E688 1 A5 D1 lda $D1 ; $E688: A5 D1
00E68A 1 20 11 E6 jsr MultiplyByteBySignedWord
00E68D 1 ; $E68A: 20 11 E6
00E68D 1
00E68D 1 84 2F sty $2F ; $E68D: 84 2F
00E68F 1 86 30 stx $30 ; $E68F: 86 30
00E691 1
00E691 1 ; ----------------------------------------------------------------------------
00E691 1 ; X is cleared and BEQ is therefore unconditional.
00E691 1 ; ----------------------------------------------------------------------------
00E691 1
00E691 1 A2 00 ldx #$00 ; $E691: A2 00
00E693 1 F0 2C beq ProjectObjectCoordinates
00E695 1 ; $E693: F0 2C
00E695 1
00E695 1 ; ----------------------------------------------------------------------------
00E695 1 ; Alternate entry using the base movement values at $056B/$056C.
00E695 1 ; ----------------------------------------------------------------------------
00E695 1
00E695 1 ; ----------------------------------------------------------------------------
00E695 1 ; Contract:
00E695 1 ; Description: Implements Build Base Movement Transforms.
00E695 1 ; Entry: Registers: A, X, Y; Memory: $056b, $056c, $cf, $d1, $053a, $d2
00E695 1 ; Returns/products: Registers/clobbers: A, X, Y
00E695 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E695 1 ; Memory effects: $31, $32, $2f, $30
00E695 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E695 1 ; comparison, load, or store path and are not a stable API product.
00E695 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E695 1 ; ----------------------------------------------------------------------------
00E695 1 BuildBaseMovementTransforms: ; $E695
00E695 1 AC 6B 05 ldy $056B ; $E695: AC 6B 05
00E698 1 AE 6C 05 ldx $056C ; $E698: AE 6C 05
00E69B 1
00E69B 1 A5 CF lda $CF ; $E69B: A5 CF
00E69D 1 20 11 E6 jsr MultiplyByteBySignedWord
00E6A0 1 ; $E69D: 20 11 E6
00E6A0 1
00E6A0 1 84 31 sty $31 ; $E6A0: 84 31
00E6A2 1 86 32 stx SelectionValue0 ; $E6A2: 86 32
00E6A4 1
00E6A4 1 AC 6B 05 ldy $056B ; $E6A4: AC 6B 05
00E6A7 1 AE 6C 05 ldx $056C ; $E6A7: AE 6C 05
00E6AA 1
00E6AA 1 A5 D1 lda $D1 ; $E6AA: A5 D1
00E6AC 1 20 11 E6 jsr MultiplyByteBySignedWord
00E6AF 1 ; $E6AC: 20 11 E6
00E6AF 1
00E6AF 1 84 2F sty $2F ; $E6AF: 84 2F
00E6B1 1 86 30 stx $30 ; $E6B1: 86 30
00E6B3 1
00E6B3 1 A2 00 ldx #$00 ; $E6B3: A2 00
00E6B5 1 F0 0A beq ProjectObjectCoordinates
00E6B7 1 ; $E6B5: F0 0A
00E6B7 1
00E6B7 1 ; ----------------------------------------------------------------------------
00E6B7 1 ; Alternate entry that clears every transformed component.
00E6B7 1 ; ----------------------------------------------------------------------------
00E6B7 1
00E6B7 1 ; ----------------------------------------------------------------------------
00E6B7 1 ; Contract:
00E6B7 1 ; Description: Clears or resets Movement Transforms.
00E6B7 1 ; Entry: Registers: A, X, Y; Memory: $053a, $d2, $053b, $d3, $ce, $cc, $cd, $31
00E6B7 1 ; Returns/products: Registers/clobbers: A, X, Y
00E6B7 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E6B7 1 ; Memory effects: $31, $32, $2f, $30, $06, $08, $09, $2d
00E6B7 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E6B7 1 ; comparison, load, or store path and are not a stable API product.
00E6B7 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 15.
00E6B7 1 ; ----------------------------------------------------------------------------
00E6B7 1 ClearMovementTransforms: ; $E6B7
00E6B7 1 A9 00 lda #$00 ; $E6B7: A9 00
00E6B9 1
00E6B9 1 85 31 sta $31 ; $E6B9: 85 31
00E6BB 1 85 32 sta SelectionValue0 ; $E6BB: 85 32
00E6BD 1 85 2F sta $2F ; $E6BD: 85 2F
00E6BF 1 85 30 sta $30 ; $E6BF: 85 30
00E6C1 1
00E6C1 1 ; ============================================================================
00E6C1 1 ; $E6C1-$E737
00E6C1 1 ; Project one object's coordinates through the current transformation state.
00E6C1 1 ;
00E6C1 1 ; Entry:
00E6C1 1 ; X = source object offset
00E6C1 1 ;
00E6C1 1 ; Working values:
00E6C1 1 ; $06 = saved object offset
00E6C1 1 ; $08/$09 = adjusted source vertical coordinate
00E6C1 1 ; $2D/$2E = transformed intermediate vector
00E6C1 1 ; $36/$37 = projected horizontal result
00E6C1 1 ; $38/$39 = projected vertical result
00E6C1 1 ;
00E6C1 1 ; Return:
00E6C1 1 ; C = clear when projection succeeds
00E6C1 1 ; C = set when projection fails or lies outside the accepted range
00E6C1 1 ;
00E6C1 1 ; On success, selected projections are written to:
00E6C1 1 ; $03BC,X
00E6C1 1 ; $03DE,X
00E6C1 1 ; ============================================================================
00E6C1 1
00E6C1 1 ProjectObjectCoordinates: ; $E6C1
00E6C1 1 86 06 stx $06 ; $E6C1: 86 06
00E6C3 1
00E6C3 1 ; ----------------------------------------------------------------------------
00E6C3 1 ; Add the global vertical offset $D2/$D3 to the object's vertical coordinate.
00E6C3 1 ; ----------------------------------------------------------------------------
00E6C3 1
00E6C3 1 18 clc ; $E6C3: 18
00E6C4 1
00E6C4 1 BD 3A 05 lda $053A,x ; $E6C4: BD 3A 05
00E6C7 1 65 D2 adc $D2 ; $E6C7: 65 D2
00E6C9 1 85 08 sta $08 ; $E6C9: 85 08
00E6CB 1 A8 tay ; $E6CB: A8
00E6CC 1
00E6CC 1 BD 3B 05 lda $053B,x ; $E6CC: BD 3B 05
00E6CF 1 65 D3 adc $D3 ; $E6CF: 65 D3
00E6D1 1 85 09 sta $09 ; $E6D1: 85 09
00E6D3 1 AA tax ; $E6D3: AA
00E6D4 1
00E6D4 1 ; ----------------------------------------------------------------------------
00E6D4 1 ; Scale or transform the adjusted coordinate using parameter $CE.
00E6D4 1 ; ----------------------------------------------------------------------------
00E6D4 1
00E6D4 1 A5 CE lda $CE ; $E6D4: A5 CE
00E6D6 1 20 11 E6 jsr MultiplyByteBySignedWord
00E6D9 1 ; $E6D6: 20 11 E6
00E6D9 1
00E6D9 1 ; ----------------------------------------------------------------------------
00E6D9 1 ; Add global offsets $CC/$CD to the transformed result.
00E6D9 1 ; ----------------------------------------------------------------------------
00E6D9 1
00E6D9 1 18 clc ; $E6D9: 18
00E6DA 1
00E6DA 1 98 tya ; $E6DA: 98
00E6DB 1 65 CC adc $CC ; $E6DB: 65 CC
00E6DD 1 A8 tay ; $E6DD: A8
00E6DE 1
00E6DE 1 8A txa ; $E6DE: 8A
00E6DF 1 65 CD adc $CD ; $E6DF: 65 CD
00E6E1 1 AA tax ; $E6E1: AA
00E6E2 1
00E6E2 1 ; ----------------------------------------------------------------------------
00E6E2 1 ; Subtract transformed component $31/$32 and divide the result by two.
00E6E2 1 ; ----------------------------------------------------------------------------
00E6E2 1
00E6E2 1 98 tya ; $E6E2: 98
00E6E3 1 38 sec ; $E6E3: 38
00E6E4 1 E5 31 sbc $31 ; $E6E4: E5 31
00E6E6 1 85 2D sta $2D ; $E6E6: 85 2D
00E6E8 1
00E6E8 1 8A txa ; $E6E8: 8A
00E6E9 1 E5 32 sbc SelectionValue0 ; $E6E9: E5 32
00E6EB 1
00E6EB 1 4A lsr ; $E6EB: 4A
00E6EC 1 85 2E sta $2E ; $E6EC: 85 2E
00E6EE 1 66 2D ror $2D ; $E6EE: 66 2D
00E6F0 1
00E6F0 1 ; ----------------------------------------------------------------------------
00E6F0 1 ; Transform the adjusted source coordinate using parameter $D0.
00E6F0 1 ; ----------------------------------------------------------------------------
00E6F0 1
00E6F0 1 A4 08 ldy $08 ; $E6F0: A4 08
00E6F2 1 A6 09 ldx $09 ; $E6F2: A6 09
00E6F4 1
00E6F4 1 A5 D0 lda $D0 ; $E6F4: A5 D0
00E6F6 1 20 11 E6 jsr MultiplyByteBySignedWord
00E6F9 1 ; $E6F6: 20 11 E6
00E6F9 1
00E6F9 1 ; ----------------------------------------------------------------------------
00E6F9 1 ; Add transformed component $2F/$30.
00E6F9 1 ; ----------------------------------------------------------------------------
00E6F9 1
00E6F9 1 18 clc ; $E6F9: 18
00E6FA 1
00E6FA 1 98 tya ; $E6FA: 98
00E6FB 1 65 2F adc $2F ; $E6FB: 65 2F
00E6FD 1 A8 tay ; $E6FD: A8
00E6FE 1
00E6FE 1 8A txa ; $E6FE: 8A
00E6FF 1 65 30 adc $30 ; $E6FF: 65 30
00E701 1
00E701 1 ; ----------------------------------------------------------------------------
00E701 1 ; Normalize or divide the result through the arithmetic helper at $E63E.
00E701 1 ; ----------------------------------------------------------------------------
00E701 1
00E701 1 20 3E E6 jsr DivideOrNormalizeWord ; $E701: 20
00E704 1 ; ----------------------------------------------------------------------------
00E704 1 ; Reject a zero normalization result.
00E704 1 ; ----------------------------------------------------------------------------
00E704 1
00E704 1 F0 30 beq ProjectObjectCoordinates_Fail
00E706 1 ; $E704: F0 30
00E706 1
00E706 1 ; ----------------------------------------------------------------------------
00E706 1 ; Convert the returned vertical result into the projected display coordinate.
00E706 1 ; ----------------------------------------------------------------------------
00E706 1
00E706 1 E9 00 sbc #$00 ; $E706: E9 00
00E708 1 49 7F eor #$7F ; $E708: 49 7F
00E70A 1
00E70A 1 85 38 sta ObjectScreenY ; $E70A: 85 38
00E70C 1 86 39 stx ObjectScreenYHi ; $E70C: 86 39
00E70E 1
00E70E 1 ; ----------------------------------------------------------------------------
00E70E 1 ; Restore the source object offset and normalize its horizontal coordinate.
00E70E 1 ; ----------------------------------------------------------------------------
00E70E 1
00E70E 1 A6 06 ldx $06 ; $E70E: A6 06
00E710 1
00E710 1 BC 09 05 ldy $0509,x ; $E710: BC 09 05
00E713 1 BD 0A 05 lda $050A,x ; $E713: BD 0A 05
00E716 1
00E716 1 20 3E E6 jsr DivideOrNormalizeWord ; $E716: 20 3E E6
00E719 1
00E719 1 F0 1B beq ProjectObjectCoordinates_Fail
00E71B 1 ; $E719: F0 1B
00E71B 1
00E71B 1 ; ----------------------------------------------------------------------------
00E71B 1 ; Convert the returned horizontal result into the projected display coordinate.
00E71B 1 ; ----------------------------------------------------------------------------
00E71B 1
00E71B 1 69 80 adc #$80 ; $E71B: 69 80
00E71D 1
00E71D 1 85 36 sta ObjectScreenX ; $E71D: 85 36
00E71F 1 86 37 stx ObjectScreenXHi ; $E71F: 86 37
00E721 1
00E721 1 ; ----------------------------------------------------------------------------
00E721 1 ; Convert the source object offset to its display-array index.
00E721 1 ; ----------------------------------------------------------------------------
00E721 1
00E721 1 A6 06 ldx $06 ; $E721: A6 06
00E723 1
00E723 1 20 38 E7 jsr ConvertObjectOffsetToDisplayIndex
00E726 1 ; $E723: 20 38 E7
00E726 1
00E726 1 ; ----------------------------------------------------------------------------
00E726 1 ; Display indices $22 and above return without writing to the projection
00E726 1 ; arrays. Carry remains set from CPX #$22 in that case.
00E726 1 ; ----------------------------------------------------------------------------
00E726 1
00E726 1 E0 22 cpx #$22 ; $E726: E0 22
00E728 1 B0 0B bcs ProjectObjectCoordinates_Return
00E72A 1 ; $E728: B0 0B
00E72A 1
00E72A 1 ; ----------------------------------------------------------------------------
00E72A 1 ; Save the projected horizontal and vertical coordinates.
00E72A 1 ; ----------------------------------------------------------------------------
00E72A 1
00E72A 1 A5 36 lda ObjectScreenX ; $E72A: A5 36
00E72C 1 9D BC 03 sta $03BC,x ; $E72C: 9D BC 03
00E72F 1
00E72F 1 A5 38 lda ObjectScreenY ; $E72F: A5 38
00E731 1 9D DE 03 sta $03DE,x ; $E731: 9D DE 03
00E734 1
00E734 1 18 clc ; $E734: 18
00E735 1
00E735 1 ProjectObjectCoordinates_Return: ; $E735
00E735 1 60 rts ; $E735: 60
00E736 1
00E736 1 ; ----------------------------------------------------------------------------
00E736 1 ; A normalization failure returns carry set.
00E736 1 ; ----------------------------------------------------------------------------
00E736 1
00E736 1 ProjectObjectCoordinates_Fail: ; $E736
00E736 1 38 sec ; $E736: 38
00E737 1 60 rts ; $E737: 60
00E738 1
00E738 1 ; ============================================================================
00E738 1 ; $E738-$E740
00E738 1 ; Convert an object-array offset into a display-array index.
00E738 1 ;
00E738 1 ; Entry:
00E738 1 ; X = even object-array offset
00E738 1 ;
00E738 1 ; Calculation:
00E738 1 ; X = (X / 2) + $C9 + 1
00E738 1 ;
00E738 1 ; Exit:
00E738 1 ; X = converted display-array index
00E738 1 ; Flags reflect CPX #$16
00E738 1 ;
00E738 1 ; This helper does not branch on the final comparison. Callers inspect X or
00E738 1 ; the returned flags themselves.
00E738 1 ; ============================================================================
00E738 1
00E738 1 ; ----------------------------------------------------------------------------
00E738 1 ; Contract:
00E738 1 ; Description: Implements Convert Object Offset To Display Index.
00E738 1 ; Entry: Registers: A, X; Memory: spritesortbaseindex
00E738 1 ; Returns/products: Registers/clobbers: A, X; Flags: condition flags may carry result state
00E738 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E738 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00E738 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E738 1 ; comparison, load, or store path and are not a stable API product.
00E738 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 5.
00E738 1 ; ----------------------------------------------------------------------------
00E738 1 ConvertObjectOffsetToDisplayIndex: ; $E738
00E738 1 8A txa ; $E738: 8A
00E739 1 4A lsr ; $E739: 4A
00E73A 1 ; Divide the even object offset by two.
00E73A 1
00E73A 1 65 C9 adc SpriteSortBaseIndex ; $E73A: 65 C9
00E73C 1 ; Carry from LSR is normally clear for even
00E73C 1 ; object offsets.
00E73C 1
00E73C 1 AA tax ; $E73C: AA
00E73D 1 E8 inx ; $E73D: E8
00E73E 1
00E73E 1 E0 16 cpx #$16 ; $E73E: E0 16
00E740 1 60 rts ; $E740: 60
00E741 1
00E741 1 ; ============================================================================
00E741 1 ; $E741-$E760
00E741 1 ; Initialize rendering state and copy 13 bytes from RenderingStateTable.
00E741 1 ;
00E741 1 ; Two effective entry points exist:
00E741 1 ;
00E741 1 ; $E741:
00E741 1 ; Sets ObjectScreenY to $F0 and forces carry clear before selecting the table
00E741 1 ; range beginning at index $0C.
00E741 1 ;
00E741 1 ; $E746:
00E741 1 ; Uses incoming carry to choose between two table ranges:
00E741 1 ;
00E741 1 ; C=0 -> start at table index $0C
00E741 1 ; C=1 -> start at table index $19 and set bit 1 of $DD
00E741 1 ;
00E741 1 ; The selected 13 bytes are copied in reverse order into zero-page $C7-$D3.
00E741 1 ; ============================================================================
00E741 1
00E741 1 InitializeRenderingState: ; $E741
00E741 1 A9 F0 lda #$F0 ; $E741: A9 F0
00E743 1 85 38 sta ObjectScreenY ; $E743: 85 38
00E745 1 ; Default projected/display coordinate.
00E745 1
00E745 1 18 clc ; $E745: 18
00E746 1
00E746 1 ; ----------------------------------------------------------------------------
00E746 1 ; Alternate entry that preserves caller-supplied carry.
00E746 1 ; ----------------------------------------------------------------------------
00E746 1
00E746 1 ; ----------------------------------------------------------------------------
00E746 1 ; Contract:
00E746 1 ; Description: Initializes Rendering State From Carry.
00E746 1 ; Entry: Registers: A, X, Y; Memory: ppuctrlshadow, renderingstatetable
00E746 1 ; Returns/products: Registers/clobbers: A, X, Y
00E746 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E746 1 ; Memory effects: ppuctrlshadow, $c7
00E746 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E746 1 ; comparison, load, or store path and are not a stable API product.
00E746 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E746 1 ; ----------------------------------------------------------------------------
00E746 1 InitializeRenderingStateFromCarry: ; $E746
00E746 1 A5 DD lda PpuCtrlShadow ; $E746: A5 DD
00E748 1 29 FD and #$FD ; $E748: 29 FD
00E74A 1 ; Clear bit 1 by default.
00E74A 1
00E74A 1 A0 0C ldy #$0C ; $E74A: A0 0C
00E74C 1 ; Default table range ends at index $0C.
00E74C 1
00E74C 1 90 04 bcc InitializeRenderingState_SaveFlags
00E74E 1 ; $E74C: 90 04
00E74E 1
00E74E 1 ; ----------------------------------------------------------------------------
00E74E 1 ; Carry-set path.
00E74E 1 ;
00E74E 1 ; Select the second 13-byte range and set bit 1 of $DD.
00E74E 1 ; ----------------------------------------------------------------------------
00E74E 1
00E74E 1 A0 19 ldy #$19 ; $E74E: A0 19
00E750 1 09 02 ora #$02 ; $E750: 09 02
00E752 1
00E752 1 InitializeRenderingState_SaveFlags: ; $E752
00E752 1 85 DD sta PpuCtrlShadow ; $E752: 85 DD
00E754 1
00E754 1 ; ----------------------------------------------------------------------------
00E754 1 ; Copy 13 bytes in reverse order.
00E754 1 ;
00E754 1 ; Source indices:
00E754 1 ;
00E754 1 ; C clear: $0C down to $00
00E754 1 ; C set: $19 down to $0D
00E754 1 ;
00E754 1 ; Destination:
00E754 1 ;
00E754 1 ; $D3 down to $C7
00E754 1 ; ----------------------------------------------------------------------------
00E754 1
00E754 1 A2 0C ldx #$0C ; $E754: A2 0C
00E756 1
00E756 1 InitializeRenderingState_CopyLoop: ; $E756
00E756 1 B9 61 E7 lda RenderingStateTable,y ; $E756: B9 61 E7
00E759 1 95 C7 sta ObjectListFlag,x ; $E759: 95 C7
00E75B 1
00E75B 1 88 dey ; $E75B: 88
00E75C 1 CA dex ; $E75C: CA
00E75D 1 10 F7 bpl InitializeRenderingState_CopyLoop
00E75F 1 ; $E75D: 10 F7
00E75F 1
00E75F 1 ; ----------------------------------------------------------------------------
00E75F 1 ; Return carry set.
00E75F 1 ; ----------------------------------------------------------------------------
00E75F 1
00E75F 1 38 sec ; $E75F: 38
00E760 1 60 rts ; $E760: 60
00E761 1
00E761 1 ; ============================================================================
00E761 1 ; $E761-$E77A
00E761 1 ; Rendering-state lookup data.
00E761 1 ;
00E761 1 ; The initialization routine copies one of two 13-byte ranges:
00E761 1 ;
00E761 1 ; Range 0:
00E761 1 ; indices $00-$0C
00E761 1 ;
00E761 1 ; Range 1:
00E761 1 ; indices $0D-$19
00E761 1 ;
00E761 1 ; Both ranges are copied backward into zero-page $C7-$D3.
00E761 1 ; ============================================================================
00E761 1
00E761 1 RenderingStateTable: ; $E761
00E761 1
00E761 1 ; First 13-byte state.
00E761 1 RenderingStateTable_Default: ; $E761, indices $00-$0C
00E761 1 00 15 00 14 .byte $00,$15,$00,$14,$00,$14,$2D
00E765 1 00 14 2D
00E768 1 58 3D 92 D2 .byte $58,$3D,$92,$D2,$FB,$F4
00E76C 1 FB F4
00E76E 1
00E76E 1 ; Second 13-byte state.
00E76E 1 RenderingStateTable_Alternate: ; $E76E, indices $0D-$19
00E76E 1 08 0D 15 21 .byte $08,$0D,$15,$21,$06,$42,$16
00E772 1 06 42 16
00E775 1 98 F7 DA 86 .byte $98,$F7,$DA,$86,$6F,$02
00E779 1 6F 02
00E77B 1
00E77B 1 ; ============================================================================
00E77B 1 ; $E77B-$E7BB
00E77B 1 ; Expand a sprite-record list into the OAM shadow buffer at $0200.
00E77B 1 ;
00E77B 1 ; Entry:
00E77B 1 ; A = index into the pointer table at $0400
00E77B 1 ;
00E77B 1 ; Pointer table:
00E77B 1 ; $0400/$0401 contains little-endian source pointers.
00E77B 1 ; A is doubled before indexing the pointer table.
00E77B 1 ;
00E77B 1 ; Source record format:
00E77B 1 ;
00E77B 1 ; byte 0:
00E77B 1 ; number of four-byte sprite records
00E77B 1 ;
00E77B 1 ; each sprite record:
00E77B 1 ; byte 0 = relative Y coordinate
00E77B 1 ; byte 1 = tile index
00E77B 1 ; byte 2 = sprite attributes
00E77B 1 ; byte 3 = relative X coordinate
00E77B 1 ;
00E77B 1 ; Destination:
00E77B 1 ; OAM shadow buffer at $0200
00E77B 1 ;
00E77B 1 ; Coordinate adjustments:
00E77B 1 ; destination Y = source Y + $38
00E77B 1 ; destination X = source X + $36
00E77B 1 ;
00E77B 1 ; Exit:
00E77B 1 ; $3F = updated OAM shadow write offset
00E77B 1 ; $20 incremented after a nonempty sprite list
00E77B 1 ; ============================================================================
00E77B 1
00E77B 1 ; ----------------------------------------------------------------------------
00E77B 1 ; Contract:
00E77B 1 ; Description: Implements Render Sprite Record List.
00E77B 1 ; Entry: Registers: A, X, Y; Memory: $0400, $0401, (indirectptrlo), oamwriteoffset, objectscreeny
00E77B 1 ; Returns/products: Registers/clobbers: A, X, Y
00E77B 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E77B 1 ; Memory effects: indirectptrlo, indirectptrhi, $04, $0200, oamwriteoffset
00E77B 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E77B 1 ; comparison, load, or store path and are not a stable API product.
00E77B 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E77B 1 ; ----------------------------------------------------------------------------
00E77B 1 RenderSpriteRecordList: ; $E77B
00E77B 1 0A asl ; $E77B: 0A
00E77C 1 ; Convert pointer index to byte offset.
00E77C 1
00E77C 1 A8 tay ; $E77C: A8
00E77D 1
00E77D 1 ; ----------------------------------------------------------------------------
00E77D 1 ; Load the selected little-endian source pointer from $0400.
00E77D 1 ; ----------------------------------------------------------------------------
00E77D 1
00E77D 1 B9 00 04 lda $0400,y ; $E77D: B9 00 04
00E780 1 85 00 sta IndirectPtrLo ; $E780: 85 00
00E782 1
00E782 1 B9 01 04 lda $0401,y ; $E782: B9 01 04
00E785 1 85 01 sta IndirectPtrHi ; $E785: 85 01
00E787 1
00E787 1 ; ----------------------------------------------------------------------------
00E787 1 ; Read the sprite count.
00E787 1 ; ----------------------------------------------------------------------------
00E787 1
00E787 1 A0 00 ldy #$00 ; $E787: A0 00
00E789 1
00E789 1 B1 00 lda (IndirectPtrLo),y ; $E789: B1 00
00E78B 1 F0 2E beq RenderSpriteRecordList_Return
00E78D 1 ; $E78B: F0 2E
00E78D 1
00E78D 1 85 04 sta $04 ; $E78D: 85 04
00E78F 1 ; Number of four-byte sprite records.
00E78F 1
00E78F 1 ; ----------------------------------------------------------------------------
00E78F 1 ; Load the current OAM shadow write position.
00E78F 1 ; ----------------------------------------------------------------------------
00E78F 1
00E78F 1 A6 3F ldx OamWriteOffset ; $E78F: A6 3F
00E791 1
00E791 1 ; ----------------------------------------------------------------------------
00E791 1 ; Copy one sprite record.
00E791 1 ; ----------------------------------------------------------------------------
00E791 1
00E791 1 RenderSpriteRecordList_Loop: ; $E791
00E791 1 C8 iny ; $E791: C8
00E792 1
00E792 1 ; ----------------------------------------------------------------------------
00E792 1 ; OAM byte 0: Y coordinate.
00E792 1 ; ----------------------------------------------------------------------------
00E792 1
00E792 1 18 clc ; $E792: 18
00E793 1
00E793 1 B1 00 lda (IndirectPtrLo),y ; $E793: B1 00
00E795 1 65 38 adc ObjectScreenY ; $E795: 65 38
00E797 1 9D 00 02 sta $0200,x ; $E797: 9D 00 02
00E79A 1
00E79A 1 E8 inx ; $E79A: E8
00E79B 1 C8 iny ; $E79B: C8
00E79C 1
00E79C 1 ; ----------------------------------------------------------------------------
00E79C 1 ; OAM byte 1: tile index.
00E79C 1 ; ----------------------------------------------------------------------------
00E79C 1
00E79C 1 B1 00 lda (IndirectPtrLo),y ; $E79C: B1 00
00E79E 1 9D 00 02 sta $0200,x ; $E79E: 9D 00 02
00E7A1 1
00E7A1 1 E8 inx ; $E7A1: E8
00E7A2 1 C8 iny ; $E7A2: C8
00E7A3 1
00E7A3 1 ; ----------------------------------------------------------------------------
00E7A3 1 ; OAM byte 2: sprite attributes.
00E7A3 1 ; ----------------------------------------------------------------------------
00E7A3 1
00E7A3 1 B1 00 lda (IndirectPtrLo),y ; $E7A3: B1 00
00E7A5 1 9D 00 02 sta $0200,x ; $E7A5: 9D 00 02
00E7A8 1
00E7A8 1 E8 inx ; $E7A8: E8
00E7A9 1 C8 iny ; $E7A9: C8
00E7AA 1
00E7AA 1 ; ----------------------------------------------------------------------------
00E7AA 1 ; OAM byte 3: X coordinate.
00E7AA 1 ; ----------------------------------------------------------------------------
00E7AA 1
00E7AA 1 18 clc ; $E7AA: 18
00E7AB 1
00E7AB 1 B1 00 lda (IndirectPtrLo),y ; $E7AB: B1 00
00E7AD 1 65 36 adc ObjectScreenX ; $E7AD: 65 36
00E7AF 1 9D 00 02 sta $0200,x ; $E7AF: 9D 00 02
00E7B2 1
00E7B2 1 E8 inx ; $E7B2: E8
00E7B3 1
00E7B3 1 ; ----------------------------------------------------------------------------
00E7B3 1 ; Continue until all sprite records are copied.
00E7B3 1 ; ----------------------------------------------------------------------------
00E7B3 1
00E7B3 1 C6 04 dec $04 ; $E7B3: C6 04
00E7B5 1 D0 DA bne RenderSpriteRecordList_Loop
00E7B7 1 ; $E7B5: D0 DA
00E7B7 1
00E7B7 1 ; ----------------------------------------------------------------------------
00E7B7 1 ; Save the updated OAM write offset and mark that another sprite group was
00E7B7 1 ; emitted.
00E7B7 1 ; ----------------------------------------------------------------------------
00E7B7 1
00E7B7 1 86 3F stx OamWriteOffset ; $E7B7: 86 3F
00E7B9 1 E6 20 inc FrameState20 ; $E7B9: E6 20
00E7BB 1
00E7BB 1 RenderSpriteRecordList_Return: ; $E7BB
00E7BB 1 60 rts
00E7BC 1 ; ============================================================================
00E7BC 1 ; $E7BC-$E7CA
00E7BC 1 ; Hide a caller-selected number of sprites in the OAM shadow buffer.
00E7BC 1 ;
00E7BC 1 ; Entry:
00E7BC 1 ; Y = number of sprites to hide
00E7BC 1 ;
00E7BC 1 ; Operation:
00E7BC 1 ; Each OAM entry occupies four bytes:
00E7BC 1 ;
00E7BC 1 ; byte 0 = Y coordinate
00E7BC 1 ; byte 1 = tile
00E7BC 1 ; byte 2 = attributes
00E7BC 1 ; byte 3 = X coordinate
00E7BC 1 ;
00E7BC 1 ; This routine writes $F0 to each sprite's Y coordinate, placing it below
00E7BC 1 ; the visible screen, then advances X by four bytes to the next sprite.
00E7BC 1 ;
00E7BC 1 ; Note:
00E7BC 1 ; The OAM write offset in $3F is read but not updated.
00E7BC 1 ; ============================================================================
00E7BC 1
00E7BC 1 HideOamSprites: ; $E7BC
00E7BC 1 A6 3F ldx OamWriteOffset ; $E7BC: A6 3F
00E7BE 1 ; Start at the current OAM shadow offset.
00E7BE 1
00E7BE 1 A9 F0 lda #$F0 ; $E7BE: A9 F0
00E7C0 1 ; Off-screen Y coordinate.
00E7C0 1
00E7C0 1 HideOamSprites_Loop: ; $E7C0
00E7C0 1 9D 00 02 sta $0200,x ; $E7C0: 9D 00 02
00E7C3 1 ; Hide the current sprite.
00E7C3 1
00E7C3 1 E8 inx ; $E7C3: E8
00E7C4 1 E8 inx ; $E7C4: E8
00E7C5 1 E8 inx ; $E7C5: E8
00E7C6 1 E8 inx ; $E7C6: E8
00E7C7 1 ; Advance to the next sprite's Y byte.
00E7C7 1
00E7C7 1 88 dey ; $E7C7: 88
00E7C8 1 D0 F6 bne HideOamSprites_Loop ; $E7C8: D0 F6
00E7CA 1
00E7CA 1 60 rts ; $E7CA: 60
00E7CB 1
00E7CB 1 ; ============================================================================
00E7CB 1 ; $E7CB-$E7DA
00E7CB 1 ; Convert a signed 16-bit value in A:Y to its absolute magnitude.
00E7CB 1 ;
00E7CB 1 ; Entry:
00E7CB 1 ; A = signed high byte
00E7CB 1 ; Y = low byte
00E7CB 1 ;
00E7CB 1 ; Exit:
00E7CB 1 ; A:Y = absolute magnitude
00E7CB 1 ;
00E7CB 1 ; If A is nonnegative, the value is returned unchanged. Otherwise, the
00E7CB 1 ; complete 16-bit pair is negated using one's complement plus one.
00E7CB 1 ; ============================================================================
00E7CB 1
00E7CB 1 ; ----------------------------------------------------------------------------
00E7CB 1 ; Contract:
00E7CB 1 ; Description: Implements Absolute Value A Y.
00E7CB 1 ; Entry: Registers: A, Y
00E7CB 1 ; Returns/products: Registers/clobbers: A, Y; Flags: condition flags may carry result state
00E7CB 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E7CB 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00E7CB 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E7CB 1 ; comparison, load, or store path and are not a stable API product.
00E7CB 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 6.
00E7CB 1 ; ----------------------------------------------------------------------------
00E7CB 1 AbsoluteValueAY: ; $E7CB
00E7CB 1 10 0D bpl AbsoluteValueAY_Return ; $E7CB: 10 0D
00E7CD 1
00E7CD 1 ; ----------------------------------------------------------------------------
00E7CD 1 ; Negate the high byte and preserve it while processing the low byte.
00E7CD 1 ; ----------------------------------------------------------------------------
00E7CD 1
00E7CD 1 49 FF eor #$FF ; $E7CD: 49 FF
00E7CF 1 48 pha ; $E7CF: 48
00E7D0 1
00E7D0 1 ; ----------------------------------------------------------------------------
00E7D0 1 ; Negate the low byte.
00E7D0 1 ;
00E7D0 1 ; SEC followed by ADC #$00 adds one to the complemented byte.
00E7D0 1 ; ----------------------------------------------------------------------------
00E7D0 1
00E7D0 1 98 tya ; $E7D0: 98
00E7D1 1 49 FF eor #$FF ; $E7D1: 49 FF
00E7D3 1
00E7D3 1 38 sec ; $E7D3: 38
00E7D4 1 69 00 adc #$00 ; $E7D4: 69 00
00E7D6 1 A8 tay ; $E7D6: A8
00E7D7 1
00E7D7 1 ; ----------------------------------------------------------------------------
00E7D7 1 ; Restore the complemented high byte and propagate carry from the low-byte
00E7D7 1 ; negation.
00E7D7 1 ; ----------------------------------------------------------------------------
00E7D7 1
00E7D7 1 68 pla ; $E7D7: 68
00E7D8 1 69 00 adc #$00 ; $E7D8: 69 00
00E7DA 1
00E7DA 1 AbsoluteValueAY_Return: ; $E7DA
00E7DA 1 60 rts ; $E7DA: 60
00E7DB 1
00E7DB 1 ; ============================================================================
00E7DB 1 ; $E7DB-$E7F4
00E7DB 1 ; Calculate an eight-bit scaled product.
00E7DB 1 ;
00E7DB 1 ; Entry:
00E7DB 1 ; A = multiplicand/value
00E7DB 1 ; X = scale or shift count plus one
00E7DB 1 ;
00E7DB 1 ; Operation:
00E7DB 1 ; X is decremented once and saved in $2B. The routine then performs eight
00E7DB 1 ; shift-and-add rounds using $28 as the high/result byte.
00E7DB 1 ;
00E7DB 1 ; Exit:
00E7DB 1 ; A = result low byte
00E7DB 1 ; X = result high byte from $28
00E7DB 1 ; ============================================================================
00E7DB 1
00E7DB 1 ; ----------------------------------------------------------------------------
00E7DB 1 ; Contract:
00E7DB 1 ; Description: Calculates Scaled Product.
00E7DB 1 ; Entry: Registers: A, X; Memory: $2b, $28
00E7DB 1 ; Returns/products: Registers/clobbers: A, X
00E7DB 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E7DB 1 ; Memory effects: $2b, $28
00E7DB 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E7DB 1 ; comparison, load, or store path and are not a stable API product.
00E7DB 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E7DB 1 ; ----------------------------------------------------------------------------
00E7DB 1 CalculateScaledProduct: ; $E7DB
00E7DB 1 CA dex ; $E7DB: CA
00E7DC 1 86 2B stx $2B ; $E7DC: 86 2B
00E7DE 1
00E7DE 1 85 28 sta $28 ; $E7DE: 85 28
00E7E0 1
00E7E0 1 A9 00 lda #$00 ; $E7E0: A9 00
00E7E2 1 A2 08 ldx #$08 ; $E7E2: A2 08
00E7E4 1
00E7E4 1 ; ----------------------------------------------------------------------------
00E7E4 1 ; Shift the 16-bit A:$28 result left.
00E7E4 1 ;
00E7E4 1 ; Whenever carry is set after rotating $28, add the saved scale value from
00E7E4 1 ; $2B. Carry from that addition increments $28.
00E7E4 1 ; ----------------------------------------------------------------------------
00E7E4 1
00E7E4 1 CalculateScaledProduct_Loop: ; $E7E4
00E7E4 1 0A asl ; $E7E4: 0A
00E7E5 1 26 28 rol $28 ; $E7E5: 26 28
00E7E7 1
00E7E7 1 90 06 bcc CalculateScaledProduct_Next
00E7E9 1 ; $E7E7: 90 06
00E7E9 1
00E7E9 1 65 2B adc $2B ; $E7E9: 65 2B
00E7EB 1 90 02 bcc CalculateScaledProduct_Next
00E7ED 1 ; $E7EB: 90 02
00E7ED 1
00E7ED 1 E6 28 inc $28 ; $E7ED: E6 28
00E7EF 1
00E7EF 1 CalculateScaledProduct_Next: ; $E7EF
00E7EF 1 CA dex ; $E7EF: CA
00E7F0 1 D0 F2 bne CalculateScaledProduct_Loop
00E7F2 1 ; $E7F0: D0 F2
00E7F2 1
00E7F2 1 A6 28 ldx $28 ; $E7F2: A6 28
00E7F4 1 60 rts ; $E7F4: 60
00E7F5 1
00E7F5 1 ; ============================================================================
00E7F5 1 ; $E7F5-$E80A
00E7F5 1 ; Perform a nine-round restoring division.
00E7F5 1 ;
00E7F5 1 ; Entry:
00E7F5 1 ; A = dividend
00E7F5 1 ; Y = divisor
00E7F5 1 ; X = initial high or remainder byte
00E7F5 1 ;
00E7F5 1 ; Working storage:
00E7F5 1 ; $28 = quotient/result shift register
00E7F5 1 ; $2B = divisor
00E7F5 1 ;
00E7F5 1 ; Exit:
00E7F5 1 ; A = quotient/result byte from $28
00E7F5 1 ;
00E7F5 1 ; Each round conditionally subtracts the divisor, then rotates the result bit
00E7F5 1 ; into $28.
00E7F5 1 ; ============================================================================
00E7F5 1
00E7F5 1 ; ----------------------------------------------------------------------------
00E7F5 1 ; Contract:
00E7F5 1 ; Description: Implements Divide Unsigned Byte.
00E7F5 1 ; Entry: Registers: A, X, Y; Memory: $2b, $28
00E7F5 1 ; Returns/products: Registers/clobbers: A, X
00E7F5 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E7F5 1 ; Memory effects: $28, $2b
00E7F5 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E7F5 1 ; comparison, load, or store path and are not a stable API product.
00E7F5 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E7F5 1 ; ----------------------------------------------------------------------------
00E7F5 1 DivideUnsignedByte: ; $E7F5
00E7F5 1 85 28 sta $28 ; $E7F5: 85 28
00E7F7 1 84 2B sty $2B ; $E7F7: 84 2B
00E7F9 1
00E7F9 1 8A txa ; $E7F9: 8A
00E7FA 1
00E7FA 1 A2 09 ldx #$09 ; $E7FA: A2 09
00E7FC 1
00E7FC 1 DivideUnsignedByte_Loop: ; $E7FC
00E7FC 1 C5 2B cmp $2B ; $E7FC: C5 2B
00E7FE 1 90 02 bcc DivideUnsignedByte_Shift
00E800 1 ; $E7FE: 90 02
00E800 1
00E800 1 E5 2B sbc $2B ; $E800: E5 2B
00E802 1
00E802 1 DivideUnsignedByte_Shift: ; $E802
00E802 1 26 28 rol $28 ; $E802: 26 28
00E804 1 2A rol ; $E804: 2A
00E805 1
00E805 1 CA dex ; $E805: CA
00E806 1 D0 F4 bne DivideUnsignedByte_Loop ; $E806: D0 F4
00E808 1
00E808 1 A5 28 lda $28 ; $E808: A5 28
00E80A 1 60 rts ; $E80A: 60
00E80B 1
00E80B 1 ; ============================================================================
00E80B 1 ; $E80B-$E821
00E80B 1 ; Initialize an eight-round vector or magnitude calculation.
00E80B 1 ;
00E80B 1 ; Entry:
00E80B 1 ; X = signed horizontal input
00E80B 1 ; Y = vertical input
00E80B 1 ;
00E80B 1 ; Working state:
00E80B 1 ; $D4 = absolute or complemented horizontal input
00E80B 1 ; $D5 = vertical input
00E80B 1 ; $DB = round/shift state, initialized to $FF and then incremented to zero
00E80B 1 ;
00E80B 1 ; Exit:
00E80B 1 ; Result is returned by the state accumulated through $E8DA.
00E80B 1 ;
00E80B 1 ; The precise mathematical operation depends on the helper at $E8DA, but this
00E80B 1 ; routine clearly normalizes the sign of X and performs eight identical rounds.
00E80B 1 ; ============================================================================
00E80B 1
00E80B 1 ; ----------------------------------------------------------------------------
00E80B 1 ; Contract:
00E80B 1 ; Description: Calculates Vector Magnitude.
00E80B 1 ; Entry: Registers: A, X, Y
00E80B 1 ; Returns/products: Registers/clobbers: A, X, Y
00E80B 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E80B 1 ; Memory effects: $d4, $d5, $db
00E80B 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E80B 1 ; comparison, load, or store path and are not a stable API product.
00E80B 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E80B 1 ; ----------------------------------------------------------------------------
00E80B 1 CalculateVectorMagnitude: ; $E80B
00E80B 1 8A txa ; $E80B: 8A
00E80C 1 10 02 bpl CalculateVectorMagnitude_SaveX
00E80E 1 ; $E80C: 10 02
00E80E 1
00E80E 1 ; ----------------------------------------------------------------------------
00E80E 1 ; Convert a negative X input using one's complement.
00E80E 1 ;
00E80E 1 ; Unlike a full absolute-value conversion, this does not add one here. The
00E80E 1 ; lower-level iterative helper accounts for the representation.
00E80E 1 ; ----------------------------------------------------------------------------
00E80E 1
00E80E 1 49 FF eor #$FF ; $E80E: 49 FF
00E810 1
00E810 1 CalculateVectorMagnitude_SaveX: ; $E810
00E810 1 85 D4 sta $D4 ; $E810: 85 D4
00E812 1 84 D5 sty $D5 ; $E812: 84 D5
00E814 1
00E814 1 ; ----------------------------------------------------------------------------
00E814 1 ; Initialize the round state.
00E814 1 ;
00E814 1 ; X is first set to $FF and stored in $DB, then incremented to zero before the
00E814 1 ; eight processing rounds begin.
00E814 1 ; ----------------------------------------------------------------------------
00E814 1
00E814 1 A2 FF ldx #$FF ; $E814: A2 FF
00E816 1 86 DB stx $DB ; $E816: 86 DB
00E818 1
00E818 1 E8 inx ; $E818: E8
00E819 1 ; X = $00.
00E819 1
00E819 1 A0 08 ldy #$08 ; $E819: A0 08
00E81B 1
00E81B 1 CalculateVectorMagnitude_Loop: ; $E81B
00E81B 1 20 DA E8 jsr UpdatePrimaryArithmeticPair ; $E81B: 20 DA E8
00E81E 1
00E81E 1 88 dey ; $E81E: 88
00E81F 1 D0 FA bne CalculateVectorMagnitude_Loop
00E821 1 ; $E81F: D0 FA
00E821 1
00E821 1 60 rts ; $E821: 60
00E822 1
00E822 1 ; ============================================================================
00E822 1 ; $E822-$E854
00E822 1 ; Initialize and run a signed two-component vector calculation.
00E822 1 ;
00E822 1 ; Entry:
00E822 1 ; A = first result or vector component
00E822 1 ; X = signed horizontal component
00E822 1 ; Y = vertical component
00E822 1 ;
00E822 1 ; Working state:
00E822 1 ; $D4/$D5 = normalized signed source pair
00E822 1 ; $D6/$D7 = result or secondary pair
00E822 1 ; $D9 = sign-extension byte, $00 or $FF
00E822 1 ; $DB = round/shift state
00E822 1 ;
00E822 1 ; Exit:
00E822 1 ; A = $D9 XOR $D6
00E822 1 ; Y = $D9 XOR $D7
00E822 1 ;
00E822 1 ; The routine performs eight rounds using both $E8DA and $E908, then applies
00E822 1 ; the original sign extension to the result pair.
00E822 1 ; ============================================================================
00E822 1
00E822 1 CalculateSignedVector: ; $E822
00E822 1 85 D6 sta $D6 ; $E822: 85 D6
00E824 1
00E824 1 A9 00 lda #$00 ; $E824: A9 00
00E826 1 85 D7 sta $D7 ; $E826: 85 D7
00E828 1
00E828 1 ; ----------------------------------------------------------------------------
00E828 1 ; Alternate entry used by callers that have already initialized $D6/$D7.
00E828 1 ;
00E828 1 ; Entry:
00E828 1 ; X = signed horizontal component
00E828 1 ; Y = vertical component
00E828 1 ; ----------------------------------------------------------------------------
00E828 1
00E828 1 CalculateSignedVectorFromResult: ; $E828
00E828 1 84 D5 sty $D5 ; $E828: 84 D5
00E82A 1
00E82A 1 A0 00 ldy #$00 ; $E82A: A0 00
00E82C 1 ; Default sign-extension byte.
00E82C 1
00E82C 1 8A txa ; $E82C: 8A
00E82D 1 10 03 bpl CalculateSignedVector_SaveSign
00E82F 1 ; $E82D: 10 03
00E82F 1
00E82F 1 ; ----------------------------------------------------------------------------
00E82F 1 ; Normalize a negative X component using one's complement and set the sign
00E82F 1 ; extension byte to $FF.
00E82F 1 ; ----------------------------------------------------------------------------
00E82F 1
00E82F 1 49 FF eor #$FF ; $E82F: 49 FF
00E831 1 88 dey ; $E831: 88
00E832 1 ; Y = $FF.
00E832 1
00E832 1 CalculateSignedVector_SaveSign: ; $E832
00E832 1 84 D9 sty $D9 ; $E832: 84 D9
00E834 1 85 D4 sta $D4 ; $E834: 85 D4
00E836 1
00E836 1 ; ----------------------------------------------------------------------------
00E836 1 ; Apply the sign extension to the vertical source component.
00E836 1 ; ----------------------------------------------------------------------------
00E836 1
00E836 1 98 tya ; $E836: 98
00E837 1 45 D5 eor $D5 ; $E837: 45 D5
00E839 1 85 D5 sta $D5 ; $E839: 85 D5
00E83B 1
00E83B 1 ; ----------------------------------------------------------------------------
00E83B 1 ; Initialize the round state.
00E83B 1 ; ----------------------------------------------------------------------------
00E83B 1
00E83B 1 A2 FF ldx #$FF ; $E83B: A2 FF
00E83D 1 86 DB stx $DB ; $E83D: 86 DB
00E83F 1
00E83F 1 E8 inx ; $E83F: E8
00E840 1 ; X = $00.
00E840 1
00E840 1 A0 08 ldy #$08 ; $E840: A0 08
00E842 1
00E842 1 ; ----------------------------------------------------------------------------
00E842 1 ; Run eight rounds. Each round performs the common step at $E8DA followed by
00E842 1 ; the signed-result accumulation step at $E908.
00E842 1 ; ----------------------------------------------------------------------------
00E842 1
00E842 1 CalculateSignedVector_Loop: ; $E842
00E842 1 20 DA E8 jsr UpdatePrimaryArithmeticPair ; $E842: 20 DA E8
00E845 1 20 08 E9 jsr UpdateSecondaryArithmeticPair ; $E845: 20 08 E9
00E848 1
00E848 1 88 dey ; $E848: 88
00E849 1 D0 F7 bne CalculateSignedVector_Loop
00E84B 1 ; $E849: D0 F7
00E84B 1
00E84B 1 ; ----------------------------------------------------------------------------
00E84B 1 ; Apply the original sign extension to the resulting pair.
00E84B 1 ; ----------------------------------------------------------------------------
00E84B 1
00E84B 1 A5 D9 lda $D9 ; $E84B: A5 D9
00E84D 1 45 D7 eor $D7 ; $E84D: 45 D7
00E84F 1 A8 tay ; $E84F: A8
00E850 1
00E850 1 A5 D9 lda $D9 ; $E850: A5 D9
00E852 1 45 D6 eor $D6 ; $E852: 45 D6
00E854 1
00E854 1 60 rts ; $E854: 60
00E855 1
00E855 1 ; ============================================================================
00E855 1 ; $E855-$E876
00E855 1 ; Run an eight-round signed vector calculation using a caller-supplied result
00E855 1 ; pair in X:Y.
00E855 1 ;
00E855 1 ; Entry:
00E855 1 ; A = signed/control input, transformed by XOR #$80
00E855 1 ; X = first result component
00E855 1 ; Y = second result component
00E855 1 ;
00E855 1 ; Working state:
00E855 1 ; $D8 = transformed input shift register
00E855 1 ; $D6 = saved X component
00E855 1 ; $D7 = saved Y component
00E855 1 ; $DA = per-round sign or mask byte
00E855 1 ; $DB = round index, progressing from $00 through $07
00E855 1 ;
00E855 1 ; Exit:
00E855 1 ; A = value left by the final $E908 call
00E855 1 ; Y = original input Y component
00E855 1 ; ============================================================================
00E855 1
00E855 1 ; ----------------------------------------------------------------------------
00E855 1 ; Contract:
00E855 1 ; Description: Calculates Vector From Rotated Mask.
00E855 1 ; Entry: Registers: A, X, Y; Memory: $d7
00E855 1 ; Returns/products: Registers/clobbers: A, X, Y
00E855 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E855 1 ; Memory effects: $d8, $d6, $d7, $db, $da
00E855 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E855 1 ; comparison, load, or store path and are not a stable API product.
00E855 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 2.
00E855 1 ; ----------------------------------------------------------------------------
00E855 1 CalculateVectorFromRotatedMask: ; $E855
00E855 1 49 80 eor #$80 ; $E855: 49 80
00E857 1 85 D8 sta $D8 ; $E857: 85 D8
00E859 1
00E859 1 86 D6 stx $D6 ; $E859: 86 D6
00E85B 1 84 D7 sty $D7 ; $E85B: 84 D7
00E85D 1
00E85D 1 ; ----------------------------------------------------------------------------
00E85D 1 ; Initialize the round index to $FF. It is incremented at the start of each
00E85D 1 ; round, producing indices $00-$07.
00E85D 1 ; ----------------------------------------------------------------------------
00E85D 1
00E85D 1 A9 FF lda #$FF ; $E85D: A9 FF
00E85F 1 85 DB sta $DB ; $E85F: 85 DB
00E861 1
00E861 1 A0 08 ldy #$08 ; $E861: A0 08
00E863 1
00E863 1 CalculateVectorFromRotatedMask_Loop: ; $E863
00E863 1 E6 DB inc $DB ; $E863: E6 DB
00E865 1
00E865 1 ; ----------------------------------------------------------------------------
00E865 1 ; Shift the next bit from $D8 into carry.
00E865 1 ;
00E865 1 ; X becomes:
00E865 1 ; $00 when carry is clear
00E865 1 ; $FF when carry is set
00E865 1 ;
00E865 1 ; This creates a sign-extension or conditional-mask byte in $DA.
00E865 1 ; ----------------------------------------------------------------------------
00E865 1
00E865 1 A2 00 ldx #$00 ; $E865: A2 00
00E867 1
00E867 1 26 D8 rol $D8 ; $E867: 26 D8
00E869 1 90 01 bcc CalculateVectorFromRotatedMask_SaveMask
00E86B 1 ; $E869: 90 01
00E86B 1
00E86B 1 CA dex ; $E86B: CA
00E86C 1 ; X = $FF.
00E86C 1
00E86C 1 CalculateVectorFromRotatedMask_SaveMask: ; $E86C
00E86C 1 86 DA stx $DA ; $E86C: 86 DA
00E86E 1
00E86E 1 ; ----------------------------------------------------------------------------
00E86E 1 ; Apply the per-round result update.
00E86E 1 ; ----------------------------------------------------------------------------
00E86E 1
00E86E 1 20 08 E9 jsr UpdateSecondaryArithmeticPair ; $E86E: 20 08 E9
00E871 1
00E871 1 88 dey ; $E871: 88
00E872 1 D0 EF bne CalculateVectorFromRotatedMask_Loop
00E874 1 ; $E872: D0 EF
00E874 1
00E874 1 ; ----------------------------------------------------------------------------
00E874 1 ; Restore the original Y component before returning.
00E874 1 ; ----------------------------------------------------------------------------
00E874 1
00E874 1 A4 D7 ldy $D7 ; $E874: A4 D7
00E876 1 60 rts ; $E876: 60
00E877 1
00E877 1 ; ============================================================================
00E877 1 ; $E877-$E8A4
00E877 1 ; Run an eight-round signed-vector normalization using source values in
00E877 1 ; $D4-$D7.
00E877 1 ;
00E877 1 ; Entry:
00E877 1 ; $D4 = signed primary source component
00E877 1 ; $D5 = secondary source component
00E877 1 ; $D6/$D7 = result or destination pair
00E877 1 ;
00E877 1 ; Working state:
00E877 1 ; $D9 = sign-extension byte derived from $D4
00E877 1 ; $DA = per-round working mask/result
00E877 1 ; $DB = shift/round state, initialized to $FF
00E877 1 ;
00E877 1 ; Exit:
00E877 1 ; A = normalized first result component
00E877 1 ; X = complemented sign-extension byte
00E877 1 ; Y = normalized second result component
00E877 1 ; ============================================================================
00E877 1
00E877 1 ; ----------------------------------------------------------------------------
00E877 1 ; Contract:
00E877 1 ; Description: Implements Normalize Signed Vector.
00E877 1 ; Entry: Registers: A, X, Y; Memory: $d4, $da, $d9, $d7, $d6
00E877 1 ; Returns/products: Registers/clobbers: A, X, Y
00E877 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E877 1 ; Memory effects: $db, $d9, $d4, $da
00E877 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E877 1 ; comparison, load, or store path and are not a stable API product.
00E877 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E877 1 ; ----------------------------------------------------------------------------
00E877 1 NormalizeSignedVector: ; $E877
00E877 1 A0 FF ldy #$FF ; $E877: A0 FF
00E879 1 84 DB sty $DB ; $E879: 84 DB
00E87B 1
00E87B 1 ; ----------------------------------------------------------------------------
00E87B 1 ; Normalize the signed source byte at $D4.
00E87B 1 ;
00E87B 1 ; For a nonnegative value:
00E87B 1 ; $D9 = $FF
00E87B 1 ; $D4 remains unchanged
00E87B 1 ;
00E87B 1 ; For a negative value:
00E87B 1 ; $D9 = $00
00E87B 1 ; $D4 is one's-complemented
00E87B 1 ; ----------------------------------------------------------------------------
00E87B 1
00E87B 1 A5 D4 lda $D4 ; $E87B: A5 D4
00E87D 1 10 03 bpl NormalizeSignedVector_SaveSign
00E87F 1 ; $E87D: 10 03
00E87F 1
00E87F 1 C8 iny ; $E87F: C8
00E880 1 ; Y changes from $FF to $00.
00E880 1
00E880 1 49 FF eor #$FF ; $E880: 49 FF
00E882 1
00E882 1 NormalizeSignedVector_SaveSign: ; $E882
00E882 1 84 D9 sty $D9 ; $E882: 84 D9
00E884 1 85 D4 sta $D4 ; $E884: 85 D4
00E886 1
00E886 1 ; ----------------------------------------------------------------------------
00E886 1 ; Initialize X to zero and perform eight processing rounds.
00E886 1 ; ----------------------------------------------------------------------------
00E886 1
00E886 1 A2 00 ldx #$00 ; $E886: A2 00
00E888 1 A0 08 ldy #$08 ; $E888: A0 08
00E88A 1
00E88A 1 NormalizeSignedVector_Loop: ; $E88A
00E88A 1 20 DA E8 jsr UpdatePrimaryArithmeticPair ; $E88A: 20 DA E8
00E88D 1
00E88D 1 ; ----------------------------------------------------------------------------
00E88D 1 ; Apply the saved sign extension to $DA before updating the result pair.
00E88D 1 ; ----------------------------------------------------------------------------
00E88D 1
00E88D 1 A5 DA lda $DA ; $E88D: A5 DA
00E88F 1 45 D9 eor $D9 ; $E88F: 45 D9
00E891 1 85 DA sta $DA ; $E891: 85 DA
00E893 1
00E893 1 20 08 E9 jsr UpdateSecondaryArithmeticPair ; $E893: 20 08 E9
00E896 1
00E896 1 88 dey ; $E896: 88
00E897 1 D0 F1 bne NormalizeSignedVector_Loop
00E899 1 ; $E897: D0 F1
00E899 1
00E899 1 ; ----------------------------------------------------------------------------
00E899 1 ; Apply the final sign correction to the output pair.
00E899 1 ; ----------------------------------------------------------------------------
00E899 1
00E899 1 A5 D9 lda $D9 ; $E899: A5 D9
00E89B 1 49 FF eor #$FF ; $E89B: 49 FF
00E89D 1 AA tax ; $E89D: AA
00E89E 1 ; X = complement of sign-extension byte.
00E89E 1
00E89E 1 45 D7 eor $D7 ; $E89E: 45 D7
00E8A0 1 A8 tay ; $E8A0: A8
00E8A1 1
00E8A1 1 8A txa ; $E8A1: 8A
00E8A2 1 45 D6 eor $D6 ; $E8A2: 45 D6
00E8A4 1
00E8A4 1 60 rts ; $E8A4: 60
00E8A5 1
00E8A5 1 ; ============================================================================
00E8A5 1 ; $E8A5-$E8B6
00E8A5 1 ; Run an eight-round arithmetic transformation using the input pair X:Y.
00E8A5 1 ;
00E8A5 1 ; Entry:
00E8A5 1 ; X = first input component
00E8A5 1 ; Y = second input component
00E8A5 1 ;
00E8A5 1 ; Working state:
00E8A5 1 ; $D4 = saved X component
00E8A5 1 ; $D5 = saved Y component
00E8A5 1 ; $DB = round state, initialized to $FF
00E8A5 1 ;
00E8A5 1 ; Exit:
00E8A5 1 ; Result is returned in the state/registers produced by the final call to
00E8A5 1 ; $E931.
00E8A5 1 ;
00E8A5 1 ; The exact mathematical role depends on the shared helper at $E931, but this
00E8A5 1 ; routine is clearly an eight-round wrapper around that operation.
00E8A5 1 ; ============================================================================
00E8A5 1
00E8A5 1 ; ----------------------------------------------------------------------------
00E8A5 1 ; Contract:
00E8A5 1 ; Description: Runs Eight Round Transform.
00E8A5 1 ; Entry: Registers: X, Y
00E8A5 1 ; Returns/products: Registers/clobbers: X, Y
00E8A5 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E8A5 1 ; Memory effects: $d4, $d5, $db
00E8A5 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E8A5 1 ; comparison, load, or store path and are not a stable API product.
00E8A5 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E8A5 1 ; ----------------------------------------------------------------------------
00E8A5 1 RunEightRoundTransform: ; $E8A5
00E8A5 1 86 D4 stx $D4 ; $E8A5: 86 D4
00E8A7 1 84 D5 sty $D5 ; $E8A7: 84 D5
00E8A9 1
00E8A9 1 ; ----------------------------------------------------------------------------
00E8A9 1 ; Initialize the round state.
00E8A9 1 ;
00E8A9 1 ; X is first set to $FF and stored in $DB, then incremented to zero.
00E8A9 1 ; ----------------------------------------------------------------------------
00E8A9 1
00E8A9 1 A2 FF ldx #$FF ; $E8A9: A2 FF
00E8AB 1 86 DB stx $DB ; $E8AB: 86 DB
00E8AD 1
00E8AD 1 E8 inx ; $E8AD: E8
00E8AE 1 ; X = $00.
00E8AE 1
00E8AE 1 A0 08 ldy #$08 ; $E8AE: A0 08
00E8B0 1
00E8B0 1 RunEightRoundTransform_Loop: ; $E8B0
00E8B0 1 20 31 E9 jsr UpdatePrimaryArithmeticPairAlternate ; $E8B0: 20 31 E9
00E8B3 1
00E8B3 1 88 dey ; $E8B3: 88
00E8B4 1 D0 FA bne RunEightRoundTransform_Loop
00E8B6 1 ; $E8B4: D0 FA
00E8B6 1
00E8B6 1 60 rts ; $E8B6: 60
00E8B7 1
00E8B7 1 ; ============================================================================
00E8B7 1 ; $E8B7-$E8D9
00E8B7 1 ; Convert the A:Y input pair to component magnitudes, perform eight common
00E8B7 1 ; arithmetic rounds, and return a transformed high/result byte.
00E8B7 1 ;
00E8B7 1 ; Entry:
00E8B7 1 ; A = first signed component
00E8B7 1 ; Y = second signed component
00E8B7 1 ;
00E8B7 1 ; Normalization:
00E8B7 1 ; Negative components are one's-complemented.
00E8B7 1 ;
00E8B7 1 ; Working state:
00E8B7 1 ; $D4 = normalized first component
00E8B7 1 ; $D5 = normalized second component
00E8B7 1 ; $D9/$DA = common round result pair
00E8B7 1 ; $DB = round state, initialized to $FF
00E8B7 1 ;
00E8B7 1 ; Exit:
00E8B7 1 ; A = $D9 XOR $7F
00E8B7 1 ;
00E8B7 1 ; This is not a standard two's-complement absolute-value conversion because no
00E8B7 1 ; one is added after the complement. The shared round helper accounts for the
00E8B7 1 ; representation.
00E8B7 1 ; ============================================================================
00E8B7 1
00E8B7 1 TransformSignedComponentPair: ; $E8B7
00E8B7 1 10 02 bpl TransformSignedComponentPair_SaveA
00E8B9 1 ; $E8B7: 10 02
00E8B9 1
00E8B9 1 49 FF eor #$FF ; $E8B9: 49 FF
00E8BB 1
00E8BB 1 TransformSignedComponentPair_SaveA: ; $E8BB
00E8BB 1 85 D4 sta $D4 ; $E8BB: 85 D4
00E8BD 1
00E8BD 1 ; ----------------------------------------------------------------------------
00E8BD 1 ; Normalize the Y component.
00E8BD 1 ; ----------------------------------------------------------------------------
00E8BD 1
00E8BD 1 98 tya ; $E8BD: 98
00E8BE 1 10 02 bpl TransformSignedComponentPair_SaveY
00E8C0 1 ; $E8BE: 10 02
00E8C0 1
00E8C0 1 49 FF eor #$FF ; $E8C0: 49 FF
00E8C2 1
00E8C2 1 TransformSignedComponentPair_SaveY: ; $E8C2
00E8C2 1 85 D5 sta $D5 ; $E8C2: 85 D5
00E8C4 1
00E8C4 1 ; ----------------------------------------------------------------------------
00E8C4 1 ; Initialize the round state.
00E8C4 1 ; ----------------------------------------------------------------------------
00E8C4 1
00E8C4 1 A2 FF ldx #$FF ; $E8C4: A2 FF
00E8C6 1 86 DB stx $DB ; $E8C6: 86 DB
00E8C8 1
00E8C8 1 E8 inx ; $E8C8: E8
00E8C9 1 ; X = $00.
00E8C9 1
00E8C9 1 A0 08 ldy #$08 ; $E8C9: A0 08
00E8CB 1
00E8CB 1 ; ----------------------------------------------------------------------------
00E8CB 1 ; Run eight common arithmetic rounds.
00E8CB 1 ;
00E8CB 1 ; After each round:
00E8CB 1 ; $DA is shifted left.
00E8CB 1 ; Carry is rotated into $D9.
00E8CB 1 ; ----------------------------------------------------------------------------
00E8CB 1
00E8CB 1 TransformSignedComponentPair_Loop: ; $E8CB
00E8CB 1 20 DA E8 jsr UpdatePrimaryArithmeticPair ; $E8CB: 20 DA E8
00E8CE 1
00E8CE 1 06 DA asl $DA ; $E8CE: 06 DA
00E8D0 1 26 D9 rol $D9 ; $E8D0: 26 D9
00E8D2 1
00E8D2 1 88 dey ; $E8D2: 88
00E8D3 1 D0 F6 bne TransformSignedComponentPair_Loop
00E8D5 1 ; $E8D3: D0 F6
00E8D5 1
00E8D5 1 ; ----------------------------------------------------------------------------
00E8D5 1 ; Return the transformed result.
00E8D5 1 ; ----------------------------------------------------------------------------
00E8D5 1
00E8D5 1 A5 D9 lda $D9 ; $E8D5: A5 D9
00E8D7 1 49 7F eor #$7F ; $E8D7: 49 7F
00E8D9 1
00E8D9 1 60 rts ; $E8D9: 60
00E8DA 1
00E8DA 1 ; ============================================================================
00E8DA 1 ; $E8DA-$E907
00E8DA 1 ; Shared per-round arithmetic update for source pair $D4/$D5.
00E8DA 1 ;
00E8DA 1 ; Working state:
00E8DA 1 ; $D4/$D5 = signed or fixed-point accumulator
00E8DA 1 ; $DA = per-round sign/mask byte
00E8DA 1 ; $DB = shift count, incremented at the start of the round
00E8DA 1 ;
00E8DA 1 ; Operation:
00E8DA 1 ; 1. Increment the shift count.
00E8DA 1 ; 2. Derive $DA from the sign of $D5.
00E8DA 1 ; 3. Shift and add $D4 into itself.
00E8DA 1 ; 4. Shift a sign-corrected form of $D4.
00E8DA 1 ; 5. Add the result into $D5.
00E8DA 1 ;
00E8DA 1 ; Exit:
00E8DA 1 ; $D4/$D5 updated in place
00E8DA 1 ; ============================================================================
00E8DA 1
00E8DA 1 ; ----------------------------------------------------------------------------
00E8DA 1 ; Contract:
00E8DA 1 ; Description: Updates Primary Arithmetic Pair.
00E8DA 1 ; Entry: Registers: A, X; Memory: $d5, $db, $d4, $da
00E8DA 1 ; Returns/products: Registers/clobbers: A, X
00E8DA 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E8DA 1 ; Memory effects: $da, $d5, $d4
00E8DA 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E8DA 1 ; comparison, load, or store path and are not a stable API product.
00E8DA 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 4.
00E8DA 1 ; ----------------------------------------------------------------------------
00E8DA 1 UpdatePrimaryArithmeticPair: ; $E8DA
00E8DA 1 E6 DB inc $DB ; $E8DA: E6 DB
00E8DC 1 ; Advance the per-round shift count.
00E8DC 1
00E8DC 1 A5 D5 lda $D5 ; $E8DC: A5 D5
00E8DE 1 10 03 bpl UpdatePrimaryArithmeticPair_SaveMask
00E8E0 1 ; $E8DE: 10 03
00E8E0 1
00E8E0 1 ; ----------------------------------------------------------------------------
00E8E0 1 ; Negative high/source byte:
00E8E0 1 ;
00E8E0 1 ; X is decremented from the caller's current value.
00E8E0 1 ; A is one's-complemented.
00E8E0 1 ; ----------------------------------------------------------------------------
00E8E0 1
00E8E0 1 CA dex ; $E8E0: CA
00E8E1 1 49 FF eor #$FF ; $E8E1: 49 FF
00E8E3 1
00E8E3 1 UpdatePrimaryArithmeticPair_SaveMask: ; $E8E3
00E8E3 1 86 DA stx $DA ; $E8E3: 86 DA
00E8E5 1
00E8E5 1 ; ----------------------------------------------------------------------------
00E8E5 1 ; Shift A right by the current count in $DB.
00E8E5 1 ;
00E8E5 1 ; When $DB is zero, no shift is performed.
00E8E5 1 ; ----------------------------------------------------------------------------
00E8E5 1
00E8E5 1 A6 DB ldx $DB ; $E8E5: A6 DB
00E8E7 1 F0 04 beq UpdatePrimaryArithmeticPair_AddLow
00E8E9 1 ; $E8E7: F0 04
00E8E9 1
00E8E9 1 UpdatePrimaryArithmeticPair_ShiftLow: ; $E8E9
00E8E9 1 4A lsr ; $E8E9: 4A
00E8EA 1 CA dex ; $E8EA: CA
00E8EB 1 D0 FC bne UpdatePrimaryArithmeticPair_ShiftLow
00E8ED 1 ; $E8EB: D0 FC
00E8ED 1
00E8ED 1 ; ----------------------------------------------------------------------------
00E8ED 1 ; Add the shifted value to $D4.
00E8ED 1 ;
00E8ED 1 ; Carry intentionally comes from the final LSR or from the preceding sign
00E8ED 1 ; setup when no shift occurred.
00E8ED 1 ; ----------------------------------------------------------------------------
00E8ED 1
00E8ED 1 UpdatePrimaryArithmeticPair_AddLow: ; $E8ED
00E8ED 1 65 D4 adc $D4 ; $E8ED: 65 D4
00E8EF 1 48 pha ; $E8EF: 48
00E8F0 1 ; Preserve the new low/result byte.
00E8F0 1
00E8F0 1 ; ----------------------------------------------------------------------------
00E8F0 1 ; Build the high/source contribution:
00E8F0 1 ;
00E8F0 1 ; A = ($DA XOR $FF XOR $D4)
00E8F0 1 ;
00E8F0 1 ; Then arithmetically shift it right by $DB.
00E8F0 1 ; ----------------------------------------------------------------------------
00E8F0 1
00E8F0 1 A5 DA lda $DA ; $E8F0: A5 DA
00E8F2 1 49 FF eor #$FF ; $E8F2: 49 FF
00E8F4 1 45 D4 eor $D4 ; $E8F4: 45 D4
00E8F6 1
00E8F6 1 A6 DB ldx $DB ; $E8F6: A6 DB
00E8F8 1 F0 06 beq UpdatePrimaryArithmeticPair_AddHigh
00E8FA 1 ; $E8F8: F0 06
00E8FA 1
00E8FA 1 UpdatePrimaryArithmeticPair_ShiftHigh: ; $E8FA
00E8FA 1 C9 80 cmp #$80 ; $E8FA: C9 80
00E8FC 1 ; Copy the sign bit into carry.
00E8FC 1
00E8FC 1 6A ror ; $E8FC: 6A
00E8FD 1 ; Arithmetic right shift.
00E8FD 1
00E8FD 1 CA dex ; $E8FD: CA
00E8FE 1 D0 FA bne UpdatePrimaryArithmeticPair_ShiftHigh
00E900 1 ; $E8FE: D0 FA
00E900 1
00E900 1 ; ----------------------------------------------------------------------------
00E900 1 ; Add the shifted high/source result to $D5.
00E900 1 ; ----------------------------------------------------------------------------
00E900 1
00E900 1 UpdatePrimaryArithmeticPair_AddHigh: ; $E900
00E900 1 65 D5 adc $D5 ; $E900: 65 D5
00E902 1 85 D5 sta $D5 ; $E902: 85 D5
00E904 1
00E904 1 ; ----------------------------------------------------------------------------
00E904 1 ; Restore and save the low/result byte.
00E904 1 ; ----------------------------------------------------------------------------
00E904 1
00E904 1 68 pla ; $E904: 68
00E905 1 85 D4 sta $D4 ; $E905: 85 D4
00E907 1
00E907 1 60 rts ; $E907: 60
00E908 1
00E908 1 ; ============================================================================
00E908 1 ; $E908-$E930
00E908 1 ; Apply the current per-round mask and shift state to result pair $D6/$D7.
00E908 1 ;
00E908 1 ; Working state:
00E908 1 ; $D6/$D7 = secondary accumulator/result pair
00E908 1 ; $DA = sign/mask byte
00E908 1 ; $DB = shift count
00E908 1 ;
00E908 1 ; Exit:
00E908 1 ; $D6/$D7 updated in place
00E908 1 ;
00E908 1 ; This routine is paired with UpdatePrimaryArithmeticPair and is called after
00E908 1 ; each common arithmetic round by multiple vector helpers.
00E908 1 ; ============================================================================
00E908 1
00E908 1 ; ----------------------------------------------------------------------------
00E908 1 ; Contract:
00E908 1 ; Description: Updates Secondary Arithmetic Pair.
00E908 1 ; Entry: Registers: A, X; Memory: $da, $d7, $db, $d6
00E908 1 ; Returns/products: Registers/clobbers: A, X
00E908 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E908 1 ; Memory effects: $d7, $d6
00E908 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E908 1 ; comparison, load, or store path and are not a stable API product.
00E908 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 3.
00E908 1 ; ----------------------------------------------------------------------------
00E908 1 UpdateSecondaryArithmeticPair: ; $E908
00E908 1 A5 DA lda $DA ; $E908: A5 DA
00E90A 1 49 FF eor #$FF ; $E90A: 49 FF
00E90C 1 45 D7 eor $D7 ; $E90C: 45 D7
00E90E 1
00E90E 1 ; ----------------------------------------------------------------------------
00E90E 1 ; Arithmetically shift the sign-corrected high contribution by $DB.
00E90E 1 ; ----------------------------------------------------------------------------
00E90E 1
00E90E 1 A6 DB ldx $DB ; $E90E: A6 DB
00E910 1 F0 06 beq UpdateSecondaryArithmeticPair_AddLow
00E912 1 ; $E910: F0 06
00E912 1
00E912 1 UpdateSecondaryArithmeticPair_ShiftLow: ; $E912
00E912 1 C9 80 cmp #$80 ; $E912: C9 80
00E914 1 6A ror ; $E914: 6A
00E915 1
00E915 1 CA dex ; $E915: CA
00E916 1 D0 FA bne UpdateSecondaryArithmeticPair_ShiftLow
00E918 1 ; $E916: D0 FA
00E918 1
00E918 1 ; ----------------------------------------------------------------------------
00E918 1 ; Add the shifted contribution to $D6.
00E918 1 ; ----------------------------------------------------------------------------
00E918 1
00E918 1 UpdateSecondaryArithmeticPair_AddLow: ; $E918
00E918 1 65 D6 adc $D6 ; $E918: 65 D6
00E91A 1 48 pha ; $E91A: 48
00E91B 1 ; Preserve the new low/result byte.
00E91B 1
00E91B 1 ; ----------------------------------------------------------------------------
00E91B 1 ; Build and shift the contribution for $D7.
00E91B 1 ; ----------------------------------------------------------------------------
00E91B 1
00E91B 1 A5 DA lda $DA ; $E91B: A5 DA
00E91D 1 45 D6 eor $D6 ; $E91D: 45 D6
00E91F 1
00E91F 1 A6 DB ldx $DB ; $E91F: A6 DB
00E921 1 F0 06 beq UpdateSecondaryArithmeticPair_AddHigh
00E923 1 ; $E921: F0 06
00E923 1
00E923 1 UpdateSecondaryArithmeticPair_ShiftHigh: ; $E923
00E923 1 C9 80 cmp #$80 ; $E923: C9 80
00E925 1 6A ror ; $E925: 6A
00E926 1
00E926 1 CA dex ; $E926: CA
00E927 1 D0 FA bne UpdateSecondaryArithmeticPair_ShiftHigh
00E929 1 ; $E927: D0 FA
00E929 1
00E929 1 ; ----------------------------------------------------------------------------
00E929 1 ; Add the shifted contribution to $D7.
00E929 1 ; ----------------------------------------------------------------------------
00E929 1
00E929 1 UpdateSecondaryArithmeticPair_AddHigh: ; $E929
00E929 1 65 D7 adc $D7 ; $E929: 65 D7
00E92B 1 85 D7 sta $D7 ; $E92B: 85 D7
00E92D 1
00E92D 1 ; ----------------------------------------------------------------------------
00E92D 1 ; Restore and save the low/result byte.
00E92D 1 ; ----------------------------------------------------------------------------
00E92D 1
00E92D 1 68 pla ; $E92D: 68
00E92E 1 85 D6 sta $D6 ; $E92E: 85 D6
00E930 1
00E930 1 60 rts ; $E930: 60
00E931 1
00E931 1 ; ============================================================================
00E931 1 ; $E931-$E964
00E931 1 ; Alternate per-round update for source pair $D4/$D5.
00E931 1 ;
00E931 1 ; This helper differs from the $E8DA version in two ways:
00E931 1 ;
00E931 1 ; 1. It derives $DA from the opposite sign condition.
00E931 1 ; 2. Shift counts below four are increased by one.
00E931 1 ;
00E931 1 ; Working state:
00E931 1 ; $D4/$D5 = signed or fixed-point accumulator
00E931 1 ; $DA = per-round sign/mask byte
00E931 1 ; $DB = shift count, incremented at the start of the round
00E931 1 ;
00E931 1 ; Exit:
00E931 1 ; $D4/$D5 updated in place
00E931 1 ; ============================================================================
00E931 1
00E931 1 ; ----------------------------------------------------------------------------
00E931 1 ; Contract:
00E931 1 ; Description: Updates Primary Arithmetic Pair Alternate.
00E931 1 ; Entry: Registers: A, X; Memory: $d5, $db, $d4, $da
00E931 1 ; Returns/products: Registers/clobbers: A, X
00E931 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E931 1 ; Memory effects: $da, $d5, $d4
00E931 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E931 1 ; comparison, load, or store path and are not a stable API product.
00E931 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E931 1 ; ----------------------------------------------------------------------------
00E931 1 UpdatePrimaryArithmeticPairAlternate: ; $E931
00E931 1 E6 DB inc $DB ; $E931: E6 DB
00E933 1
00E933 1 A5 D5 lda $D5 ; $E933: A5 D5
00E935 1 30 03 bmi UpdatePrimaryArithmeticPairAlternate_SaveMask
00E937 1 ; $E935: 30 03
00E937 1
00E937 1 ; ----------------------------------------------------------------------------
00E937 1 ; Nonnegative high/source byte:
00E937 1 ;
00E937 1 ; A is one's-complemented.
00E937 1 ; X is decremented.
00E937 1 ; ----------------------------------------------------------------------------
00E937 1
00E937 1 49 FF eor #$FF ; $E937: 49 FF
00E939 1 CA dex ; $E939: CA
00E93A 1
00E93A 1 UpdatePrimaryArithmeticPairAlternate_SaveMask: ; $E93A
00E93A 1 86 DA stx $DA ; $E93A: 86 DA
00E93C 1
00E93C 1 ; ----------------------------------------------------------------------------
00E93C 1 ; Load the shift count.
00E93C 1 ;
00E93C 1 ; Counts below four are increased by one.
00E93C 1 ; ----------------------------------------------------------------------------
00E93C 1
00E93C 1 A6 DB ldx $DB ; $E93C: A6 DB
00E93E 1 E0 04 cpx #$04 ; $E93E: E0 04
00E940 1 B0 01 bcs UpdatePrimaryArithmeticPairAlternate_ShiftLow
00E942 1 ; $E940: B0 01
00E942 1
00E942 1 E8 inx ; $E942: E8
00E943 1
00E943 1 ; ----------------------------------------------------------------------------
00E943 1 ; Arithmetically shift A right by the adjusted count.
00E943 1 ; ----------------------------------------------------------------------------
00E943 1
00E943 1 UpdatePrimaryArithmeticPairAlternate_ShiftLow: ; $E943
00E943 1 C9 80 cmp #$80 ; $E943: C9 80
00E945 1 6A ror ; $E945: 6A
00E946 1
00E946 1 CA dex ; $E946: CA
00E947 1 D0 FA bne UpdatePrimaryArithmeticPairAlternate_ShiftLow
00E949 1 ; $E947: D0 FA
00E949 1
00E949 1 ; ----------------------------------------------------------------------------
00E949 1 ; Add the shifted result to $D4.
00E949 1 ; ----------------------------------------------------------------------------
00E949 1
00E949 1 65 D4 adc $D4 ; $E949: 65 D4
00E94B 1 48 pha ; $E94B: 48
00E94C 1
00E94C 1 ; ----------------------------------------------------------------------------
00E94C 1 ; Build the contribution for $D5.
00E94C 1 ; ----------------------------------------------------------------------------
00E94C 1
00E94C 1 A5 DA lda $DA ; $E94C: A5 DA
00E94E 1 45 D4 eor $D4 ; $E94E: 45 D4
00E950 1
00E950 1 ; ----------------------------------------------------------------------------
00E950 1 ; Apply the same adjusted shift-count rule.
00E950 1 ; ----------------------------------------------------------------------------
00E950 1
00E950 1 A6 DB ldx $DB ; $E950: A6 DB
00E952 1 E0 04 cpx #$04 ; $E952: E0 04
00E954 1 B0 01 bcs UpdatePrimaryArithmeticPairAlternate_ShiftHigh
00E956 1 ; $E954: B0 01
00E956 1
00E956 1 E8 inx ; $E956: E8
00E957 1
00E957 1 UpdatePrimaryArithmeticPairAlternate_ShiftHigh: ; $E957
00E957 1 C9 80 cmp #$80 ; $E957: C9 80
00E959 1 6A ror ; $E959: 6A
00E95A 1
00E95A 1 CA dex ; $E95A: CA
00E95B 1 D0 FA bne UpdatePrimaryArithmeticPairAlternate_ShiftHigh
00E95D 1 ; $E95B: D0 FA
00E95D 1
00E95D 1 ; ----------------------------------------------------------------------------
00E95D 1 ; Add the shifted contribution to $D5.
00E95D 1 ; ----------------------------------------------------------------------------
00E95D 1
00E95D 1 65 D5 adc $D5 ; $E95D: 65 D5
00E95F 1 85 D5 sta $D5 ; $E95F: 85 D5
00E961 1
00E961 1 ; ----------------------------------------------------------------------------
00E961 1 ; Restore and save the updated low/result byte.
00E961 1 ; ----------------------------------------------------------------------------
00E961 1
00E961 1 68 pla ; $E961: 68
00E962 1 85 D4 sta $D4 ; $E962: 85 D4
00E964 1
00E964 1 60 rts ; $E964: 60
00E965 1
00E965 1 ; ============================================================================
00E965 1 ; $E965-$E96B
00E965 1 ; Calculate a scaled ratio by chaining the multiplication and division helpers.
00E965 1 ;
00E965 1 ; Entry and exit registers depend on the callers:
00E965 1 ;
00E965 1 ; CalculateScaledProduct = $E7DB
00E965 1 ; DivideUnsignedByte = $E7F5
00E965 1 ; ============================================================================
00E965 1
00E965 1 ; ----------------------------------------------------------------------------
00E965 1 ; Contract:
00E965 1 ; Description: Calculates Scaled Ratio.
00E965 1 ; Entry: No register input inferred
00E965 1 ; Returns/products: No direct product inferred
00E965 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E965 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00E965 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E965 1 ; comparison, load, or store path and are not a stable API product.
00E965 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E965 1 ; ----------------------------------------------------------------------------
00E965 1 CalculateScaledRatio: ; $E965
00E965 1 20 DB E7 jsr CalculateScaledProduct ; $E965: 20 DB E7
00E968 1 20 F5 E7 jsr DivideUnsignedByte ; $E968: 20 F5 E7
00E96B 1 60 rts ; $E96B: 60
00E96C 1
00E96C 1 ; ============================================================================
00E96C 1 ; $E96C-$E977
00E96C 1 ; Disable PPU rendering and read PPUSTATUS.
00E96C 1 ;
00E96C 1 ; Exit:
00E96C 1 ; Rendering is disabled.
00E96C 1 ; A contains the value read from PPUSTATUS.
00E96C 1 ; ============================================================================
00E96C 1
00E96C 1 ; ----------------------------------------------------------------------------
00E96C 1 ; Contract:
00E96C 1 ; Description: Implements Disable Ppu Rendering.
00E96C 1 ; Entry: Registers: A; Memory: $2002
00E96C 1 ; Returns/products: Registers/clobbers: A
00E96C 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E96C 1 ; Memory effects: $2000, $2001
00E96C 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E96C 1 ; comparison, load, or store path and are not a stable API product.
00E96C 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 4.
00E96C 1 ; ----------------------------------------------------------------------------
00E96C 1 DisablePpuRendering: ; $E96C
00E96C 1 A9 00 lda #$00 ; $E96C: A9 00
00E96E 1
00E96E 1 8D 00 20 sta $2000 ; $E96E: 8D 00 20
00E971 1 ; Disable NMI and reset PPUCTRL state.
00E971 1
00E971 1 8D 01 20 sta $2001 ; $E971: 8D 01 20
00E974 1 ; Disable background and sprite rendering.
00E974 1
00E974 1 AD 02 20 lda $2002 ; $E974: AD 02 20
00E977 1 ; Read PPUSTATUS and reset the address latch.
00E977 1
00E977 1 60 rts ; $E977: 60
00E978 1
00E978 1 ; ============================================================================
00E978 1 ; $E978-$E982
00E978 1 ; Reset the PPU address latch, enable NMI, and jump to the frame-wait helper.
00E978 1 ; ============================================================================
00E978 1
00E978 1 ; ----------------------------------------------------------------------------
00E978 1 ; Contract:
00E978 1 ; Description: Implements Enable Nmi And Wait For Frame.
00E978 1 ; Entry: Registers: A; Memory: $2002
00E978 1 ; Returns/products: Registers/clobbers: A
00E978 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E978 1 ; Memory effects: $2000
00E978 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E978 1 ; comparison, load, or store path and are not a stable API product.
00E978 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 2.
00E978 1 ; ----------------------------------------------------------------------------
00E978 1 EnableNmiAndWaitForFrame: ; $E978
00E978 1 AD 02 20 lda $2002 ; $E978: AD 02 20
00E97B 1 ; Reset the PPU address latch.
00E97B 1
00E97B 1 A9 80 lda #$80 ; $E97B: A9 80
00E97D 1 8D 00 20 sta $2000 ; $E97D: 8D 00 20
00E980 1 ; Enable NMI.
00E980 1
00E980 1 4C 48 EB jmp SelectObjectEventBank1 ; $E980: 4C 48 EB
00E983 1
00E983 1 ; ============================================================================
00E983 1 ; $E983-$E999
00E983 1 ; Fill $1000 bytes of PPU memory with tile/value $26.
00E983 1 ;
00E983 1 ; The helper at $E9DB consumes the two inline bytes following its JSR:
00E983 1 ;
00E983 1 ; $00,$20
00E983 1 ;
00E983 1 ; These bytes appear to specify PPU address $2000 in little-endian order.
00E983 1 ; Execution resumes at the PLA instruction at $E98B.
00E983 1 ;
00E983 1 ; Operation:
00E983 1 ; 1. Preserve fill value $26 on the stack.
00E983 1 ; 2. Set the PPU destination address to $2000.
00E983 1 ; 3. Restore fill value $26.
00E983 1 ; 4. Write $26 to PPUDATA $1000 times.
00E983 1 ;
00E983 1 ; Total writes:
00E983 1 ; $10 outer iterations * $100 inner iterations = $1000 bytes.
00E983 1 ; ============================================================================
00E983 1
00E983 1 ; ----------------------------------------------------------------------------
00E983 1 ; Contract:
00E983 1 ; Description: Implements Fill Ppu Memory With 2 6.
00E983 1 ; Entry: Registers: A, X, Y
00E983 1 ; Returns/products: Registers/clobbers: A, X, Y
00E983 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E983 1 ; Memory effects: $2007
00E983 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E983 1 ; comparison, load, or store path and are not a stable API product.
00E983 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E983 1 ; ----------------------------------------------------------------------------
00E983 1 FillPpuMemoryWith26: ; $E983
00E983 1 A9 26 lda #$26 ; $E983: A9 26
00E985 1 ; Tile or fill value.
00E985 1
00E985 1 ; ----------------------------------------------------------------------------
00E985 1 ; Contract:
00E985 1 ; Description: Internal PPU-fill entry after the fill value has been pushed.
00E985 1 ; Entry: Stack top = fill value.
00E985 1 ; Returns/products: PPU region filled; A/X/Y clobbered.
00E985 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E985 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00E985 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E985 1 ; comparison, load, or store path and are not a stable API product.
00E985 1 ; Validation: Internal-entry contract; call sites: internal entry.
00E985 1 ; ----------------------------------------------------------------------------
00E985 1 FillPpuMemoryAfterValueSaved:
00E985 1 48 pha ; $E985: 48
00E986 1 ; Preserve the fill value while the inline
00E986 1 ; PPU-address helper runs.
00E986 1
00E986 1 ; ----------------------------------------------------------------------------
00E986 1 ; Set the PPU destination address using the inline address record.
00E986 1 ;
00E986 1 ; The JSR return-address logic in $E9DB advances execution past the two inline
00E986 1 ; bytes, so execution resumes at $E98B.
00E986 1 ; ----------------------------------------------------------------------------
00E986 1
00E986 1 20 DB E9 jsr SetPpuAddressFromInlineRecord ; $E986: 20 DB E9
00E989 1
00E989 1 00 20 .byte $00,$20 ; $E989-$E98A
00E98B 1 ; Inline PPU address: $2000.
00E98B 1
00E98B 1 ; ----------------------------------------------------------------------------
00E98B 1 ; Restore the fill value.
00E98B 1 ; ----------------------------------------------------------------------------
00E98B 1
00E98B 1 68 pla ; $E98B: 68
00E98C 1 ; A = $26.
00E98C 1
00E98C 1 ; ----------------------------------------------------------------------------
00E98C 1 ; Initialize the outer and inner loop counters.
00E98C 1 ;
00E98C 1 ; X = $10 outer blocks.
00E98C 1 ; Y = $00, which produces 256 iterations because DEY wraps to $FF.
00E98C 1 ; ----------------------------------------------------------------------------
00E98C 1
00E98C 1 A2 10 ldx #$10 ; $E98C: A2 10
00E98E 1 A0 00 ldy #$00 ; $E98E: A0 00
00E990 1
00E990 1 ; ----------------------------------------------------------------------------
00E990 1 ; Write one byte to PPUDATA.
00E990 1 ;
00E990 1 ; The PPU automatically increments its internal VRAM address after the write.
00E990 1 ; ----------------------------------------------------------------------------
00E990 1
00E990 1 FillPpuMemoryWith26_Loop: ; $E990
00E990 1 8D 07 20 sta $2007 ; $E990: 8D 07 20
00E993 1
00E993 1 ; ----------------------------------------------------------------------------
00E993 1 ; Process 256 bytes in the current outer block.
00E993 1 ;
00E993 1 ; Starting from Y=$00:
00E993 1 ;
00E993 1 ; first DEY -> $FF
00E993 1 ; ...
00E993 1 ; final DEY -> $00
00E993 1 ; ----------------------------------------------------------------------------
00E993 1
00E993 1 88 dey ; $E993: 88
00E994 1 D0 FA bne FillPpuMemoryWith26_Loop
00E996 1 ; $E994: D0 FA
00E996 1
00E996 1 ; ----------------------------------------------------------------------------
00E996 1 ; Process sixteen 256-byte blocks.
00E996 1 ;
00E996 1 ; The branch returns directly to the PPUDATA write at $E990. Y is already zero
00E996 1 ; after each completed inner iteration, so the next block again runs 256 times.
00E996 1 ; ----------------------------------------------------------------------------
00E996 1
00E996 1 CA dex ; $E996: CA
00E997 1 D0 F7 bne FillPpuMemoryWith26_Loop
00E999 1 ; $E997: D0 F7
00E999 1
00E999 1 60 rts ; $E999: 60
00E99A 1
00E99A 1 ; ============================================================================
00E99A 1 ; $E99A-$E9B3
00E99A 1 ; Decode inline parameters following a caller's JSR instruction.
00E99A 1 ;
00E99A 1 ; This routine manipulates two return addresses:
00E99A 1 ;
00E99A 1 ; 1. The return address from JSR $E99A.
00E99A 1 ; 2. The return address belonging to the helper that called $E99A.
00E99A 1 ;
00E99A 1 ; It reads two inline parameter bytes through ReadInlineWord, advances the
00E99A 1 ; outer return address past the inline record, and jumps to that continuation.
00E99A 1 ;
00E99A 1 ; ReadInlineWord restores the immediate caller's return address to the stack,
00E99A 1 ; allowing that helper to return normally after processing the parameters.
00E99A 1 ; ============================================================================
00E99A 1
00E99A 1 ; ----------------------------------------------------------------------------
00E99A 1 ; Contract:
00E99A 1 ; Description: Implements Decode Inline Parameters.
00E99A 1 ; Entry: Registers: A, Y; Memory: $00
00E99A 1 ; Returns/products: Registers/clobbers: A, X, Y
00E99A 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E99A 1 ; Memory effects: $00, $01
00E99A 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E99A 1 ; comparison, load, or store path and are not a stable API product.
00E99A 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 10.
00E99A 1 ; ----------------------------------------------------------------------------
00E99A 1 DecodeInlineParameters: ; $E99A
00E99A 1 68 pla ; $E99A: 68
00E99B 1 AA tax ; $E99B: AA
00E99C 1 ; X = low byte of the immediate return address.
00E99C 1
00E99C 1 68 pla ; $E99C: 68
00E99D 1 A8 tay ; $E99D: A8
00E99E 1 ; Y = high byte of the immediate return address.
00E99E 1
00E99E 1 ; ----------------------------------------------------------------------------
00E99E 1 ; Remove the outer caller's return address and store it as a pointer.
00E99E 1 ; ----------------------------------------------------------------------------
00E99E 1
00E99E 1 68 pla ; $E99E: 68
00E99F 1 85 00 sta $00 ; $E99F: 85 00
00E9A1 1
00E9A1 1 68 pla ; $E9A1: 68
00E9A2 1 85 01 sta $01 ; $E9A2: 85 01
00E9A4 1
00E9A4 1 ; ----------------------------------------------------------------------------
00E9A4 1 ; Restore the immediate return address and read two bytes following the outer
00E9A4 1 ; caller's JSR.
00E9A4 1 ;
00E9A4 1 ; Exit from ReadInlineWord:
00E9A4 1 ; X = first inline byte
00E9A4 1 ; A = second inline byte
00E9A4 1 ; Y = $03
00E9A4 1 ; ----------------------------------------------------------------------------
00E9A4 1
00E9A4 1 20 B4 E9 jsr ReadInlineWord ; $E9A4: 20 B4 E9
00E9A7 1
00E9A7 1 ; ----------------------------------------------------------------------------
00E9A7 1 ; Advance the outer return pointer by three:
00E9A7 1 ;
00E9A7 1 ; one byte for the JSR return-address convention
00E9A7 1 ; two bytes for the inline parameter record
00E9A7 1 ; ----------------------------------------------------------------------------
00E9A7 1
00E9A7 1 18 clc ; $E9A7: 18
00E9A8 1
00E9A8 1 98 tya ; $E9A8: 98
00E9A9 1 65 00 adc $00 ; $E9A9: 65 00
00E9AB 1 85 00 sta $00 ; $E9AB: 85 00
00E9AD 1
00E9AD 1 90 02 bcc DecodeInlineParameters_Jump
00E9AF 1 ; $E9AD: 90 02
00E9AF 1
00E9AF 1 E6 01 inc $01 ; $E9AF: E6 01
00E9B1 1
00E9B1 1 ; ----------------------------------------------------------------------------
00E9B1 1 ; Continue execution immediately after the inline record.
00E9B1 1 ; ----------------------------------------------------------------------------
00E9B1 1
00E9B1 1 DecodeInlineParameters_Jump: ; $E9B1
00E9B1 1 6C 00 00 jmp ($0000) ; $E9B1: 6C 00 00
00E9B4 1
00E9B4 1 ; ============================================================================
00E9B4 1 ; $E9B4-$E9C1
00E9B4 1 ; Restore an immediate caller return address and read a two-byte inline word.
00E9B4 1 ;
00E9B4 1 ; Entry:
00E9B4 1 ; X/Y = low/high bytes of the immediate caller's return address
00E9B4 1 ; $00/$01 = pointer to the outer caller's return address
00E9B4 1 ;
00E9B4 1 ; Exit:
00E9B4 1 ; X = first byte following the outer caller's JSR
00E9B4 1 ; A = second byte following the outer caller's JSR
00E9B4 1 ; Y = $03
00E9B4 1 ;
00E9B4 1 ; The initial TYA/PHA and TXA/PHA restore the immediate return address to the
00E9B4 1 ; stack in the order required by RTS.
00E9B4 1 ; ============================================================================
00E9B4 1
00E9B4 1 ; ----------------------------------------------------------------------------
00E9B4 1 ; Contract:
00E9B4 1 ; Description: Implements Read Inline Word.
00E9B4 1 ; Entry: Registers: A, X, Y; Memory: ($00)
00E9B4 1 ; Returns/products: Registers/clobbers: A, X, Y
00E9B4 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E9B4 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00E9B4 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E9B4 1 ; comparison, load, or store path and are not a stable API product.
00E9B4 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E9B4 1 ; ----------------------------------------------------------------------------
00E9B4 1 ReadInlineWord: ; $E9B4
00E9B4 1 98 tya ; $E9B4: 98
00E9B5 1 48 pha ; $E9B5: 48
00E9B6 1 ; Restore return-address high byte.
00E9B6 1
00E9B6 1 8A txa ; $E9B6: 8A
00E9B7 1 48 pha ; $E9B7: 48
00E9B8 1 ; Restore return-address low byte.
00E9B8 1
00E9B8 1 A0 01 ldy #$01 ; $E9B8: A0 01
00E9BA 1
00E9BA 1 B1 00 lda ($00),y ; $E9BA: B1 00
00E9BC 1 AA tax ; $E9BC: AA
00E9BD 1 ; X = first inline parameter.
00E9BD 1
00E9BD 1 C8 iny ; $E9BD: C8
00E9BE 1
00E9BE 1 B1 00 lda ($00),y ; $E9BE: B1 00
00E9C0 1 ; A = second inline parameter.
00E9C0 1
00E9C0 1 C8 iny ; $E9C0: C8
00E9C1 1 ; Y = $03.
00E9C1 1
00E9C1 1 60 rts ; $E9C1: 60
00E9C2 1
00E9C2 1 ; ============================================================================
00E9C2 1 ; $E9C2-$E9D1
00E9C2 1 ; Copy a counted inline byte sequence into zero page.
00E9C2 1 ;
00E9C2 1 ; Inline record:
00E9C2 1 ; byte 0 = destination zero-page address
00E9C2 1 ; byte 1 = byte count
00E9C2 1 ; remaining bytes = data to copy
00E9C2 1 ;
00E9C2 1 ; DecodeInlineParameters returns:
00E9C2 1 ; X = destination zero-page address
00E9C2 1 ; A = byte count
00E9C2 1 ; Y = index of the first data byte
00E9C2 1 ;
00E9C2 1 ; Exit:
00E9C2 1 ; X points immediately after the destination range.
00E9C2 1 ; ============================================================================
00E9C2 1
00E9C2 1 CopyInlineBytesToZeroPage: ; $E9C2
00E9C2 1 20 9A E9 jsr DecodeInlineParameters ; $E9C2: 20 9A E9
00E9C5 1
00E9C5 1 85 04 sta $04 ; $E9C5: 85 04
00E9C7 1 ; Save byte count.
00E9C7 1
00E9C7 1 CopyInlineBytesToZeroPage_Loop: ; $E9C7
00E9C7 1 B1 00 lda ($00),y ; $E9C7: B1 00
00E9C9 1 95 00 sta $00,x ; $E9C9: 95 00
00E9CB 1
00E9CB 1 C8 iny ; $E9CB: C8
00E9CC 1 E8 inx ; $E9CC: E8
00E9CD 1
00E9CD 1 C6 04 dec $04 ; $E9CD: C6 04
00E9CF 1 D0 F6 bne CopyInlineBytesToZeroPage_Loop
00E9D1 1 ; $E9CF: D0 F6
00E9D1 1
00E9D1 1 60 rts ; $E9D1: 60
00E9D2 1
00E9D2 1 ; ============================================================================
00E9D2 1 ; $E9D2-$E9DA
00E9D2 1 ; Set PPUCTRL according to the incoming carry flag.
00E9D2 1 ;
00E9D2 1 ; Entry:
00E9D2 1 ; C = clear -> write $00 to PPUCTRL
00E9D2 1 ; C = set -> write $04 to PPUCTRL
00E9D2 1 ;
00E9D2 1 ; LDA #$00 preserves carry. Three ROL instructions move the incoming carry
00E9D2 1 ; into bit two of A.
00E9D2 1 ; ============================================================================
00E9D2 1
00E9D2 1 WritePpuControlFromCarry: ; $E9D2
00E9D2 1 A9 00 lda #$00 ; $E9D2: A9 00
00E9D4 1
00E9D4 1 2A rol ; $E9D4: 2A
00E9D5 1 2A rol ; $E9D5: 2A
00E9D6 1 2A rol ; $E9D6: 2A
00E9D7 1
00E9D7 1 8D 00 20 sta $2000 ; $E9D7: 8D 00 20
00E9DA 1
00E9DA 1 60 rts ; $E9DA: 60
00E9DB 1
00E9DB 1 ; ============================================================================
00E9DB 1 ; $E9DB-$E9FB
00E9DB 1 ; Decode an inline PPU address, update the address shadow in $23/$24, and write
00E9DB 1 ; the resulting address to PPUADDR.
00E9DB 1 ;
00E9DB 1 ; Inline record:
00E9DB 1 ; byte 0 = low address byte or signed relative offset
00E9DB 1 ; byte 1 = high address byte
00E9DB 1 ;
00E9DB 1 ; Modes:
00E9DB 1 ;
00E9DB 1 ; High byte nonzero:
00E9DB 1 ; Use the decoded X:A pair as an absolute PPU address.
00E9DB 1 ;
00E9DB 1 ; High byte zero:
00E9DB 1 ; Treat the decoded low byte in X as a signed offset and add it to the
00E9DB 1 ; current shadow PPU address in $23/$24.
00E9DB 1 ;
00E9DB 1 ; Exit:
00E9DB 1 ; $23/$24 = selected PPU address
00E9DB 1 ; PPUADDR = selected PPU address
00E9DB 1 ; X restored from $05
00E9DB 1 ; ============================================================================
00E9DB 1
00E9DB 1 ; ----------------------------------------------------------------------------
00E9DB 1 ; Contract:
00E9DB 1 ; Description: Implements Set Ppu Address From Inline Record.
00E9DB 1 ; Entry: Registers: A, X, Y; Memory: $23, $24, mathtemp05
00E9DB 1 ; Returns/products: Registers/clobbers: A, X, Y
00E9DB 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00E9DB 1 ; Memory effects: $05, $24, ppuaddr, $23
00E9DB 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00E9DB 1 ; comparison, load, or store path and are not a stable API product.
00E9DB 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00E9DB 1 ; ----------------------------------------------------------------------------
00E9DB 1 SetPpuAddressFromInlineRecord: ; $E9DB
00E9DB 1 20 9A E9 jsr DecodeInlineParameters ; $E9DB: 20 9A E9
00E9DE 1 ; X = first inline byte
00E9DE 1 ; A = second inline byte
00E9DE 1
00E9DE 1 ; ----------------------------------------------------------------------------
00E9DE 1 ; A nonzero high byte selects the absolute-address path.
00E9DE 1 ;
00E9DE 1 ; The decoded values remain:
00E9DE 1 ; A = address high byte
00E9DE 1 ; X = address low byte
00E9DE 1 ; ----------------------------------------------------------------------------
00E9DE 1
00E9DE 1 D0 0F bne SetPpuAddress_Write ; $E9DE: D0 0F
00E9E0 1
00E9E0 1 ; ----------------------------------------------------------------------------
00E9E0 1 ; A is zero, so interpret X as a signed relative offset.
00E9E0 1 ;
00E9E0 1 ; Preserve the decoded low byte in $05 because X is used during the signed
00E9E0 1 ; addition.
00E9E0 1 ; ----------------------------------------------------------------------------
00E9E0 1 SetRelativePpuAddressFromInlineRecord:
00E9E0 1 86 05 stx $05 ; $E9E0: 86 05
00E9E2 1
00E9E2 1 A0 00 ldy #$00 ; $E9E2: A0 00
00E9E4 1 ; Default sign-extension byte.
00E9E4 1
00E9E4 1 AA tax ; $E9E4: AA
00E9E5 1 ; A is zero, so X becomes zero.
00E9E5 1
00E9E5 1 ; ----------------------------------------------------------------------------
00E9E5 1 ; Test the sign of the decoded relative offset.
00E9E5 1 ;
00E9E5 1 ; DecodeInlineParameters left the low parameter in X before TAX. The flags used
00E9E5 1 ; by BPL are preserved from TAX, which loaded zero here. Preserve the original
00E9E5 1 ; instruction sequence byte-for-byte because callers may depend on the helper's
00E9E5 1 ; exact inline-data convention.
00E9E5 1 ; ----------------------------------------------------------------------------
00E9E5 1
00E9E5 1 10 01 bpl SetPpuAddress_AddOffset ; $E9E5: 10 01
00E9E7 1
00E9E7 1 88 dey ; $E9E7: 88
00E9E8 1 ; Sign extension $FF for a negative offset.
00E9E8 1
00E9E8 1 ; ----------------------------------------------------------------------------
00E9E8 1 ; Add the signed offset to the current PPU address shadow.
00E9E8 1 ; ----------------------------------------------------------------------------
00E9E8 1
00E9E8 1 SetPpuAddress_AddOffset: ; $E9E8
00E9E8 1 18 clc ; $E9E8: 18
00E9E9 1
00E9E9 1 65 23 adc $23 ; $E9E9: 65 23
00E9EB 1 AA tax ; $E9EB: AA
00E9EC 1 ; X = resulting low address byte.
00E9EC 1
00E9EC 1 98 tya ; $E9EC: 98
00E9ED 1 65 24 adc $24 ; $E9ED: 65 24
00E9EF 1 ; A = resulting high address byte.
00E9EF 1
00E9EF 1 ; ----------------------------------------------------------------------------
00E9EF 1 ; Store and write the high address byte first.
00E9EF 1 ; ----------------------------------------------------------------------------
00E9EF 1
00E9EF 1 SetPpuAddress_Write: ; $E9EF
00E9EF 1 85 24 sta $24 ; $E9EF: 85 24
00E9F1 1 8D 06 20 sta PPUADDR ; $E9F1: 8D 06 20
00E9F4 1
00E9F4 1 ; ----------------------------------------------------------------------------
00E9F4 1 ; Store and write the low address byte.
00E9F4 1 ; ----------------------------------------------------------------------------
00E9F4 1
00E9F4 1 86 23 stx $23 ; $E9F4: 86 23
00E9F6 1 8E 06 20 stx PPUADDR ; $E9F6: 8E 06 20
00E9F9 1
00E9F9 1 ; ----------------------------------------------------------------------------
00E9F9 1 ; Restore X from the scratch value at $05.
00E9F9 1 ; ----------------------------------------------------------------------------
00E9F9 1
00E9F9 1 A6 05 ldx MathTemp05 ; $E9F9: A6 05
00E9FB 1
00E9FB 1 60 rts ; $E9FB: 60
00E9FC 1
00E9FC 1 ; ============================================================================
00E9FC 1 ; $E9FC-$EA01
00E9FC 1 ; Write the pending PPU data byte from $25 to PPUDATA.
00E9FC 1 ;
00E9FC 1 ; Entry:
00E9FC 1 ; $25 = byte to write
00E9FC 1 ;
00E9FC 1 ; Exit:
00E9FC 1 ; A = value written
00E9FC 1 ; ============================================================================
00E9FC 1
00E9FC 1 WritePendingPpuByte: ; $E9FC
00E9FC 1 A5 25 lda $25 ; $E9FC: A5 25
00E9FE 1 8D 07 20 sta PPUDATA ; $E9FE: 8D 07 20
00EA01 1 60 rts ; $EA01: 60
00EA02 1
00EA02 1 ; ============================================================================
00EA02 1 ; $EA02-$EA16
00EA02 1 ; Set a PPU address from inline data, then write a counted inline byte sequence
00EA02 1 ; to PPUDATA.
00EA02 1 ;
00EA02 1 ; Inline record structure:
00EA02 1 ;
00EA02 1 ; bytes 0-1:
00EA02 1 ; PPU address record consumed by SetPpuAddressFromInlineRecord
00EA02 1 ;
00EA02 1 ; byte 2:
00EA02 1 ; transfer count returned in X by DecodeInlineParameters
00EA02 1 ;
00EA02 1 ; byte 3 onward:
00EA02 1 ; data bytes written to PPUDATA
00EA02 1 ;
00EA02 1 ; Entry:
00EA02 1 ; X may contain caller state that must be restored before return.
00EA02 1 ;
00EA02 1 ; Exit:
00EA02 1 ; X restored from $05
00EA02 1 ; Y points back to the final byte consumed from the inline record
00EA02 1 ; ============================================================================
00EA02 1
00EA02 1 WriteInlinePpuBlock: ; $EA02
00EA02 1 20 E0 E9 jsr SetRelativePpuAddressFromInlineRecord
00EA05 1 ; $EA02: 20 E0 E9
00EA05 1
00EA05 1 ; ----------------------------------------------------------------------------
00EA05 1 ; Preserve X while the inline record is decoded.
00EA05 1 ; ----------------------------------------------------------------------------
00EA05 1
00EA05 1 ; ----------------------------------------------------------------------------
00EA05 1 ; Contract:
00EA05 1 ; Description: Internal PPU block writer after PPUADDR has already been set.
00EA05 1 ; Entry: X = caller state; inline transfer record follows caller.
00EA05 1 ; Returns/products: PPUDATA written; X restored from scratch state.
00EA05 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00EA05 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00EA05 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00EA05 1 ; comparison, load, or store path and are not a stable API product.
00EA05 1 ; Validation: Internal-entry contract; call sites: internal entry.
00EA05 1 ; ----------------------------------------------------------------------------
00EA05 1 WriteInlinePpuBlockAfterAddress:
00EA05 1 86 05 stx MathTemp05 ; $EA05: 86 05
00EA07 1
00EA07 1 ; ----------------------------------------------------------------------------
00EA07 1 ; Decode the following inline parameter record.
00EA07 1 ;
00EA07 1 ; DecodeInlineParameters returns:
00EA07 1 ; X = transfer count
00EA07 1 ; A = first data byte
00EA07 1 ; Y = index into the remaining inline data
00EA07 1 ; ----------------------------------------------------------------------------
00EA07 1
00EA07 1 20 9A E9 jsr DecodeInlineParameters ; $EA07: 20 9A E9
00EA0A 1
00EA0A 1 ; ----------------------------------------------------------------------------
00EA0A 1 ; Write the first data byte returned directly in A.
00EA0A 1 ; ----------------------------------------------------------------------------
00EA0A 1
00EA0A 1 WriteInlinePpuBlock_Loop: ; $EA0A
00EA0A 1 8D 07 20 sta PPUDATA ; $EA0A: 8D 07 20
00EA0D 1
00EA0D 1 ; ----------------------------------------------------------------------------
00EA0D 1 ; Load the next inline byte, advance the source index, and count down the
00EA0D 1 ; number of bytes remaining.
00EA0D 1 ;
00EA0D 1 ; On the final iteration, the loaded byte is not written because X reaches
00EA0D 1 ; zero immediately after the load. DEY then restores Y to the last byte that
00EA0D 1 ; was actually consumed.
00EA0D 1 ; ----------------------------------------------------------------------------
00EA0D 1
00EA0D 1 B1 00 lda ($00),y ; $EA0D: B1 00
00EA0F 1 C8 iny ; $EA0F: C8
00EA10 1
00EA10 1 CA dex ; $EA10: CA
00EA11 1 D0 F7 bne WriteInlinePpuBlock_Loop
00EA13 1 ; $EA11: D0 F7
00EA13 1
00EA13 1 ; ----------------------------------------------------------------------------
00EA13 1 ; Restore Y and X to the state expected by the inline dispatcher.
00EA13 1 ; ----------------------------------------------------------------------------
00EA13 1
00EA13 1 88 dey ; $EA13: 88
00EA14 1
00EA14 1 A6 05 ldx MathTemp05 ; $EA14: A6 05
00EA16 1
00EA16 1 60 rts ; $EA16: 60
00EA17 1
00EA17 1 ; ============================================================================
00EA17 1 ; $EA17-$EA3D
00EA17 1 ; Copy a counted inline record into the display buffer at $0300,X.
00EA17 1 ;
00EA17 1 ; The routine first calls $EA3E to reserve or initialize a display-buffer
00EA17 1 ; record. It then removes its caller's return address from the stack and uses
00EA17 1 ; that address as a pointer to inline data.
00EA17 1 ;
00EA17 1 ; Inline record:
00EA17 1 ; byte 0 = number of data bytes
00EA17 1 ; byte 1...N = bytes copied into $0300,X
00EA17 1 ;
00EA17 1 ; After copying the record, the routine rebuilds the return address so RTS
00EA17 1 ; resumes execution immediately after the inline data.
00EA17 1 ;
00EA17 1 ; Entry:
00EA17 1 ; A, X, Y and carry contain parameters consumed by $EA3E.
00EA17 1 ;
00EA17 1 ; Exit:
00EA17 1 ; X points immediately after the copied display-buffer bytes.
00EA17 1 ; ============================================================================
00EA17 1 PPUWriteString:
00EA17 1 ; ----------------------------------------------------------------------------
00EA17 1 ; Contract:
00EA17 1 ; Description: Copies Inline Display Record.
00EA17 1 ; Entry: Registers: A, X, Y; Memory: ($26), $26, $04, $27
00EA17 1 ; Returns/products: Registers/clobbers: A, X, Y
00EA17 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00EA17 1 ; Memory effects: $26, $27, $04, $0300
00EA17 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00EA17 1 ; comparison, load, or store path and are not a stable API product.
00EA17 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 12.
00EA17 1 ; ----------------------------------------------------------------------------
00EA17 1 CopyInlineDisplayRecord: ; $EA17
00EA17 1 20 3E EA jsr AllocateDisplayBufferRecord ; $EA17: 20 3E EA
00EA1A 1 ; Reserve or initialize the destination record.
00EA1A 1 ; Returns the destination offset in X.
00EA1A 1
00EA1A 1 ; ----------------------------------------------------------------------------
00EA1A 1 ; Remove the caller's return address from the stack.
00EA1A 1 ;
00EA1A 1 ; JSR stores the address of the final JSR operand byte. Therefore, inline byte
00EA1A 1 ; zero is found at offset one from the saved address.
00EA1A 1 ; ----------------------------------------------------------------------------
00EA1A 1
00EA1A 1 68 pla ; $EA1A: 68
00EA1B 1 85 26 sta $26 ; $EA1B: 85 26
00EA1D 1 ; Saved return-address low byte.
00EA1D 1
00EA1D 1 68 pla ; $EA1D: 68
00EA1E 1 85 27 sta $27 ; $EA1E: 85 27
00EA20 1 ; Saved return-address high byte.
00EA20 1
00EA20 1 ; ----------------------------------------------------------------------------
00EA20 1 ; Read the inline byte count.
00EA20 1 ; ----------------------------------------------------------------------------
00EA20 1
00EA20 1 A0 01 ldy #$01 ; $EA20: A0 01
00EA22 1
00EA22 1 B1 26 lda ($26),y ; $EA22: B1 26
00EA24 1 85 04 sta $04 ; $EA24: 85 04
00EA26 1 ; Number of data bytes to copy.
00EA26 1
00EA26 1 ; ----------------------------------------------------------------------------
00EA26 1 ; Copy the inline data into the display buffer at $0300,X.
00EA26 1 ; ----------------------------------------------------------------------------
00EA26 1
00EA26 1 CopyInlineDisplayRecord_Loop: ; $EA26
00EA26 1 C8 iny ; $EA26: C8
00EA27 1 ; Advance to the next inline data byte.
00EA27 1
00EA27 1 B1 26 lda ($26),y ; $EA27: B1 26
00EA29 1 9D 00 03 sta $0300,x ; $EA29: 9D 00 03
00EA2C 1
00EA2C 1 E8 inx ; $EA2C: E8
00EA2D 1 ; Advance the destination offset.
00EA2D 1
00EA2D 1 C6 04 dec $04 ; $EA2D: C6 04
00EA2F 1 D0 F5 bne CopyInlineDisplayRecord_Loop
00EA31 1 ; $EA2F: D0 F5
00EA31 1
00EA31 1 ; ----------------------------------------------------------------------------
00EA31 1 ; Advance the saved return address past the complete inline record.
00EA31 1 ;
00EA31 1 ; Y now equals:
00EA31 1 ;
00EA31 1 ; byte count + 1
00EA31 1 ;
00EA31 1 ; Adding Y to the original return address produces the address of the final
00EA31 1 ; inline byte. RTS will increment that address and resume at the instruction
00EA31 1 ; immediately following the inline record.
00EA31 1 ; ----------------------------------------------------------------------------
00EA31 1
00EA31 1 18 clc ; $EA31: 18
00EA32 1
00EA32 1 98 tya ; $EA32: 98
00EA33 1 65 26 adc $26 ; $EA33: 65 26
00EA35 1 A8 tay ; $EA35: A8
00EA36 1 ; Y = adjusted return-address low byte.
00EA36 1
00EA36 1 ; ----------------------------------------------------------------------------
00EA36 1 ; $04 is zero after the copy loop. ADC therefore propagates only carry into
00EA36 1 ; the saved return-address high byte.
00EA36 1 ; ----------------------------------------------------------------------------
00EA36 1
00EA36 1 A5 04 lda $04 ; $EA36: A5 04
00EA38 1 ; A = $00.
00EA38 1
00EA38 1 65 27 adc $27 ; $EA38: 65 27
00EA3A 1 ; A = adjusted return-address high byte.
00EA3A 1
00EA3A 1 ; ----------------------------------------------------------------------------
00EA3A 1 ; Rebuild the adjusted return address on the stack.
00EA3A 1 ;
00EA3A 1 ; RTS pulls low byte first, then high byte, so the high byte is pushed first.
00EA3A 1 ; ----------------------------------------------------------------------------
00EA3A 1
00EA3A 1 48 pha ; $EA3A: 48
00EA3B 1 ; Push adjusted high byte.
00EA3B 1
00EA3B 1 98 tya ; $EA3B: 98
00EA3C 1 48 pha ; $EA3C: 48
00EA3D 1 ; Push adjusted low byte.
00EA3D 1
00EA3D 1 60 rts ; $EA3D: 60
00EA3E 1 ; Resume after the inline record.
00EA3E 1
00EA3E 1 ; ============================================================================
00EA3E 1 ; $EA3E-$EA62
00EA3E 1 ; Allocate and initialize a variable-length record in the display buffer.
00EA3E 1 ;
00EA3E 1 ; Entry:
00EA3E 1 ; A = record parameter stored at offset +1
00EA3E 1 ; X = record parameter stored at offset +2
00EA3E 1 ; Y = payload length
00EA3E 1 ; C = Boolean flag encoded at offset +3
00EA3E 1 ; $3E = current display-buffer write offset
00EA3E 1 ;
00EA3E 1 ; Record layout:
00EA3E 1 ;
00EA3E 1 ; +0 = payload length
00EA3E 1 ; +1 = incoming A
00EA3E 1 ; +2 = incoming X
00EA3E 1 ; +3 = incoming carry encoded as $00 or $04
00EA3E 1 ; +4 = beginning of payload
00EA3E 1 ;
00EA3E 1 ; Exit:
00EA3E 1 ; X = payload destination offset
00EA3E 1 ; $3E = next free record offset
00EA3E 1 ; ============================================================================
00EA3E 1
00EA3E 1 ; ----------------------------------------------------------------------------
00EA3E 1 ; Contract:
00EA3E 1 ; Description: Implements Allocate Display Buffer Record.
00EA3E 1 ; Entry: Registers: A, X, Y; Memory: $3e, $06, $05
00EA3E 1 ; Returns/products: Registers/clobbers: A, X, Y
00EA3E 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00EA3E 1 ; Memory effects: $05, $06, $0301, $0302, $0303, $0300, $3e
00EA3E 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00EA3E 1 ; comparison, load, or store path and are not a stable API product.
00EA3E 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 11.
00EA3E 1 ; ----------------------------------------------------------------------------
00EA3E 1 AllocateDisplayBufferRecord: ; $EA3E
00EA3E 1 84 05 sty $05 ; $EA3E: 84 05
00EA40 1 ; Save payload length.
00EA40 1
00EA40 1 A0 00 ldy #$00 ; $EA40: A0 00
00EA42 1 84 06 sty $06 ; $EA42: 84 06
00EA44 1 ; Clear flag accumulator without changing C.
00EA44 1
00EA44 1 A4 3E ldy PpuQueueOffset ; $EA44: A4 3E
00EA46 1 ; Y = current record offset.
00EA46 1
00EA46 1 ; ----------------------------------------------------------------------------
00EA46 1 ; Store the caller parameters.
00EA46 1 ; ----------------------------------------------------------------------------
00EA46 1
00EA46 1 99 01 03 sta $0301,y ; $EA46: 99 01 03
00EA49 1 ; Record byte +1 = incoming A.
00EA49 1
00EA49 1 8A txa ; $EA49: 8A
00EA4A 1 99 02 03 sta $0302,y ; $EA4A: 99 02 03
00EA4D 1 ; Record byte +2 = incoming X.
00EA4D 1
00EA4D 1 ; ----------------------------------------------------------------------------
00EA4D 1 ; Encode incoming carry as bit two:
00EA4D 1 ;
00EA4D 1 ; C clear -> $00
00EA4D 1 ; C set -> $04
00EA4D 1 ;
00EA4D 1 ; LDA preserves carry. Starting from zero, three ROL instructions move the
00EA4D 1 ; incoming carry into bit two.
00EA4D 1 ; ----------------------------------------------------------------------------
00EA4D 1
00EA4D 1 A5 06 lda $06 ; $EA4D: A5 06
00EA4F 1 2A rol ; $EA4F: 2A
00EA50 1 2A rol ; $EA50: 2A
00EA51 1 2A rol ; $EA51: 2A
00EA52 1
00EA52 1 99 03 03 sta $0303,y ; $EA52: 99 03 03
00EA55 1 ; Record byte +3 = encoded flag.
00EA55 1
00EA55 1 ; ----------------------------------------------------------------------------
00EA55 1 ; Store the payload length as record byte zero.
00EA55 1 ; ----------------------------------------------------------------------------
00EA55 1
00EA55 1 A5 05 lda $05 ; $EA55: A5 05
00EA57 1 99 00 03 sta $0300,y ; $EA57: 99 00 03
00EA5A 1
00EA5A 1 ; ----------------------------------------------------------------------------
00EA5A 1 ; Calculate the payload destination:
00EA5A 1 ;
00EA5A 1 ; X = record offset + 4
00EA5A 1 ; ----------------------------------------------------------------------------
00EA5A 1
00EA5A 1 98 tya ; $EA5A: 98
00EA5B 1 69 04 adc #$04 ; $EA5B: 69 04
00EA5D 1 AA tax ; $EA5D: AA
00EA5E 1 ; X points to the payload area.
00EA5E 1 ;
00EA5E 1 ; Carry is normally clear after the third ROL:
00EA5E 1 ; the original carry has moved into bit two.
00EA5E 1
00EA5E 1 ; ----------------------------------------------------------------------------
00EA5E 1 ; Calculate the next free record offset:
00EA5E 1 ;
00EA5E 1 ; $3E = payload offset + payload length
00EA5E 1 ; ----------------------------------------------------------------------------
00EA5E 1
00EA5E 1 65 05 adc $05 ; $EA5E: 65 05
00EA60 1 85 3E sta PpuQueueOffset ; $EA60: 85 3E
00EA62 1
00EA62 1 60 rts ; $EA62: 60
00EA63 1
00EA63 1 ; ============================================================================
00EA63 1 ; $EA63-$EAAE
00EA63 1 ; Decode and render an inline stream of PPU transfer records.
00EA63 1 ;
00EA63 1 ; The routine obtains an inline pointer through DecodeInlineParameters and
00EA63 1 ; processes records until a zero terminator is encountered.
00EA63 1 ;
00EA63 1 ; Initial decoded values:
00EA63 1 ; X = stream pointer low byte
00EA63 1 ; A = stream pointer high byte
00EA63 1 ;
00EA63 1 ; Stream record format:
00EA63 1 ;
00EA63 1 ; byte 0:
00EA63 1 ; PPU address high byte
00EA63 1 ;
00EA63 1 ; byte 1:
00EA63 1 ; PPU address low byte
00EA63 1 ;
00EA63 1 ; byte 2:
00EA63 1 ; control byte
00EA63 1 ;
00EA63 1 ; remaining bytes:
00EA63 1 ; one literal byte or one repeated byte, according to the control byte
00EA63 1 ;
00EA63 1 ; A zero byte at the start of the next record terminates the stream.
00EA63 1 ; ============================================================================
00EA63 1
00EA63 1 ; ----------------------------------------------------------------------------
00EA63 1 ; Contract:
00EA63 1 ; Description: Processes Inline Ppu Stream.
00EA63 1 ; Entry: Registers: A, X, Y; Memory: ($08), $08, $09, $2002
00EA63 1 ; Returns/products: Registers/clobbers: A, X, Y
00EA63 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00EA63 1 ; Memory effects: $09, $08, $2006, $2000, $2007
00EA63 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00EA63 1 ; comparison, load, or store path and are not a stable API product.
00EA63 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 3.
00EA63 1 ; ----------------------------------------------------------------------------
00EA63 1 ProcessInlinePpuStream: ; $EA63
00EA63 1 20 9A E9 jsr DecodeInlineParameters ; $EA63: 20 9A E9
00EA66 1 ; X = stream-pointer low byte
00EA66 1 ; A = stream-pointer high byte
00EA66 1
00EA66 1 85 09 sta $09 ; $EA66: 85 09
00EA68 1 ; Save stream-pointer high byte.
00EA68 1
00EA68 1 86 08 stx $08 ; $EA68: 86 08
00EA6A 1 ; Save stream-pointer low byte.
00EA6A 1
00EA6A 1 ; ----------------------------------------------------------------------------
00EA6A 1 ; A nonzero high byte skips directly to the initial terminator check.
00EA6A 1 ;
00EA6A 1 ; A zero high byte falls through and processes the first record using A as the
00EA6A 1 ; first PPU address byte. This dual entry behavior is intentional.
00EA6A 1 ; ----------------------------------------------------------------------------
00EA6A 1
00EA6A 1 D0 37 bne ProcessInlinePpuStream_CheckRecord
00EA6C 1 ; $EA6A: D0 37
00EA6C 1
00EA6C 1 ; ============================================================================
00EA6C 1 ; $EA6C
00EA6C 1 ; Process one PPU transfer record.
00EA6C 1 ; ============================================================================
00EA6C 1
00EA6C 1 ProcessInlinePpuStream_Record: ; $EA6C
00EA6C 1 8D 06 20 sta $2006 ; $EA6C: 8D 06 20
00EA6F 1 ; Write PPU address high byte.
00EA6F 1
00EA6F 1 C8 iny ; $EA6F: C8
00EA70 1
00EA70 1 B1 08 lda ($08),y ; $EA70: B1 08
00EA72 1 8D 06 20 sta $2006 ; $EA72: 8D 06 20
00EA75 1 ; Write PPU address low byte.
00EA75 1
00EA75 1 ; ----------------------------------------------------------------------------
00EA75 1 ; Read and preserve the record control byte.
00EA75 1 ; ----------------------------------------------------------------------------
00EA75 1
00EA75 1 C8 iny ; $EA75: C8
00EA76 1
00EA76 1 B1 08 lda ($08),y ; $EA76: B1 08
00EA78 1 0A asl ; $EA78: 0A
00EA79 1 48 pha ; $EA79: 48
00EA7A 1 ; Preserve shifted control byte.
00EA7A 1
00EA7A 1 ; ----------------------------------------------------------------------------
00EA7A 1 ; Derive PPUCTRL bit two from the original control-byte high bit.
00EA7A 1 ;
00EA7A 1 ; After ASL, the original bit seven is in carry. Beginning with zero, three
00EA7A 1 ; ROL instructions move that carry into bit two.
00EA7A 1 ; ----------------------------------------------------------------------------
00EA7A 1
00EA7A 1 A9 00 lda #$00 ; $EA7A: A9 00
00EA7C 1 2A rol ; $EA7C: 2A
00EA7D 1 2A rol ; $EA7D: 2A
00EA7E 1 2A rol ; $EA7E: 2A
00EA7F 1
00EA7F 1 8D 00 20 sta $2000 ; $EA7F: 8D 00 20
00EA82 1 ; Select PPU address increment mode.
00EA82 1
00EA82 1 ; ----------------------------------------------------------------------------
00EA82 1 ; Restore and further decode the shifted control byte.
00EA82 1 ; ----------------------------------------------------------------------------
00EA82 1
00EA82 1 68 pla ; $EA82: 68
00EA83 1 0A asl ; $EA83: 0A
00EA84 1 ; Carry receives the next control flag.
00EA84 1
00EA84 1 90 03 bcc ProcessInlinePpuStream_DecodeCount
00EA86 1 ; $EA84: 90 03
00EA86 1
00EA86 1 ; ----------------------------------------------------------------------------
00EA86 1 ; Repeated-value mode.
00EA86 1 ;
00EA86 1 ; Set bit one in the working control byte and advance Y so the same source byte
00EA86 1 ; can be written repeatedly.
00EA86 1 ; ----------------------------------------------------------------------------
00EA86 1
00EA86 1 09 02 ora #$02 ; $EA86: 09 02
00EA88 1 C8 iny ; $EA88: C8
00EA89 1
00EA89 1 ; ----------------------------------------------------------------------------
00EA89 1 ; Divide the working control byte by four.
00EA89 1 ;
00EA89 1 ; Exit:
00EA89 1 ; X = transfer count
00EA89 1 ; Carry = literal/repeated source-advance flag
00EA89 1 ; ----------------------------------------------------------------------------
00EA89 1
00EA89 1 ProcessInlinePpuStream_DecodeCount: ; $EA89
00EA89 1 4A lsr ; $EA89: 4A
00EA8A 1 4A lsr ; $EA8A: 4A
00EA8B 1 AA tax ; $EA8B: AA
00EA8C 1
00EA8C 1 ; ============================================================================
00EA8C 1 ; $EA8C
00EA8C 1 ; Write the current record's payload to PPUDATA.
00EA8C 1 ;
00EA8C 1 ; Carry controls whether the source pointer advances for each output byte:
00EA8C 1 ;
00EA8C 1 ; C clear -> increment Y before reading
00EA8C 1 ; C set -> reuse the same source byte
00EA8C 1 ; ============================================================================
00EA8C 1
00EA8C 1 ProcessInlinePpuStream_WriteLoop: ; $EA8C
00EA8C 1 B0 01 bcs ProcessInlinePpuStream_Write
00EA8E 1 ; $EA8C: B0 01
00EA8E 1
00EA8E 1 C8 iny ; $EA8E: C8
00EA8F 1
00EA8F 1 ProcessInlinePpuStream_Write: ; $EA8F
00EA8F 1 B1 08 lda ($08),y ; $EA8F: B1 08
00EA91 1 8D 07 20 sta $2007 ; $EA91: 8D 07 20
00EA94 1
00EA94 1 CA dex ; $EA94: CA
00EA95 1 D0 F5 bne ProcessInlinePpuStream_WriteLoop
00EA97 1 ; $EA95: D0 F5
00EA97 1
00EA97 1 ; ----------------------------------------------------------------------------
00EA97 1 ; Advance the stream pointer past the record just processed.
00EA97 1 ;
00EA97 1 ; Y is the final source index consumed. Increment it, then add it to $08/$09.
00EA97 1 ; ----------------------------------------------------------------------------
00EA97 1
00EA97 1 C8 iny ; $EA97: C8
00EA98 1
00EA98 1 18 clc ; $EA98: 18
00EA99 1
00EA99 1 98 tya ; $EA99: 98
00EA9A 1 65 08 adc $08 ; $EA9A: 65 08
00EA9C 1 85 08 sta $08 ; $EA9C: 85 08
00EA9E 1
00EA9E 1 8A txa ; $EA9E: 8A
00EA9F 1 ; X is zero after the transfer loop.
00EA9F 1
00EA9F 1 65 09 adc $09 ; $EA9F: 65 09
00EAA1 1 85 09 sta $09 ; $EAA1: 85 09
00EAA3 1
00EAA3 1 ; ============================================================================
00EAA3 1 ; $EAA3
00EAA3 1 ; Check the next record for the zero terminator.
00EAA3 1 ; ============================================================================
00EAA3 1
00EAA3 1 ProcessInlinePpuStream_CheckRecord: ; $EAA3
00EAA3 1 AE 02 20 ldx $2002 ; $EAA3: AE 02 20
00EAA6 1 ; Reset PPU address latch.
00EAA6 1 ; The status value itself is unused.
00EAA6 1
00EAA6 1 A0 00 ldy #$00 ; $EAA6: A0 00
00EAA8 1
00EAA8 1 B1 08 lda ($08),y ; $EAA8: B1 08
00EAAA 1 D0 C0 bne ProcessInlinePpuStream_Record
00EAAC 1 ; $EAAA: D0 C0
00EAAC 1
00EAAC 1 ; ----------------------------------------------------------------------------
00EAAC 1 ; End of stream.
00EAAC 1 ;
00EAAC 1 ; Return Y=$03, matching the inline-record convention used by nearby helpers.
00EAAC 1 ; ----------------------------------------------------------------------------
00EAAC 1
00EAAC 1 A0 03 ldy #$03 ; $EAAC: A0 03
00EAAE 1 60 rts ; $EAAE: 60
00EAAF 1
00EAAF 1 ; ============================================================================
00EAAF 1 ; $EAAF-$EAF4
00EAAF 1 ; Run a complete display or screen transition.
00EAAF 1 ;
00EAAF 1 ; Entry:
00EAAF 1 ; Y = $03
00EAAF 1 ;
00EAAF 1 ; The preceding PPU stream routine returns with Y set to $03. This routine
00EAAF 1 ; saves that value in $E4 and uses it during the transition.
00EAAF 1 ; ============================================================================
00EAAF 1
00EAAF 1 RunDisplayTransition: ; $EAAF
00EAAF 1 84 E4 sty $E4 ; $EAAF: 84 E4
00EAB1 1
00EAB1 1 20 66 EB jsr DispatchNextQueuedEvent ; $EAB1: 20 66 EB
00EAB4 1 20 4C EB jsr SelectObjectEventBank0 ; $EAB4: 20 4C EB
00EAB7 1 20 9D EB jsr InitializeQueuedEventSystem ; $EAB7: 20 9D EB
00EABA 1
00EABA 1 20 6C E9 jsr DisablePpuRendering ; $EABA: 20 6C E9
00EABD 1
00EABD 1 ; ----------------------------------------------------------------------------
00EABD 1 ; Set PPU address $2324.
00EABD 1 ; ----------------------------------------------------------------------------
00EABD 1
00EABD 1 20 DB E9 jsr SetPpuAddressFromInlineRecord
00EAC0 1 ; $EABD: 20 DB E9
00EAC0 1
00EAC0 1 24 23 .byte $24,$23 ; $EAC0-$EAC1
00EAC2 1
00EAC2 1 A5 E4 lda $E4 ; $EAC2: A5 E4
00EAC4 1 20 00 EB jsr WriteGeneratedPpuWord ; $EAC4: 20 00 EB
00EAC7 1
00EAC7 1 ; ----------------------------------------------------------------------------
00EAC7 1 ; Set PPU address $2B24.
00EAC7 1 ; ----------------------------------------------------------------------------
00EAC7 1
00EAC7 1 20 DB E9 jsr SetPpuAddressFromInlineRecord
00EACA 1 ; $EAC7: 20 DB E9
00EACA 1
00EACA 1 24 2B .byte $24,$2B ; $EACA-$EACB
00EACC 1
00EACC 1 A5 E4 lda $E4 ; $EACC: A5 E4
00EACE 1 20 00 EB jsr WriteGeneratedPpuWord ; $EACE: 20 00 EB
00EAD1 1
00EAD1 1 ; ----------------------------------------------------------------------------
00EAD1 1 ; Set PPU address $2337.
00EAD1 1 ; ----------------------------------------------------------------------------
00EAD1 1
00EAD1 1 20 DB E9 jsr SetPpuAddressFromInlineRecord
00EAD4 1 ; $EAD1: 20 DB E9
00EAD4 1
00EAD4 1 37 23 .byte $37,$23 ; $EAD4-$EAD5
00EAD6 1
00EAD6 1 20 F5 EA jsr WriteFixedPpuSequence ; $EAD6: 20 F5 EA
00EAD9 1
00EAD9 1 ; ----------------------------------------------------------------------------
00EAD9 1 ; Set PPU address $2B37.
00EAD9 1 ; ----------------------------------------------------------------------------
00EAD9 1
00EAD9 1 20 DB E9 jsr SetPpuAddressFromInlineRecord
00EADC 1 ; $EAD9: 20 DB E9
00EADC 1
00EADC 1 37 2B .byte $37,$2B ; $EADC-$EADD
00EADE 1
00EADE 1 20 F5 EA jsr WriteFixedPpuSequence ; $EADE: 20 F5 EA
00EAE1 1
00EAE1 1 ; ----------------------------------------------------------------------------
00EAE1 1 ; Initialize the next transition phase.
00EAE1 1 ; ----------------------------------------------------------------------------
00EAE1 1
00EAE1 1 A9 0A lda #$0A ; $EAE1: A9 0A
00EAE3 1 85 DE sta PpuMaskShadow ; $EAE3: 85 DE
00EAE5 1
00EAE5 1 ; ----------------------------------------------------------------------------
00EAE5 1 ; Reset the PPU address latch, enable NMI, and wait for a frame.
00EAE5 1 ; ----------------------------------------------------------------------------
00EAE5 1
00EAE5 1 20 78 E9 jsr EnableNmiAndWaitForFrame
00EAE8 1 ; $EAE5: 20 78 E9
00EAE8 1
00EAE8 1 ; ----------------------------------------------------------------------------
00EAE8 1 ; Perform two waits using delay value $FF.
00EAE8 1 ; ----------------------------------------------------------------------------
00EAE8 1
00EAE8 1 A9 FF lda #$FF ; $EAE8: A9 FF
00EAEA 1 20 41 EB jsr StoreObjectEventBankValue ; $EAEA: 20 41 EB
00EAED 1
00EAED 1 A9 FF lda #$FF ; $EAED: A9 FF
00EAEF 1 20 41 EB jsr StoreObjectEventBankValue ; $EAEF: 20 41 EB
00EAF2 1
00EAF2 1 ; ----------------------------------------------------------------------------
00EAF2 1 ; Transfer to the common display-transition continuation.
00EAF2 1 ; ----------------------------------------------------------------------------
00EAF2 1
00EAF2 1 4C 0B C4 jmp Reset ; $EAF2: 4C 0B C4
00EAF5 1
00EAF5 1 ; ============================================================================
00EAF5 1 ; $EAF5-$EAFF
00EAF5 1 ; Write a fixed six-byte sequence to PPUDATA.
00EAF5 1 ;
00EAF5 1 ; Entry:
00EAF5 1 ; The caller has already selected the destination PPU address through
00EAF5 1 ; SetPpuAddressFromInlineRecord.
00EAF5 1 ;
00EAF5 1 ; This routine enters WriteInlinePpuBlock at its internal $EA05 entry,
00EAF5 1 ; skipping the PPU-address setup call at $EA02.
00EAF5 1 ;
00EAF5 1 ; Inline record:
00EAF5 1 ;
00EAF5 1 ; byte 0 = transfer count, $06
00EAF5 1 ; bytes 1-6 = PPU data:
00EAF5 1 ; $0C,$0A,$15,$15,$0E,$0D
00EAF5 1 ;
00EAF5 1 ; WriteInlinePpuBlock adjusts the return address past the inline data, so
00EAF5 1 ; execution resumes at the RTS at $EAFF.
00EAF5 1 ; ============================================================================
00EAF5 1
00EAF5 1 ; ----------------------------------------------------------------------------
00EAF5 1 ; Contract:
00EAF5 1 ; Description: Writes Fixed Ppu Sequence.
00EAF5 1 ; Entry: No register input inferred
00EAF5 1 ; Returns/products: No direct product inferred
00EAF5 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00EAF5 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00EAF5 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00EAF5 1 ; comparison, load, or store path and are not a stable API product.
00EAF5 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 2.
00EAF5 1 ; ----------------------------------------------------------------------------
00EAF5 1 WriteFixedPpuSequence: ; $EAF5
00EAF5 1 20 05 EA jsr WriteInlinePpuBlockAfterAddress ; $EAF5: 20 05 EA
00EAF8 1 ; Internal entry in WriteInlinePpuBlock.
00EAF8 1 ;
00EAF8 1 ; $EA05: STX $05
00EAF8 1 ; $EA07: JSR DecodeInlineParameters
00EAF8 1
00EAF8 1 ; ----------------------------------------------------------------------------
00EAF8 1 ; Inline transfer record consumed by the helper at $EA05.
00EAF8 1 ; ----------------------------------------------------------------------------
00EAF8 1
00EAF8 1 06 .byte $06 ; $EAF8
00EAF9 1 ; Number of bytes to write.
00EAF9 1
00EAF9 1 0C 0A 15 .byte $0C,$0A,$15 ; $EAF9-$EAFB
00EAFC 1 15 0E 0D .byte $15,$0E,$0D ; $EAFC-$EAFE
00EAFF 1
00EAFF 1 ; ----------------------------------------------------------------------------
00EAFF 1 ; Execution resumes here after the inline record has been consumed.
00EAFF 1 ; ----------------------------------------------------------------------------
00EAFF 1
00EAFF 1 60 rts ; $EAFF: 60
00EB00 1
00EB00 1 ; ============================================================================
00EB00 1 ; $EB00-$EB0A
00EB00 1 ; Generate a two-byte value through $D01D and write both bytes to PPUDATA.
00EB00 1 ;
00EB00 1 ; The helper at $D01D returns:
00EB00 1 ;
00EB00 1 ; Y = first byte
00EB00 1 ; A = second byte
00EB00 1 ;
00EB00 1 ; Both values are written consecutively to the current PPU address.
00EB00 1 ; ============================================================================
00EB00 1
00EB00 1 ; ----------------------------------------------------------------------------
00EB00 1 ; Contract:
00EB00 1 ; Description: Writes Generated Ppu Word.
00EB00 1 ; Entry: Registers: A, Y
00EB00 1 ; Returns/products: Primary products are committed to memory.
00EB00 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00EB00 1 ; Memory effects: ppudata
00EB00 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00EB00 1 ; comparison, load, or store path and are not a stable API product.
00EB00 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 2.
00EB00 1 ; ----------------------------------------------------------------------------
00EB00 1 WriteGeneratedPpuWord: ; $EB00
00EB00 1 20 1D D0 jsr DivideABy10 ; $EB00: 20 1D D0
00EB03 1 ; Generate or retrieve a two-byte value.
00EB03 1 ;
00EB03 1 ; Return:
00EB03 1 ; Y = first byte
00EB03 1 ; A = second byte
00EB03 1
00EB03 1 ; ----------------------------------------------------------------------------
00EB03 1 ; Write the first byte returned in Y.
00EB03 1 ; ----------------------------------------------------------------------------
00EB03 1
00EB03 1 8C 07 20 sty PPUDATA ; $EB03: 8C 07 20
00EB06 1
00EB06 1 ; ----------------------------------------------------------------------------
00EB06 1 ; Write the second byte returned in A.
00EB06 1 ; ----------------------------------------------------------------------------
00EB06 1
00EB06 1 8D 07 20 sta PPUDATA ; $EB06: 8D 07 20
00EB09 1
00EB09 1 60 rts ; $EB09: 60
00EB0A 1
00EB0A 1 ; ============================================================================
00EB0A 1 ; $EB0A-$EB29
00EB0A 1 ; Decode an inline event record, update the event arrays for object X, and
00EB0A 1 ; either start the display transition immediately or enqueue the object.
00EB0A 1 ;
00EB0A 1 ; Entry:
00EB0A 1 ; X = object/event index
00EB0A 1 ;
00EB0A 1 ; Inline record:
00EB0A 1 ; byte 0 = value stored in $069F,X
00EB0A 1 ; byte 1 = value stored in $06CF,X
00EB0A 1 ;
00EB0A 1 ; DecodeInlineParameters returns:
00EB0A 1 ; X = first inline byte
00EB0A 1 ; A = second inline byte
00EB0A 1 ; Y = index into the caller's inline record
00EB0A 1 ;
00EB0A 1 ; Important:
00EB0A 1 ; This routine is also entered internally at $EB0D by the helper at $E29B.
00EB0A 1 ; That entry skips DecodeInlineParameters because $E99A was already called.
00EB0A 1 ; ============================================================================
00EB0A 1
00EB0A 1 ; ----------------------------------------------------------------------------
00EB0A 1 ; Contract:
00EB0A 1 ; Description: Queues Inline Object Event.
00EB0A 1 ; Entry: Registers: A, X, Y; Memory: ($00), $06ff, $e2
00EB0A 1 ; Returns/products: Registers/clobbers: A, Y
00EB0A 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00EB0A 1 ; Memory effects: $069f, $06cf, $06ff, $0670
00EB0A 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00EB0A 1 ; comparison, load, or store path and are not a stable API product.
00EB0A 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 45.
00EB0A 1 ; ----------------------------------------------------------------------------
00EB0A 1 QueueInlineObjectEvent: ; $EB0A
00EB0A 1 20 9A E9 jsr DecodeInlineParameters ; $EB0A: 20 9A E9
00EB0D 1
00EB0D 1 ; ============================================================================
00EB0D 1 ; $EB0D
00EB0D 1 ; Internal entry used by DispatchInlineObjectCommand at $E29B.
00EB0D 1 ;
00EB0D 1 ; Entry:
00EB0D 1 ; X = object/event index restored by $E29B
00EB0D 1 ; A = second decoded inline byte
00EB0D 1 ; Y = inline source index established by DecodeInlineParameters
00EB0D 1 ; $00/$01 = pointer to the inline record
00EB0D 1 ; ============================================================================
00EB0D 1
00EB0D 1 QueueDecodedObjectEvent: ; $EB0D
00EB0D 1 9D 9F 06 sta $069F,x ; $EB0D: 9D 9F 06
00EB10 1 ; Save the second inline parameter.
00EB10 1
00EB10 1 B1 00 lda ($00),y ; $EB10: B1 00
00EB12 1 ; Load the next inline byte.
00EB12 1
00EB12 1 9D CF 06 sta $06CF,x ; $EB12: 9D CF 06
00EB15 1 ; Save it in the parallel event array.
00EB15 1
00EB15 1 ; ----------------------------------------------------------------------------
00EB15 1 ; Use the object/event index as an index into the active-event array.
00EB15 1 ; ----------------------------------------------------------------------------
00EB15 1
00EB15 1 ; ----------------------------------------------------------------------------
00EB15 1 ; Contract:
00EB15 1 ; Description: Internal event-queue entry after inline values have been stored.
00EB15 1 ; Entry: X = object/event index.
00EB15 1 ; Returns/products: Queues or dispatches event context.
00EB15 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00EB15 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00EB15 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00EB15 1 ; comparison, load, or store path and are not a stable API product.
00EB15 1 ; Validation: Internal-entry contract; call sites: internal entry.
00EB15 1 ; ----------------------------------------------------------------------------
00EB15 1 QueueDecodedObjectEventSelectIndex:
00EB15 1 8A txa ; $EB15: 8A
00EB16 1 ; ----------------------------------------------------------------------------
00EB16 1 ; Contract:
00EB16 1 ; Description: Internal event-queue entry with object index transferred to Y.
00EB16 1 ; Entry: X/Y identify object/event entry.
00EB16 1 ; Returns/products: Queues or dispatches event context.
00EB16 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00EB16 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00EB16 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00EB16 1 ; comparison, load, or store path and are not a stable API product.
00EB16 1 ; Validation: Internal-entry contract; call sites: internal entry.
00EB16 1 ; ----------------------------------------------------------------------------
00EB16 1 QueueDecodedObjectEventCheckActive:
00EB16 1 A8 tay ; $EB16: A8
00EB17 1
00EB17 1 B9 FF 06 lda $06FF,y ; $EB17: B9 FF 06
00EB1A 1 D0 93 bne RunDisplayTransition ; $EB1A: D0 93
00EB1C 1 ; Target $EAAF.
00EB1C 1 ;
00EB1C 1 ; If the object already has a nonzero active
00EB1C 1 ; entry, immediately run the display transition.
00EB1C 1
00EB1C 1 ; ----------------------------------------------------------------------------
00EB1C 1 ; Mark this object/event entry active.
00EB1C 1 ;
00EB1C 1 ; A is zero here because the preceding BNE was not taken. TYA restores the
00EB1C 1 ; object index, which is stored in the active-event array.
00EB1C 1 ; ----------------------------------------------------------------------------
00EB1C 1
00EB1C 1 98 tya ; $EB1C: 98
00EB1D 1 99 FF 06 sta $06FF,y ; $EB1D: 99 FF 06
00EB20 1
00EB20 1 ; ----------------------------------------------------------------------------
00EB20 1 ; Append the object/event index to the queue at $0670.
00EB20 1 ;
00EB20 1 ; $E2 is the current queue length or next free queue slot.
00EB20 1 ; ----------------------------------------------------------------------------
00EB20 1
00EB20 1 A4 E2 ldy $E2 ; $EB20: A4 E2
00EB22 1 E6 E2 inc $E2 ; $EB22: E6 E2
00EB24 1
00EB24 1 99 70 06 sta $0670,y ; $EB24: 99 70 06
00EB27 1
00EB27 1 ; ----------------------------------------------------------------------------
00EB27 1 ; Return Y=$04. Nearby inline-data and event helpers use this value as their
00EB27 1 ; resume/index convention.
00EB27 1 ; ----------------------------------------------------------------------------
00EB27 1
00EB27 1 A0 04 ldy #$04 ; $EB27: A0 04
00EB29 1 60 rts ; $EB29: 60
00EB2A 1
00EB2A 1 ; ============================================================================
00EB2A 1 ; $EB2A-$EB3A
00EB2A 1 ; Process an active queued-event entry until its event-state byte becomes zero.
00EB2A 1 ;
00EB2A 1 ; Entry:
00EB2A 1 ; X = object/event index
00EB2A 1 ;
00EB2A 1 ; Event arrays:
00EB2A 1 ; $0600,X = active event identifier or state
00EB2A 1 ; $060F,Y = event-state table inspected after processing
00EB2A 1 ;
00EB2A 1 ; Behavior:
00EB2A 1 ; If $0600,X is already zero, return immediately.
00EB2A 1 ;
00EB2A 1 ; Otherwise:
00EB2A 1 ; 1. Call the event-processing entry at $EB16.
00EB2A 1 ; 2. Use the returned value in A as an index into $060F.
00EB2A 1 ; 3. Repeat while the indexed event-state byte remains nonzero.
00EB2A 1 ; 4. Clear $0600,X when processing completes.
00EB2A 1 ; ============================================================================
00EB2A 1
00EB2A 1 ; ----------------------------------------------------------------------------
00EB2A 1 ; Contract:
00EB2A 1 ; Description: Processes Queued Object Event.
00EB2A 1 ; Entry: Registers: A; Memory: $0600, $060f
00EB2A 1 ; Returns/products: Registers/clobbers: A, Y
00EB2A 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00EB2A 1 ; Memory effects: $0600
00EB2A 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00EB2A 1 ; comparison, load, or store path and are not a stable API product.
00EB2A 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 5.
00EB2A 1 ; ----------------------------------------------------------------------------
00EB2A 1 ProcessQueuedObjectEvent: ; $EB2A
00EB2A 1 BD 00 06 lda $0600,x ; $EB2A: BD 00 06
00EB2D 1 F0 0C beq ProcessQueuedObjectEvent_Return
00EB2F 1 ; $EB2D: F0 0C
00EB2F 1
00EB2F 1 ProcessQueuedObjectEvent_Loop: ; $EB2F
00EB2F 1 20 16 EB jsr QueueDecodedObjectEventCheckActive ; $EB2F: 20 16 EB
00EB32 1
00EB32 1 A8 tay ; $EB32: A8
00EB33 1
00EB33 1 B9 0F 06 lda $060F,y ; $EB33: B9 0F 06
00EB36 1 D0 F7 bne ProcessQueuedObjectEvent_Loop
00EB38 1 ; $EB36: D0 F7
00EB38 1
00EB38 1 9D 00 06 sta $0600,x ; $EB38: 9D 00 06
00EB3B 1 ; Clear the entry with A=$00.
00EB3B 1
00EB3B 1 ProcessQueuedObjectEvent_Return: ; $EB3B
00EB3B 1 60 rts ; $EB3B: 60
00EB3C 1 ; ============================================================================
00EB3C 1 ; $EB3C-$EB64
00EB3C 1 ; Update the current object's queue-bank selection and restore two saved event
00EB3C 1 ; values from the stack.
00EB3C 1 ;
00EB3C 1 ; Entry:
00EB3C 1 ; A = value used to derive an index relative to $E3
00EB3C 1 ; C = significant input to SBC
00EB3C 1 ; $E1 = current object/event index
00EB3C 1 ;
00EB3C 1 ; The routine:
00EB3C 1 ; 1. Calculates a three-bit value and stores it in $063F,Y.
00EB3C 1 ; 2. Selects queue bank zero or one.
00EB3C 1 ; 3. Exchanges the current object's $060F entry with the selected bank's
00EB3C 1 ; $0600 entry.
00EB3C 1 ; 4. Restores values from the stack into $069F,Y and $06CF,Y.
00EB3C 1 ; 5. Branches to the common engine exit at $EB6A.
00EB3C 1 ; ============================================================================
00EB3C 1
00EB3C 1 UpdateObjectEventBank: ; $EB3C
00EB3C 1 38 sec ; $EB3C: 38
00EB3D 1
00EB3D 1 E5 E3 sbc FrameCounter ; $EB3D: E5 E3
00EB3F 1 ; Calculate a value relative to the current
00EB3F 1 ; event/queue state.
00EB3F 1
00EB3F 1 29 07 and #$07 ; $EB3F: 29 07
00EB41 1 ; Limit the result to three bits.
00EB41 1
00EB41 1 ; ----------------------------------------------------------------------------
00EB41 1 ; Contract:
00EB41 1 ; Description: Internal event-bank entry after the three-bit value is prepared in A.
00EB41 1 ; Entry: A = event-bank value; current object index set.
00EB41 1 ; Returns/products: $063F,Y updated; may continue into bank exchange.
00EB41 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00EB41 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00EB41 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00EB41 1 ; comparison, load, or store path and are not a stable API product.
00EB41 1 ; Validation: Internal-entry contract; call sites: internal entry.
00EB41 1 ; ----------------------------------------------------------------------------
00EB41 1 StoreObjectEventBankValue:
00EB41 1 A4 E1 ldy CurrentObjectIndex ; $EB41: A4 E1
00EB43 1
00EB43 1 99 3F 06 sta $063F,y ; $EB43: 99 3F 06
00EB46 1 ; Save the calculated three-bit value.
00EB46 1
00EB46 1 ; ----------------------------------------------------------------------------
00EB46 1 ; A nonzero calculated value skips the queue-bank exchange and proceeds
00EB46 1 ; directly to the stack-restoration path.
00EB46 1 ; ----------------------------------------------------------------------------
00EB46 1
00EB46 1 D0 12 bne UpdateObjectEventBank_Restore
00EB48 1 ; $EB46: D0 12
00EB48 1
00EB48 1 ; ============================================================================
00EB48 1 ; $EB48
00EB48 1 ; Select queue bank one.
00EB48 1 ;
00EB48 1 ; This address is also called directly throughout the ROM as a frame/event
00EB48 1 ; synchronization helper. The direct-entry behavior begins by selecting bank
00EB48 1 ; one and continues through the exchange below.
00EB48 1 ; ============================================================================
00EB48 1
00EB48 1 ; ----------------------------------------------------------------------------
00EB48 1 ; Contract:
00EB48 1 ; Description: Implements Select Object Event Bank 1.
00EB48 1 ; Entry: Registers: A, Y; Memory: currentobjectindex, $0600
00EB48 1 ; Returns/products: Registers/clobbers: A, X, Y
00EB48 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00EB48 1 ; Memory effects: $060f, $0600, $069f, $06cf
00EB48 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00EB48 1 ; comparison, load, or store path and are not a stable API product.
00EB48 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 42.
00EB48 1 ; ----------------------------------------------------------------------------
00EB48 1 SelectObjectEventBank1: ; $EB48
00EB48 1 A2 01 ldx #$01 ; $EB48: A2 01
00EB4A 1
00EB4A 1 D0 02 bne UpdateObjectEventBank_Exchange
00EB4C 1 ; $EB4A: D0 02
00EB4C 1 ; Always taken because X is nonzero.
00EB4C 1
00EB4C 1 ; ============================================================================
00EB4C 1 ; $EB4C
00EB4C 1 ; Select queue bank zero.
00EB4C 1 ;
00EB4C 1 ; This is another direct entry used elsewhere in the ROM.
00EB4C 1 ; ============================================================================
00EB4C 1
00EB4C 1 ; ----------------------------------------------------------------------------
00EB4C 1 ; Contract:
00EB4C 1 ; Description: Implements Select Object Event Bank 0.
00EB4C 1 ; Entry: Registers: A, Y; Memory: currentobjectindex, $0600
00EB4C 1 ; Returns/products: Registers/clobbers: A, X, Y
00EB4C 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00EB4C 1 ; Memory effects: $060f, $0600, $069f, $06cf
00EB4C 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00EB4C 1 ; comparison, load, or store path and are not a stable API product.
00EB4C 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 7.
00EB4C 1 ; ----------------------------------------------------------------------------
00EB4C 1 SelectObjectEventBank0: ; $EB4C
00EB4C 1 A2 00 ldx #$00 ; $EB4C: A2 00
00EB4E 1
00EB4E 1 ; ----------------------------------------------------------------------------
00EB4E 1 ; Exchange the current object's $060F entry with the selected bank's $0600
00EB4E 1 ; entry.
00EB4E 1 ;
00EB4E 1 ; Before:
00EB4E 1 ; A = $0600,X
00EB4E 1 ; Y = CurrentObjectIndex
00EB4E 1 ;
00EB4E 1 ; After:
00EB4E 1 ; $060F,Y = old $0600,X
00EB4E 1 ; $0600,X = CurrentObjectIndex
00EB4E 1 ; ----------------------------------------------------------------------------
00EB4E 1
00EB4E 1 ; ----------------------------------------------------------------------------
00EB4E 1 ; Contract:
00EB4E 1 ; Description: Updates Object Event Bank Exchange.
00EB4E 1 ; Entry: Registers: A, Y; Memory: currentobjectindex, $0600
00EB4E 1 ; Returns/products: Registers/clobbers: A, Y
00EB4E 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00EB4E 1 ; Memory effects: $060f, $0600, $069f, $06cf
00EB4E 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00EB4E 1 ; comparison, load, or store path and are not a stable API product.
00EB4E 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 3.
00EB4E 1 ; ----------------------------------------------------------------------------
00EB4E 1 UpdateObjectEventBank_Exchange: ; $EB4E
00EB4E 1 A4 E1 ldy CurrentObjectIndex ; $EB4E: A4 E1
00EB50 1
00EB50 1 BD 00 06 lda $0600,x ; $EB50: BD 00 06
00EB53 1 99 0F 06 sta $060F,y ; $EB53: 99 0F 06
00EB56 1
00EB56 1 98 tya ; $EB56: 98
00EB57 1 9D 00 06 sta $0600,x ; $EB57: 9D 00 06
00EB5A 1
00EB5A 1 ; ============================================================================
00EB5A 1 ; $EB5A
00EB5A 1 ; Restore two saved event values from the stack.
00EB5A 1 ;
00EB5A 1 ; Entry paths:
00EB5A 1 ; From $EB46:
00EB5A 1 ; Y was loaded from CurrentObjectIndex at $EB41.
00EB5A 1 ;
00EB5A 1 ; From $EB48/$EB4C:
00EB5A 1 ; Y was reloaded from CurrentObjectIndex at $EB4E.
00EB5A 1 ; ============================================================================
00EB5A 1
00EB5A 1 UpdateObjectEventBank_Restore: ; $EB5A
00EB5A 1 18 clc ; $EB5A: 18
00EB5B 1 ; Establish carry clear for the final BCC.
00EB5B 1
00EB5B 1 ; ----------------------------------------------------------------------------
00EB5B 1 ; Contract:
00EB5B 1 ; Description: Internal event-context restoration entry.
00EB5B 1 ; Entry: Y = object/event index; stack contains two saved context bytes; carry controls final branch.
00EB5B 1 ; Returns/products: Context arrays restored; stack consumed.
00EB5B 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00EB5B 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00EB5B 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00EB5B 1 ; comparison, load, or store path and are not a stable API product.
00EB5B 1 ; Validation: Internal-entry contract; call sites: internal entry.
00EB5B 1 ; ----------------------------------------------------------------------------
00EB5B 1 RestoreObjectEventContext:
00EB5B 1 68 pla ; $EB5B: 68
00EB5C 1 99 9F 06 sta $069F,y ; $EB5C: 99 9F 06
00EB5F 1
00EB5F 1 68 pla ; $EB5F: 68
00EB60 1 99 CF 06 sta $06CF,y ; $EB60: 99 CF 06
00EB63 1
00EB63 1 ; ----------------------------------------------------------------------------
00EB63 1 ; Transfer to the common exit at $EB6A.
00EB63 1 ;
00EB63 1 ; CLC makes this branch unconditional.
00EB63 1 ; ----------------------------------------------------------------------------
00EB63 1
00EB63 1 90 05 bcc CommonEngineExit ; $EB63: 90 05
00EB65 1 ; Target $EB6A.
00EB65 1
00EB65 1 ; ============================================================================
00EB65 1 ; The supplied dump ends at $EB64.
00EB65 1 ;
00EB65 1 ; Leave $EB65 onward untouched until its bytes are verified. The branch above
00EB65 1 ; targets the already-known common engine exit at $EB6A.
00EB65 1 ; ============================================================================
00EB65 1
00EB65 1 ; ============================================================================
00EB65 1 ; $EB65
00EB65 1 ; Standalone return entry.
00EB65 1 ;
00EB65 1 ; The preceding code at $EB63 branches over this byte to the common exit at
00EB65 1 ; $EB6A. Other callers may use $EB65 as an immediate no-operation return.
00EB65 1 ; ============================================================================
00EB65 1
00EB65 1 Return_EB65: ; $EB65
00EB65 1 60 rts ; $EB65: 60
00EB66 1
00EB66 1 ; ============================================================================
00EB66 1 ; $EB66-$EB9C
00EB66 1 ; Finish the current event, then restore and dispatch the newest queued event.
00EB66 1 ;
00EB66 1 ; Entry:
00EB66 1 ; Y = object/event index used by the shared stack-restoration path
00EB66 1 ;
00EB66 1 ; Operation:
00EB66 1 ; 1. Enter the stack-restoration path at $EB5B with carry set.
00EB66 1 ; 2. Clear the current object's active-event entry at $06FF,X.
00EB66 1 ; 3. Wait until at least one queued event exists.
00EB66 1 ; 4. Disable NMI while modifying the queue.
00EB66 1 ; 5. Pop the newest queued object index from $0670.
00EB66 1 ; 6. Reset the stack pointer.
00EB66 1 ; 7. Push that object's saved handler/event values.
00EB66 1 ; 8. Return into the queued event's saved continuation.
00EB66 1 ;
00EB66 1 ; This routine implements a stack-based event-context switch.
00EB66 1 ; ============================================================================
00EB66 1
00EB66 1 ; ----------------------------------------------------------------------------
00EB66 1 ; Contract:
00EB66 1 ; Description: Implements Dispatch Next Queued Event.
00EB66 1 ; Entry: Registers: A, X; Memory: currentobjectindex, $e2, $2002, $dd, $0670, $06cf
00EB66 1 ; Returns/products: Registers/clobbers: A, X, Y
00EB66 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00EB66 1 ; Memory effects: $06ff, $2000, $e2, currentobjectindex
00EB66 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00EB66 1 ; comparison, load, or store path and are not a stable API product.
00EB66 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 20.
00EB66 1 ; ----------------------------------------------------------------------------
00EB66 1 DispatchNextQueuedEvent: ; $EB66
00EB66 1 38 sec ; $EB66: 38
00EB67 1
00EB67 1 20 5B EB jsr RestoreObjectEventContext ; $EB67: 20 5B EB
00EB6A 1 ; Enter the previous routine after its CLC.
00EB6A 1 ;
00EB6A 1 ; Since entry is at $EB5B, carry remains set
00EB6A 1 ; through the two PLA/STA operations. Its final
00EB6A 1 ; BCC is therefore not taken, allowing this
00EB6A 1 ; routine to continue at $EB6A.
00EB6A 1
00EB6A 1 ; ============================================================================
00EB6A 1 ; $EB6A
00EB6A 1 ; Common continuation used by multiple earlier paths.
00EB6A 1 ; ============================================================================
00EB6A 1
00EB6A 1 CommonEngineExit: ; $EB6A
00EB6A 1 A6 E1 ldx CurrentObjectIndex ; $EB6A: A6 E1
00EB6C 1
00EB6C 1 A9 00 lda #$00 ; $EB6C: A9 00
00EB6E 1 9D FF 06 sta $06FF,x ; $EB6E: 9D FF 06
00EB71 1 ; Mark the current object/event inactive.
00EB71 1
00EB71 1 ; ----------------------------------------------------------------------------
00EB71 1 ; Check the queued-event count in $E2.
00EB71 1 ; ----------------------------------------------------------------------------
00EB71 1
00EB71 1 A6 E2 ldx $E2 ; $EB71: A6 E2
00EB73 1 D0 0C bne DispatchNextQueuedEvent_HaveEntry
00EB75 1 ; $EB73: D0 0C
00EB75 1
00EB75 1 ; ----------------------------------------------------------------------------
00EB75 1 ; No event is currently queued.
00EB75 1 ;
00EB75 1 ; Read PPUSTATUS to reset the PPU address latch, then restore PPUCTRL from $DD.
00EB75 1 ; Wait until an NMI or another producer adds an event to the queue.
00EB75 1 ; ----------------------------------------------------------------------------
00EB75 1
00EB75 1 AD 02 20 lda $2002 ; $EB75: AD 02 20
00EB78 1 ; Reset the PPU address latch.
00EB78 1
00EB78 1 A5 DD lda PpuCtrlShadow ; $EB78: A5 DD
00EB7A 1 8D 00 20 sta $2000 ; $EB7A: 8D 00 20
00EB7D 1 ; Restore the current PPUCTRL value.
00EB7D 1
00EB7D 1 DispatchNextQueuedEvent_Wait: ; $EB7D
00EB7D 1 A6 E2 ldx $E2 ; $EB7D: A6 E2
00EB7F 1 F0 FC beq DispatchNextQueuedEvent_Wait
00EB81 1 ; $EB7F: F0 FC
00EB81 1
00EB81 1 ; ----------------------------------------------------------------------------
00EB81 1 ; At least one queued event exists.
00EB81 1 ;
00EB81 1 ; Disable NMI by clearing bit seven of the saved PPUCTRL value.
00EB81 1 ; ----------------------------------------------------------------------------
00EB81 1
00EB81 1 DispatchNextQueuedEvent_HaveEntry: ; $EB81
00EB81 1 A5 DD lda PpuCtrlShadow ; $EB81: A5 DD
00EB83 1 29 7F and #$7F ; $EB83: 29 7F
00EB85 1 8D 00 20 sta $2000 ; $EB85: 8D 00 20
00EB88 1
00EB88 1 ; ----------------------------------------------------------------------------
00EB88 1 ; Remove the newest object/event index from the queue.
00EB88 1 ;
00EB88 1 ; $E2 behaves as a count/next-free index:
00EB88 1 ;
00EB88 1 ; X = $E2 - 1
00EB88 1 ; CurrentObjectIndex = $0670,X
00EB88 1 ; $E2 = X
00EB88 1 ; ----------------------------------------------------------------------------
00EB88 1
00EB88 1 CA dex ; $EB88: CA
00EB89 1 86 E2 stx $E2 ; $EB89: 86 E2
00EB8B 1
00EB8B 1 BD 70 06 lda $0670,x ; $EB8B: BD 70 06
00EB8E 1 85 E1 sta CurrentObjectIndex ; $EB8E: 85 E1
00EB90 1 A8 tay ; $EB90: A8
00EB91 1 ; Y = queued object/event index.
00EB91 1
00EB91 1 ; ----------------------------------------------------------------------------
00EB91 1 ; Reset the hardware stack.
00EB91 1 ;
00EB91 1 ; Setting SP to $FF discards the current call chain. The saved event values
00EB91 1 ; pushed below become the return context used by RTS.
00EB91 1 ; ----------------------------------------------------------------------------
00EB91 1
00EB91 1 A2 FF ldx #$FF ; $EB91: A2 FF
00EB93 1 9A txs ; $EB93: 9A
00EB94 1
00EB94 1 ; ----------------------------------------------------------------------------
00EB94 1 ; Push the queued object's saved continuation/context bytes.
00EB94 1 ;
00EB94 1 ; RTS at $EB9C pulls these bytes as its return address. The low byte is pushed
00EB94 1 ; second because RTS pulls low byte first.
00EB94 1 ; ----------------------------------------------------------------------------
00EB94 1
00EB94 1 B9 CF 06 lda $06CF,y ; $EB94: B9 CF 06
00EB97 1 48 pha ; $EB97: 48
00EB98 1 ; Push saved high byte.
00EB98 1
00EB98 1 B9 9F 06 lda $069F,y ; $EB98: B9 9F 06
00EB9B 1 48 pha ; $EB9B: 48
00EB9C 1 ; Push saved low byte.
00EB9C 1
00EB9C 1 60 rts ; $EB9C: 60
00EB9D 1 ; Resume the queued event continuation.
00EB9D 1
00EB9D 1 ; ============================================================================
00EB9D 1 ; $EB9D-$EBB3
00EB9D 1 ; Initialize the queued-event system and clear its event arrays.
00EB9D 1 ;
00EB9D 1 ; Operation:
00EB9D 1 ; 1. Clear the full $0600-$06FF page.
00EB9D 1 ; 2. Clear the queue count at $E2.
00EB9D 1 ; 3. Set CurrentObjectIndex to $01.
00EB9D 1 ; 4. Clear $30 entries in the active-event array beginning at $06FF.
00EB9D 1 ;
00EB9D 1 ; Exit:
00EB9D 1 ; A = $00
00EB9D 1 ; X = $00
00EB9D 1 ; $E2 = $00
00EB9D 1 ; CurrentObjectIndex = $01
00EB9D 1 ; ============================================================================
00EB9D 1
00EB9D 1 ; ----------------------------------------------------------------------------
00EB9D 1 ; Contract:
00EB9D 1 ; Description: Initializes Queued Event System.
00EB9D 1 ; Entry: Registers: A, X
00EB9D 1 ; Returns/products: Registers/clobbers: A, X
00EB9D 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00EB9D 1 ; Memory effects: $0600, $e2, currentobjectindex, $06ff
00EB9D 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00EB9D 1 ; comparison, load, or store path and are not a stable API product.
00EB9D 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 4.
00EB9D 1 ; ----------------------------------------------------------------------------
00EB9D 1 InitializeQueuedEventSystem: ; $EB9D
00EB9D 1 A9 00 lda #$00 ; $EB9D: A9 00
00EB9F 1 AA tax ; $EB9F: AA
00EBA0 1 ; A = $00, X = $00.
00EBA0 1
00EBA0 1 ; ----------------------------------------------------------------------------
00EBA0 1 ; Clear the full $0600-$06FF page.
00EBA0 1 ;
00EBA0 1 ; X begins at zero and wraps after 256 iterations:
00EBA0 1 ;
00EBA0 1 ; $0600,X = $00
00EBA0 1 ; ...
00EBA0 1 ; $06FF,X = $00
00EBA0 1 ; ----------------------------------------------------------------------------
00EBA0 1
00EBA0 1 InitializeQueuedEventSystem_ClearPage: ; $EBA0
00EBA0 1 9D 00 06 sta $0600,x ; $EBA0: 9D 00 06
00EBA3 1
00EBA3 1 E8 inx ; $EBA3: E8
00EBA4 1 D0 FA bne InitializeQueuedEventSystem_ClearPage
00EBA6 1 ; $EBA4: D0 FA
00EBA6 1
00EBA6 1 ; ----------------------------------------------------------------------------
00EBA6 1 ; Clear the queued-event count or next-free queue index.
00EBA6 1 ; ----------------------------------------------------------------------------
00EBA6 1
00EBA6 1 85 E2 sta $E2 ; $EBA6: 85 E2
00EBA8 1
00EBA8 1 ; ----------------------------------------------------------------------------
00EBA8 1 ; X wrapped to zero after the page clear. Increment it to one and use that as
00EBA8 1 ; the initial current-object/event index.
00EBA8 1 ; ----------------------------------------------------------------------------
00EBA8 1
00EBA8 1 E8 inx ; $EBA8: E8
00EBA9 1 ; X = $01.
00EBA9 1
00EBA9 1 86 E1 stx CurrentObjectIndex ; $EBA9: 86 E1
00EBAB 1
00EBAB 1 ; ----------------------------------------------------------------------------
00EBAB 1 ; Clear the active-event entries $06FF-$072E.
00EBAB 1 ;
00EBAB 1 ; X begins at $30. Because the indexed base is $06FF, the effective addresses
00EBAB 1 ; are:
00EBAB 1 ;
00EBAB 1 ; X=$30 -> $072F
00EBAB 1 ; ...
00EBAB 1 ; X=$01 -> $0700
00EBAB 1 ;
00EBAB 1 ; The loop does not write with X=$00.
00EBAB 1 ;
00EBAB 1 ; Note that $06FF itself was already cleared by the full-page loop above.
00EBAB 1 ; ----------------------------------------------------------------------------
00EBAB 1
00EBAB 1 A2 30 ldx #$30 ; $EBAB: A2 30
00EBAD 1
00EBAD 1 InitializeQueuedEventSystem_ClearActive: ; $EBAD
00EBAD 1 9D FF 06 sta $06FF,x ; $EBAD: 9D FF 06
00EBB0 1
00EBB0 1 CA dex ; $EBB0: CA
00EBB1 1 D0 FA bne InitializeQueuedEventSystem_ClearActive
00EBB3 1 ; $EBB1: D0 FA
00EBB3 1
00EBB3 1 60 rts ; $EBB3: 60
00EBB4 1
00EBB4 1 ; ============================================================================
00EBB4 1 ; $EBB4-$EBBB
00EBB4 1 ; Convert A into a three-bit value relative to $E3, then enter the common
00EBB4 1 ; object-event bank routine at $EB41.
00EBB4 1 ;
00EBB4 1 ; Entry:
00EBB4 1 ; A = source value
00EBB4 1 ;
00EBB4 1 ; Calculation:
00EBB4 1 ; A = (A - $E3) & $07
00EBB4 1 ; ============================================================================
00EBB4 1
00EBB4 1 UpdateRelativeObjectEventBank: ; $EBB4
00EBB4 1 38 sec ; $EBB4: 38
00EBB5 1
00EBB5 1 E5 E3 sbc FrameCounter ; $EBB5: E5 E3
00EBB7 1
00EBB7 1 29 07 and #$07 ; $EBB7: 29 07
00EBB9 1
00EBB9 1 4C 41 EB jmp StoreObjectEventBankValue ; $EBB9: 4C 41 EB
00EBBC 1
00EBBC 1 ; ============================================================================
00EBBC 1 ; $EBBC-$EBDB
00EBBC 1 ; Structured rendering or animation data.
00EBBC 1 ;
00EBBC 1 ; This region does not begin with a plausible executable entry point:
00EBBC 1 ;
00EBBC 1 ; $EBBC: D6 E1
00EBBC 1 ; $EBBE: B1 C7
00EBBC 1 ; $EBC0: BE C2
00EBBC 1 ;
00EBBC 1 ; The following bytes contain repeating values and fields resembling sprite or
00EBBC 1 ; animation records. Keep the exact byte layout until the routines that index
00EBBC 1 ; this region reveal its record boundaries.
00EBBC 1 ; ============================================================================
00EBBC 1
00EBBC 1 RenderingData_EBBC: ; $EBBC
00EBBC 1 D6 E1 B1 C7 .byte $D6,$E1,$B1,$C7,$BE,$C2,$50,$03
00EBC0 1 BE C2 50 03
00EBC4 1 00 27 50 03 .byte $00,$27,$50,$03,$00,$1F,$A8,$02
00EBC8 1 00 1F A8 02
00EBCC 1 3F 27 A8 02 .byte $3F,$27,$A8,$02,$3F,$1F,$A4,$03
00EBD0 1 3F 1F A4 03
00EBD4 1 F3 17 05 F0 .byte $F3,$17,$05,$F0,$C8,$41,$04,$E0
00EBD8 1 C8 41 04 E0
00EBDC 1
00EBDC 1 ; ============================================================================
00EBDC 1 ; $EBDC-$EBFB
00EBDC 1 ; Structured rendering or animation data, continued.
00EBDC 1 ;
00EBDC 1 ; The repeating $41 values and surrounding control-like fields suggest compact
00EBDC 1 ; rendering records, but the record boundaries remain unverified. Preserve the
00EBDC 1 ; exact raw byte layout.
00EBDC 1 ; ============================================================================
00EBDC 1
00EBDC 1 RenderingData_EBDC: ; $EBDC
00EBDC 1 C9 41 FC E8 .byte $C9,$41,$FC,$E8,$CA,$41,$FC,$F0
00EBE0 1 CA 41 FC F0
00EBE4 1 CB 41 FC F8 .byte $CB,$41,$FC,$F8,$CC,$41,$FC,$04
00EBE8 1 CC 41 FC 04
00EBEC 1 F0 CD 41 04 .byte $F0,$CD,$41,$04,$E8,$CE,$41,$FC
00EBF0 1 E8 CE 41 FC
00EBF4 1 F0 CF 41 FC .byte $F0,$CF,$41,$FC,$F8,$D0,$41,$FC
00EBF8 1 F8 D0 41 FC
00EBFC 1
00EBFC 1 ; ============================================================================
00EBFC 1 ; $EBFC-$EC1B
00EBFC 1 ; Structured rendering or animation data, continued.
00EBFC 1 ;
00EBFC 1 ; This block retains the same compact record pattern seen in the preceding
00EBFC 1 ; region. Preserve the raw bytes until the consuming renderer reveals the
00EBFC 1 ; exact record boundaries and field meanings.
00EBFC 1 ; ============================================================================
00EBFC 1
00EBFC 1 RenderingData_EBFC: ; $EBFC
00EBFC 1 05 E8 D1 41 .byte $05,$E8,$D1,$41,$FC,$F0,$D2,$41
00EC00 1 FC F0 D2 41
00EC04 1 FC F8 D3 41 .byte $FC,$F8,$D3,$41,$FC,$F0,$D4,$41
00EC08 1 FC F0 D4 41
00EC0C 1 F4 F6 D5 41 .byte $F4,$F6,$D5,$41,$EC,$05,$E8,$D7
00EC10 1 EC 05 E8 D7
00EC14 1 41 FC F0 D8 .byte $41,$FC,$F0,$D8,$41,$FC,$F8,$D9
00EC18 1 41 FC F8 D9
00EC1C 1
00EC1C 1 ; ============================================================================
00EC1C 1 ; Resume untouched PRG-ROM at file offset $2C1C.
00EC1C 1 ;
00EC1C 1 ; CPU data range: $EBFC-$EC1B
00EC1C 1 ; ROM data range: $2BFC-$2C1B
00EC1C 1 ; Length decoded: $0020 bytes
00EC1C 1 ;
00EC1C 1 ; $4000 - $2C1C = $13E4 bytes remaining.
00EC1C 1 ;
00EC1C 1 ; The structured data continues at CPU $EC1C.
00EC1C 1 ; ============================================================================
00EC1C 1 ; $EC1C-$F9CF
00EC1C 1 ; Structured rendering, animation, sprite, text, and lookup data.
00EC1C 1 ;
00EC1C 1 ; This continues the record data beginning at $EBBC. The region contains many
00EC1C 1 ; repeating compact record formats, including:
00EC1C 1 ;
00EC1C 1 ; - animation frame descriptions
00EC1C 1 ; - sprite coordinate and attribute records
00EC1C 1 ; - display and text data
00EC1C 1 ; - pointer and lookup tables
00EC1C 1 ; - unused $FF padding near the end
00EC1C 1 ;
00EC1C 1 ; No reliable executable entry point occurs inside this range. Preserve the
00EC1C 1 ; bytes directly until all consuming routines and record formats are mapped.
00EC1C 1 ;
00EC1C 1 ; CPU range:
00EC1C 1 ; $EC1C-$F9CF
00EC1C 1 ;
00EC1C 1 ; ROM range:
00EC1C 1 ; $2C1C-$39CF
00EC1C 1 ;
00EC1C 1 ; Length:
00EC1C 1 ; $39D0 - $2C1C = $0DB4 bytes
00EC1C 1 ; ============================================================================
00EC1C 1
00EC1C 1 RenderingAndAnimationData_EC1C:
00EC1C 1 ; ============================================================================
00EC1C 1 ; $EC1C-$F9CF
00EC1C 1 ; Structured rendering, animation, sprite, text, and lookup data.
00EC1C 1 ;
00EC1C 1 ; This region has no executable entry points. The only confirmed direct code
00EC1C 1 ; reference is FrameOamTemplate_F94D, copied as 88 bytes into OAM shadow RAM
00EC1C 1 ; by CopyTransitionOamTemplate at $C2E6.
00EC1C 1 ;
00EC1C 1 ; Record boundaries outside the confirmed OAM template remain provisional, so
00EC1C 1 ; the bytes are preserved explicitly without assigning unsupported semantics.
00EC1C 1 ; ============================================================================
00EC1C 1
00EC1C 1 ; Explicit bytes begin at CPU $EC1C.
00EC1C 1 41 FC F0 DA .byte $41,$FC,$F0,$DA,$41,$F4,$F0,$DB,$41,$EC,$05,$E8,$DC,$41,$FC,$F0 ; $EC1C
00EC20 1 41 F4 F0 DB
00EC24 1 41 EC 05 E8
00EC2C 1 DD 41 FC F8 .byte $DD,$41,$FC,$F8,$DE,$41,$FC,$E8,$DF,$41,$F4,$E5,$E0,$41,$EC,$05 ; $EC2C
00EC30 1 DE 41 FC E8
00EC34 1 DF 41 F4 E5
00EC3C 1 E8 E2 41 04 .byte $E8,$E2,$41,$04,$F0,$E3,$41,$04,$E8,$E4,$41,$FC,$F0,$DD,$41,$FC ; $EC3C
00EC40 1 F0 E3 41 04
00EC44 1 E8 E4 41 FC
00EC4C 1 F8 DE 41 FC .byte $F8,$DE,$41,$FC,$00,$05,$E8,$A5,$40,$00,$F0,$A0,$40,$00,$F8,$A1 ; $EC4C
00EC50 1 00 05 E8 A5
00EC54 1 40 00 F0 A0
00EC5C 1 40 FB E8 A6 .byte $40,$FB,$E8,$A6,$40,$F8,$F0,$A3,$40,$F8,$04,$E8,$9F,$40,$FC,$F0 ; $EC5C
00EC60 1 40 F8 F0 A3
00EC64 1 40 F8 04 E8
00EC6C 1 A0 40 00 F8 .byte $A0,$40,$00,$F8,$A1,$40,$FB,$F0,$A3,$40,$F8,$05,$E8,$A7,$40,$00 ; $EC6C
00EC70 1 A1 40 FB F0
00EC74 1 A3 40 F8 05
00EC7C 1 F0 A8 40 00 .byte $F0,$A8,$40,$00,$F8,$A9,$40,$FA,$E8,$AA,$40,$F8,$F0,$AB,$40,$F8 ; $EC7C
00EC80 1 F8 A9 40 FA
00EC84 1 E8 AA 40 F8
00EC8C 1 05 E8 AD 40 .byte $05,$E8,$AD,$40,$00,$F0,$A8,$40,$00,$F8,$A9,$40,$FA,$E8,$AE,$40 ; $EC8C
00EC90 1 00 F0 A8 40
00EC94 1 00 F8 A9 40
00EC9C 1 F8 F0 AB 40 .byte $F8,$F0,$AB,$40,$F8,$05,$F3,$C1,$40,$04,$E8,$C3,$40,$FC,$F0,$C4 ; $EC9C
00ECA0 1 F8 05 F3 C1
00ECA4 1 40 04 E8 C3
00ECAC 1 40 FC F8 C5 .byte $40,$FC,$F8,$C5,$40,$FC,$EB,$C6,$40,$F4,$05,$EC,$93,$40,$04,$E8 ; $ECAC
00ECB0 1 40 FC EB C6
00ECB4 1 40 F4 05 EC
00ECBC 1 C3 00 FC F0 .byte $C3,$00,$FC,$F0,$94,$40,$FC,$F8,$C5,$00,$FC,$F3,$C1,$00,$F4,$06 ; $ECBC
00ECC0 1 94 40 FC F8
00ECC4 1 C5 00 FC F3
00ECCC 1 EC AF 40 04 .byte $EC,$AF,$40,$04,$F8,$B0,$40,$04,$EC,$B2,$40,$FC,$F4,$B3,$40,$FC ; $ECCC
00ECD0 1 F8 B0 40 04
00ECD4 1 EC B2 40 FC
00ECDC 1 FC B4 40 FC .byte $FC,$B4,$40,$FC,$F4,$B5,$40,$F4,$06,$EC,$AF,$40,$04,$F4,$B6,$40 ; $ECDC
00ECE0 1 F4 B5 40 F4
00ECE4 1 06 EC AF 40
00ECEC 1 04 EC B2 40 .byte $04,$EC,$B2,$40,$FC,$F4,$B3,$40,$FC,$FC,$B4,$40,$FC,$F4,$B5,$40 ; $ECEC
00ECF0 1 FC F4 B3 40
00ECF4 1 FC FC B4 40
00ECFC 1 F4 04 EC B7 .byte $F4,$04,$EC,$B7 ; $ECFC
00ED00 1
00ED00 1 RenderingAnimationData_ED00: ; $ED00
00ED00 1 40 04 EC B8 .byte $40,$04,$EC,$B8,$40,$FC,$F4,$B9,$40,$FC,$FC,$BA,$40,$FC,$05,$F0 ; $ED00
00ED04 1 40 FC F4 B9
00ED08 1 40 FC FC BA
00ED10 1 BB 40 FC F8 .byte $BB,$40,$FC,$F8,$BC,$40,$00,$00,$BD,$40,$00,$F8,$BF,$40,$F8,$00 ; $ED10
00ED14 1 BC 40 00 00
00ED18 1 BD 40 00 F8
00ED20 1 C0 40 F8 05 .byte $C0,$40,$F8,$05,$E8,$E7,$40,$00,$F0,$E8,$40,$00,$F8,$A9,$40,$FA ; $ED20
00ED24 1 E8 E7 40 00
00ED28 1 F0 E8 40 00
00ED30 1 E8 AA 40 F8 .byte $E8,$AA,$40,$F8,$F0,$E9,$40,$F8,$00,$05,$F0,$C8,$01,$F4,$E0,$C9 ; $ED30
00ED34 1 F0 E9 40 F8
00ED38 1 00 05 F0 C8
00ED40 1 01 FC E8 CA .byte $01,$FC,$E8,$CA,$01,$FC,$F0,$CB,$01,$FC,$F8,$CC,$01,$FC,$04,$F0 ; $ED40
00ED44 1 01 FC F0 CB
00ED48 1 01 FC F8 CC
00ED50 1 CD 01 F4 E8 .byte $CD,$01,$F4,$E8,$CE,$01,$FC,$F0,$CF,$01,$FC,$F8,$D0,$01,$FC,$05 ; $ED50
00ED54 1 CE 01 FC F0
00ED58 1 CF 01 FC F8
00ED60 1 E8 D1 01 FC .byte $E8,$D1,$01,$FC,$F0,$D2,$01,$FC,$F8,$D3,$01,$FC,$F0,$D4,$01,$04 ; $ED60
00ED64 1 F0 D2 01 FC
00ED68 1 F8 D3 01 FC
00ED70 1 F6 D5 01 0C .byte $F6,$D5,$01,$0C,$05,$E8,$D7,$01,$FC,$F0,$D8,$01,$FC,$F8,$D9,$01 ; $ED70
00ED74 1 05 E8 D7 01
00ED78 1 FC F0 D8 01
00ED80 1 FC F0 DA 01 .byte $FC,$F0,$DA,$01,$04,$F0,$DB,$01,$0C,$05,$E8,$DC,$01,$FC,$F0,$DD ; $ED80
00ED84 1 04 F0 DB 01
00ED88 1 0C 05 E8 DC
00ED90 1 01 FC F8 DE .byte $01,$FC,$F8,$DE,$01,$FC,$E8,$DF,$01,$04,$E5,$E0,$01,$0C,$05,$E8 ; $ED90
00ED94 1 01 FC E8 DF
00ED98 1 01 04 E5 E0
00EDA0 1 E2 01 F4 F0 .byte $E2,$01,$F4,$F0,$E3,$01,$F4,$E8,$E4,$01,$FC,$F0,$DD,$01,$FC,$F8 ; $EDA0
00EDA4 1 E3 01 F4 E8
00EDA8 1 E4 01 FC F0
00EDB0 1 DE 01 FC 00 .byte $DE,$01,$FC,$00,$05,$E8,$A5,$00,$F8,$F0,$A0,$00,$F8,$F8,$A1,$00 ; $EDB0
00EDB4 1 05 E8 A5 00
00EDB8 1 F8 F0 A0 00
00EDC0 1 FD E8 A6 00 .byte $FD,$E8,$A6,$00,$00,$F0,$A3,$00,$00,$04,$E8,$9F,$00,$FC,$F0,$A0 ; $EDC0
00EDC4 1 00 F0 A3 00
00EDC8 1 00 04 E8 9F
00EDD0 1 00 F8 F8 A1 .byte $00,$F8,$F8,$A1,$00,$FD,$F0,$A3,$00,$00,$05,$E8,$A7,$00,$F8,$F0 ; $EDD0
00EDD4 1 00 FD F0 A3
00EDD8 1 00 00 05 E8
00EDE0 1 A8 00 F8 F8 .byte $A8,$00,$F8,$F8,$A9,$00,$FE,$E8,$AA,$00,$00,$F0,$AB,$00,$00,$05 ; $EDE0
00EDE4 1 A9 00 FE E8
00EDE8 1 AA 00 00 F0
00EDF0 1 E8 AD 00 F8 .byte $E8,$AD,$00,$F8,$F0,$A8,$00,$F8,$F8,$A9,$00,$FE,$E8,$AE,$00,$00 ; $EDF0
00EDF4 1 F0 A8 00 F8
00EDF8 1 F8 A9 00 FE
00EE00 1
00EE00 1 RenderingAnimationData_EE00: ; $EE00
00EE00 1 F0 AB 00 00 .byte $F0,$AB,$00,$00,$05,$EC,$93,$00,$EC,$E8,$C3,$40,$F4,$F0,$94,$00 ; $EE00
00EE04 1 05 EC 93 00
00EE08 1 EC E8 C3 40
00EE10 1 F4 F8 C5 40 .byte $F4,$F8,$C5,$40,$F4,$F3,$C1,$40,$FC,$05,$F1,$C1,$00,$F4,$E6,$C3 ; $EE10
00EE14 1 F4 F3 C1 40
00EE18 1 FC 05 F1 C1
00EE20 1 00 FC EE C4 .byte $00,$FC,$EE,$C4,$00,$FC,$F6,$C5,$00,$FC,$E9,$C6,$00,$04,$06,$EC ; $EE20
00EE24 1 00 FC F6 C5
00EE28 1 00 FC E9 C6
00EE30 1 AF 00 F4 F8 .byte $AF,$00,$F4,$F8,$B0,$00,$F4,$EC,$B2,$00,$FC,$F4,$B3,$00,$FC,$FC ; $EE30
00EE34 1 B0 00 F4 EC
00EE38 1 B2 00 FC F4
00EE40 1 B4 00 FC F4 .byte $B4,$00,$FC,$F4,$B5,$00,$04,$06,$EC,$AF,$00,$F4,$F4,$B6,$00,$F4 ; $EE40
00EE44 1 B5 00 04 06
00EE48 1 EC AF 00 F4
00EE50 1 EC B2 00 FC .byte $EC,$B2,$00,$FC,$F4,$B3,$00,$FC,$FC,$B4,$00,$FC,$F4,$B5,$00,$04 ; $EE50
00EE54 1 F4 B3 00 FC
00EE58 1 FC B4 00 FC
00EE60 1 04 EC B7 00 .byte $04,$EC,$B7,$00,$F4,$EC,$B8,$00,$FC,$F4,$B9,$00,$FC,$FC,$BA,$00 ; $EE60
00EE64 1 F4 EC B8 00
00EE68 1 FC F4 B9 00
00EE70 1 FC 05 F0 BB .byte $FC,$05,$F0,$BB,$00,$FC,$F8,$BC,$00,$F8,$00,$BD,$00,$F8,$F8,$BF ; $EE70
00EE74 1 00 FC F8 BC
00EE78 1 00 F8 00 BD
00EE80 1 00 00 00 C0 .byte $00,$00,$00,$C0,$00,$00,$05,$E8,$E7,$00,$F8,$F0,$E8,$00,$F8,$F8 ; $EE80
00EE84 1 00 00 05 E8
00EE88 1 E7 00 F8 F0
00EE90 1 A9 00 FE E8 .byte $A9,$00,$FE,$E8,$AA,$00,$00,$F0,$E9,$00,$00,$00,$04,$F0,$68,$40 ; $EE90
00EE94 1 AA 00 00 F0
00EE98 1 E9 00 00 00
00EEA0 1 F8 F8 69 40 .byte $F8,$F8,$69,$40,$F8,$F0,$68,$00,$00,$F8,$69,$00,$00,$06,$E8,$6A ; $EEA0
00EEA4 1 F8 F0 68 00
00EEA8 1 00 F8 69 00
00EEB0 1 40 F8 F0 6B .byte $40,$F8,$F0,$6B,$40,$F8,$F8,$6C,$40,$F8,$E8,$6D,$00,$00,$F0,$6E ; $EEB0
00EEB4 1 40 F8 F8 6C
00EEB8 1 40 F8 E8 6D
00EEC0 1 00 00 F8 6F .byte $00,$00,$F8,$6F,$00,$00,$06,$E8,$6A,$40,$F8,$F0,$6B,$40,$F8,$F8 ; $EEC0
00EEC4 1 00 00 06 E8
00EEC8 1 6A 40 F8 F0
00EED0 1 6C 40 F8 E8 .byte $6C,$40,$F8,$E8,$6A,$00,$00,$F0,$6B,$00,$00,$F8,$6C,$00,$00,$05 ; $EED0
00EED4 1 6A 00 00 F0
00EED8 1 6B 00 00 F8
00EEE0 1 F1 97 00 F8 .byte $F1,$97,$00,$F8,$F9,$7E,$00,$F8,$E9,$98,$00,$FE,$F1,$10,$00,$00 ; $EEE0
00EEE4 1 F9 7E 00 F8
00EEE8 1 E9 98 00 FE
00EEF0 1 F9 81 00 00 .byte $F9,$81,$00,$00,$05,$F0,$11,$00,$F8,$F8,$83,$00,$F8,$E8,$98,$00 ; $EEF0
00EEF4 1 05 F0 11 00
00EEF8 1 F8 F8 83 00
00EF00 1
00EF00 1 RenderingAnimationData_EF00: ; $EF00
00EF00 1 FE F0 12 00 .byte $FE,$F0,$12,$00,$00,$F8,$8E,$00,$00,$05,$F0,$13,$00,$F8,$F8,$90 ; $EF00
00EF04 1 00 F8 8E 00
00EF08 1 00 05 F0 13
00EF10 1 00 F8 E8 98 .byte $00,$F8,$E8,$98,$00,$FE,$F0,$14,$00,$00,$F8,$92,$00,$00,$05,$F1 ; $EF10
00EF14 1 00 FE F0 14
00EF18 1 00 00 F8 92
00EF20 1 97 40 00 F9 .byte $97,$40,$00,$F9,$7E,$40,$00,$E9,$98,$40,$FA,$F1,$10,$40,$F8,$F9 ; $EF20
00EF24 1 7E 40 00 E9
00EF28 1 98 40 FA F1
00EF30 1 81 40 F8 05 .byte $81,$40,$F8,$05,$F0,$11,$40,$00,$F8,$83,$40,$00,$E8,$98,$40,$FA ; $EF30
00EF34 1 F0 11 40 00
00EF38 1 F8 83 40 00
00EF40 1 F0 12 40 F8 .byte $F0,$12,$40,$F8,$F8,$8E,$40,$F8,$05,$F0,$13,$40,$00,$F8,$90,$40 ; $EF40
00EF44 1 F8 8E 40 F8
00EF48 1 05 F0 13 40
00EF50 1 00 E8 98 40 .byte $00,$E8,$98,$40,$FA,$F0,$14,$40,$F8,$F8,$92,$40,$F8,$05,$F1,$7D ; $EF50
00EF54 1 FA F0 14 40
00EF58 1 F8 F8 92 40
00EF60 1 01 F8 F9 7E .byte $01,$F8,$F9,$7E,$01,$F8,$E9,$7F,$01,$00,$F1,$80,$01,$00,$F9,$81 ; $EF60
00EF64 1 01 F8 E9 7F
00EF68 1 01 00 F1 80
00EF70 1 01 00 05 F0 .byte $01,$00,$05,$F0,$82,$01,$F8,$F8,$83,$01,$F8,$E8,$7F,$01,$00,$F0 ; $EF70
00EF74 1 82 01 F8 F8
00EF78 1 83 01 F8 E8
00EF80 1 8D 01 00 F8 .byte $8D,$01,$00,$F8,$8E,$01,$00,$05,$F0,$8F,$01,$F8,$F8,$90,$01,$F8 ; $EF80
00EF84 1 8E 01 00 05
00EF88 1 F0 8F 01 F8
00EF90 1 E8 7F 01 00 .byte $E8,$7F,$01,$00,$F0,$91,$01,$00,$F8,$92,$01,$00,$04,$F0,$89,$01 ; $EF90
00EF94 1 F0 91 01 00
00EF98 1 F8 92 01 00
00EFA0 1 F8 F8 8A 01 .byte $F8,$F8,$8A,$01,$F8,$F0,$8B,$01,$00,$F8,$8C,$01,$00,$05,$F1,$7D ; $EFA0
00EFA4 1 F8 F0 8B 01
00EFA8 1 00 F8 8C 01
00EFB0 1 41 00 F9 7E .byte $41,$00,$F9,$7E,$41,$00,$E9,$7F,$41,$F8,$F1,$80,$41,$F8,$F9,$81 ; $EFB0
00EFB4 1 41 00 E9 7F
00EFB8 1 41 F8 F1 80
00EFC0 1 41 F8 05 F0 .byte $41,$F8,$05,$F0,$82,$41,$00,$F8,$83,$41,$00,$E8,$7F,$41,$F8,$F0 ; $EFC0
00EFC4 1 82 41 00 F8
00EFC8 1 83 41 00 E8
00EFD0 1 8D 41 F8 F8 .byte $8D,$41,$F8,$F8,$8E,$41,$F8,$05,$F0,$8F,$41,$00,$F8,$90,$41,$00 ; $EFD0
00EFD4 1 8E 41 F8 05
00EFD8 1 F0 8F 41 00
00EFE0 1 E8 7F 41 F8 .byte $E8,$7F,$41,$F8,$F0,$91,$41,$F8,$F8,$92,$41,$F8,$05,$F8,$99,$01 ; $EFE0
00EFE4 1 F0 91 41 F8
00EFE8 1 F8 92 41 F8
00EFF0 1 F4 F8 9A 01 .byte $F4,$F8,$9A,$01,$FC,$F0,$9B,$01,$04,$F8,$9C,$01,$04,$F8,$9D,$03 ; $EFF0
00EFF4 1 FC F0 9B 01
00EFF8 1 04 F8 9C 01
00F000 1
00F000 1 RenderingAnimationData_F000: ; $F000
00F000 1 0C 05 F8 99 .byte $0C,$05,$F8,$99,$01,$F4,$F8,$9A,$01,$FC,$F0,$9B,$01,$04,$F8,$9C ; $F000
00F004 1 01 F4 F8 9A
00F008 1 01 FC F0 9B
00F010 1 01 04 F8 9E .byte $01,$04,$F8,$9E,$03,$14,$05,$F0,$70,$41,$00,$F8,$71,$41,$00,$E8 ; $F010
00F014 1 03 14 05 F0
00F018 1 70 41 00 F8
00F020 1 72 41 F8 F0 .byte $72,$41,$F8,$F0,$73,$41,$F8,$F8,$74,$41,$F8,$05,$F0,$75,$41,$00 ; $F020
00F024 1 73 41 F8 F8
00F028 1 74 41 F8 05
00F030 1 F8 76 41 00 .byte $F8,$76,$41,$00,$E8,$72,$41,$F8,$F0,$77,$41,$F8,$F8,$78,$41,$F8 ; $F030
00F034 1 E8 72 41 F8
00F038 1 F0 77 41 F8
00F040 1 05 F1 79 41 .byte $05,$F1,$79,$41,$00,$F9,$7A,$41,$00,$E9,$72,$41,$F8,$F1,$7B,$41 ; $F040
00F044 1 00 F9 7A 41
00F048 1 00 E9 72 41
00F050 1 F8 F9 7C 41 .byte $F8,$F9,$7C,$41,$F8,$05,$E8,$84,$01,$F8,$F0,$85,$01,$F8,$F8,$86 ; $F050
00F054 1 F8 05 E8 84
00F058 1 01 F8 F0 85
00F060 1 01 F8 F0 87 .byte $01,$F8,$F0,$87,$01,$00,$F8,$88,$01,$00,$05,$F0,$70,$01,$F8,$F8 ; $F060
00F064 1 01 00 F8 88
00F068 1 01 00 05 F0
00F070 1 71 01 F8 E8 .byte $71,$01,$F8,$E8,$72,$01,$00,$F0,$73,$01,$00,$F8,$74,$01,$00,$05 ; $F070
00F074 1 72 01 00 F0
00F078 1 73 01 00 F8
00F080 1 F0 75 01 F8 .byte $F0,$75,$01,$F8,$F8,$76,$01,$F8,$E8,$72,$01,$00,$F0,$77,$01,$00 ; $F080
00F084 1 F8 76 01 F8
00F088 1 E8 72 01 00
00F090 1 F8 78 01 00 .byte $F8,$78,$01,$00,$05,$F1,$79,$01,$F8,$F9,$7A,$01,$F8,$E9,$72,$01 ; $F090
00F094 1 05 F1 79 01
00F098 1 F8 F9 7A 01
00F0A0 1 00 F1 7B 01 .byte $00,$F1,$7B,$01,$00,$F9,$7C,$01,$00,$04,$F0,$5B,$00,$F8,$F8,$5C ; $F0A0
00F0A4 1 00 F9 7C 01
00F0A8 1 00 04 F0 5B
00F0B0 1 00 F8 F0 5D .byte $00,$F8,$F0,$5D,$00,$00,$F8,$5E,$00,$00,$04,$F0,$5B,$40,$00,$F8 ; $F0B0
00F0B4 1 00 00 F8 5E
00F0B8 1 00 00 04 F0
00F0C0 1 5C 40 00 F0 .byte $5C,$40,$00,$F0,$5D,$40,$F8,$F8,$5E,$40,$F8,$04,$F0,$5F,$00,$F8 ; $F0C0
00F0C4 1 5D 40 F8 F8
00F0C8 1 5E 40 F8 04
00F0D0 1 F8 60 00 F8 .byte $F8,$60,$00,$F8,$F0,$61,$00,$00,$F8,$62,$00,$00,$05,$F0,$63,$00 ; $F0D0
00F0D4 1 F0 61 00 00
00F0D8 1 F8 62 00 00
00F0E0 1 F0 F0 64 00 .byte $F0,$F0,$64,$00,$F8,$F8,$65,$00,$F8,$F0,$66,$00,$00,$F8,$67,$00 ; $F0E0
00F0E4 1 F8 F8 65 00
00F0E8 1 F8 F0 66 00
00F0F0 1 00 05 F0 63 .byte $00,$05,$F0,$63,$40,$08,$F0,$64,$40,$00,$F8,$65,$40,$00,$F0,$66 ; $F0F0
00F0F4 1 40 08 F0 64
00F0F8 1 40 00 F8 65
00F100 1
00F100 1 RenderingAnimationData_F100: ; $F100
00F100 1 40 F8 F8 67 .byte $40,$F8,$F8,$67,$40,$F8,$04,$F0,$44,$00,$F8,$F8,$95,$00,$F8,$F0 ; $F100
00F104 1 40 F8 04 F0
00F108 1 44 00 F8 F8
00F110 1 46 00 00 F8 .byte $46,$00,$00,$F8,$96,$00,$00,$04,$F0,$40,$00,$F8,$F8,$41,$00,$F8 ; $F110
00F114 1 96 00 00 04
00F118 1 F0 40 00 F8
00F120 1 F0 42 00 00 .byte $F0,$42,$00,$00,$F8,$43,$00,$00,$04,$F0,$44,$00,$F8,$F8,$45,$00 ; $F120
00F124 1 F8 43 00 00
00F128 1 04 F0 44 00
00F130 1 F8 F0 46 00 .byte $F8,$F0,$46,$00,$00,$F8,$47,$00,$00,$05,$F1,$97,$00,$F8,$F9,$7E ; $F130
00F134 1 00 F8 47 00
00F138 1 00 05 F1 97
00F140 1 00 F8 E9 7F .byte $00,$F8,$E9,$7F,$00,$00,$F1,$10,$00,$00,$F9,$81,$00,$00,$05,$F0 ; $F140
00F144 1 00 00 F1 10
00F148 1 00 00 F9 81
00F150 1 11 00 F8 F8 .byte $11,$00,$F8,$F8,$83,$00,$F8,$E8,$7F,$00,$00,$F0,$12,$00,$00,$F8 ; $F150
00F154 1 83 00 F8 E8
00F158 1 7F 00 00 F0
00F160 1 8E 00 00 05 .byte $8E,$00,$00,$05,$F0,$13,$00,$F8,$F8,$90,$00,$F8,$E8,$7F,$00,$00 ; $F160
00F164 1 F0 13 00 F8
00F168 1 F8 90 00 F8
00F170 1 F0 14 00 00 .byte $F0,$14,$00,$00,$F8,$92,$00,$00,$05,$F1,$97,$40,$00,$F9,$7E,$40 ; $F170
00F174 1 F8 92 00 00
00F178 1 05 F1 97 40
00F180 1 00 E9 7F 40 .byte $00,$E9,$7F,$40,$F8,$F1,$10,$40,$F8,$F9,$81,$40,$F8,$05,$F0,$11 ; $F180
00F184 1 F8 F1 10 40
00F188 1 F8 F9 81 40
00F190 1 40 00 F8 83 .byte $40,$00,$F8,$83,$40,$00,$E8,$7F,$40,$F8,$F0,$12,$40,$F8,$F8,$8E ; $F190
00F194 1 40 00 E8 7F
00F198 1 40 F8 F0 12
00F1A0 1 40 F8 05 F0 .byte $40,$F8,$05,$F0,$13,$40,$00,$F8,$90,$40,$00,$E8,$7F,$40,$F8,$F0 ; $F1A0
00F1A4 1 13 40 00 F8
00F1A8 1 90 40 00 E8
00F1B0 1 14 40 F8 F8 .byte $14,$40,$F8,$F8,$92,$40,$F8,$05,$F0,$15,$40,$00,$F8,$71,$40,$00 ; $F1B0
00F1B4 1 92 40 F8 05
00F1B8 1 F0 15 40 00
00F1C0 1 E8 72 40 F8 .byte $E8,$72,$40,$F8,$F0,$E5,$40,$F8,$F8,$74,$40,$F8,$05,$F0,$15,$40 ; $F1C0
00F1C4 1 F0 E5 40 F8
00F1C8 1 F8 74 40 F8
00F1D0 1 00 F8 76 40 .byte $00,$F8,$76,$40,$00,$E8,$72,$40,$F8,$F0,$E5,$40,$F8,$F8,$78,$40 ; $F1D0
00F1D4 1 00 E8 72 40
00F1D8 1 F8 F0 E5 40
00F1E0 1 F8 05 F1 79 .byte $F8,$05,$F1,$79,$40,$00,$F9,$7A,$40,$00,$E9,$72,$40,$F8,$F1,$E6 ; $F1E0
00F1E4 1 40 00 F9 7A
00F1E8 1 40 00 E9 72
00F1F0 1 40 F8 F9 7C .byte $40,$F8,$F9,$7C,$40,$F8,$05,$F0,$15,$00,$F8,$F8,$71,$00,$F8,$E8 ; $F1F0
00F1F4 1 40 F8 05 F0
00F1F8 1 15 00 F8 F8
00F200 1
00F200 1 RenderingAnimationData_F200: ; $F200
00F200 1 72 00 00 F0 .byte $72,$00,$00,$F0,$E5,$00,$00,$F8,$74,$00,$00,$05,$F0,$15,$00,$F8 ; $F200
00F204 1 E5 00 00 F8
00F208 1 74 00 00 05
00F210 1 F8 76 00 F8 .byte $F8,$76,$00,$F8,$E8,$72,$00,$00,$F0,$E5,$00,$00,$F8,$78,$00,$00 ; $F210
00F214 1 E8 72 00 00
00F218 1 F0 E5 00 00
00F220 1 05 F1 79 00 .byte $05,$F1,$79,$00,$F8,$F9,$7A,$00,$F8,$E9,$72,$00,$00,$F1,$E6,$00 ; $F220
00F224 1 F8 F9 7A 00
00F228 1 F8 E9 72 00
00F230 1 00 F9 7C 00 .byte $00,$F9,$7C,$00,$00,$04,$F0,$48,$00,$F8,$F8,$49,$00,$F8,$F0,$4A ; $F230
00F234 1 00 04 F0 48
00F238 1 00 F8 F8 49
00F240 1 00 00 F8 4B .byte $00,$00,$F8,$4B,$00,$00,$04,$F0,$4C,$00,$F8,$F8,$4D,$00,$F8,$F0 ; $F240
00F244 1 00 00 04 F0
00F248 1 4C 00 F8 F8
00F250 1 4E 00 00 F8 .byte $4E,$00,$00,$F8,$4F,$00,$00,$04,$F0,$4C,$40,$00,$F8,$4D,$40,$00 ; $F250
00F254 1 4F 00 00 04
00F258 1 F0 4C 40 00
00F260 1 F0 4E 40 F8 .byte $F0,$4E,$40,$F8,$F8,$4F,$40,$F8,$05,$F0,$50,$00,$F8,$F8,$51,$00 ; $F260
00F264 1 F8 4F 40 F8
00F268 1 05 F0 50 00
00F270 1 F8 E8 52 00 .byte $F8,$E8,$52,$00,$00,$F0,$53,$00,$00,$F8,$54,$00,$00,$05,$F0,$50 ; $F270
00F274 1 00 F0 53 00
00F278 1 00 F8 54 00
00F280 1 00 F8 F8 55 .byte $00,$F8,$F8,$55,$00,$F8,$E8,$52,$00,$00,$F0,$53,$00,$00,$F8,$56 ; $F280
00F284 1 00 F8 E8 52
00F288 1 00 00 F0 53
00F290 1 00 00 04 F0 .byte $00,$00,$04,$F0,$84,$00,$F8,$F8,$85,$00,$F8,$F0,$86,$00,$00,$F8 ; $F290
00F294 1 84 00 F8 F8
00F298 1 85 00 F8 F0
00F2A0 1 87 00 00 04 .byte $87,$00,$00,$04,$F8,$57,$40,$04,$F0,$58,$40,$00,$F8,$59,$40,$00 ; $F2A0
00F2A4 1 F8 57 40 04
00F2A8 1 F0 58 40 00
00F2B0 1 F8 5A 40 F8 .byte $F8,$5A,$40,$F8,$06,$F0,$EA,$02,$F8,$F8,$EB,$02,$F8,$E8,$EC,$02 ; $F2B0
00F2B4 1 06 F0 EA 02
00F2B8 1 F8 F8 EB 02
00F2C0 1 00 F0 F0 02 .byte $00,$F0,$F0,$02,$00,$F8,$EE,$02,$00,$F0,$F1,$02,$08,$06,$F0,$EA ; $F2C0
00F2C4 1 00 F8 EE 02
00F2C8 1 00 F0 F1 02
00F2D0 1 02 F8 F8 EB .byte $02,$F8,$F8,$EB,$02,$F8,$E8,$EC,$02,$00,$F0,$F0,$02,$00,$F8,$EE ; $F2D0
00F2D4 1 02 F8 E8 EC
00F2D8 1 02 00 F0 F0
00F2E0 1 02 00 ED F2 .byte $02,$00,$ED,$F2,$02,$08,$04,$F0,$F4,$42,$F8,$F8,$F5,$42,$F8,$F0 ; $F2E0
00F2E4 1 02 08 04 F0
00F2E8 1 F4 42 F8 F8
00F2F0 1 F4 02 00 F8 .byte $F4,$02,$00,$F8,$F5,$02,$00,$04,$F0,$F6,$42,$F8,$F8,$F7,$42,$F8 ; $F2F0
00F2F4 1 F5 02 00 04
00F2F8 1 F0 F6 42 F8
00F300 1
00F300 1 RenderingAnimationData_F300: ; $F300
00F300 1 F0 F6 02 00 .byte $F0,$F6,$02,$00,$F8,$F7,$02,$00,$06,$F0,$EA,$02,$F8,$F8,$EB,$02 ; $F300
00F304 1 F8 F7 02 00
00F308 1 06 F0 EA 02
00F310 1 F8 E8 EC 02 .byte $F8,$E8,$EC,$02,$00,$F0,$ED,$02,$00,$F8,$EE,$02,$00,$F0,$EF,$02 ; $F310
00F314 1 00 F0 ED 02
00F318 1 00 F8 EE 02
00F320 1 08 04 F0 FC .byte $08,$04,$F0,$FC,$02,$F8,$F8,$FD,$02,$F8,$F0,$FE,$02,$00,$F8,$FF ; $F320
00F324 1 02 F8 F8 FD
00F328 1 02 F8 F0 FE
00F330 1 02 00 04 F0 .byte $02,$00,$04,$F0,$F8,$42,$F8,$F8,$F9,$42,$F8,$F0,$F8,$02,$00,$F8 ; $F330
00F334 1 F8 42 F8 F8
00F338 1 F9 42 F8 F0
00F340 1 F9 02 00 04 .byte $F9,$02,$00,$04,$F0,$FA,$42,$F8,$F8,$FB,$42,$F8,$F0,$FA,$02,$00 ; $F340
00F344 1 F0 FA 42 F8
00F348 1 F8 FB 42 F8
00F350 1 F8 FB 02 00 .byte $F8,$FB,$02,$00,$02,$F0,$1C,$01,$FC,$F8,$1D,$01,$FC,$02,$F0,$1E ; $F350
00F354 1 02 F0 1C 01
00F358 1 FC F8 1D 01
00F360 1 01 FC F8 1F .byte $01,$FC,$F8,$1F,$01,$FC,$02,$F0,$20,$01,$FC,$F8,$21,$01,$FC,$02 ; $F360
00F364 1 01 FC 02 F0
00F368 1 20 01 FC F8
00F370 1 F0 1C 41 FC .byte $F0,$1C,$41,$FC,$F8,$1D,$41,$FC,$02,$F0,$1E,$41,$FC,$F8,$1F,$41 ; $F370
00F374 1 F8 1D 41 FC
00F378 1 02 F0 1E 41
00F380 1 FC 02 F0 20 .byte $FC,$02,$F0,$20,$41,$FC,$F8,$21,$41,$FC,$02,$F0,$16,$41,$FC,$F8 ; $F380
00F384 1 41 FC F8 21
00F388 1 41 FC 02 F0
00F390 1 17 41 FC 02 .byte $17,$41,$FC,$02,$F0,$18,$41,$FC,$F8,$19,$41,$FC,$02,$F0,$1A,$41 ; $F390
00F394 1 F0 18 41 FC
00F398 1 F8 19 41 FC
00F3A0 1 FC F8 1B 41 .byte $FC,$F8,$1B,$41,$FC,$02,$F0,$16,$01,$FC,$F8,$17,$01,$FC,$02,$F0 ; $F3A0
00F3A4 1 FC 02 F0 16
00F3A8 1 01 FC F8 17
00F3B0 1 18 01 FC F8 .byte $18,$01,$FC,$F8,$19,$01,$FC,$02,$F0,$1A,$01,$FC,$F8,$1B,$01,$FC ; $F3B0
00F3B4 1 19 01 FC 02
00F3B8 1 F0 1A 01 FC
00F3C0 1 02 F0 24 00 .byte $02,$F0,$24,$00,$FC,$F8,$25,$00,$FC,$02,$F0,$22,$00,$FC,$F8,$23 ; $F3C0
00F3C4 1 FC F8 25 00
00F3C8 1 FC 02 F0 22
00F3D0 1 00 FC 02 F0 .byte $00,$FC,$02,$F0,$3D,$00,$FC,$F8,$3E,$00,$FC,$02,$F0,$00,$00,$FC ; $F3D0
00F3D4 1 3D 00 FC F8
00F3D8 1 3E 00 FC 02
00F3E0 1 F8 01 00 FC .byte $F8,$01,$00,$FC,$02,$F0,$02,$00,$FC,$F8,$03,$00,$FC,$02,$F0,$04 ; $F3E0
00F3E4 1 02 F0 02 00
00F3E8 1 FC F8 03 00
00F3F0 1 00 FC F8 05 .byte $00,$FC,$F8,$05,$00,$FC,$02,$F0,$06,$00,$FC,$F8,$07,$00,$FC,$02 ; $F3F0
00F3F4 1 00 FC 02 F0
00F3F8 1 06 00 FC F8
00F400 1
00F400 1 RenderingAnimationData_F400: ; $F400
00F400 1 F0 08 00 FC .byte $F0,$08,$00,$FC,$F8,$09,$00,$FC,$02,$F0,$0A,$40,$FC,$F8,$0B,$40 ; $F400
00F404 1 F8 09 00 FC
00F408 1 02 F0 0A 40
00F410 1 FC 02 F0 0C .byte $FC,$02,$F0,$0C,$40,$FC,$F8,$0D,$40,$FC,$02,$F0,$0E,$40,$FC,$F8 ; $F410
00F414 1 40 FC F8 0D
00F418 1 40 FC 02 F0
00F420 1 0F 40 FC 02 .byte $0F,$40,$FC,$02,$F0,$0A,$00,$FC,$F8,$0B,$00,$FC,$02,$F0,$0C,$00 ; $F420
00F424 1 F0 0A 00 FC
00F428 1 F8 0B 00 FC
00F430 1 FC F8 0D 00 .byte $FC,$F8,$0D,$00,$FC,$02,$F0,$0E,$00,$FC,$F8,$0F,$00,$FC,$02,$F0 ; $F430
00F434 1 FC 02 F0 0E
00F438 1 00 FC F8 0F
00F440 1 00 00 FC F8 .byte $00,$00,$FC,$F8,$3C,$00,$FC,$02,$F0,$28,$02,$FC,$F8,$29,$02,$FC ; $F440
00F444 1 3C 00 FC 02
00F448 1 F0 28 02 FC
00F450 1 02 F0 26 02 .byte $02,$F0,$26,$02,$FC,$F8,$27,$02,$FC,$02,$F0,$2A,$02,$FC,$F8,$2B ; $F450
00F454 1 FC F8 27 02
00F458 1 FC 02 F0 2A
00F460 1 02 FC 02 F0 .byte $02,$FC,$02,$F0,$2C,$02,$FC,$F8,$2D,$02,$FC,$02,$F0,$2E,$02,$FC ; $F460
00F464 1 2C 02 FC F8
00F468 1 2D 02 FC 02
00F470 1 F8 2D 02 FC .byte $F8,$2D,$02,$FC,$03,$F0,$31,$02,$FC,$F8,$32,$02,$FC,$F8,$33,$02 ; $F470
00F474 1 03 F0 31 02
00F478 1 FC F8 32 02
00F480 1 04 02 F0 2F .byte $04,$02,$F0,$2F,$02,$FC,$F8,$30,$02,$FC,$02,$F0,$34,$02,$FC,$F8 ; $F480
00F484 1 02 FC F8 30
00F488 1 02 FC 02 F0
00F490 1 35 02 FC 01 .byte $35,$02,$FC,$01,$F8,$36,$03,$00,$04,$FF,$36,$C3,$F8,$F7,$36,$43 ; $F490
00F494 1 F8 36 03 00
00F498 1 04 FF 36 C3
00F4A0 1 F8 FF 36 83 .byte $F8,$FF,$36,$83,$00,$F7,$36,$03,$00,$04,$FE,$37,$C3,$F8,$F6,$37 ; $F4A0
00F4A4 1 00 F7 36 03
00F4A8 1 00 04 FE 37
00F4B0 1 43 F8 FE 37 .byte $43,$F8,$FE,$37,$83,$00,$F6,$37,$03,$00,$01,$F9,$38,$03,$FD,$01 ; $F4B0
00F4B4 1 83 00 F6 37
00F4B8 1 03 00 01 F9
00F4C0 1 F8 39 03 FD .byte $F8,$39,$03,$FD,$04,$F0,$3A,$03,$F8,$F0,$3A,$43,$00,$F8,$3A,$83 ; $F4C0
00F4C4 1 04 F0 3A 03
00F4C8 1 F8 F0 3A 43
00F4D0 1 F8 F8 3A C3 .byte $F8,$F8,$3A,$C3,$00,$01,$F8,$36,$02,$00,$02,$F8,$36,$02,$00,$F8 ; $F4D0
00F4D4 1 00 01 F8 36
00F4D8 1 02 00 02 F8
00F4E0 1 36 42 F8 02 .byte $36,$42,$F8,$02,$F9,$37,$02,$00,$FF,$37,$C2,$F8,$01,$FE,$3B,$02 ; $F4E0
00F4E4 1 F9 37 02 00
00F4E8 1 FF 37 C2 F8
00F4F0 1 FC 00 3F 00 .byte $FC,$00,$3F,$00,$20,$30,$18,$1A,$07,$30,$01,$1A,$28,$30,$0F,$1A ; $F4F0
00F4F4 1 20 30 18 1A
00F4F8 1 07 30 01 1A
00F500 1
00F500 1 RenderingAnimationData_F500: ; $F500
00F500 1 30 30 0F 2C .byte $30,$30,$0F,$2C,$28,$30,$16,$27,$30,$30,$0F,$27,$30,$30,$11,$27 ; $F500
00F504 1 28 30 16 27
00F508 1 30 30 0F 27
00F510 1 0F 30 28 22 .byte $0F,$30,$28,$22,$30,$2B,$C0,$60,$00,$2B,$E0,$60,$00,$2B,$E8,$02 ; $F510
00F514 1 30 2B C0 60
00F518 1 00 2B E0 60
00F520 1 88 22 2B F0 .byte $88,$22,$2B,$F0,$02,$88,$22,$2B,$F5,$03,$88,$AA,$22,$2B,$E3,$42 ; $F520
00F524 1 02 88 22 2B
00F528 1 F5 03 88 AA
00F530 1 AA 23 E0 60 .byte $AA,$23,$E0,$60,$00,$23,$C0,$48,$FF,$23,$C8,$08,$5F,$5F,$5B,$5A ; $F530
00F534 1 00 23 C0 48
00F538 1 FF 23 C8 08
00F540 1 5A 5E 5F 5F .byte $5A,$5E,$5F,$5F,$23,$D0,$51,$55,$23,$DA,$44,$AA,$23,$E7,$01,$55 ; $F540
00F544 1 23 D0 51 55
00F548 1 23 DA 44 AA
00F550 1 23 F0 02 88 .byte $23,$F0,$02,$88,$22,$23,$F5,$03,$88,$AA,$22,$2A,$AD,$06,$B2,$34 ; $F550
00F554 1 22 23 F5 03
00F558 1 88 AA 22 2A
00F560 1 25 25 BD C0 .byte $25,$25,$BD,$C0,$2A,$CC,$08,$B0,$B3,$B6,$B9,$BB,$BE,$C1,$C4,$2A ; $F560
00F564 1 2A CC 08 B0
00F568 1 B3 B6 B9 BB
00F570 1 EB 0A B0 25 .byte $EB,$0A,$B0,$25,$B4,$B7,$BA,$BC,$21,$C2,$25,$C4,$2B,$0B,$0A,$25 ; $F570
00F574 1 B4 B7 BA BC
00F578 1 21 C2 25 C4
00F580 1 25 B5 B8 25 .byte $25,$B5,$B8,$25,$25,$BF,$C3,$25,$25,$2B,$2B,$0A,$B1,$25,$25,$B4 ; $F580
00F584 1 25 BF C3 25
00F588 1 25 2B 2B 0A
00F590 1 25 25 C2 25 .byte $25,$25,$C2,$25,$25,$C5,$2B,$4C,$08,$B1,$25,$B5,$C6,$C6,$C3,$25 ; $F590
00F594 1 25 C5 2B 4C
00F598 1 08 B1 25 B5
00F5A0 1 C5 2B 6D 06 .byte $C5,$2B,$6D,$06,$B1,$25,$25,$25,$25,$C5,$29,$4E,$04,$CB,$CC,$CD ; $F5A0
00F5A4 1 B1 25 25 25
00F5A8 1 25 C5 29 4E
00F5B0 1 CE 29 6E 04 .byte $CE,$29,$6E,$04,$CF,$27,$27,$D0,$29,$8E,$04,$D1,$D2,$D3,$D4,$29 ; $F5B0
00F5B4 1 CF 27 27 D0
00F5B8 1 29 8E 04 D1
00F5C0 1 77 06 FE FF .byte $77,$06,$FE,$FF,$DF,$E0,$C9,$CA,$29,$98,$05,$E1,$E2,$E3,$E4,$D8 ; $F5C0
00F5C4 1 DF E0 C9 CA
00F5C8 1 29 98 05 E1
00F5D0 1 29 B8 05 E5 .byte $29,$B8,$05,$E5,$E6,$E7,$E8,$E9,$29,$D8,$04,$C9,$EA,$EB,$E9,$28 ; $F5D0
00F5D4 1 E6 E7 E8 E9
00F5D8 1 29 D8 04 C9
00F5E0 1 AE 04 D5 D6 .byte $AE,$04,$D5,$D6,$D7,$D8,$28,$CE,$04,$D9,$DA,$DB,$DC,$28,$EC,$08 ; $F5E0
00F5E4 1 D7 D8 28 CE
00F5E8 1 04 D9 DA DB
00F5F0 1 FB FC FD DD .byte $FB,$FC,$FD,$DD,$DE,$FE,$FF,$49,$29,$63,$06,$C7,$C8,$EC,$ED,$FC ; $F5F0
00F5F4 1 DE FE FF 49
00F5F8 1 29 63 06 C7
00F600 1
00F600 1 RenderingAnimationData_F600: ; $F600
00F600 1 FD 29 83 05 .byte $FD,$29,$83,$05,$D5,$EE,$EF,$F0,$F1,$29,$A3,$05,$F2,$F3,$F4,$F5 ; $F600
00F604 1 D5 EE EF F0
00F608 1 F1 29 A3 05
00F610 1 F6 29 C4 04 .byte $F6,$29,$C4,$04,$F2,$F7,$F8,$C8,$29,$00,$02,$C7,$C8,$29,$21,$02 ; $F610
00F614 1 F2 F7 F8 C8
00F618 1 29 00 02 C7
00F620 1 C7 C8 29 42 .byte $C7,$C8,$29,$42,$02,$C7,$C8,$29,$E7,$02,$C7,$C8,$2A,$08,$02,$C7 ; $F620
00F624 1 02 C7 C8 29
00F628 1 E7 02 C7 C8
00F630 1 C8 2A 29 02 .byte $C8,$2A,$29,$02,$C7,$C8,$2A,$4A,$02,$C7,$C8,$2A,$6B,$02,$C7,$C8 ; $F630
00F634 1 C7 C8 2A 4A
00F638 1 02 C7 C8 2A
00F640 1 2A 8C 02 C7 .byte $2A,$8C,$02,$C7,$C8,$2A,$92,$02,$C9,$CA,$2A,$73,$02,$C9,$CA,$2A ; $F640
00F644 1 C8 2A 92 02
00F648 1 C9 CA 2A 73
00F650 1 54 02 C9 CA .byte $54,$02,$C9,$CA,$2A,$35,$02,$C9,$CA,$2A,$16,$02,$C9,$CA,$29,$F7 ; $F650
00F654 1 2A 35 02 C9
00F658 1 CA 2A 16 02
00F660 1 02 C9 CA 29 .byte $02,$C9,$CA,$29,$5C,$02,$C9,$CA,$29,$3D,$02,$C9,$CA,$29,$1E,$02 ; $F660
00F664 1 5C 02 C9 CA
00F668 1 29 3D 02 C9
00F670 1 C9 CA 29 48 .byte $C9,$CA,$29,$48,$02,$F9,$FA,$29,$29,$03,$FB,$FC,$FD,$29,$0B,$02 ; $F670
00F674 1 02 F9 FA 29
00F678 1 29 03 FB FC
00F680 1 F9 FA 29 13 .byte $F9,$FA,$29,$13,$02,$4A,$4B,$29,$34,$03,$FE,$FF,$49,$29,$56,$02 ; $F680
00F684 1 02 4A 4B 29
00F688 1 34 03 FE FF
00F690 1 4A 4B 2A 83 .byte $4A,$4B,$2A,$83,$01,$3B,$2B,$02,$83,$0B,$1C,$18,$2A,$A3,$C6,$25 ; $F690
00F694 1 01 3B 2B 02
00F698 1 83 0B 1C 18
00F6A0 1 2A A4 C6 25 .byte $2A,$A4,$C6,$25,$2A,$A5,$C6,$25,$2A,$E2,$44,$26,$2A,$A5,$C2,$00 ; $F6A0
00F6A4 1 2A A5 C6 25
00F6A8 1 2A E2 44 26
00F6B0 1 2B 16 48 25 .byte $2B,$16,$48,$25,$2B,$36,$48,$25,$2B,$56,$48,$25,$20,$4A,$4C,$37 ; $F6B0
00F6B4 1 2B 36 48 25
00F6B8 1 2B 56 48 25
00F6C0 1 20 6A 0C 33 .byte $20,$6A,$0C,$33,$29,$2A,$2B,$2C,$2D,$2E,$2F,$30,$31,$33,$35,$20 ; $F6C0
00F6C4 1 29 2A 2B 2C
00F6C8 1 2D 2E 2F 30
00F6D0 1 8A 4B 33 20 .byte $8A,$4B,$33,$20,$AA,$4B,$33,$20,$95,$C2,$28,$20,$56,$84,$C8,$36 ; $F6D0
00F6D4 1 AA 4B 33 20
00F6D8 1 95 C2 28 20
00F6E0 1 36 36 20 A4 .byte $36,$36,$20,$A4,$05,$38,$26,$38,$26,$38,$20,$B7,$05,$38,$26,$38 ; $F6E0
00F6E4 1 05 38 26 38
00F6E8 1 26 38 20 B7
00F6F0 1 26 38 20 C0 .byte $26,$38,$20,$C0,$60,$6A,$20,$E0,$7F,$6B,$21,$1F,$66,$6B,$21,$5B ; $F6F0
00F6F4 1 60 6A 20 E0
00F6F8 1 7F 6B 21 1F
00F700 1
00F700 1 RenderingAnimationData_F700: ; $F700
00F700 1 47 6B 20 C8 .byte $47,$6B,$20,$C8,$03,$53,$50,$40,$20,$CB,$4A,$41,$20,$D5,$03,$42 ; $F700
00F704 1 03 53 50 40
00F708 1 20 CB 4A 41
00F710 1 70 73 20 E8 .byte $70,$73,$20,$E8,$03,$54,$50,$43,$20,$EB,$4A,$25,$20,$F5,$03,$43 ; $F710
00F714 1 03 54 50 43
00F718 1 20 EB 4A 25
00F720 1 70 74 21 09 .byte $70,$74,$21,$09,$03,$51,$44,$45,$21,$0C,$48,$46,$21,$14,$03,$47 ; $F720
00F724 1 03 51 44 45
00F728 1 21 0C 48 46
00F730 1 48 71 21 28 .byte $48,$71,$21,$28,$10,$55,$52,$56,$57,$17,$12,$17,$1D,$0E,$17,$0D ; $F730
00F734 1 10 55 52 56
00F738 1 57 17 12 17
00F740 1 18 77 76 72 .byte $18,$77,$76,$72,$75,$21,$45,$07,$58,$59,$5A,$5B,$5C,$5D,$5E,$21 ; $F740
00F744 1 75 21 45 07
00F748 1 58 59 5A 5B
00F750 1 54 07 7E 7D .byte $54,$07,$7E,$7D,$7C,$7B,$7A,$79,$78,$21,$63,$05,$62,$61,$25,$5F ; $F750
00F754 1 7C 7B 7A 79
00F758 1 78 21 63 05
00F760 1 60 21 78 0F .byte $60,$21,$78,$0F,$80,$7F,$25,$81,$82,$87,$6B,$6B,$6B,$62,$63,$25 ; $F760
00F764 1 80 7F 25 81
00F768 1 82 87 6B 6B
00F770 1 25 24 23 21 .byte $25,$24,$23,$21,$99,$0C,$1A,$1F,$25,$25,$83,$82,$6B,$61,$25,$64 ; $F770
00F774 1 99 0C 1A 1F
00F778 1 25 25 83 82
00F780 1 25 66 21 BB .byte $25,$66,$21,$BB,$09,$86,$25,$84,$25,$81,$25,$25,$64,$66,$21,$DC ; $F780
00F784 1 09 86 25 84
00F788 1 25 81 25 25
00F790 1 07 86 84 25 .byte $07,$86,$84,$25,$25,$25,$25,$65,$21,$FD,$07,$85,$25,$25,$25,$66 ; $F790
00F794 1 25 25 25 65
00F798 1 21 FD 07 85
00F7A0 1 6E 6F 22 1C .byte $6E,$6F,$22,$1C,$0A,$4E,$4F,$86,$25,$66,$26,$26,$26,$6C,$6D,$20 ; $F7A0
00F7A4 1 0A 4E 4F 86
00F7A8 1 25 66 26 26
00F7B0 1 82 88 69 69 .byte $82,$88,$69,$69,$68,$67,$67,$67,$67,$67,$20,$9D,$87,$89,$89,$88 ; $F7B0
00F7B4 1 68 67 67 67
00F7B8 1 67 67 20 9D
00F7C0 1 87 87 87 87 .byte $87,$87,$87,$87,$22,$2E,$04,$8A,$8B,$8C,$8D,$22,$3A,$06,$4C,$4D ; $F7C0
00F7C4 1 22 2E 04 8A
00F7C8 1 8B 8C 8D 22
00F7D0 1 26 26 26 86 .byte $26,$26,$26,$86,$22,$45,$02,$6E,$6F,$22,$4D,$06,$AA,$AB,$8E,$8F ; $F7D0
00F7D4 1 22 45 02 6E
00F7D8 1 6F 22 4D 06
00F7E0 1 A8 A9 22 59 .byte $A8,$A9,$22,$59,$02,$4E,$4F,$22,$67,$12,$6C,$6D,$26,$26,$AA,$AB ; $F7E0
00F7E4 1 02 4E 4F 22
00F7E8 1 67 12 6C 6D
00F7F0 1 26 26 9C 9E .byte $26,$26,$9C,$9E,$26,$26,$A8,$A9,$26,$26,$4C,$4D,$22,$88,$03,$6E ; $F7F0
00F7F4 1 26 26 A8 A9
00F7F8 1 26 26 4C 4D
00F800 1
00F800 1 RenderingAnimationData_F800: ; $F800
00F800 1 A4 A6 22 8F .byte $A4,$A6,$22,$8F,$02,$9D,$9F,$22,$95,$03,$A0,$A2,$4F,$22,$A9,$03 ; $F800
00F804 1 02 9D 9F 22
00F808 1 95 03 A0 A2
00F810 1 A5 A7 6D 22 .byte $A5,$A7,$6D,$22,$B4,$03,$4C,$A1,$A3,$22,$CB,$02,$6E,$6F,$22,$D3 ; $F810
00F814 1 B4 03 4C A1
00F818 1 A3 22 CB 02
00F820 1 02 4E 4F 22 .byte $02,$4E,$4F,$22,$ED,$06,$6C,$6D,$26,$26,$4C,$4D,$23,$0E,$04,$90 ; $F820
00F824 1 ED 06 6C 6D
00F828 1 26 26 4C 4D
00F830 1 93 96 99 23 .byte $93,$96,$99,$23,$2E,$04,$91,$94,$97,$9A,$23,$4E,$04,$92,$95,$98 ; $F830
00F834 1 2E 04 91 94
00F838 1 97 9A 23 4E
00F840 1 9B 23 02 83 .byte $9B,$23,$02,$83,$0B,$1C,$18,$23,$03,$43,$25,$23,$23,$43,$25,$23 ; $F840
00F844 1 0B 1C 18 23
00F848 1 03 43 25 23
00F850 1 43 43 25 23 .byte $43,$43,$25,$23,$16,$48,$25,$23,$36,$48,$25,$23,$56,$48,$25,$21 ; $F850
00F854 1 16 48 25 23
00F858 1 36 48 25 23
00F860 1 88 10 1C 0E .byte $88,$10,$1C,$0E,$15,$0E,$0C,$1D,$25,$22,$18,$1E,$1B,$25,$1D,$0E ; $F860
00F864 1 15 0E 0C 1D
00F868 1 25 22 18 1E
00F870 1 0A 16 21 A8 .byte $0A,$16,$21,$A8,$50,$25,$21,$C8,$50,$25,$21,$CA,$0B,$0A,$25,$0C ; $F870
00F874 1 50 25 21 C8
00F878 1 50 25 21 CA
00F880 1 25 0D 25 19 .byte $25,$0D,$25,$19,$25,$1B,$25,$22,$21,$E8,$50,$25,$00,$3F,$00,$14 ; $F880
00F884 1 25 1B 25 22
00F888 1 21 E8 50 25
00F890 1 0F 0F 11 30 .byte $0F,$0F,$11,$30,$0F,$0F,$0F,$24,$0F,$0F,$0F,$27,$0F,$0F,$0F,$30 ; $F890
00F894 1 0F 0F 0F 24
00F898 1 0F 0F 0F 27
00F8A0 1 0F 0F 11 30 .byte $0F,$0F,$11,$30,$23,$C0,$6A,$00,$23,$EA,$01,$99,$23,$EB,$45,$AA ; $F8A0
00F8A4 1 23 C0 6A 00
00F8A8 1 23 EA 01 99
00F8B0 1 23 F0 50 FF .byte $23,$F0,$50,$FF,$20,$A4,$53,$AE,$20,$E4,$53,$AE,$21,$24,$53,$AE ; $F8B0
00F8B4 1 20 A4 53 AE
00F8B8 1 20 E4 53 AE
00F8C0 1 21 69 48 AE .byte $21,$69,$48,$AE,$21,$A9,$49,$AE,$21,$E9,$43,$AE,$21,$F3,$49,$AE ; $F8C0
00F8C4 1 21 A9 49 AE
00F8C8 1 21 E9 43 AE
00F8D0 1 20 A4 C5 AE .byte $20,$A4,$C5,$AE,$20,$C9,$CA,$AE,$20,$CC,$C4,$AE,$21,$8E,$C4,$AE ; $F8D0
00F8D4 1 20 C9 CA AE
00F8D8 1 20 CC C4 AE
00F8E0 1 21 91 C4 AE .byte $21,$91,$C4,$AE,$20,$B3,$CB,$AE,$21,$78,$C5,$AE,$20,$A7,$48,$25 ; $F8E0
00F8E4 1 20 B3 CB AE
00F8E8 1 21 78 C5 AE
00F8F0 1 20 E7 42 25 .byte $20,$E7,$42,$25,$21,$27,$42,$25,$21,$2A,$42,$25,$21,$6C,$47,$25 ; $F8F0
00F8F4 1 21 27 42 25
00F8F8 1 21 2A 42 25
00F900 1
00F900 1 RenderingAnimationData_F900: ; $F900
00F900 1 21 AC 42 25 .byte $21,$AC,$42,$25,$21,$F7,$01,$25,$21,$49,$4B,$25,$20,$ED,$C3,$25 ; $F900
00F904 1 21 F7 01 25
00F908 1 21 49 4B 25
00F910 1 20 B2 C5 25 .byte $20,$B2,$C5,$25,$20,$AE,$C5,$25,$20,$B1,$C5,$25,$20,$63,$5A,$26 ; $F910
00F914 1 20 AE C5 25
00F918 1 20 B1 C5 25
00F920 1 22 23 5A 26 .byte $22,$23,$5A,$26,$20,$82,$CD,$26,$20,$9D,$CD,$26,$22,$AA,$0D,$01 ; $F920
00F924 1 20 82 CD 26
00F928 1 20 9D CD 26
00F930 1 25 19 15 0A .byte $25,$19,$15,$0A,$22,$0E,$1B,$25,$10,$0A,$16,$0E,$22,$EA,$0D,$02 ; $F930
00F934 1 22 0E 1B 25
00F938 1 10 0A 16 0E
00F940 1 25 19 15 0A .byte $25,$19,$15,$0A,$22,$0E,$1B,$25,$10,$0A,$16,$0E,$00 ; $F940
00F944 1 22 0E 1B 25
00F948 1 10 0A 16 0E
00F94D 1
00F94D 1 FrameOamTemplate_F94D: ; $F94D
00F94D 1 ; 22 OAM entries x 4 bytes = 88 bytes.
00F94D 1 ; Entry format: Y, tile, attributes, X.
00F94D 1 2F AE 00 34 .byte $2F,$AE,$00,$34,$3B,$AE,$00,$38,$43,$AE,$00,$38,$27,$AE,$00,$4C ; $F94D
00F951 1 3B AE 00 38
00F955 1 43 AE 00 38
00F95D 1 27 AE 00 54 .byte $27,$AE,$00,$54,$27,$AE,$00,$5C,$2B,$AE,$00,$70,$33,$AE,$00,$70 ; $F95D
00F961 1 27 AE 00 5C
00F965 1 2B AE 00 70
00F96D 1 43 AE 00 70 .byte $43,$AE,$00,$70,$2B,$AE,$00,$88,$3B,$AE,$00,$88,$43,$AE,$00,$88 ; $F96D
00F971 1 2B AE 00 88
00F975 1 3B AE 00 88
00F97D 1 5F AE 00 5C .byte $5F,$AE,$00,$5C,$6B,$AE,$00,$60,$73,$AE,$00,$60,$57,$AE,$00,$74 ; $F97D
00F981 1 6B AE 00 60
00F985 1 73 AE 00 60
00F98D 1 57 AE 00 7C .byte $57,$AE,$00,$7C,$57,$AE,$00,$84,$17,$13,$00,$10,$17,$13,$40,$E8 ; $F98D
00F991 1 57 AE 00 84
00F995 1 17 13 00 10
00F99D 1 87 13 80 10 .byte $87,$13,$80,$10,$87,$13,$C0,$E8 ; $F99D
00F9A1 1 87 13 C0 E8
00F9A5 1
00F9A5 1 RenderingAnimationData_F9A5: ; $F9A5
00F9A5 1 FF FF FF FF .byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; $F9A5
00F9A9 1 FF FF FF FF
00F9AD 1 FF FF FF FF
00F9B5 1 FF FF FF FF .byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; $F9B5
00F9B9 1 FF FF FF FF
00F9BD 1 FF FF FF FF
00F9C5 1 FF FF FF FF .byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; $F9C5
00F9C9 1 FF FF FF FF
00F9CD 1 FF FF FF
00F9D0 1
00F9D0 1 ; ============================================================================
00F9D0 1 ; $F9D0-$F9F4
00F9D0 1 ; Initialize the audio engine and APU output state.
00F9D0 1 ;
00F9D0 1 ; Operation:
00F9D0 1 ; 1. Configure the APU frame counter.
00F9D0 1 ; 2. Initialize the main audio subsystem through $FB05.
00F9D0 1 ; 3. Clear three audio/engine state bytes.
00F9D0 1 ; 4. Decrement the startup value at $07FF up to two times.
00F9D0 1 ; 5. Write the resulting value to the APU DMC direct-load register.
00F9D0 1 ;
00F9D0 1 ; Exit:
00F9D0 1 ; A = final value from $07FF
00F9D0 1 ; ============================================================================
00F9D0 1
00F9D0 1 ; ----------------------------------------------------------------------------
00F9D0 1 ; Contract:
00F9D0 1 ; Description: Initializes Audio Engine.
00F9D0 1 ; Entry: Registers: A; Memory: $07ff
00F9D0 1 ; Returns/products: Registers/clobbers: A
00F9D0 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00F9D0 1 ; Memory effects: $4017, $ff, pendingaudioflags, $fd, $4011
00F9D0 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00F9D0 1 ; comparison, load, or store path and are not a stable API product.
00F9D0 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00F9D0 1 ; ----------------------------------------------------------------------------
00F9D0 1 InitializeAudioEngine: ; $F9D0
00F9D0 1 A9 C0 lda #$C0 ; $F9D0: A9 C0
00F9D2 1 8D 17 40 sta $4017 ; $F9D2: 8D 17 40
00F9D5 1 ; Configure the APU frame counter:
00F9D5 1 ; bit 7 = five-step sequence
00F9D5 1 ; bit 6 = inhibit frame IRQ
00F9D5 1
00F9D5 1 ; ----------------------------------------------------------------------------
00F9D5 1 ; Initialize the remaining audio subsystem state.
00F9D5 1 ; ----------------------------------------------------------------------------
00F9D5 1
00F9D5 1 20 05 FB jsr UpdateAudioEngine ; $F9D5: 20 05 FB
00F9D8 1
00F9D8 1 ; ----------------------------------------------------------------------------
00F9D8 1 ; Clear shared audio and engine state.
00F9D8 1 ; ----------------------------------------------------------------------------
00F9D8 1
00F9D8 1 A9 00 lda #$00 ; $F9D8: A9 00
00F9DA 1
00F9DA 1 85 FF sta RenderStateFlags ; $F9DA: 85 FF
00F9DC 1 85 FE sta PendingAudioFlags ; $F9DC: 85 FE
00F9DE 1 85 FD sta $FD ; $F9DE: 85 FD
00F9E0 1
00F9E0 1 ; ----------------------------------------------------------------------------
00F9E0 1 ; Apply a short two-step countdown to the value at $07FF.
00F9E0 1 ;
00F9E0 1 ; If the initial value is zero:
00F9E0 1 ; no decrement occurs.
00F9E0 1 ;
00F9E0 1 ; If the initial value is one:
00F9E0 1 ; one decrement occurs, producing zero.
00F9E0 1 ;
00F9E0 1 ; If the initial value is two or greater:
00F9E0 1 ; two decrements occur.
00F9E0 1 ; ----------------------------------------------------------------------------
00F9E0 1
00F9E0 1 AD FF 07 lda $07FF ; $F9E0: AD FF 07
00F9E3 1 F0 08 beq InitializeAudioEngine_WriteDmc
00F9E5 1 ; $F9E3: F0 08
00F9E5 1
00F9E5 1 CE FF 07 dec $07FF ; $F9E5: CE FF 07
00F9E8 1 F0 03 beq InitializeAudioEngine_WriteDmc
00F9EA 1 ; $F9E8: F0 03
00F9EA 1
00F9EA 1 CE FF 07 dec $07FF ; $F9EA: CE FF 07
00F9ED 1
00F9ED 1 ; ----------------------------------------------------------------------------
00F9ED 1 ; Write the resulting value to the APU DMC direct-load register.
00F9ED 1 ;
00F9ED 1 ; $4011 controls the seven-bit DMC output level.
00F9ED 1 ; ----------------------------------------------------------------------------
00F9ED 1
00F9ED 1 InitializeAudioEngine_WriteDmc: ; $F9ED
00F9ED 1 AD FF 07 lda $07FF ; $F9ED: AD FF 07
00F9F0 1 8D 11 40 sta $4011 ; $F9F0: 8D 11 40
00F9F3 1
00F9F3 1 60 rts ; $F9F3: 60
00F9F4 1
00F9F4 1 ; ============================================================================
00F9F4 1 ; $F9F4-$F9FF
00F9F4 1 ; Unused/padding bytes.
00F9F4 1 ; ============================================================================
00F9F4 1
00F9F4 1 AudioPadding_F9F4: ; $F9F4
00F9F4 1 FF FF FF FF .byte $FF,$FF,$FF,$FF
00F9F8 1 FF FF FF FF .byte $FF,$FF,$FF,$FF
00F9FC 1 FF FF FF FF .byte $FF,$FF,$FF,$FF
00FA00 1
00FA00 1 ; ============================================================================
00FA00 1 ; $FA00-$FA5F
00FA00 1 ; Audio engine lookup data.
00FA00 1 ;
00FA00 1 ; This region contains several adjacent tables used by the audio routines that
00FA00 1 ; follow. The first portion consists primarily of little-endian timer or period
00FA00 1 ; values, followed by smaller rhythm, duration, envelope, or index tables.
00FA00 1 ;
00FA00 1 ; Keep the exact byte layout because later routines reference internal
00FA00 1 ; addresses such as $FA01 and $FA4A directly.
00FA00 1 ; ============================================================================
00FA00 1
00FA00 1 AudioLookupData_FA00: ; $FA00
00FA00 1 07 F0 00 69 .byte $07,$F0,$00,$69,$00,$00,$00,$D4
00FA04 1 00 00 00 D4
00FA08 1 00 BD 00 B2 .byte $00,$BD,$00,$B2,$00,$A8,$00,$9F
00FA0C 1 00 A8 00 9F
00FA10 1 00 96 00 8D .byte $00,$96,$00,$8D,$00,$7E,$00,$70
00FA14 1 00 7E 00 70
00FA18 1 01 AB 01 93 .byte $01,$AB,$01,$93,$01,$7C,$01,$67
00FA1C 1 01 7C 01 67
00FA20 1 01 52 01 3F .byte $01,$52,$01,$3F,$01,$2D,$01,$1C
00FA24 1 01 2D 01 1C
00FA28 1 01 0C 00 FD .byte $01,$0C,$00,$FD,$00,$EE,$00,$E1
00FA2C 1 00 EE 00 E1
00FA30 1 03 57 02 F9 .byte $03,$57,$02,$F9,$02,$A6,$02,$80
00FA34 1 02 A6 02 80
00FA38 1 02 3A 01 FC .byte $02,$3A,$01,$FC,$01,$C4,$00,$5E
00FA3C 1 01 C4 00 5E
00FA40 1 00 53 00 4F .byte $00,$53,$00,$4F,$00,$4A,$00,$3E
00FA44 1 00 4A 00 3E
00FA48 1 00 20 05 0A .byte $00,$20,$05,$0A,$14,$28,$0D,$21
00FA4C 1 14 28 0D 21
00FA50 1 06 07 06 0C .byte $06,$07,$06,$0C,$18,$30,$10,$24
00FA54 1 18 30 10 24
00FA58 1 48 08 FF FF .byte $48,$08,$FF,$FF,$FF,$FF,$FF,$FF
00FA5C 1 FF FF FF FF
00FA60 1
00FA60 1 ; ============================================================================
00FA60 1 ; Useful internal table bases referenced by later audio routines.
00FA60 1 ; ============================================================================
00FA60 1
00FA60 1 ApuTimerTableHighBytes = $FA00
00FA60 1 ApuTimerTableLowBytes = $FA01
00FA60 1
00FA60 1 NoteDurationTable = $FA4A
00FA60 1 ; ============================================================================
00FA60 1 ; $FA60-$FA70
00FA60 1 ; Write preset or caller-supplied control values to pulse channel 1.
00FA60 1 ; ============================================================================
00FA60 1
00FA60 1 ConfigurePulse1ControlPreset: ; $FA60
00FA60 1 A2 90 ldx #$90 ; $FA60: A2 90
00FA62 1 D0 09 bne WritePulse1Control ; $FA62: D0 09
00FA64 1 ; Target $FA6D.
00FA64 1
00FA64 1 ; ============================================================================
00FA64 1 ; $FA64-$FA67
00FA64 1 ; Write preset control value $90 to pulse channel 2.
00FA64 1 ; ============================================================================
00FA64 1
00FA64 1 ConfigurePulse2ControlPreset: ; $FA64
00FA64 1 A2 90 ldx #$90 ; $FA64: A2 90
00FA66 1 D0 0E bne WritePulse2Control ; $FA66: D0 0E
00FA68 1 ; Target $FA76.
00FA68 1
00FA68 1 ; ============================================================================
00FA68 1 ; $FA68-$FA70
00FA68 1 ; Write a caller-supplied pulse 1 control value and reset its sweep state.
00FA68 1 ;
00FA68 1 ; Entry:
00FA68 1 ; X = value for $4000
00FA68 1 ; ============================================================================
00FA68 1
00FA68 1 ; ----------------------------------------------------------------------------
00FA68 1 ; Contract:
00FA68 1 ; Description: Writes Pulse 1 Sweep And Control.
00FA68 1 ; Entry: Registers: X, Y
00FA68 1 ; Returns/products: Registers/clobbers: Y
00FA68 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00FA68 1 ; Memory effects: $4001, $4000
00FA68 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00FA68 1 ; comparison, load, or store path and are not a stable API product.
00FA68 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00FA68 1 ; ----------------------------------------------------------------------------
00FA68 1 WritePulse1SweepAndControl: ; $FA68
00FA68 1 A0 7F ldy #$7F ; $FA68: A0 7F
00FA6A 1 ; ----------------------------------------------------------------------------
00FA6A 1 ; Contract:
00FA6A 1 ; Description: Internal pulse-1 register writer.
00FA6A 1 ; Entry: Y = sweep value; X = control value.
00FA6A 1 ; Returns/products: APU $4001/$4000 written.
00FA6A 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00FA6A 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00FA6A 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00FA6A 1 ; comparison, load, or store path and are not a stable API product.
00FA6A 1 ; Validation: Internal-entry contract; call sites: internal entry.
00FA6A 1 ; ----------------------------------------------------------------------------
00FA6A 1 WritePulse1SweepAndControlFromRegisters:
00FA6A 1 8C 01 40 sty $4001 ; $FA6A: 8C 01 40
00FA6D 1
00FA6D 1 WritePulse1Control: ; $FA6D
00FA6D 1 8E 00 40 stx $4000 ; $FA6D: 8E 00 40
00FA70 1 60 rts ; $FA70: 60
00FA71 1
00FA71 1 ; ============================================================================
00FA71 1 ; $FA71-$FA79
00FA71 1 ; Write a caller-supplied pulse 2 control value and reset its sweep state.
00FA71 1 ;
00FA71 1 ; Entry:
00FA71 1 ; X = value for $4004
00FA71 1 ; ============================================================================
00FA71 1
00FA71 1 ; ----------------------------------------------------------------------------
00FA71 1 ; Contract:
00FA71 1 ; Description: Writes Pulse 2 Sweep And Control.
00FA71 1 ; Entry: Registers: X, Y
00FA71 1 ; Returns/products: Registers/clobbers: Y
00FA71 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00FA71 1 ; Memory effects: $4005, $4004
00FA71 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00FA71 1 ; comparison, load, or store path and are not a stable API product.
00FA71 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00FA71 1 ; ----------------------------------------------------------------------------
00FA71 1 WritePulse2SweepAndControl: ; $FA71
00FA71 1 A0 7F ldy #$7F ; $FA71: A0 7F
00FA73 1 ; ----------------------------------------------------------------------------
00FA73 1 ; Contract:
00FA73 1 ; Description: Internal pulse-2 register writer.
00FA73 1 ; Entry: Y = sweep value; X = control value.
00FA73 1 ; Returns/products: APU $4005/$4004 written.
00FA73 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00FA73 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00FA73 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00FA73 1 ; comparison, load, or store path and are not a stable API product.
00FA73 1 ; Validation: Internal-entry contract; call sites: internal entry.
00FA73 1 ; ----------------------------------------------------------------------------
00FA73 1 WritePulse2SweepAndControlFromRegisters:
00FA73 1 8C 05 40 sty $4005 ; $FA73: 8C 05 40
00FA76 1
00FA76 1 WritePulse2Control: ; $FA76
00FA76 1 8E 04 40 stx $4004 ; $FA76: 8E 04 40
00FA79 1 60 rts ; $FA79: 60
00FA7A 1
00FA7A 1 ; ============================================================================
00FA7A 1 ; $FA7A-$FA85
00FA7A 1 ; Configure the APU noise channel.
00FA7A 1 ;
00FA7A 1 ; Entry:
00FA7A 1 ; A = volume and envelope value for $400C
00FA7A 1 ; X = noise period and mode value for $400E
00FA7A 1 ;
00FA7A 1 ; Operation:
00FA7A 1 ; The fixed value $08 is written to $400F to reload the noise channel's
00FA7A 1 ; length counter.
00FA7A 1 ; ============================================================================
00FA7A 1
00FA7A 1 ; ----------------------------------------------------------------------------
00FA7A 1 ; Contract:
00FA7A 1 ; Description: Implements Configure Noise Channel.
00FA7A 1 ; Entry: Registers: A, X, Y
00FA7A 1 ; Returns/products: Registers/clobbers: Y
00FA7A 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00FA7A 1 ; Memory effects: $400c, $400e, $400f
00FA7A 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00FA7A 1 ; comparison, load, or store path and are not a stable API product.
00FA7A 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00FA7A 1 ; ----------------------------------------------------------------------------
00FA7A 1 ConfigureNoiseChannel: ; $FA7A
00FA7A 1 8D 0C 40 sta $400C ; $FA7A: 8D 0C 40
00FA7D 1 ; Noise volume and envelope control.
00FA7D 1
00FA7D 1 8E 0E 40 stx $400E ; $FA7D: 8E 0E 40
00FA80 1 ; Noise mode and period.
00FA80 1
00FA80 1 A0 08 ldy #$08 ; $FA80: A0 08
00FA82 1 8C 0F 40 sty $400F ; $FA82: 8C 0F 40
00FA85 1 ; Reload the noise length counter.
00FA85 1
00FA85 1 60 rts ; $FA85: 60
00FA86 1
00FA86 1 ; ============================================================================
00FA86 1 ; $FA86-$FAA2
00FA86 1 ; Save audio state and write a timer period to an APU channel.
00FA86 1 ;
00FA86 1 ; Entry:
00FA86 1 ; A = period-table index
00FA86 1 ; X = audio state or duration value
00FA86 1 ; Y = value saved in $F0
00FA86 1 ;
00FA86 1 ; Behavior:
00FA86 1 ; 1. Save Y in $F0 and X in $F2.
00FA86 1 ; 2. If X is zero, write $7F to pulse 1 sweep through $FA6A.
00FA86 1 ; 3. Load a little-endian timer period from the table at $FA00.
00FA86 1 ; 4. Write the timer low and high bytes to the selected APU channel.
00FA86 1 ;
00FA86 1 ; Default channel:
00FA86 1 ; X = $00, selecting pulse channel 1 registers $4002/$4003.
00FA86 1 ;
00FA86 1 ; Exit:
00FA86 1 ; Returns immediately if the selected table high byte is zero.
00FA86 1 ; ============================================================================
00FA86 1
00FA86 1 WritePulsePeriodFromTable: ; $FA86
00FA86 1 84 F0 sty $F0 ; $FA86: 84 F0
00FA88 1 ; Save caller-selected audio state.
00FA88 1
00FA88 1 86 F2 stx $F2 ; $FA88: 86 F2
00FA8A 1 ; Save duration, mode, or countdown state.
00FA8A 1
00FA8A 1 ; ----------------------------------------------------------------------------
00FA8A 1 ; A nonzero X skips pulse 1 sweep initialization.
00FA8A 1 ; ----------------------------------------------------------------------------
00FA8A 1
00FA8A 1 D0 03 bne WritePulsePeriod_SelectChannel
00FA8C 1 ; $FA8A: D0 03
00FA8C 1
00FA8C 1 ; ----------------------------------------------------------------------------
00FA8C 1 ; X is zero. Enter the pulse 1 helper at $FA6A, which writes Y=$7F to $4001
00FA8C 1 ; and then falls through to write X to $4000.
00FA8C 1 ;
00FA8C 1 ; This call preserves A, the period-table index.
00FA8C 1 ; ----------------------------------------------------------------------------
00FA8C 1
00FA8C 1 ; ----------------------------------------------------------------------------
00FA8C 1 ; Contract:
00FA8C 1 ; Description: Internal period setup after $F0/$F2 were saved.
00FA8C 1 ; Entry: A = period-table index; X/Y contain saved effect context.
00FA8C 1 ; Returns/products: Pulse-1 sweep/timer fields initialized.
00FA8C 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00FA8C 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00FA8C 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00FA8C 1 ; comparison, load, or store path and are not a stable API product.
00FA8C 1 ; Validation: Internal-entry contract; call sites: internal entry.
00FA8C 1 ; ----------------------------------------------------------------------------
00FA8C 1 InitializePulse1PeriodAfterStateSaved:
00FA8C 1 20 6A FA jsr WritePulse1SweepAndControlFromRegisters ; $FA8C: 20 6A FA
00FA8F 1
00FA8F 1 ; ----------------------------------------------------------------------------
00FA8F 1 ; Select pulse channel 1 timer registers by default:
00FA8F 1 ;
00FA8F 1 ; $4002,X = timer low
00FA8F 1 ; $4003,X = timer high
00FA8F 1 ; ----------------------------------------------------------------------------
00FA8F 1
00FA8F 1 ; ----------------------------------------------------------------------------
00FA8F 1 ; Contract:
00FA8F 1 ; Description: Writes Pulse Period Select Channel.
00FA8F 1 ; Entry: Registers: A; Memory: $fa01, $fa00
00FA8F 1 ; Returns/products: Registers/clobbers: A, X, Y
00FA8F 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00FA8F 1 ; Memory effects: $4002, $4003
00FA8F 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00FA8F 1 ; comparison, load, or store path and are not a stable API product.
00FA8F 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00FA8F 1 ; ----------------------------------------------------------------------------
00FA8F 1 WritePulsePeriod_SelectChannel: ; $FA8F
00FA8F 1 A2 00 ldx #$00 ; $FA8F: A2 00
00FA91 1
00FA91 1 ; ============================================================================
00FA91 1 ; $FA91
00FA91 1 ; Shared timer-table writer.
00FA91 1 ;
00FA91 1 ; Alternate callers enter here with:
00FA91 1 ;
00FA91 1 ; X=$00 -> pulse 1, $4002/$4003
00FA91 1 ; X=$04 -> pulse 2, $4006/$4007
00FA91 1 ; X=$08 -> triangle, $400A/$400B
00FA91 1 ;
00FA91 1 ; Entry:
00FA91 1 ; A = timer-table index
00FA91 1 ; X = APU channel register offset
00FA91 1 ; ============================================================================
00FA91 1
00FA91 1 WriteApuTimerFromTable: ; $FA91
00FA91 1 A8 tay ; $FA91: A8
00FA92 1 ; Y = period-table index.
00FA92 1
00FA92 1 ; ----------------------------------------------------------------------------
00FA92 1 ; Load the timer high byte first.
00FA92 1 ;
00FA92 1 ; The table is stored as little-endian words beginning at $FA00:
00FA92 1 ;
00FA92 1 ; low byte = $FA00,Y
00FA92 1 ; high byte = $FA01,Y
00FA92 1 ; ----------------------------------------------------------------------------
00FA92 1
00FA92 1 B9 01 FA lda $FA01,y ; $FA92: B9 01 FA
00FA95 1 F0 0B beq WriteApuTimerFromTable_Return
00FA97 1 ; $FA95: F0 0B
00FA97 1 ; A zero high byte suppresses the write.
00FA97 1
00FA97 1 9D 02 40 sta $4002,x ; $FA97: 9D 02 40
00FA9A 1 ; Write timer low-register address plus X.
00FA9A 1 ;
00FA9A 1 ; Despite the table naming, this instruction
00FA9A 1 ; writes the byte loaded from $FA01,Y first.
00FA9A 1
00FA9A 1 ; ----------------------------------------------------------------------------
00FA9A 1 ; Load the adjacent table byte, set bit three, and write the timer high or
00FA9A 1 ; length-counter register.
00FA9A 1 ; ----------------------------------------------------------------------------
00FA9A 1
00FA9A 1 B9 00 FA lda $FA00,y ; $FA9A: B9 00 FA
00FA9D 1 09 08 ora #$08 ; $FA9D: 09 08
00FA9F 1
00FA9F 1 9D 03 40 sta $4003,x ; $FA9F: 9D 03 40
00FAA2 1
00FAA2 1 WriteApuTimerFromTable_Return: ; $FAA2
00FAA2 1 60 rts ; $FAA2: 60
00FAA3 1
00FAA3 1 ; ============================================================================
00FAA3 1 ; $FAA3-$FAA9
00FAA3 1 ; Write a table-selected timer period to pulse channel 2.
00FAA3 1 ;
00FAA3 1 ; $FA73 writes $7F to pulse 2 sweep register $4005. The routine then selects
00FAA3 1 ; register offset $04 and enters the shared timer writer at $FA91.
00FAA3 1 ; ============================================================================
00FAA3 1
00FAA3 1 WritePulse2PeriodFromTable: ; $FAA3
00FAA3 1 20 73 FA jsr WritePulse2SweepAndControlFromRegisters ; $FAA3: 20 73 FA
00FAA6 1 ; Write $7F to pulse 2 sweep.
00FAA6 1
00FAA6 1 ; ----------------------------------------------------------------------------
00FAA6 1 ; Contract:
00FAA6 1 ; Description: Internal pulse-2 timer writer after sweep initialization.
00FAA6 1 ; Entry: A = timer-table index.
00FAA6 1 ; Returns/products: APU pulse-2 timer fields written.
00FAA6 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00FAA6 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00FAA6 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00FAA6 1 ; comparison, load, or store path and are not a stable API product.
00FAA6 1 ; Validation: Internal-entry contract; call sites: internal entry.
00FAA6 1 ; ----------------------------------------------------------------------------
00FAA6 1 WritePulse2PeriodAfterSweep:
00FAA6 1 A2 04 ldx #$04 ; $FAA6: A2 04
00FAA8 1 ; Select $4006/$4007.
00FAA8 1
00FAA8 1 D0 E7 bne WriteApuTimerFromTable ; $FAA8: D0 E7
00FAAA 1 ; Always taken.
00FAAA 1
00FAAA 1 ; ============================================================================
00FAAA 1 ; $FAAA-$FAAD
00FAAA 1 ; Write a table-selected timer period to the triangle channel.
00FAAA 1 ;
00FAAA 1 ; Entry:
00FAAA 1 ; A = period-table index
00FAAA 1 ; ============================================================================
00FAAA 1
00FAAA 1 WriteTrianglePeriodFromTable: ; $FAAA
00FAAA 1 A2 08 ldx #$08 ; $FAAA: A2 08
00FAAC 1 ; Select $400A/$400B.
00FAAC 1
00FAAC 1 D0 E3 bne WriteApuTimerFromTable ; $FAAC: D0 E3
00FAAE 1 ; Always taken.
00FAAE 1 ; ============================================================================
00FAAE 1 ; $FAAE-$FABF
00FAAE 1 ; Reduce the value in Y by approximately one thirty-second.
00FAAE 1 ;
00FAAE 1 ; Entry:
00FAAE 1 ; Y = source value
00FAAE 1 ;
00FAAE 1 ; Calculation:
00FAAE 1 ;
00FAAE 1 ; adjustment = Y >> 5
00FAAE 1 ;
00FAAE 1 ; if adjustment == 0:
00FAAE 1 ; adjustment = 1
00FAAE 1 ;
00FAAE 1 ; A = Y - adjustment
00FAAE 1 ;
00FAAE 1 ; Exit:
00FAAE 1 ; A = adjusted value
00FAAE 1 ; Y = original input value
00FAAE 1 ; $00 = adjustment value
00FAAE 1 ;
00FAAE 1 ; For input values below $20, the routine subtracts one. For values of $20 or
00FAAE 1 ; greater, it subtracts the input divided by 32.
00FAAE 1 ; ============================================================================
00FAAE 1
00FAAE 1 ReduceValueByOneThirtySecond: ; $FAAE
00FAAE 1 98 tya ; $FAAE: 98
00FAAF 1 ; Copy the source value into A.
00FAAF 1
00FAAF 1 ; ----------------------------------------------------------------------------
00FAAF 1 ; Divide A by 32.
00FAAF 1 ; ----------------------------------------------------------------------------
00FAAF 1
00FAAF 1 4A lsr ; $FAAF: 4A
00FAB0 1 4A lsr ; $FAB0: 4A
00FAB1 1 4A lsr ; $FAB1: 4A
00FAB2 1 4A lsr ; $FAB2: 4A
00FAB3 1 4A lsr ; $FAB3: 4A
00FAB4 1
00FAB4 1 85 00 sta $00 ; $FAB4: 85 00
00FAB6 1 ; Save the calculated adjustment.
00FAB6 1
00FAB6 1 ; ----------------------------------------------------------------------------
00FAB6 1 ; Ensure the adjustment is at least one.
00FAB6 1 ;
00FAB6 1 ; If Y was below $20, shifting right five times produced zero.
00FAB6 1 ; ----------------------------------------------------------------------------
00FAB6 1
00FAB6 1 D0 02 bne ReduceValueByOneThirtySecond_Subtract
00FAB8 1 ; $FAB6: D0 02
00FAB8 1
00FAB8 1 E6 00 inc $00 ; $FAB8: E6 00
00FABA 1 ; Change zero adjustment to one.
00FABA 1
00FABA 1 ; ----------------------------------------------------------------------------
00FABA 1 ; Subtract the adjustment from the original input value.
00FABA 1 ; ----------------------------------------------------------------------------
00FABA 1
00FABA 1 ReduceValueByOneThirtySecond_Subtract: ; $FABA
00FABA 1 98 tya ; $FABA: 98
00FABB 1 ; Restore the original source value.
00FABB 1
00FABB 1 38 sec ; $FABB: 38
00FABC 1 E5 00 sbc $00 ; $FABC: E5 00
00FABE 1
00FABE 1 60 rts ; $FABE: 60
00FABF 1
00FABF 1 ; ============================================================================
00FABF 1 ; $FABF-$FACE
00FABF 1 ; Derive an audio lookup-table index from A and the current audio offset in $F6.
00FABF 1 ;
00FABF 1 ; Entry:
00FABF 1 ; A = source value
00FABF 1 ; C = participates in the initial ROR
00FABF 1 ; $F6 = base audio-table index
00FABF 1 ;
00FABF 1 ; Calculation:
00FABF 1 ; 1. Save the original A in X.
00FABF 1 ; 2. Rotate A right once.
00FABF 1 ; 3. Restore the original A from X.
00FABF 1 ; 4. Rotate left three times.
00FABF 1 ; 5. Keep the low three bits.
00FABF 1 ; 6. Add $F6.
00FABF 1 ; 7. Use the sum to index the table at $FA4A.
00FABF 1 ;
00FABF 1 ; Exit:
00FABF 1 ; A = selected byte from $FA4A,Y
00FABF 1 ; X = original input A
00FABF 1 ; Y = calculated table index
00FABF 1 ; ============================================================================
00FABF 1
00FABF 1 ; ----------------------------------------------------------------------------
00FABF 1 ; Contract:
00FABF 1 ; Description: Implements Lookup Audio Control Value.
00FABF 1 ; Entry: Registers: A, X; Memory: $f6, $fa4a
00FABF 1 ; Returns/products: Registers/clobbers: A, X, Y; Flags: condition flags may carry result state
00FABF 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00FABF 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00FABF 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00FABF 1 ; comparison, load, or store path and are not a stable API product.
00FABF 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 2.
00FABF 1 ; ----------------------------------------------------------------------------
00FABF 1 LookupAudioControlValue: ; $FABF
00FABF 1 AA tax ; $FABF: AA
00FAC0 1 ; Preserve the original source value in X.
00FAC0 1
00FAC0 1 6A ror ; $FAC0: 6A
00FAC1 1 ; Rotate the source right through carry.
00FAC1 1 ;
00FAC1 1 ; The resulting A is not used directly, but
00FAC1 1 ; this changes carry for the following ROLs.
00FAC1 1
00FAC1 1 8A txa ; $FAC1: 8A
00FAC2 1 ; Restore the original source value.
00FAC2 1
00FAC2 1 ; ----------------------------------------------------------------------------
00FAC2 1 ; Rotate the original value left three times through the carry established by
00FAC2 1 ; the preceding ROR.
00FAC2 1 ; ----------------------------------------------------------------------------
00FAC2 1
00FAC2 1 2A rol ; $FAC2: 2A
00FAC3 1 2A rol ; $FAC3: 2A
00FAC4 1 2A rol ; $FAC4: 2A
00FAC5 1
00FAC5 1 ; ----------------------------------------------------------------------------
00FAC5 1 ; Contract:
00FAC5 1 ; Description: Internal lookup entry after carry and source value are prepared.
00FAC5 1 ; Entry: A/X and carry encode lookup offset; $F6 is base index.
00FAC5 1 ; Returns/products: A = selected control value; X preserves source; Y = table index.
00FAC5 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00FAC5 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00FAC5 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00FAC5 1 ; comparison, load, or store path and are not a stable API product.
00FAC5 1 ; Validation: Internal-entry contract; call sites: internal entry.
00FAC5 1 ; ----------------------------------------------------------------------------
00FAC5 1 LookupAudioControlValueFinalRotate:
00FAC5 1 29 07 and #$07 ; $FAC5: 29 07
00FAC7 1 ; Keep a three-bit table offset.
00FAC7 1
00FAC7 1 18 clc ; $FAC7: 18
00FAC8 1 65 F6 adc $F6 ; $FAC8: 65 F6
00FACA 1 ; Add the current audio-table base.
00FACA 1
00FACA 1 A8 tay ; $FACA: A8
00FACB 1
00FACB 1 B9 4A FA lda $FA4A,y ; $FACB: B9 4A FA
00FACE 1 ; Load the selected audio control value.
00FACE 1
00FACE 1 60 rts ; $FACE: 60
00FACF 1
00FACF 1 ; ============================================================================
00FACF 1 ; $FACF-$FAD9
00FACF 1 ; Configure the first sound-effect preset.
00FACF 1 ;
00FACF 1 ; Preset values:
00FACF 1 ; X = $17
00FACF 1 ; A = $12
00FACF 1 ; Y = $84
00FACF 1 ;
00FACF 1 ; The common setup helper at $FA86 saves Y in $F0 and X in $F2, then writes an
00FACF 1 ; APU timer value selected by A.
00FACF 1 ; ============================================================================
00FACF 1
00FACF 1 StartPulse1EffectPreset1: ; $FACF
00FACF 1 A2 17 ldx #$17 ; $FACF: A2 17
00FAD1 1 ; Duration or audio-state value.
00FAD1 1
00FAD1 1 A9 12 lda #$12 ; $FAD1: A9 12
00FAD3 1 ; Timer-table index.
00FAD3 1
00FAD3 1 20 86 FA jsr WritePulsePeriodFromTable
00FAD6 1 ; $FAD3: 20 86 FA
00FAD6 1
00FAD6 1 ; ----------------------------------------------------------------------------
00FAD6 1 ; Contract:
00FAD6 1 ; Description: Internal preset-1 continuation with timer state initialized.
00FAD6 1 ; Entry: Y initialized to preset control $84.
00FAD6 1 ; Returns/products: Continues shared pulse-1 preset update.
00FAD6 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00FAD6 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00FAD6 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00FAD6 1 ; comparison, load, or store path and are not a stable API product.
00FAD6 1 ; Validation: Internal-entry contract; call sites: internal entry.
00FAD6 1 ; ----------------------------------------------------------------------------
00FAD6 1 StartPulse1EffectPreset1FromControl:
00FAD6 1 A0 84 ldy #$84 ; $FAD6: A0 84
00FAD8 1 ; Default control or envelope value.
00FAD8 1
00FAD8 1 D0 14 bne UpdatePulse1PresetEffect
00FADA 1 ; $FAD8: D0 14
00FADA 1 ; Always taken.
00FADA 1 ; Target $FAEE.
00FADA 1
00FADA 1 ; ============================================================================
00FADA 1 ; $FADA-$FAE4
00FADA 1 ; Configure the second sound-effect preset.
00FADA 1 ;
00FADA 1 ; Preset values:
00FADA 1 ; X = $1E
00FADA 1 ; A = $0C
00FADA 1 ; Y = $85
00FADA 1 ; ============================================================================
00FADA 1
00FADA 1 StartPulse1EffectPreset2: ; $FADA
00FADA 1 A2 1E ldx #$1E ; $FADA: A2 1E
00FADC 1
00FADC 1 A9 0C lda #$0C ; $FADC: A9 0C
00FADE 1
00FADE 1 20 86 FA jsr WritePulsePeriodFromTable
00FAE1 1 ; $FADE: 20 86 FA
00FAE1 1
00FAE1 1 ; ----------------------------------------------------------------------------
00FAE1 1 ; Contract:
00FAE1 1 ; Description: Internal preset-2 continuation with timer state initialized.
00FAE1 1 ; Entry: Y initialized to preset control $85.
00FAE1 1 ; Returns/products: Continues shared pulse-1 preset update.
00FAE1 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00FAE1 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00FAE1 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00FAE1 1 ; comparison, load, or store path and are not a stable API product.
00FAE1 1 ; Validation: Internal-entry contract; call sites: internal entry.
00FAE1 1 ; ----------------------------------------------------------------------------
00FAE1 1 StartPulse1EffectPreset2FromControl:
00FAE1 1 A0 85 ldy #$85 ; $FAE1: A0 85
00FAE3 1
00FAE3 1 D0 09 bne UpdatePulse1PresetEffect
00FAE5 1 ; $FAE3: D0 09
00FAE5 1 ; Always taken.
00FAE5 1 ; Target $FAEE.
00FAE5 1
00FAE5 1 ; ============================================================================
00FAE5 1 ; $FAE5-$FAED
00FAE5 1 ; Configure the third sound-effect preset.
00FAE5 1 ;
00FAE5 1 ; Preset values:
00FAE5 1 ; X = $27
00FAE5 1 ; A = $06
00FAE5 1 ; Y = $86
00FAE5 1 ;
00FAE5 1 ; This entry falls directly into the shared finalization path.
00FAE5 1 ; ============================================================================
00FAE5 1
00FAE5 1 StartPulse1EffectPreset3: ; $FAE5
00FAE5 1 A2 27 ldx #$27 ; $FAE5: A2 27
00FAE7 1
00FAE7 1 A9 06 lda #$06 ; $FAE7: A9 06
00FAE9 1
00FAE9 1 20 86 FA jsr WritePulsePeriodFromTable
00FAEC 1 ; $FAE9: 20 86 FA
00FAEC 1
00FAEC 1 ; ----------------------------------------------------------------------------
00FAEC 1 ; Contract:
00FAEC 1 ; Description: Internal preset-3 continuation with timer state initialized.
00FAEC 1 ; Entry: Y initialized to preset control $86.
00FAEC 1 ; Returns/products: Continues shared pulse-1 preset update.
00FAEC 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00FAEC 1 ; Memory effects: See symbolic operands in the routine body; zero-page scratch roles are documented locally.
00FAEC 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00FAEC 1 ; comparison, load, or store path and are not a stable API product.
00FAEC 1 ; Validation: Internal-entry contract; call sites: internal entry.
00FAEC 1 ; ----------------------------------------------------------------------------
00FAEC 1 StartPulse1EffectPreset3FromControl:
00FAEC 1 A0 86 ldy #$86 ; $FAEC: A0 86
00FAEE 1
00FAEE 1 ; ============================================================================
00FAEE 1 ; $FAEE-$FB04
00FAEE 1 ; Finalize one of the three sound-effect presets.
00FAEE 1 ;
00FAEE 1 ; The routine selects an alternate Y value when bit three of $00 is set,
00FAEE 1 ; derives a second control value in X from $F2, then tail-jumps to $FB5A.
00FAEE 1 ;
00FAEE 1 ; Entry:
00FAEE 1 ; Y = preset-specific control value
00FAEE 1 ; $F2 = duration or sound-state value saved by $FA86
00FAEE 1 ; ============================================================================
00FAEE 1
00FAEE 1 UpdatePulse1PresetEffect: ; $FAEE
00FAEE 1 A5 00 lda $00 ; $FAEE: A5 00
00FAF0 1
00FAF0 1 29 08 and #$08 ; $FAF0: 29 08
00FAF2 1 F0 02 beq FinalizeSoundEffectPreset_SelectX
00FAF4 1 ; $FAF2: F0 02
00FAF4 1
00FAF4 1 ; ----------------------------------------------------------------------------
00FAF4 1 ; When bit three of $00 is set, replace the preset-specific Y value with $8D.
00FAF4 1 ; ----------------------------------------------------------------------------
00FAF4 1
00FAF4 1 A0 8D ldy #$8D ; $FAF4: A0 8D
00FAF6 1
00FAF6 1 ; ----------------------------------------------------------------------------
00FAF6 1 ; Select the initial channel/control value.
00FAF6 1 ; ----------------------------------------------------------------------------
00FAF6 1
00FAF6 1 FinalizeSoundEffectPreset_SelectX: ; $FAF6
00FAF6 1 A2 5A ldx #$5A ; $FAF6: A2 5A
00FAF8 1
00FAF8 1 ; ----------------------------------------------------------------------------
00FAF8 1 ; For $F2 values below $14, derive X from half the value and force bits six and
00FAF8 1 ; four through OR #$50.
00FAF8 1 ;
00FAF8 1 ; For $F2 values $14 or greater, retain X=$5A.
00FAF8 1 ; ----------------------------------------------------------------------------
00FAF8 1
00FAF8 1 A5 F2 lda $F2 ; $FAF8: A5 F2
00FAFA 1
00FAFA 1 C9 14 cmp #$14 ; $FAFA: C9 14
00FAFC 1 B0 04 bcs FinalizeSoundEffectPreset_Apply
00FAFE 1 ; $FAFC: B0 04
00FAFE 1
00FAFE 1 4A lsr ; $FAFE: 4A
00FAFF 1 09 50 ora #$50 ; $FAFF: 09 50
00FB01 1 AA tax ; $FB01: AA
00FB02 1
00FB02 1 ; ----------------------------------------------------------------------------
00FB02 1 ; Tail-call the shared sound-effect register updater.
00FB02 1 ;
00FB02 1 ; Entry to $FB5A:
00FB02 1 ; X = calculated control value
00FB02 1 ; Y = preset or alternate envelope value
00FB02 1 ; ----------------------------------------------------------------------------
00FB02 1
00FB02 1 FinalizeSoundEffectPreset_Apply: ; $FB02
00FB02 1 4C 5A FB jmp UpdateAudioEffect1_Write ; $FB02: 4C 5A FB
00FB05 1
00FB05 1 ; ============================================================================
00FB05 1 ; $FB05-$FB42
00FB05 1 ; Main audio-update dispatcher.
00FB05 1 ;
00FB05 1 ; Audio state:
00FB05 1 ; $FF = pending sound-effect flags
00FB05 1 ; $F0 = active sound-effect state
00FB05 1 ; $F2 = effect countdown or phase
00FB05 1 ; $F3 = effect-specific state
00FB05 1 ; $FA = audio lock or override state
00FB05 1 ;
00FB05 1 ; The dispatcher alternates between bits in $F0 and $FF. Each carry-producing
00FB05 1 ; shift routes to a different sound-effect setup or update handler.
00FB05 1 ; ============================================================================
00FB05 1
00FB05 1 ; ----------------------------------------------------------------------------
00FB05 1 ; Contract:
00FB05 1 ; Description: Updates Audio Engine.
00FB05 1 ; Entry: Registers: A, Y; Memory: $ff, $f0, $fa
00FB05 1 ; Returns/products: Registers/clobbers: A, X, Y
00FB05 1 ; Clobbers: A, X, Y, and processor flags as indicated by the instructions below.
00FB05 1 ; Memory effects: $00, $f0, $f2, $f3
00FB05 1 ; Flags: Unless explicitly described, flags reflect the final arithmetic,
00FB05 1 ; comparison, load, or store path and are not a stable API product.
00FB05 1 ; Validation: Inferred from annotated instructions and call sites; call sites: 1.
00FB05 1 ; ----------------------------------------------------------------------------
00FB05 1 UpdateAudioEngine: ; $FB05
00FB05 1 A4 FF ldy RenderStateFlags ; $FB05: A4 FF
00FB07 1 84 00 sty $00 ; $FB07: 84 00
00FB09 1 ; Preserve the original pending-effect flags.
00FB09 1
00FB09 1 A5 F0 lda $F0 ; $FB09: A5 F0
00FB0B 1 ; Active-effect flags or state.
00FB0B 1
00FB0B 1 A6 FA ldx $FA ; $FB0B: A6 FA
00FB0D 1 D0 31 bne UpdateAudioEngine_Finalize
00FB0F 1 ; $FB0D: D0 31
00FB0F 1 ; An override or lock skips effect selection.
00FB0F 1
00FB0F 1 ; ----------------------------------------------------------------------------
00FB0F 1 ; Test active-effect bit zero.
00FB0F 1 ;
00FB0F 1 ; Carry set transfers directly into the first preset's finalization path at
00FB0F 1 ; $FAD6, where Y is initialized to $84.
00FB0F 1 ; ----------------------------------------------------------------------------
00FB0F 1
00FB0F 1 4A lsr ; $FB0F: 4A
00FB10 1 B0 C4 bcs StartPulse1EffectPreset1FromControl ; $FB10: B0 C4
00FB12 1
00FB12 1 ; ----------------------------------------------------------------------------
00FB12 1 ; Test pending-effect bit zero.
00FB12 1 ; ----------------------------------------------------------------------------
00FB12 1
00FB12 1 46 FF lsr RenderStateFlags ; $FB12: 46 FF
00FB14 1 B0 B9 bcs StartPulse1EffectPreset1 ; $FB14: B0 B9
00FB16 1
00FB16 1 ; ----------------------------------------------------------------------------
00FB16 1 ; Test active-effect bit one.
00FB16 1 ;
00FB16 1 ; Target $FAE1 initializes Y=$85 for the second preset.
00FB16 1 ; ----------------------------------------------------------------------------
00FB16 1
00FB16 1 4A lsr ; $FB16: 4A
00FB17 1 B0 C8 bcs StartPulse1EffectPreset2FromControl ; $FB17: B0 C8
00FB19 1
00FB19 1 ; ----------------------------------------------------------------------------
00FB19 1 ; Test pending-effect bit one.
00FB19 1 ; ----------------------------------------------------------------------------
00FB19 1
00FB19 1 46 FF lsr RenderStateFlags ; $FB19: 46 FF
00FB1B 1 B0 BD bcs StartPulse1EffectPreset2 ; $FB1B: B0 BD
00FB1D 1
00FB1D 1 ; ----------------------------------------------------------------------------
00FB1D 1 ; Test active-effect bit two.
00FB1D 1 ;
00FB1D 1 ; Target $FAEC initializes Y=$86 for the third preset.
00FB1D 1 ; ----------------------------------------------------------------------------
00FB1D 1
00FB1D 1 4A lsr ; $FB1D: 4A
00FB1E 1 B0 CC bcs StartPulse1EffectPreset3FromControl ; $FB1E: B0 CC
00FB20 1
00FB20 1 ; ----------------------------------------------------------------------------
00FB20 1 ; Test pending-effect bit two.
00FB20 1 ; ----------------------------------------------------------------------------
00FB20 1
00FB20 1 46 FF lsr RenderStateFlags ; $FB20: 46 FF
00FB22 1 B0 C1 bcs StartPulse1EffectPreset3 ; $FB22: B0 C1
00FB24 1
00FB24 1 ; ----------------------------------------------------------------------------
00FB24 1 ; Discard the next active and pending bits.
00FB24 1 ; ----------------------------------------------------------------------------
00FB24 1
00FB24 1 4A lsr ; $FB24: 4A
00FB25 1 46 FF lsr RenderStateFlags ; $FB25: 46 FF
00FB27 1
00FB27 1 ; ----------------------------------------------------------------------------
00FB27 1 ; Test the next active-effect bit.
00FB27 1 ; ----------------------------------------------------------------------------
00FB27 1
00FB27 1 4A lsr ; $FB27: 4A
00FB28 1 B0 20 bcs UpdatePulse1DescendingEffect ; $FB28: B0 20
00FB2A 1 ; Target $FB4A.
00FB2A 1
00FB2A 1 ; ----------------------------------------------------------------------------
00FB2A 1 ; Test the corresponding pending-effect bit.
00FB2A 1 ; ----------------------------------------------------------------------------
00FB2A 1
00FB2A 1 46 FF lsr RenderStateFlags ; $FB2A: 46 FF
00FB2C 1 B0 15 bcs StartPulse1DescendingEffect ; $FB2C: B0 15
00FB2E 1 ; Target $FB43.
00FB2E 1
00FB2E 1 ; ----------------------------------------------------------------------------
00FB2E 1 ; Test the next active-effect bit.
00FB2E 1 ; ----------------------------------------------------------------------------
00FB2E 1
00FB2E 1 4A lsr ; $FB2E: 4A
00FB2F 1 B0 3A bcs UpdatePulse1StateChangeEffect ; $FB2F: B0 3A
00FB31 1 ; Target $FB6B.
00FB31 1
00FB31 1 ; ----------------------------------------------------------------------------
00FB31 1 ; Test the corresponding pending-effect bit.
00FB31 1 ; ----------------------------------------------------------------------------
00FB31 1
00FB31 1 46 FF lsr RenderStateFlags ; $FB31: 46 FF
00FB33 1 B0 2E bcs StartPulse1StateChangeEffect ; $FB33: B0 2E
00FB35 1 ; Target $FB63.
00FB35 1
00FB35 1 ; ----------------------------------------------------------------------------
00FB35 1 ; No recognized effect remains.
00FB35 1 ;
00FB35 1 ; Reset pulse channel 1 and clear the primary effect state.
00FB35 1 ; ----------------------------------------------------------------------------
00FB35 1
00FB35 1 ClearPrimaryAudioEffect: ; $FB35
00FB35 1 20 60 FA jsr ConfigurePulse1ControlPreset
00FB38 1 ; $FB35: 20 60 FA
00FB38 1
00FB38 1 A9 00 lda #$00 ; $FB38: A9 00
00FB3A 1 85 F0 sta $F0 ; $FB3A: 85 F0
00FB3C 1 85 F2 sta $F2 ; $FB3C: 85 F2
00FB3E 1 85 F3 sta $F3 ; $FB3E: 85 F3
00FB40 1
00FB40 1 ; ----------------------------------------------------------------------------
00FB40 1 ; Continue to the common audio finalization path at $FBFF.
00FB40 1 ; ----------------------------------------------------------------------------
00FB40 1
00FB40 1 UpdateAudioEngine_Finalize: ; $FB40
00FB40 1 4C FF FB jmp UpdateSecondaryEffects ; $FB40: 4C FF FB
00FB43 1
00FB43 1 ; ============================================================================
00FB43 1 ; $FB43-$FB49
00FB43 1 ; Start audio effect 1.
00FB43 1 ;
00FB43 1 ; Preset:
00FB43 1 ; X = $14
00FB43 1 ; A = $26
00FB43 1 ;
00FB43 1 ; The period helper stores X in $F2 and writes the selected pulse period.
00FB43 1 ; Execution then falls through to the effect-update path at $FB4A.
00FB43 1 ; ============================================================================
00FB43 1
00FB43 1 StartPulse1DescendingEffect: ; $FB43
00FB43 1 A2 14 ldx #$14 ; $FB43: A2 14
00FB45 1 A9 26 lda #$26 ; $FB45: A9 26
00FB47 1
00FB47 1 20 86 FA jsr WritePulsePeriodFromTable
00FB4A 1 ; $FB47: 20 86 FA
00FB4A 1
00FB4A 1 ; ============================================================================
00FB4A 1 ; $FB4A-$FB62
00FB4A 1 ; Update audio effect 1.
00FB4A 1 ;
00FB4A 1 ; The effect changes pulse channel 1 control as $F2 counts down. Values below
00FB4A 1 ; $10 derive the control register dynamically; larger values use preset $98.
00FB4A 1 ; ============================================================================
00FB4A 1
00FB4A 1 UpdatePulse1DescendingEffect: ; $FB4A
00FB4A 1 A2 98 ldx #$98 ; $FB4A: A2 98
00FB4C 1 ; Default pulse control.
00FB4C 1
00FB4C 1 A0 84 ldy #$84 ; $FB4C: A0 84
00FB4E 1 ; Default sweep or effect state.
00FB4E 1
00FB4E 1 A5 F2 lda $F2 ; $FB4E: A5 F2
00FB50 1 C9 10 cmp #$10 ; $FB50: C9 10
00FB52 1 B0 06 bcs UpdateAudioEffect1_Write
00FB54 1 ; $FB52: B0 06
00FB54 1
00FB54 1 ; ----------------------------------------------------------------------------
00FB54 1 ; Final effect phase.
00FB54 1 ;
00FB54 1 ; Use alternate state $8D and derive the control byte from half the countdown.
00FB54 1 ; ----------------------------------------------------------------------------
00FB54 1
00FB54 1 A0 8D ldy #$8D ; $FB54: A0 8D
00FB56 1
00FB56 1 4A lsr ; $FB56: 4A
00FB57 1 09 90 ora #$90 ; $FB57: 09 90
00FB59 1 AA tax ; $FB59: AA
00FB5A 1
00FB5A 1 ; ----------------------------------------------------------------------------
00FB5A 1 ; Write pulse channel 1 sweep and control.
00FB5A 1 ; ----------------------------------------------------------------------------
00FB5A 1
00FB5A 1 UpdateAudioEffect1_Write: ; $FB5A
00FB5A 1 20 6A FA jsr WritePulse1SweepAndControlFromRegisters ; $FB5A: 20 6A FA
00FB5D 1 ; Write Y to $4001 and X to $4000.
00FB5D 1
00FB5D 1 ; ----------------------------------------------------------------------------
00FB5D 1 ; Count the effect down.
00FB5D 1 ;
00FB5D 1 ; When it expires, clear the primary effect state at $FB35. Otherwise continue
00FB5D 1 ; through the common audio finalizer at $FB40.
00FB5D 1 ; ----------------------------------------------------------------------------
00FB5D 1
00FB5D 1 C6 F2 dec $F2 ; $FB5D: C6 F2
00FB5F 1 F0 D4 beq ClearPrimaryAudioEffect ; $FB5F: F0 D4
00FB61 1
00FB61 1 D0 DD bne UpdateAudioEngine_Finalize
00FB63 1 ; $FB61: D0 DD
00FB63 1 ; Always taken while $F2 is nonzero.
00FB63 1
00FB63 1 ; ============================================================================
00FB63 1 ; $FB63-$FB6A
00FB63 1 ; Start audio effect 2.
00FB63 1 ;
00FB63 1 ; The caller reached this path because the corresponding pending-effect bit was
00FB63 1 ; set. Y still contains the original pending flags loaded at $FB05.
00FB63 1 ; ============================================================================
00FB63 1
00FB63 1 StartPulse1StateChangeEffect: ; $FB63
00FB63 1 84 F0 sty $F0 ; $FB63: 84 F0
00FB65 1 ; Save the active effect state.
00FB65 1
00FB65 1 A0 9D ldy #$9D ; $FB65: A0 9D
00FB67 1 ; Initial pulse sweep/control value.
00FB67 1
00FB67 1 A9 30 lda #$30 ; $FB67: A9 30
00FB69 1 ; Initial timer or pitch value.
00FB69 1
00FB69 1 D0 2C bne UpdateAudioEffect2_Trigger
00FB6B 1 ; $FB69: D0 2C
00FB6B 1 ; Always taken to $FB97.
00FB6B 1
00FB6B 1 ; ============================================================================
00FB6B 1 ; $FB6B-$FBA0
00FB6B 1 ; Update audio effect 2.
00FB6B 1 ;
00FB6B 1 ; This handler uses bit six of the original pending flags, the countdown in
00FB6B 1 ; $F2, and the previous state in $F3 to choose pulse control and pitch values.
00FB6B 1 ; ============================================================================
00FB6B 1
00FB6B 1 UpdatePulse1StateChangeEffect: ; $FB6B
00FB6B 1 46 FF lsr RenderStateFlags ; $FB6B: 46 FF
00FB6D 1
00FB6D 1 90 C6 bcc ClearPrimaryAudioEffect ; $FB6D: 90 C6
00FB6F 1 ; End the effect when the shifted bit is clear.
00FB6F 1
00FB6F 1 ; ----------------------------------------------------------------------------
00FB6F 1 ; Test bit six of the original pending-effect flags saved at $00.
00FB6F 1 ; ----------------------------------------------------------------------------
00FB6F 1
00FB6F 1 A5 00 lda $00 ; $FB6F: A5 00
00FB71 1 29 40 and #$40 ; $FB71: 29 40
00FB73 1 D0 0A bne UpdateAudioEffect2_CheckState
00FB75 1 ; $FB73: D0 0A
00FB75 1
00FB75 1 ; ----------------------------------------------------------------------------
00FB75 1 ; Without bit six set, wait until the countdown reaches exactly $C0.
00FB75 1 ; ----------------------------------------------------------------------------
00FB75 1
00FB75 1 A5 F2 lda $F2 ; $FB75: A5 F2
00FB77 1 C9 C0 cmp #$C0 ; $FB77: C9 C0
00FB79 1 D0 21 bne UpdateAudioEffect2_CountDown
00FB7B 1 ; $FB79: D0 21
00FB7B 1
00FB7B 1 A0 9E ldy #$9E ; $FB7B: A0 9E
00FB7D 1
00FB7D 1 D0 11 bne UpdateAudioEffect2_WriteSweep
00FB7F 1 ; $FB7D: D0 11
00FB7F 1
00FB7F 1 ; ----------------------------------------------------------------------------
00FB7F 1 ; Bit six is set. Toggle or compare the saved effect state in $F3.
00FB7F 1 ; ----------------------------------------------------------------------------
00FB7F 1
00FB7F 1 UpdateAudioEffect2_CheckState: ; $FB7F
00FB7F 1 A4 F3 ldy $F3 ; $FB7F: A4 F3
00FB81 1
00FB81 1 85 F3 sta $F3 ; $FB81: 85 F3
00FB83 1 ; Save A=$40 in $F3.
00FB83 1
00FB83 1 98 tya ; $FB83: 98
00FB84 1 45 F3 eor $F3 ; $FB84: 45 F3
00FB86 1 F0 14 beq UpdateAudioEffect2_CountDown
00FB88 1 ; $FB86: F0 14
00FB88 1
00FB88 1 ; ----------------------------------------------------------------------------
00FB88 1 ; The state changed. Use sweep/control value $A5.
00FB88 1 ; ----------------------------------------------------------------------------
00FB88 1
00FB88 1 A0 A5 ldy #$A5 ; $FB88: A0 A5
00FB8A 1
00FB8A 1 A5 F2 lda $F2 ; $FB8A: A5 F2
00FB8C 1 C9 A8 cmp #$A8 ; $FB8C: C9 A8
00FB8E 1 90 05 bcc UpdateAudioEffect2_SelectPitch
00FB90 1 ; $FB8E: 90 05
00FB90 1
00FB90 1 ; ----------------------------------------------------------------------------
00FB90 1 ; For countdown values at least $A8, write the selected sweep value directly.
00FB90 1 ; ----------------------------------------------------------------------------
00FB90 1
00FB90 1 UpdateAudioEffect2_WriteSweep: ; $FB90
00FB90 1 8C 01 40 sty $4001 ; $FB90: 8C 01 40
00FB93 1
00FB93 1 D0 07 bne UpdateAudioEffect2_CountDown
00FB95 1 ; $FB93: D0 07
00FB95 1 ; Expected to be taken because the selected Y
00FB95 1 ; values are nonzero.
00FB95 1
00FB95 1 ; ----------------------------------------------------------------------------
00FB95 1 ; Select pitch value $48 and channel control $B3.
00FB95 1 ; ----------------------------------------------------------------------------
00FB95 1
00FB95 1 UpdateAudioEffect2_SelectPitch: ; $FB95
00FB95 1 A9 48 lda #$48 ; $FB95: A9 48
00FB97 1
00FB97 1 UpdateAudioEffect2_Trigger: ; $FB97
00FB97 1 A2 B3 ldx #$B3 ; $FB97: A2 B3
00FB99 1
00FB99 1 20 8C FA jsr InitializePulse1PeriodAfterStateSaved ; $FB99: 20 8C FA
00FB9C 1 ; Initialize pulse period/control using A and X.
00FB9C 1
00FB9C 1 ; ----------------------------------------------------------------------------
00FB9C 1 ; Decrement the effect timer, then continue through the later audio sequencer
00FB9C 1 ; at $FC94.
00FB9C 1 ; ----------------------------------------------------------------------------
00FB9C 1
00FB9C 1 UpdateAudioEffect2_CountDown: ; $FB9C
00FB9C 1 C6 F2 dec $F2 ; $FB9C: C6 F2
00FB9E 1
00FB9E 1 4C 94 FC jmp UpdateMusicSequencer ; $FB9E: 4C 94 FC
00FBA1 1
00FBA1 1 ; ============================================================================
00FBA1 1 ; $FBA1-$FBD2
00FBA1 1 ; Pulse effect controlled by the phase counter in $F4.
00FBA1 1 ; ============================================================================
00FBA1 1
00FBA1 1 StartPulse2PhaseEffect: ; $FBA1
00FBA1 1 84 F1 sty $F1 ; $FBA1: 84 F1
00FBA3 1
00FBA3 1 A9 20 lda #$20 ; $FBA3: A9 20
00FBA5 1 85 F4 sta $F4 ; $FBA5: 85 F4
00FBA7 1
00FBA7 1 D0 06 bne PulseEffectF4_Phase18 ; $FBA7: D0 06
00FBA9 1
00FBA9 1 UpdatePulse2PhaseEffect: ; $FBA9
00FBA9 1 A5 F4 lda $F4 ; $FBA9: A5 F4
00FBAB 1
00FBAB 1 C9 18 cmp #$18 ; $FBAB: C9 18
00FBAD 1 D0 04 bne PulseEffectF4_Phase10 ; $FBAD: D0 04
00FBAF 1
00FBAF 1 PulseEffectF4_Phase18: ; $FBAF
00FBAF 1 A9 08 lda #$08 ; $FBAF: A9 08
00FBB1 1 D0 06 bne PulseEffectF4_WriteTimer
00FBB3 1 ; $FBB1: D0 06
00FBB3 1
00FBB3 1 PulseEffectF4_Phase10: ; $FBB3
00FBB3 1 C9 10 cmp #$10 ; $FBB3: C9 10
00FBB5 1 D0 05 bne PulseEffectF4_Configure ; $FBB5: D0 05
00FBB7 1
00FBB7 1 A9 2E lda #$2E ; $FBB7: A9 2E
00FBB9 1
00FBB9 1 PulseEffectF4_WriteTimer: ; $FBB9
00FBB9 1 20 A6 FA jsr WritePulse2PeriodAfterSweep ; $FBB9: 20 A6 FA
00FBBC 1
00FBBC 1 PulseEffectF4_Configure: ; $FBBC
00FBBC 1 A2 9D ldx #$9D ; $FBBC: A2 9D
00FBBE 1 A0 83 ldy #$83 ; $FBBE: A0 83
00FBC0 1
00FBC0 1 A5 F4 lda $F4 ; $FBC0: A5 F4
00FBC2 1
00FBC2 1 C9 0C cmp #$0C ; $FBC2: C9 0C
00FBC4 1 B0 02 bcs PulseEffectF4_CheckUpper
00FBC6 1 ; $FBC4: B0 02
00FBC6 1
00FBC6 1 A0 84 ldy #$84 ; $FBC6: A0 84
00FBC8 1
00FBC8 1 PulseEffectF4_CheckUpper: ; $FBC8
00FBC8 1 C9 1A cmp #$1A ; $FBC8: C9 1A
00FBCA 1 B0 04 bcs PulseEffectF4_Apply ; $FBCA: B0 04
00FBCC 1
00FBCC 1 4A lsr ; $FBCC: 4A
00FBCD 1 09 90 ora #$90 ; $FBCD: 09 90
00FBCF 1 AA tax ; $FBCF: AA
00FBD0 1
00FBD0 1 PulseEffectF4_Apply: ; $FBD0
00FBD0 1 4C 55 FC jmp WritePulse2PhaseRegisters
00FBD3 1 ; $FBD0: 4C 55 FC
00FBD3 1
00FBD3 1 ; ============================================================================
00FBD3 1 ; $FBD3-$FBFE
00FBD3 1 ; Alternate pulse effect using the same shared register writer.
00FBD3 1 ; ============================================================================
00FBD3 1
00FBD3 1 StartAlternatePulse2PhaseEffect: ; $FBD3
00FBD3 1 84 F1 sty $F1 ; $FBD3: 84 F1
00FBD5 1
00FBD5 1 A9 1C lda #$1C ; $FBD5: A9 1C
00FBD7 1 85 F4 sta $F4 ; $FBD7: 85 F4
00FBD9 1
00FBD9 1 A9 12 lda #$12 ; $FBD9: A9 12
00FBDB 1 A2 98 ldx #$98 ; $FBDB: A2 98
00FBDD 1 A0 96 ldy #$96 ; $FBDD: A0 96
00FBDF 1
00FBDF 1 20 A3 FA jsr WritePulse2PeriodFromTable
00FBE2 1 ; $FBDF: 20 A3 FA
00FBE2 1
00FBE2 1 D0 74 bne CountDownPulse2PhaseEffect ; $FBE2: D0 74
00FBE4 1
00FBE4 1 UpdateAlternatePulse2PhaseEffect: ; $FBE4
00FBE4 1 A2 9C ldx #$9C ; $FBE4: A2 9C
00FBE6 1 A0 96 ldy #$96 ; $FBE6: A0 96
00FBE8 1
00FBE8 1 A5 F4 lda $F4 ; $FBE8: A5 F4
00FBEA 1 C9 18 cmp #$18 ; $FBEA: C9 18
00FBEC 1 B0 0A bcs PulseEffectAlternate_TestOdd
00FBEE 1 ; $FBEC: B0 0A
00FBEE 1
00FBEE 1 A0 86 ldy #$86 ; $FBEE: A0 86
00FBF0 1
00FBF0 1 4A lsr ; $FBF0: 4A
00FBF1 1 B0 08 bcs PulseEffectAlternate_Use90
00FBF3 1 ; $FBF1: B0 08
00FBF3 1
00FBF3 1 09 90 ora #$90 ; $FBF3: 09 90
00FBF5 1 AA tax ; $FBF5: AA
00FBF6 1
00FBF6 1 D0 5D bne WritePulse2PhaseRegisters
00FBF8 1 ; $FBF6: D0 5D
00FBF8 1
00FBF8 1 PulseEffectAlternate_TestOdd: ; $FBF8
00FBF8 1 4A lsr ; $FBF8: 4A
00FBF9 1 90 5A bcc WritePulse2PhaseRegisters
00FBFB 1 ; $FBF9: 90 5A
00FBFB 1
00FBFB 1 PulseEffectAlternate_Use90: ; $FBFB
00FBFB 1 A2 90 ldx #$90 ; $FBFB: A2 90
00FBFD 1 D0 56 bne WritePulse2PhaseRegisters
00FBFF 1 ; $FBFD: D0 56
00FBFF 1
00FBFF 1 ; ============================================================================
00FBFF 1 ; $FBFF-$FC1D
00FBFF 1 ; Secondary audio-effect dispatcher.
00FBFF 1 ; ============================================================================
00FBFF 1
00FBFF 1 UpdateSecondaryEffects: ; $FBFF
00FBFF 1 A4 FE ldy PendingAudioFlags ; $FBFF: A4 FE
00FC01 1 84 00 sty $00 ; $FC01: 84 00
00FC03 1
00FC03 1 A5 F1 lda $F1 ; $FC03: A5 F1
00FC05 1
00FC05 1 A6 FB ldx $FB ; $FC05: A6 FB
00FC07 1 D0 57 bne DispatchMusicAndNoise ; $FC07: D0 57
00FC09 1
00FC09 1 4A lsr ; $FC09: 4A
00FC0A 1 B0 9D bcs UpdatePulse2PhaseEffect ; $FC0A: B0 9D
00FC0C 1
00FC0C 1 46 FE lsr PendingAudioFlags ; $FC0C: 46 FE
00FC0E 1 B0 91 bcs StartPulse2PhaseEffect ; $FC0E: B0 91
00FC10 1
00FC10 1 4A lsr ; $FC10: 4A
00FC11 1 B0 D1 bcs UpdateAlternatePulse2PhaseEffect
00FC13 1 ; $FC11: B0 D1
00FC13 1
00FC13 1 46 FE lsr PendingAudioFlags ; $FC13: 46 FE
00FC15 1 B0 BC bcs StartAlternatePulse2PhaseEffect
00FC17 1 ; $FC15: B0 BC
00FC17 1
00FC17 1 4A lsr ; $FC17: 4A
00FC18 1 B0 19 bcs UpdateTrianglePitchSweep
00FC1A 1 ; $FC18: B0 19
00FC1A 1
00FC1A 1 46 FE lsr PendingAudioFlags ; $FC1A: 46 FE
00FC1C 1 90 42 bcc DispatchMusicAndNoise ; $FC1C: 90 42
00FC1E 1
00FC1E 1 ; ============================================================================
00FC1E 1 ; $FC1E-$FC32
00FC1E 1 ; Start the triangle sweep effect.
00FC1E 1 ; ============================================================================
00FC1E 1
00FC1E 1 StartTrianglePitchSweep: ; $FC1E
00FC1E 1 84 F1 sty $F1 ; $FC1E: 84 F1
00FC20 1
00FC20 1 A9 05 lda #$05 ; $FC20: A9 05
00FC22 1 85 F4 sta $F4 ; $FC22: 85 F4
00FC24 1
00FC24 1 A2 3F ldx #$3F ; $FC24: A2 3F
00FC26 1
00FC26 1 EE FD 07 inc $07FD ; $FC26: EE FD 07
00FC29 1
00FC29 1 AD FD 07 lda $07FD ; $FC29: AD FD 07
00FC2C 1 4A lsr ; $FC2C: 4A
00FC2D 1 90 02 bcc StartTriangleSweep_Save ; $FC2D: 90 02
00FC2F 1
00FC2F 1 A2 50 ldx #$50 ; $FC2F: A2 50
00FC31 1
00FC31 1 StartTriangleSweep_Save: ; $FC31
00FC31 1 86 F5 stx $F5 ; $FC31: 86 F5
00FC33 1
00FC33 1 ; ============================================================================
00FC33 1 ; $FC33-$FC5F
00FC33 1 ; Update the triangle sweep and shared pulse registers.
00FC33 1 ; ============================================================================
00FC33 1
00FC33 1 UpdateTrianglePitchSweep: ; $FC33
00FC33 1 A5 F5 lda $F5 ; $FC33: A5 F5
00FC35 1
00FC35 1 4A lsr ; $FC35: 4A
00FC36 1 4A lsr ; $FC36: 4A
00FC37 1 4A lsr ; $FC37: 4A
00FC38 1
00FC38 1 65 F5 adc $F5 ; $FC38: 65 F5
00FC3A 1 85 F5 sta $F5 ; $FC3A: 85 F5
00FC3C 1
00FC3C 1 0A asl ; $FC3C: 0A
00FC3D 1 0A asl ; $FC3D: 0A
00FC3E 1 8D 06 40 sta $4006 ; $FC3E: 8D 06 40
00FC41 1
00FC41 1 2A rol ; $FC41: 2A
00FC42 1 29 03 and #$03 ; $FC42: 29 03
00FC44 1 8D 07 40 sta $4007 ; $FC44: 8D 07 40
00FC47 1
00FC47 1 A0 81 ldy #$81 ; $FC47: A0 81
00FC49 1 A2 50 ldx #$50 ; $FC49: A2 50
00FC4B 1
00FC4B 1 A5 F4 lda $F4 ; $FC4B: A5 F4
00FC4D 1 C9 04 cmp #$04 ; $FC4D: C9 04
00FC4F 1 90 04 bcc WritePulse2PhaseRegisters
00FC51 1 ; $FC4F: 90 04
00FC51 1
00FC51 1 18 clc ; $FC51: 18
00FC52 1 69 4F adc #$4F ; $FC52: 69 4F
00FC54 1 AA tax ; $FC54: AA
00FC55 1
00FC55 1 WritePulse2PhaseRegisters: ; $FC55
00FC55 1 20 73 FA jsr WritePulse2SweepAndControlFromRegisters ; $FC55: 20 73 FA
00FC58 1
00FC58 1 CountDownPulse2PhaseEffect: ; $FC58
00FC58 1 C6 F4 dec $F4 ; $FC58: C6 F4
00FC5A 1 D0 04 bne DispatchMusicAndNoise ; $FC5A: D0 04
00FC5C 1
00FC5C 1 A9 00 lda #$00 ; $FC5C: A9 00
00FC5E 1 85 F1 sta $F1 ; $FC5E: 85 F1
00FC60 1
00FC60 1 ; ============================================================================
00FC60 1 ; $FC60-$FC99
00FC60 1 ; Dispatch miscellaneous audio events.
00FC60 1 ; ============================================================================
00FC60 1
00FC60 1 DispatchMusicAndNoise: ; $FC60
00FC60 1 A5 EF lda GameplaySuspended ; $FC60: A5 EF
00FC62 1 D0 30 bne UpdateMusicSequencer ; $FC62: D0 30
00FC64 1
00FC64 1 A4 00 ldy $00 ; $FC64: A4 00
00FC66 1 30 2F bmi UpdateNoiseEffectSequence ; $FC66: 30 2F
00FC68 1
00FC68 1 AD F5 07 lda $07F5 ; $FC68: AD F5 07
00FC6B 1
00FC6B 1 0A asl ; $FC6B: 0A
00FC6C 1 30 3A bmi UpdateDmcOutputEffect ; $FC6C: 30 3A
00FC6E 1
00FC6E 1 06 00 asl $00 ; $FC6E: 06 00
00FC70 1 30 28 bmi StartTriangleEffectShort ; $FC70: 30 28
00FC72 1
00FC72 1 0A asl ; $FC72: 0A
00FC73 1 30 5A bmi ContinueTimedAudioEffect ; $FC73: 30 5A
00FC75 1
00FC75 1 06 00 asl $00 ; $FC75: 06 00
00FC77 1 30 3B bmi StartTriangleEffectMedium ; $FC77: 30 3B
00FC79 1
00FC79 1 0A asl ; $FC79: 0A
00FC7A 1 30 68 bmi UpdateTriangleEffectLong ; $FC7A: 30 68
00FC7C 1
00FC7C 1 06 00 asl $00 ; $FC7C: 06 00
00FC7E 1 30 56 bmi StartTriangleEffectLong ; $FC7E: 30 56
00FC80 1
00FC80 1 0A asl ; $FC80: 0A
00FC81 1 30 7E bmi UpdateTriangleEffectAlternate ; $FC81: 30 7E
00FC83 1
00FC83 1 06 00 asl $00 ; $FC83: 06 00
00FC85 1 30 6C bmi StartTriangleEffectAlternate ; $FC85: 30 6C
00FC87 1
00FC87 1 ResetTimedAudioEvents: ; $FC87
00FC87 1 A9 00 lda #$00 ; $FC87: A9 00
00FC89 1
00FC89 1 8D FA 07 sta $07FA ; $FC89: 8D FA 07
00FC8C 1 8D F5 07 sta $07F5 ; $FC8C: 8D F5 07
00FC8F 1
00FC8F 1 A9 10 lda #$10 ; $FC8F: A9 10
00FC91 1 8D 0C 40 sta $400C ; $FC91: 8D 0C 40
00FC94 1
00FC94 1 UpdateMusicSequencer: ; $FC94
00FC94 1 4C 2A FD jmp UpdateMusicEngine ; $FC94: 4C 2A FD
00FC97 1
00FC97 1 UpdateNoiseEffectSequence: ; $FC97
00FC97 1 4C 14 FD jmp UpdateNoiseEnvelopeSequence ; $FC97: 4C 14 FD
00FC9A 1
00FC9A 1 ; ============================================================================
00FC9A 1 ; $FC9A-$FCA7
00FC9A 1 ; Audio event 2.
00FC9A 1 ; ============================================================================
00FC9A 1
00FC9A 1 StartTriangleEffectShort: ; $FC9A
00FC9A 1 8C F5 07 sty $07F5 ; $FC9A: 8C F5 07
00FC9D 1
00FC9D 1 A9 09 lda #$09 ; $FC9D: A9 09
00FC9F 1 8D F8 07 sta $07F8 ; $FC9F: 8D F8 07
00FCA2 1
00FCA2 1 A9 35 lda #$35 ; $FCA2: A9 35
00FCA4 1 A0 1C ldy #$1C ; $FCA4: A0 1C
00FCA6 1
00FCA6 1 D0 18 bne ConfigureTimedTriangleEffect ; $FCA6: D0 18
00FCA8 1
00FCA8 1 ; ============================================================================
00FCA8 1 ; $FCA8-$FCB3
00FCA8 1 ; Audio event 1.
00FCA8 1 ; ============================================================================
00FCA8 1
00FCA8 1 UpdateDmcOutputEffect: ; $FCA8
00FCA8 1 AD FF 07 lda $07FF ; $FCA8: AD FF 07
00FCAB 1
00FCAB 1 18 clc ; $FCAB: 18
00FCAC 1 69 10 adc #$10 ; $FCAC: 69 10
00FCAE 1 8D FF 07 sta $07FF ; $FCAE: 8D FF 07
00FCB1 1
00FCB1 1 4C CF FC jmp CountDownTimedAudioEffect ; $FCB1: 4C CF FC
00FCB4 1
00FCB4 1 ; ============================================================================
00FCB4 1 ; $FCB4-$FCD5
00FCB4 1 ; Audio event 4 and shared triangle-channel configuration.
00FCB4 1 ; ============================================================================
00FCB4 1
00FCB4 1 StartTriangleEffectMedium: ; $FCB4
00FCB4 1 8C F5 07 sty $07F5 ; $FCB4: 8C F5 07
00FCB7 1
00FCB7 1 A9 08 lda #$08 ; $FCB7: A9 08
00FCB9 1 8D F8 07 sta $07F8 ; $FCB9: 8D F8 07
00FCBC 1
00FCBC 1 A9 54 lda #$54 ; $FCBC: A9 54
00FCBE 1 A0 0A ldy #$0A ; $FCBE: A0 0A
00FCC0 1
00FCC0 1 ConfigureTimedTriangleEffect: ; $FCC0
00FCC0 1 8D 0A 40 sta $400A ; $FCC0: 8D 0A 40
00FCC3 1
00FCC3 1 A2 08 ldx #$08 ; $FCC3: A2 08
00FCC5 1 8E 0B 40 stx $400B ; $FCC5: 8E 0B 40
00FCC8 1
00FCC8 1 8C 08 40 sty $4008 ; $FCC8: 8C 08 40
00FCCB 1
00FCCB 1 A9 00 lda #$00 ; $FCCB: A9 00
00FCCD 1 85 F0 sta $F0 ; $FCCD: 85 F0
00FCCF 1
00FCCF 1 CountDownTimedAudioEffect: ; $FCCF
00FCCF 1 CE F8 07 dec $07F8 ; $FCCF: CE F8 07
00FCD2 1 F0 B3 beq ResetTimedAudioEvents ; $FCD2: F0 B3
00FCD4 1
00FCD4 1 D0 BE bne UpdateMusicSequencer ; $FCD4: D0 BE
00FCD6 1
00FCD6 1 ; ============================================================================
00FCD6 1 ; $FCD6-$FCE3
00FCD6 1 ; Initialize audio event 6.
00FCD6 1 ;
00FCD6 1 ; This event:
00FCD6 1 ; - saves the current event flags in $07F5
00FCD6 1 ; - initializes a countdown of $12 in $07F8
00FCD6 1 ; - selects triangle linear-counter value $06
00FCD6 1 ; - selects timer value $3F
00FCD6 1 ; - enters the shared triangle-channel configuration at $FCC0
00FCD6 1 ; ============================================================================
00FCD6 1
00FCD6 1 StartTriangleEffectLong: ; $FCD6
00FCD6 1 8C F5 07 sty $07F5 ; $FCD6: 8C F5 07
00FCD9 1 ; Preserve the active event flags.
00FCD9 1
00FCD9 1 A9 12 lda #$12 ; $FCD9: A9 12
00FCDB 1 8D F8 07 sta $07F8 ; $FCDB: 8D F8 07
00FCDE 1 ; Initialize the event countdown.
00FCDE 1
00FCDE 1 A0 06 ldy #$06 ; $FCDE: A0 06
00FCE0 1 ; Triangle linear-counter value.
00FCE0 1
00FCE0 1 A9 3F lda #$3F ; $FCE0: A9 3F
00FCE2 1 ; Triangle timer-low value.
00FCE2 1
00FCE2 1 D0 DC bne ConfigureTimedTriangleEffect ; $FCE2: D0 DC
00FCE4 1 ; Always taken.
00FCE4 1 ; Target $FCC0.
00FCE4 1
00FCE4 1 ; ============================================================================
00FCE4 1 ; $FCE4-$FCF2
00FCE4 1 ; Update audio event 5.
00FCE4 1 ;
00FCE4 1 ; The handler modifies the triangle-channel parameters at two countdown
00FCE4 1 ; thresholds:
00FCE4 1 ;
00FCE4 1 ; $07F8 = $0E:
00FCE4 1 ; use timer $3F and linear-counter value $06
00FCE4 1 ;
00FCE4 1 ; $07F8 = $0A:
00FCE4 1 ; use timer $3F and linear-counter value $20
00FCE4 1 ;
00FCE4 1 ; Other countdown values continue through the common countdown path at $FCCF.
00FCE4 1 ; ============================================================================
00FCE4 1
00FCE4 1 UpdateTriangleEffectLong: ; $FCE4
00FCE4 1 AD F8 07 lda $07F8 ; $FCE4: AD F8 07
00FCE7 1
00FCE7 1 C9 0E cmp #$0E ; $FCE7: C9 0E
00FCE9 1 F0 F3 beq AudioEvent_6_Configure ; $FCE9: F0 F3
00FCEB 1 ; Target $FCDE.
00FCEB 1
00FCEB 1 C9 0A cmp #$0A ; $FCEB: C9 0A
00FCED 1 D0 E0 bne CountDownTimedAudioEffect ; $FCED: D0 E0
00FCEF 1 ; Target $FCCF.
00FCEF 1
00FCEF 1 ; ----------------------------------------------------------------------------
00FCEF 1 ; At countdown $0A, use a larger triangle linear-counter value.
00FCEF 1 ; ----------------------------------------------------------------------------
00FCEF 1
00FCEF 1 A0 20 ldy #$20 ; $FCEF: A0 20
00FCF1 1
00FCF1 1 D0 ED bne AudioEvent_5_SetTimer ; $FCF1: D0 ED
00FCF3 1 ; Always taken.
00FCF3 1 ; Target $FCE0.
00FCF3 1
00FCF3 1 ; ----------------------------------------------------------------------------
00FCF3 1 ; Internal entry shared with StartTriangleEffectLong.
00FCF3 1 ; ----------------------------------------------------------------------------
00FCF3 1
00FCF3 1 AudioEvent_6_Configure = $FCDE
00FCF3 1 AudioEvent_5_SetTimer = $FCE0
00FCF3 1
00FCF3 1 ; ============================================================================
00FCF3 1 ; $FCF3-$FD00
00FCF3 1 ; Initialize audio event 8.
00FCF3 1 ;
00FCF3 1 ; This event:
00FCF3 1 ; - saves the current event flags
00FCF3 1 ; - initializes a countdown of $14
00FCF3 1 ; - selects triangle linear-counter value $18
00FCF3 1 ; - selects timer value $6A
00FCF3 1 ; - enters the shared triangle-channel configuration at $FCC0
00FCF3 1 ; ============================================================================
00FCF3 1
00FCF3 1 StartTriangleEffectAlternate: ; $FCF3
00FCF3 1 8C F5 07 sty $07F5 ; $FCF3: 8C F5 07
00FCF6 1
00FCF6 1 A9 14 lda #$14 ; $FCF6: A9 14
00FCF8 1 8D F8 07 sta $07F8 ; $FCF8: 8D F8 07
00FCFB 1
00FCFB 1 A0 18 ldy #$18 ; $FCFB: A0 18
00FCFD 1
00FCFD 1 AudioEvent_8_SetTimer: ; $FCFD
00FCFD 1 A9 6A lda #$6A ; $FCFD: A9 6A
00FCFF 1
00FCFF 1 D0 BF bne ConfigureTimedTriangleEffect ; $FCFF: D0 BF
00FD01 1 ; Always taken.
00FD01 1 ; Target $FCC0.
00FD01 1
00FD01 1 ; ============================================================================
00FD01 1 ; $FD01-$FD0B
00FD01 1 ; Update audio event 7.
00FD01 1 ;
00FD01 1 ; At countdown value $08, the triangle linear-counter value changes to $10
00FD01 1 ; while retaining timer value $6A.
00FD01 1 ;
00FD01 1 ; All other countdown values use the common countdown path at $FCCF.
00FD01 1 ; ============================================================================
00FD01 1
00FD01 1 UpdateTriangleEffectAlternate: ; $FD01
00FD01 1 AD F8 07 lda $07F8 ; $FD01: AD F8 07
00FD04 1
00FD04 1 C9 08 cmp #$08 ; $FD04: C9 08
00FD06 1 D0 C7 bne CountDownTimedAudioEffect ; $FD06: D0 C7
00FD08 1 ; Target $FCCF.
00FD08 1
00FD08 1 A0 10 ldy #$10 ; $FD08: A0 10
00FD0A 1
00FD0A 1 D0 F1 bne AudioEvent_8_SetTimer ; $FD0A: D0 F1
00FD0C 1 ; Always taken.
00FD0C 1 ; Target $FCFD.
00FD0C 1
00FD0C 1 ; ============================================================================
00FD0C 1 ; Existing target definition.
00FD0C 1 ;
00FD0C 1 ; ContinueTimedAudioEffect is the shared countdown path itself. The dispatcher branch at
00FD0C 1 ; $FC73 intentionally enters at $FCCF.
00FD0C 1 ; ============================================================================
00FD0C 1
00FD0C 1 ContinueTimedAudioEffect = CountDownTimedAudioEffect
00FD0C 1
00FD0C 1 ; ============================================================================
00FD0C 1 ; $FD0C-$FD13
00FD0C 1 ; Eight-entry audio lookup table.
00FD0C 1 ;
00FD0C 1 ; The routine beginning at $FD14 derives a three-bit index and uses it to load
00FD0C 1 ; one of these values.
00FD0C 1 ; ============================================================================
00FD0C 1
00FD0C 1 NoiseEnvelopeSequence: ; $FD0C
00FD0C 1 12 13 14 15 .byte $12,$13,$14,$15
00FD10 1 15 14 13 13 .byte $15,$14,$13,$13
00FD14 1
00FD14 1 ; ============================================================================
00FD14 1 ; $FD14-$FD29
00FD14 1 ; Update a table-driven noise or effect value from the sequence counter $07FA.
00FD14 1 ;
00FD14 1 ; The high five bits of $07FA select one of eight entries in the table at
00FD14 1 ; $FD0C. The selected value is passed to ConfigureNoiseChannel at $FA7A with
00FD14 1 ; X=$0E.
00FD14 1 ;
00FD14 1 ; Exit:
00FD14 1 ; $07FA incremented
00FD14 1 ; ============================================================================
00FD14 1
00FD14 1 UpdateNoiseEnvelopeSequence: ; $FD14
00FD14 1 AD FA 07 lda $07FA ; $FD14: AD FA 07
00FD17 1
00FD17 1 4A lsr ; $FD17: 4A
00FD18 1 4A lsr ; $FD18: 4A
00FD19 1 4A lsr ; $FD19: 4A
00FD1A 1 4A lsr ; $FD1A: 4A
00FD1B 1 4A lsr ; $FD1B: 4A
00FD1C 1
00FD1C 1 29 07 and #$07 ; $FD1C: 29 07
00FD1E 1 A8 tay ; $FD1E: A8
00FD1F 1
00FD1F 1 B9 0C FD lda NoiseEnvelopeSequence,y
00FD22 1 ; $FD1F: B9 0C FD
00FD22 1
00FD22 1 A2 0E ldx #$0E ; $FD22: A2 0E
00FD24 1
00FD24 1 20 7A FA jsr ConfigureNoiseChannel ; $FD24: 20 7A FA
00FD27 1
00FD27 1 EE FA 07 inc $07FA ; $FD27: EE FA 07
00FD2A 1
00FD2A 1 ; ============================================================================
00FD2A 1 ; $FD2A-$FD66
00FD2A 1 ; Initialize a music or note-sequence stream when required.
00FD2A 1 ;
00FD2A 1 ; State:
00FD2A 1 ; $FD = sequence request or selector
00FD2A 1 ; $FC = selected sequence bank
00FD2A 1 ; $FA/$FB = channel stream cursors
00FD2A 1 ; $F6-$FA = five-byte stream descriptor loaded from the table at $FE40
00FD2A 1 ; $07F0-$07F2 = per-channel countdowns
00FD2A 1 ; ============================================================================
00FD2A 1
00FD2A 1 UpdateMusicEngine: ; $FD2A
00FD2A 1 A5 FD lda $FD ; $FD2A: A5 FD
00FD2C 1 D0 06 bne StartMusicSequence ; $FD2C: D0 06
00FD2E 1
00FD2E 1 AD F4 07 lda $07F4 ; $FD2E: AD F4 07
00FD31 1 D0 34 bne UpdatePulse1MusicChannel ; $FD31: D0 34
00FD33 1
00FD33 1 60 rts ; $FD33: 60
00FD34 1
00FD34 1 ; ----------------------------------------------------------------------------
00FD34 1 ; Convert the sequence selector in A into a bank index in Y.
00FD34 1 ;
00FD34 1 ; The loop shifts A left until carry becomes set, decrementing Y for each
00FD34 1 ; unsuccessful shift.
00FD34 1 ; ----------------------------------------------------------------------------
00FD34 1
00FD34 1 StartMusicSequence: ; $FD34
00FD34 1 A0 07 ldy #$07 ; $FD34: A0 07
00FD36 1
00FD36 1 InitializeMusicSequence_FindBank: ; $FD36
00FD36 1 0A asl ; $FD36: 0A
00FD37 1 B0 03 bcs InitializeMusicSequence_BankFound
00FD39 1 ; $FD37: B0 03
00FD39 1
00FD39 1 88 dey ; $FD39: 88
00FD3A 1 D0 FA bne InitializeMusicSequence_FindBank
00FD3C 1 ; $FD3A: D0 FA
00FD3C 1
00FD3C 1 ; ----------------------------------------------------------------------------
00FD3C 1 ; Mark that a sequence is active and save the selected bank.
00FD3C 1 ; ----------------------------------------------------------------------------
00FD3C 1
00FD3C 1 InitializeMusicSequence_BankFound: ; $FD3C
00FD3C 1 EE F4 07 inc $07F4 ; $FD3C: EE F4 07
00FD3F 1
00FD3F 1 84 FC sty $FC ; $FD3F: 84 FC
00FD41 1
00FD41 1 ; ----------------------------------------------------------------------------
00FD41 1 ; Bank one is remapped to bank zero.
00FD41 1 ; ----------------------------------------------------------------------------
00FD41 1
00FD41 1 C0 01 cpy #$01 ; $FD41: C0 01
00FD43 1 D0 04 bne InitializeMusicSequence_LoadPointer
00FD45 1 ; $FD43: D0 04
00FD45 1
00FD45 1 A9 00 lda #$00 ; $FD45: A9 00
00FD47 1 85 FC sta $FC ; $FD47: 85 FC
00FD49 1
00FD49 1 ; ----------------------------------------------------------------------------
00FD49 1 ; The table at $FE40 contains an outer pointer/index byte followed by a five-byte
00FD49 1 ; stream descriptor. The first lookup maps the selected bank to the descriptor
00FD49 1 ; offset.
00FD49 1 ; ----------------------------------------------------------------------------
00FD49 1
00FD49 1 InitializeMusicSequence_LoadPointer: ; $FD49
00FD49 1 B9 40 FE lda $FE40,y ; $FD49: B9 40 FE
00FD4C 1 A8 tay ; $FD4C: A8
00FD4D 1
00FD4D 1 A2 00 ldx #$00 ; $FD4D: A2 00
00FD4F 1 86 FB stx $FB ; $FD4F: 86 FB
00FD51 1
00FD51 1 ; ----------------------------------------------------------------------------
00FD51 1 ; Copy five bytes from the selected descriptor into $F6-$FA.
00FD51 1 ; ----------------------------------------------------------------------------
00FD51 1
00FD51 1 InitializeMusicSequence_CopyDescriptor: ; $FD51
00FD51 1 B9 40 FE lda $FE40,y ; $FD51: B9 40 FE
00FD54 1 95 F6 sta $F6,x ; $FD54: 95 F6
00FD56 1
00FD56 1 C8 iny ; $FD56: C8
00FD57 1 E8 inx ; $FD57: E8
00FD58 1
00FD58 1 E0 05 cpx #$05 ; $FD58: E0 05
00FD5A 1 D0 F5 bne InitializeMusicSequence_CopyDescriptor
00FD5C 1 ; $FD5A: D0 F5
00FD5C 1
00FD5C 1 ; ----------------------------------------------------------------------------
00FD5C 1 ; Initialize all three channel countdowns to one so each channel fetches its
00FD5C 1 ; first command immediately.
00FD5C 1 ; ----------------------------------------------------------------------------
00FD5C 1
00FD5C 1 A9 01 lda #$01 ; $FD5C: A9 01
00FD5E 1
00FD5E 1 8D F0 07 sta $07F0 ; $FD5E: 8D F0 07
00FD61 1 8D F1 07 sta $07F1 ; $FD61: 8D F1 07
00FD64 1 8D F2 07 sta $07F2 ; $FD64: 8D F2 07
00FD67 1
00FD67 1 ; ============================================================================
00FD67 1 ; $FD67-$FDB8
00FD67 1 ; Update the first music channel.
00FD67 1 ;
00FD67 1 ; $FA is the channel stream cursor. $07F1 is its countdown.
00FD67 1 ; ============================================================================
00FD67 1
00FD67 1 UpdatePulse1MusicChannel: ; $FD67
00FD67 1 A4 FA ldy $FA ; $FD67: A4 FA
00FD69 1 F0 4E beq UpdatePulse2MusicChannel ; $FD69: F0 4E
00FD6B 1
00FD6B 1 ; ----------------------------------------------------------------------------
00FD6B 1 ; For sequence bank zero, reset pulse 1 when the countdown reaches two.
00FD6B 1 ; ----------------------------------------------------------------------------
00FD6B 1
00FD6B 1 A5 FC lda $FC ; $FD6B: A5 FC
00FD6D 1 D0 0A bne UpdateMusicChannel1_Decrement
00FD6F 1 ; $FD6D: D0 0A
00FD6F 1
00FD6F 1 AD F1 07 lda $07F1 ; $FD6F: AD F1 07
00FD72 1 C9 02 cmp #$02 ; $FD72: C9 02
00FD74 1 D0 03 bne UpdateMusicChannel1_Decrement
00FD76 1 ; $FD74: D0 03
00FD76 1
00FD76 1 20 60 FA jsr ConfigurePulse1ControlPreset
00FD79 1 ; $FD76: 20 60 FA
00FD79 1
00FD79 1 ; ----------------------------------------------------------------------------
00FD79 1 ; Count down the current note duration.
00FD79 1 ; ----------------------------------------------------------------------------
00FD79 1
00FD79 1 UpdateMusicChannel1_Decrement: ; $FD79
00FD79 1 CE F1 07 dec $07F1 ; $FD79: CE F1 07
00FD7C 1 D0 3B bne UpdatePulse2MusicChannel ; $FD7C: D0 3B
00FD7E 1
00FD7E 1 ; ----------------------------------------------------------------------------
00FD7E 1 ; Fetch the next stream command.
00FD7E 1 ; ----------------------------------------------------------------------------
00FD7E 1
00FD7E 1 E6 FA inc $FA ; $FD7E: E6 FA
00FD80 1
00FD80 1 B1 F7 lda ($F7),y ; $FD80: B1 F7
00FD82 1 10 0C bpl UpdateMusicChannel1_HaveNote
00FD84 1 ; $FD82: 10 0C
00FD84 1
00FD84 1 ; ----------------------------------------------------------------------------
00FD84 1 ; Negative bytes are extended commands. Decode the duration/control value and
00FD84 1 ; fetch the following note byte.
00FD84 1 ; ----------------------------------------------------------------------------
00FD84 1
00FD84 1 20 C5 FA jsr LookupAudioControlValueFinalRotate ; $FD84: 20 C5 FA
00FD87 1 8D F3 07 sta $07F3 ; $FD87: 8D F3 07
00FD8A 1
00FD8A 1 A4 FA ldy $FA ; $FD8A: A4 FA
00FD8C 1 E6 FA inc $FA ; $FD8C: E6 FA
00FD8E 1
00FD8E 1 B1 F7 lda ($F7),y ; $FD8E: B1 F7
00FD90 1
00FD90 1 ; ----------------------------------------------------------------------------
00FD90 1 ; Convert the note value through the audio period helper at $FA8F.
00FD90 1 ; ----------------------------------------------------------------------------
00FD90 1
00FD90 1 UpdateMusicChannel1_HaveNote: ; $FD90
00FD90 1 20 8F FA jsr WritePulsePeriod_SelectChannel ; $FD90: 20 8F FA
00FD93 1
00FD93 1 D0 04 bne UpdateMusicChannel1_SelectControl
00FD95 1 ; $FD93: D0 04
00FD95 1
00FD95 1 A2 10 ldx #$10 ; $FD95: A2 10
00FD97 1 D0 17 bne UpdateMusicChannel1_Write
00FD99 1 ; $FD97: D0 17
00FD99 1
00FD99 1 ; ----------------------------------------------------------------------------
00FD99 1 ; Select pulse control according to sequence bank, duration, and channel state.
00FD99 1 ; ----------------------------------------------------------------------------
00FD99 1
00FD99 1 UpdateMusicChannel1_SelectControl: ; $FD99
00FD99 1 A2 5A ldx #$5A ; $FD99: A2 5A
00FD9B 1
00FD9B 1 A5 FC lda $FC ; $FD9B: A5 FC
00FD9D 1 F0 11 beq UpdateMusicChannel1_Write
00FD9F 1 ; $FD9D: F0 11
00FD9F 1
00FD9F 1 A2 46 ldx #$46 ; $FD9F: A2 46
00FDA1 1
00FDA1 1 AD F3 07 lda $07F3 ; $FDA1: AD F3 07
00FDA4 1 C9 08 cmp #$08 ; $FDA4: C9 08
00FDA6 1 B0 02 bcs UpdateMusicChannel1_CheckAlt
00FDA8 1 ; $FDA6: B0 02
00FDA8 1
00FDA8 1 A2 42 ldx #$42 ; $FDA8: A2 42
00FDAA 1
00FDAA 1 UpdateMusicChannel1_CheckAlt: ; $FDAA
00FDAA 1 A5 F9 lda $F9 ; $FDAA: A5 F9
00FDAC 1 D0 02 bne UpdateMusicChannel1_Write
00FDAE 1 ; $FDAC: D0 02
00FDAE 1
00FDAE 1 A2 86 ldx #$86 ; $FDAE: A2 86
00FDB0 1
00FDB0 1 ; ----------------------------------------------------------------------------
00FDB0 1 ; Write pulse channel 1 sweep/control and reload the note countdown.
00FDB0 1 ; ----------------------------------------------------------------------------
00FDB0 1
00FDB0 1 UpdateMusicChannel1_Write: ; $FDB0
00FDB0 1 20 68 FA jsr WritePulse1SweepAndControl ; $FDB0: 20 68 FA
00FDB3 1
00FDB3 1 AD F3 07 lda $07F3 ; $FDB3: AD F3 07
00FDB6 1 8D F1 07 sta $07F1 ; $FDB6: 8D F1 07
00FDB9 1
00FDB9 1 ; ============================================================================
00FDB9 1 ; $FDB9-$FE04
00FDB9 1 ; Update the second music channel.
00FDB9 1 ;
00FDB9 1 ; $FB is the channel stream cursor. $07F0 is its countdown.
00FDB9 1 ; ============================================================================
00FDB9 1
00FDB9 1 UpdatePulse2MusicChannel: ; $FDB9
00FDB9 1 A5 FC lda $FC ; $FDB9: A5 FC
00FDBB 1 D0 0A bne UpdateMusicChannel2_Decrement
00FDBD 1 ; $FDBB: D0 0A
00FDBD 1
00FDBD 1 AD F0 07 lda $07F0 ; $FDBD: AD F0 07
00FDC0 1 C9 02 cmp #$02 ; $FDC0: C9 02
00FDC2 1 D0 03 bne UpdateMusicChannel2_Decrement
00FDC4 1 ; $FDC2: D0 03
00FDC4 1
00FDC4 1 20 64 FA jsr ConfigurePulse2ControlPreset
00FDC7 1 ; $FDC4: 20 64 FA
00FDC7 1
00FDC7 1 UpdateMusicChannel2_Decrement: ; $FDC7
00FDC7 1 CE F0 07 dec $07F0 ; $FDC7: CE F0 07
00FDCA 1 D0 39 bne UpdateTriangleMusicChannel ; $FDCA: D0 39
00FDCC 1
00FDCC 1 ; ----------------------------------------------------------------------------
00FDCC 1 ; Fetch the next byte from the second channel stream.
00FDCC 1 ; ----------------------------------------------------------------------------
00FDCC 1
00FDCC 1 A4 FB ldy $FB ; $FDCC: A4 FB
00FDCE 1 E6 FB inc $FB ; $FDCE: E6 FB
00FDD0 1
00FDD0 1 B1 F7 lda ($F7),y ; $FDD0: B1 F7
00FDD2 1 D0 0B bne UpdateMusicChannel2_HaveCommand
00FDD4 1 ; $FDD2: D0 0B
00FDD4 1
00FDD4 1 ; ----------------------------------------------------------------------------
00FDD4 1 ; A zero byte terminates the complete music sequence.
00FDD4 1 ; ----------------------------------------------------------------------------
00FDD4 1
00FDD4 1 85 FB sta $FB ; $FDD4: 85 FB
00FDD6 1 85 FA sta $FA ; $FDD6: 85 FA
00FDD8 1 8D F4 07 sta $07F4 ; $FDD8: 8D F4 07
00FDDB 1
00FDDB 1 20 60 FA jsr ConfigurePulse1ControlPreset
00FDDE 1 ; $FDDB: 20 60 FA
00FDDE 1
00FDDE 1 60 rts ; $FDDE: 60
00FDDF 1
00FDDF 1 ; ----------------------------------------------------------------------------
00FDDF 1 ; Decode the command and write the pulse 2 period/control.
00FDDF 1 ; ----------------------------------------------------------------------------
00FDDF 1
00FDDF 1 UpdateMusicChannel2_HaveCommand: ; $FDDF
00FDDF 1 20 BF FA jsr LookupAudioControlValue ; $FDDF: 20 BF FA
00FDE2 1 8D F0 07 sta $07F0 ; $FDE2: 8D F0 07
00FDE5 1
00FDE5 1 8A txa ; $FDE5: 8A
00FDE6 1 29 3E and #$3E ; $FDE6: 29 3E
00FDE8 1
00FDE8 1 20 A6 FA jsr WritePulse2PeriodAfterSweep ; $FDE8: 20 A6 FA
00FDEB 1
00FDEB 1 D0 04 bne UpdateMusicChannel2_SelectControl
00FDED 1 ; $FDEB: D0 04
00FDED 1
00FDED 1 A2 90 ldx #$90 ; $FDED: A2 90
00FDEF 1 D0 11 bne UpdateMusicChannel2_Write
00FDF1 1 ; $FDEF: D0 11
00FDF1 1
00FDF1 1 UpdateMusicChannel2_SelectControl: ; $FDF1
00FDF1 1 A2 9D ldx #$9D ; $FDF1: A2 9D
00FDF3 1
00FDF3 1 A5 FC lda $FC ; $FDF3: A5 FC
00FDF5 1 F0 0B beq UpdateMusicChannel2_Write
00FDF7 1 ; $FDF5: F0 0B
00FDF7 1
00FDF7 1 A2 86 ldx #$86 ; $FDF7: A2 86
00FDF9 1
00FDF9 1 AD F0 07 lda $07F0 ; $FDF9: AD F0 07
00FDFC 1 C9 08 cmp #$08 ; $FDFC: C9 08
00FDFE 1 B0 02 bcs UpdateMusicChannel2_Write
00FE00 1 ; $FDFE: B0 02
00FE00 1
00FE00 1 A2 82 ldx #$82 ; $FE00: A2 82
00FE02 1
00FE02 1 UpdateMusicChannel2_Write: ; $FE02
00FE02 1 20 71 FA jsr WritePulse2SweepAndControl ; $FE02: 20 71 FA
00FE05 1
00FE05 1 ; ============================================================================
00FE05 1 ; $FE05-$FE3F
00FE05 1 ; Update the triangle music channel.
00FE05 1 ;
00FE05 1 ; $F9 is the stream cursor and $07F2 is the countdown.
00FE05 1 ; ============================================================================
00FE05 1
00FE05 1 UpdateTriangleMusicChannel: ; $FE05
00FE05 1 A4 F9 ldy $F9 ; $FE05: A4 F9
00FE07 1 F0 36 beq UpdateMusicSequence_Return
00FE09 1 ; $FE07: F0 36
00FE09 1
00FE09 1 AD F2 07 lda $07F2 ; $FE09: AD F2 07
00FE0C 1 C9 02 cmp #$02 ; $FE0C: C9 02
00FE0E 1 D0 05 bne UpdateMusicChannel3_Decrement
00FE10 1 ; $FE0E: D0 05
00FE10 1
00FE10 1 A9 00 lda #$00 ; $FE10: A9 00
00FE12 1 8D 08 40 sta $4008 ; $FE12: 8D 08 40
00FE15 1
00FE15 1 UpdateMusicChannel3_Decrement: ; $FE15
00FE15 1 CE F2 07 dec $07F2 ; $FE15: CE F2 07
00FE18 1 D0 25 bne UpdateMusicSequence_Return
00FE1A 1 ; $FE18: D0 25
00FE1A 1
00FE1A 1 ; ----------------------------------------------------------------------------
00FE1A 1 ; Fetch and decode the next triangle-channel command.
00FE1A 1 ; ----------------------------------------------------------------------------
00FE1A 1
00FE1A 1 E6 F9 inc $F9 ; $FE1A: E6 F9
00FE1C 1
00FE1C 1 B1 F7 lda ($F7),y ; $FE1C: B1 F7
00FE1E 1 20 BF FA jsr LookupAudioControlValue ; $FE1E: 20 BF FA
00FE21 1
00FE21 1 8D F2 07 sta $07F2 ; $FE21: 8D F2 07
00FE24 1
00FE24 1 ; ----------------------------------------------------------------------------
00FE24 1 ; Select the triangle linear-counter value.
00FE24 1 ; ----------------------------------------------------------------------------
00FE24 1
00FE24 1 A0 38 ldy #$38 ; $FE24: A0 38
00FE26 1
00FE26 1 18 clc ; $FE26: 18
00FE27 1 69 FF adc #$FF ; $FE27: 69 FF
00FE29 1
00FE29 1 C9 0E cmp #$0E ; $FE29: C9 0E
00FE2B 1 B0 03 bcs UpdateMusicChannel3_CheckBank
00FE2D 1 ; $FE2B: B0 03
00FE2D 1
00FE2D 1 0A asl ; $FE2D: 0A
00FE2E 1 0A asl ; $FE2E: 0A
00FE2F 1 A8 tay ; $FE2F: A8
00FE30 1
00FE30 1 UpdateMusicChannel3_CheckBank: ; $FE30
00FE30 1 A5 FC lda $FC ; $FE30: A5 FC
00FE32 1 D0 02 bne UpdateMusicChannel3_WriteLinear
00FE34 1 ; $FE32: D0 02
00FE34 1
00FE34 1 A0 88 ldy #$88 ; $FE34: A0 88
00FE36 1
00FE36 1 UpdateMusicChannel3_WriteLinear: ; $FE36
00FE36 1 8C 08 40 sty $4008 ; $FE36: 8C 08 40
00FE39 1
00FE39 1 ; ----------------------------------------------------------------------------
00FE39 1 ; Use the command byte preserved in X by LookupAudioControlValue to select the
00FE39 1 ; triangle timer period.
00FE39 1 ; ----------------------------------------------------------------------------
00FE39 1
00FE39 1 8A txa ; $FE39: 8A
00FE3A 1 29 3E and #$3E ; $FE3A: 29 3E
00FE3C 1
00FE3C 1 20 AA FA jsr WriteTrianglePeriodFromTable
00FE3F 1 ; $FE3C: 20 AA FA
00FE3F 1
00FE3F 1 UpdateMusicSequence_Return: ; $FE3F
00FE3F 1 60 rts ; $FE3F: 60
00FE40 1
00FE40 1 ; ============================================================================
00FE40 1 ; $FE40-$FFCF
00FE40 1 ; Music sequence, note, duration, envelope, and instrument data.
00FE40 1 ;
00FE40 1 ; This region is consumed by the sequence engine decoded at $FD14-$FE3F.
00FE40 1 ; It includes:
00FE40 1 ;
00FE40 1 ; - sequence descriptor records
00FE40 1 ; - note and duration command streams
00FE40 1 ; - channel-control values
00FE40 1 ; - instrument and envelope sequences
00FE40 1 ; - pointers or offsets into the surrounding audio data
00FE40 1 ;
00FE40 1 ; Preserve the bytes exactly. Several streams use zero bytes, negative command
00FE40 1 ; bytes, and compact variable-length records, so speculative instruction
00FE40 1 ; decoding would incorrectly interpret data as executable code.
00FE40 1 ; ============================================================================
00FE40 1
00FE40 1 MusicSequenceData: ; $FE40
00FE40 1 08 08 0D 17 .byte $08,$08,$0D,$17,$12,$1C,$21,$26
00FE44 1 12 1C 21 26
00FE48 1 08 6B FE 15 .byte $08,$6B,$FE,$15,$20,$08,$20,$FF
00FE4C 1 20 08 20 FF
00FE50 1 28 0C 00 D9 .byte $28,$0C,$00,$D9,$FF,$00,$00,$00
00FE54 1 FF 00 00 00
00FE58 1 51 FF 6E 2A .byte $51,$FF,$6E,$2A,$08,$02,$FF,$0E
00FE5C 1 08 02 FF 0E
00FE60 1
00FE60 1 MusicSequenceData_FE60: ; $FE60
00FE60 1 00 08 EA FE .byte $00,$08,$EA,$FE,$0C,$00,$08,$A5
00FE64 1 0C 00 08 A5
00FE68 1 FE 1A 2A 18 .byte $FE,$1A,$2A,$18,$04,$18,$18,$58
00FE6C 1 04 18 18 58
00FE70 1 A0 58 20 04 .byte $A0,$58,$20,$04,$20,$20,$60,$A6
00FE74 1 20 20 60 A6
00FE78 1 60 26 04 26 .byte $60,$26,$04,$26,$26,$66,$87,$00
00FE7C 1 26 66 87 00
00FE80 1
00FE80 1 MusicSequenceData_FE80: ; $FE80
00FE80 1 45 45 45 98 .byte $45,$45,$45,$98,$78,$18,$04,$18
00FE84 1 78 18 04 18
00FE88 1 18 58 A7 85 .byte $18,$58,$A7,$85,$04,$82,$18,$81
00FE8C 1 04 82 18 81
00FE90 1 38 80 18 04 .byte $38,$80,$18,$04,$18,$18,$81,$18
00FE94 1 18 18 81 18
00FE98 1 82 20 81 18 .byte $82,$20,$81,$18,$80,$20,$04,$20
00FE9C 1 80 20 04 20
00FEA0 1
00FEA0 1 MusicSequenceData_FEA0: ; $FEA0
00FEA0 1 20 81 20 86 .byte $20,$81,$20,$86,$20,$10,$12,$10
00FEA4 1 20 10 12 10
00FEA8 1 12 02 10 12 .byte $12,$02,$10,$12,$02,$10,$12,$10
00FEAC 1 02 10 12 10
00FEB0 1 12 02 10 12 .byte $12,$02,$10,$12,$02,$10,$12,$10
00FEB4 1 02 10 12 10
00FEB8 1 12 02 06 0A .byte $12,$02,$06,$0A,$0C,$C6,$00,$58
00FEBC 1 0C C6 00 58
00FEC0 1
00FEC0 1 MusicSequenceData_FEC0: ; $FEC0
00FEC0 1 04 18 B8 58 .byte $04,$18,$B8,$58,$04,$18,$B8,$58
00FEC4 1 04 18 B8 58
00FEC8 1 1C 1E 20 26 .byte $1C,$1E,$20,$26,$2A,$26,$C6,$80
00FECC 1 2A 26 C6 80
00FED0 1 3C 18 18 18 .byte $3C,$18,$18,$18,$3C,$3C,$3C,$18
00FED4 1 3C 3C 3C 18
00FED8 1 3C 18 18 18 .byte $3C,$18,$18,$18,$3C,$3C,$3C,$18
00FEDC 1 3C 3C 3C 18
00FEE0 1
00FEE0 1 MusicSequenceData_FEE0: ; $FEE0
00FEE0 1 18 3C 3A 38 .byte $18,$3C,$3A,$38,$36,$38,$3A,$3C
00FEE4 1 36 38 3A 3C
00FEE8 1 83 1C 98 21 .byte $83,$1C,$98,$21,$E3,$67,$26,$26
00FEEC 1 E3 67 26 26
00FEF0 1 6A 6E 6A 6E .byte $6A,$6E,$6A,$6E,$C6,$00,$98,$B8
00FEF4 1 C6 00 98 B8
00FEF8 1 58 78 78 78 .byte $58,$78,$78,$78,$58,$60,$58,$60
00FEFC 1 58 60 58 60
00FF00 1
00FF00 1 MusicSequenceData_FF00: ; $FF00
00FF00 1 A6 F8 58 18 .byte $A6,$F8,$58,$18,$18,$60,$20,$20
00FF04 1 18 60 20 20
00FF08 1 66 26 26 6C .byte $66,$26,$26,$6C,$2C,$2C,$C6,$00
00FF0C 1 2C 2C C6 00
00FF10 1 58 18 18 78 .byte $58,$18,$18,$78,$38,$38,$58,$18
00FF14 1 38 38 58 18
00FF18 1 18 78 38 38 .byte $18,$78,$38,$38,$58,$18,$18,$98
00FF1C 1 58 18 18 98
00FF20 1
00FF20 1 MusicSequenceData_FF20: ; $FF20
00FF20 1 C7 2F C7 0D .byte $C7,$2F,$C7,$0D,$CF,$13,$CF,$8C
00FF24 1 CF 13 CF 8C
00FF28 1 88 C6 C4 00 .byte $88,$C6,$C4,$00,$87,$2A,$84,$26
00FF2C 1 87 2A 84 26
00FF30 1 87 22 18 38 .byte $87,$22,$18,$38,$34,$18,$38,$34
00FF34 1 34 18 38 34
00FF38 1 3C 38 32 3C .byte $3C,$38,$32,$3C,$38,$32,$84,$18
00FF3C 1 38 32 84 18
00FF40 1
00FF40 1 MusicSequenceData_FF40: ; $FF40
00FF40 1 87 38 38 3A .byte $87,$38,$38,$3A,$3C,$82,$18,$18
00FF44 1 3C 82 18 18
00FF48 1 C5 84 98 B8 .byte $C5,$84,$98,$B8,$A6,$9C,$D8,$98
00FF4C 1 A6 9C D8 98
00FF50 1 98 6B E9 67 .byte $98,$6B,$E9,$67,$E5,$2B,$E7,$25
00FF54 1 E5 2B E7 25
00FF58 1 E1 DD 85 DB .byte $E1,$DD,$85,$DB,$1D,$DF,$A0,$86
00FF5C 1 1D DF A0 86
00FF60 1
00FF60 1 MusicSequenceData_FF60: ; $FF60
00FF60 1 AE AA 2F E7 .byte $AE,$AA,$2F,$E7,$3D,$E1,$DD,$85
00FF64 1 3D E1 DD 85
00FF68 1 FD 19 DD 60 .byte $FD,$19,$DD,$60,$44,$A0,$64,$44
00FF6C 1 44 A0 64 44
00FF70 1 A4 E7 85 DD .byte $A4,$E7,$85,$DD,$1B,$DD,$66,$44
00FF74 1 1B DD 66 44
00FF78 1 66 44 00 85 .byte $66,$44,$00,$85,$44,$87,$42,$85
00FF7C 1 44 87 42 85
00FF80 1
00FF80 1 MusicSequenceData_FF80: ; $FF80
00FF80 1 40 87 3E 84 .byte $40,$87,$3E,$84,$02,$87,$16,$84
00FF84 1 02 87 16 84
00FF88 1 14 87 12 87 .byte $14,$87,$12,$87,$10,$85,$04,$87
00FF8C 1 10 85 04 87
00FF90 1 04 12 02 84 .byte $04,$12,$02,$84,$40,$87,$12,$12
00FF94 1 40 87 12 12
00FF98 1 40 12 84 02 .byte $40,$12,$84,$02,$86,$0C,$04,$08
00FF9C 1 86 0C 04 08
00FFA0 1
00FFA0 1 MusicSequenceData_FFA0: ; $FFA0
00FFA0 1 16 84 3E 87 .byte $16,$84,$3E,$87,$12,$12,$16,$12
00FFA4 1 12 12 16 12
00FFA8 1 84 14 87 16 .byte $84,$14,$87,$16,$81,$02,$04,$82
00FFAC 1 81 02 04 82
00FFB0 1 02 81 3E 04 .byte $02,$81,$3E,$04,$82,$02,$87,$16
00FFB4 1 82 02 87 16
00FFB8 1 85 04 81 2E .byte $85,$04,$81,$2E,$04,$2E,$04,$09
00FFBC 1 04 2E 04 09
00FFC0 1
00FFC0 1 MusicSequenceData_FFC0: ; $FFC0
00FFC0 1 DD 9C 2B FB .byte $DD,$9C,$2B,$FB,$BA,$9C,$BA,$DC
00FFC4 1 BA 9C BA DC
00FFC8 1 98 A6 86 98 .byte $98,$A6,$86,$98,$A6,$9C,$A6,$88
00FFCC 1 A6 9C A6 88
00FFD0 1
00FFD0 1 ; ============================================================================
00FFD0 1 ; $FFD0-$FFE9
00FFD0 1 ; Final music/audio sequence data.
00FFD0 1 ; ============================================================================
00FFD0 1
00FFD0 1 MusicSequenceData_FFD0: ; $FFD0
00FFD0 1 07 D9 86 09 .byte $07,$D9,$86,$09,$DD,$88,$E6,$A6
00FFD4 1 DD 88 E6 A6
00FFD8 1 B8 02 12 02 .byte $B8,$02,$12,$02,$12,$02,$12,$02
00FFDC 1 12 02 12 02
00FFE0 1 52 00 .byte $52,$00
00FFE2 1
00FFE2 1 ; ============================================================================
00FFE2 1 ; $FFE2-$FFF9
00FFE2 1 ; Unused/padding bytes.
00FFE2 1 ;
00FFE2 1 ; The first two bytes, $52,$00, complete the audio data above. The remaining
00FFE2 1 ; bytes through $FFF9 are $FF padding.
00FFE2 1 ; ============================================================================
00FFE2 1
00FFE2 1 UnusedRomPadding: ; $FFE2
00FFE2 1 FF FF FF FF .byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
00FFE6 1 FF FF FF FF
00FFEA 1 FF FF FF FF .byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
00FFEE 1 FF FF FF FF
00FFF2 1 FF FF FF FF .byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
00FFF6 1 FF FF FF FF
00FFFA 1
00FFFA 1 ; ============================================================================
00FFFA 1 ; $FFFA-$FFFF
00FFFA 1 ; 6502 interrupt vectors.
00FFFA 1 ;
00FFFA 1 ; Each vector is stored little-endian:
00FFFA 1 ;
00FFFA 1 ; NMI: $C046
00FFFA 1 ; RESET: $C40B
00FFFA 1 ; IRQ: $C43E
00FFFA 1 ; ============================================================================
00FFFA 1
00FFFA 1 InterruptVectors: ; $FFFA
00FFFA 1
00FFFA 1 NmiVectorWord: ; $FFFA
00FFFA 1 46 C0 .word $C046 ; $FFFA: 46 C0
00FFFC 1
00FFFC 1 ResetVectorWord: ; $FFFC
00FFFC 1 0B C4 .word $C40B ; $FFFC: 0B C4
00FFFE 1
00FFFE 1 IrqBrkVectorWord: ; $FFFE
00FFFE 1 3E C4 .word $C43E ; $FFFE: 3E C4
010000 1
010000 1 ; ============================================================================
010000 1 ; End of 16 KB PRG-ROM.
010000 1 ;
010000 1 ; CPU range completed: $C000-$FFFF
010000 1 ; ROM range completed: $0000-$3FFF
010000 1 ; ============================================================================
010000 1