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