********************************************************************************
* Super Mario Bros for the NES *
* Copyright 1985 Nintendo, Inc. *
********************************************************************************
* Disassembly by doppelganger (doppelheathen@gmail.com). Obtained from *
* https://gist.github.com/1wErt3r/4048722 (SMBDIS.ASM, posted 9-Nov-2012). *
* *
* The binary for this project is the iNES image for the "Japan, USA" version *
* of the ROM. It has three distinct parts: *
* (1) 16 byte iNES header *
* (2) 32KB PRG ROM *
* (3) 8KB CHR ROM *
* *
* Only the PRG section is directly addressable by the 6502. *
********************************************************************************
* Project created by Andy McFadden, using 6502bench SourceGen v1.8. This is a *
* straight conversion from the original text listing to SourceGen format. *
* Very little has been changed other than formatting (and, most likely, the *
* introduction of some errors). I have left spelling errors (e.g. LSFR vs. *
* LFSR) in place. *
* *
* I converted the player and enemy graphics with the "tile grid" visualizer, *
* which mostly worked but some things need to be flipped horizontally partway *
* through (e.g. the top half is A-B, but the bottom half is A-flipA). On the *
* bright side, the CHR ROM rendering looks pretty good. *
* *
* First posted 2020/05/14 *
* Last updated 2021/10/23 *
********************************************************************************
GreenKoopa .eq $00 {const}
DeathMusic .eq %00000001 {const}
GameModeValue .eq 1 {const}
GroundMusic .eq %00000001 {const}
Sfx_BigJump .eq %00000001 {const}
Sfx_BrickShatter .eq %00000001 {const}
Sfx_CoinGrab .eq %00000001 {const}
World2 .eq 1 {const}
BuzzyBeetle .eq $02 {const}
GameOverMusic .eq %00000010 {const}
Level3 .eq 2 {const}
Sfx_BowserFlame .eq %00000010 {const}
Sfx_Bump .eq %00000010 {const}
Sfx_GrowPowerUp .eq %00000010 {const}
VictoryModeValue .eq 2 {const}
WaterMusic .eq %00000010 {const}
GameOverModeValue .eq 3 {const}
RedKoopa .eq $03 {const}
Sfx_EnemyStomp .eq %00000100 {const}
Sfx_GrowVine .eq %00000100 {const}
UndergroundMusic .eq %00000100 {const}
VictoryMusic .eq %00000100 {const}
World5 .eq 4 {const}
HammerBro .eq $05 {const}
World6 .eq 5 {const}
Goomba .eq $06 {const}
World7 .eq 6 {const}
Bloober .eq $07 {const}
World8 .eq 7 {const}
BulletBill_FrenzyVar .eq $08 {const}
CastleMusic .eq %00001000 {const}
EndOfCastleMusic .eq %00001000 {const}
Sfx_Blast .eq %00001000 {const}
Sfx_EnemySmack .eq %00001000 {const}
TallEnemy .eq $09 {const}
GreyCheepCheep .eq $0a {const}
RedCheepCheep .eq $0b {const}
Podoboo .eq $0c {const}
PiranhaPlant .eq $0d {const}
GreenParatroopaJump .eq $0e {const}
CloudMusic .eq %00010000 {const}
Sfx_PipeDown_Injury .eq %00010000 {const}
Sfx_TimerTick .eq %00010000 {const}
Start_Button .eq %00010000 {const}
Lakitu .eq $11 {const}
Spiny .eq $12 {const}
FlyCheepCheepFrenzy .eq $14 {const}
FlyingCheepCheep .eq $14 {const}
Fireworks .eq $16 {const}
BBill_CCheep_Frenzy .eq $17 {const}
Stop_Frenzy .eq $18 {const}
EndOfLevelMusic .eq %00100000 {const}
PipeIntroMusic .eq %00100000 {const}
Select_Button .eq %00100000 {const}
Sfx_Fireball .eq %00100000 {const}
Sfx_PowerUpGrab .eq %00100000 {const}
Bowser .eq $2d {const}
PowerUpObject .eq $2e {const}
VineObject .eq $2f {const}
FlagpoleFlagObject .eq $30 {const}
StarFlagObject .eq $31 {const}
JumpspringObject .eq $32 {const}
BulletBill_CannonVar .eq $33 {const}
B_Button .eq %01000000 {const}
.eq %01000000 {const}
StarPowerMusic .eq %01000000 {const}
TimeRunningOutMusic .eq %01000000 {const}
A_Button .eq %10000000 {const}
Sfx_BowserFall .eq %10000000 {const}
Sfx_SmallJump .eq %10000000 {const}
Silence .eq %10000000 {const}
TitleScreenDataOffset .eq $1ec0 {const}
ObjectOffset .eq $08
FrameCounter .eq $09
A_B_Buttons .eq $0a
Up_Down_Buttons .eq $0b
Left_Right_Buttons .eq $0c
PreviousA_B_Buttons .eq $0d
GameEngineSubroutine .eq $0e
Enemy_Flag .eq $0f {addr/6}
Enemy_ID .eq $16 {addr/6}
Player_State .eq $1d
Enemy_State .eq $1e {addr/6}
Fireball_State .eq $24
Block_State .eq $26
Misc_State .eq $2a
PlayerFacingDir .eq $33
DestinationPageLoc .eq $34 ;2 defs for $34
FirebarSpinDirection .eq $34
VictoryWalkControl .eq $35
PowerUpType .eq $39
FireballBouncingFlag .eq $3a
HammerBroJumpTimer .eq $3c
Player_MovingDir .eq $45
Enemy_MovingDir .eq $46
Player_X_Speed .eq $57
SprObject_X_Speed .eq $57
BlooperMoveSpeed .eq $58 ;11 defs for $58
CheepCheepMoveMFlag .eq $58
Enemy_X_Speed .eq $58
ExplosionGfxCounter .eq $58
FirebarSpinState_Low .eq $58
Jumpspring_FixedYPos .eq $58
LakituMoveSpeed .eq $58
PiranhaPlant_Y_Speed .eq $58
RedPTroopaCenterYPos .eq $58
XMoveSecondaryCounter .eq $58
YPlatformCenterYPos .eq $58
Fireball_X_Speed .eq $5e
Block_X_Speed .eq $60 {addr/3}
Misc_X_Speed .eq $64
Player_PageLoc .eq $6d ;2 defs for $6d
SprObject_PageLoc .eq $6d
Enemy_PageLoc .eq $6e {addr/6}
Fireball_PageLoc .eq $74
Block_PageLoc .eq $76 {addr/3}
Misc_PageLoc .eq $7a
Bubble_PageLoc .eq $83
Player_X_Position .eq $86 ;2 defs for $86
SprObject_X_Position .eq $86
Enemy_X_Position .eq $87 {addr/6}
Fireball_X_Position .eq $8d
Block_X_Position .eq $8f {addr/3}
Misc_X_Position .eq $93
Bubble_X_Position .eq $9c
Player_Y_Speed .eq $9f
SprObject_Y_Speed .eq $9f
BlooperMoveCounter .eq $a0 ;7 defs for $a0
Enemy_Y_Speed .eq $a0
ExplosionTimerCounter .eq $a0
FirebarSpinState_High .eq $a0
LakituMoveDirection .eq $a0
PiranhaPlant_MoveFlag .eq $a0
XMovePrimaryCounter .eq $a0
Fireball_Y_Speed .eq $a6
Block_Y_Speed .eq $a8 {addr/3}
Misc_Y_Speed .eq $ac
Player_Y_HighPos .eq $b5 ;2 defs for $b5
SprObject_Y_HighPos .eq $b5
Enemy_Y_HighPos .eq $b6 {addr/6}
Fireball_Y_HighPos .eq $bc
Block_Y_HighPos .eq $be
Misc_Y_HighPos .eq $c2
Bubble_Y_HighPos .eq $cb
Player_Y_Position .eq $ce ;2 defs for $ce
SprObject_Y_Position .eq $ce
Enemy_Y_Position .eq $cf {addr/6}
Fireball_Y_Position .eq $d5
Block_Y_Position .eq $d7 {addr/3}
Misc_Y_Position .eq $db
Bubble_Y_Position .eq $e4
AreaData .eq $e7 {addr/2}
EnemyData .eq $e9 {addr/2}
NoteLenLookupTblOfs .eq $f0
Square1SoundBuffer .eq $f1
Square2SoundBuffer .eq $f2
NoiseSoundBuffer .eq $f3
AreaMusicBuffer .eq $f4
MusicData .eq $f5 {addr/2}
MusicOffset_Square2 .eq $f7
MusicOffset_Square1 .eq $f8
MusicOffset_Triangle .eq $f9
PauseSoundQueue .eq $fa
AreaMusicQueue .eq $fb
EventMusicQueue .eq $fc
NoiseSoundQueue .eq $fd
Square2SoundQueue .eq $fe
Square1SoundQueue .eq $ff
VerticalFlipFlag .eq $0109
FlagpoleFNum_Y_Pos .eq $010d
FlagpoleFNum_YMFDummy .eq $010e
FlagpoleScore .eq $010f
FloateyNum_Control .eq $0110
FloateyNum_X_Pos .eq $0117
FloateyNum_Y_Pos .eq $011e
ShellChainCounter .eq $0125
FloateyNum_Timer .eq $012c
DigitModifier .eq $0134 {addr/6}
Sprite_Data .eq $0200 {addr/32}
Sprite_Y_Position .eq $0200
Sprite_Tilenumber .eq $0201
Sprite_Attributes .eq $0202
Sprite_X_Position .eq $0203 {addr/5}
VRAM_Buffer1_Offset .eq $0300
VRAM_Buffer1 .eq $0301 {addr/63}
VRAM_Buffer2_Offset .eq $0340
VRAM_Buffer2 .eq $0341 {addr/63}
BowserBodyControls .eq $0363
BowserFeetCounter .eq $0364
BowserMovementSpeed .eq $0365
BowserOrigXPos .eq $0366
BowserFlameTimerCtrl .eq $0367
BowserFront_Offset .eq $0368
BridgeCollapseOffset .eq $0369
BowserGfxFlag .eq $036a
FirebarSpinSpeed .eq $0388
VineFlagOffset .eq $0398
VineHeight .eq $0399
VineObjOffset .eq $039a
VineStart_Y_Position .eq $039d
BalPlatformAlignment .eq $03a0
Platform_X_Scroll .eq $03a1
HammerThrowingTimer .eq $03a2 ;2 defs for $03a2
PlatformCollisionFlag .eq $03a2
Player_Rel_XPos .eq $03ad ;2 defs for $03ad
SprObject_Rel_XPos .eq $03ad
Enemy_Rel_XPos .eq $03ae
Fireball_Rel_XPos .eq $03af
Bubble_Rel_XPos .eq $03b0
Block_Rel_XPos .eq $03b1
Misc_Rel_XPos .eq $03b3
Player_Rel_YPos .eq $03b8 ;2 defs for $03b8
SprObject_Rel_YPos .eq $03b8
Enemy_Rel_YPos .eq $03b9
Fireball_Rel_YPos .eq $03ba
Bubble_Rel_YPos .eq $03bb
Block_Rel_YPos .eq $03bc
Misc_Rel_YPos .eq $03be
Player_SprAttrib .eq $03c4
Enemy_SprAttrib .eq $03c5 {addr/6}
Player_OffscreenBits .eq $03d0 ;2 defs for $03d0
SprObject_OffscrBits .eq $03d0
Enemy_OffscreenBits .eq $03d1
FBall_OffscreenBits .eq $03d2
Bubble_OffscreenBits .eq $03d3
Block_OffscreenBits .eq $03d4
Misc_OffscreenBits .eq $03d6
EnemyOffscrBitsMasked .eq $03d8
Block_Orig_YPos .eq $03e4
Block_BBuf_Low .eq $03e6
Block_Metatile .eq $03e8
Block_PageLoc2 .eq $03ea
Block_RepFlag .eq $03ec
SprDataOffset_Ctrl .eq $03ee
Block_ResidualCounter .eq $03f0
Block_Orig_XPos .eq $03f1
AttributeBuffer .eq $03f9
SprObject_X_MoveForce .eq $0400
Enemy_X_MoveForce .eq $0401 ;3 defs for $0401
RedPTroopaOrigXPos .eq $0401
YPlatformTopYPos .eq $0401
Player_YMF_Dummy .eq $0416
SprObject_YMF_Dummy .eq $0416
BowserFlamePRandomOfs .eq $0417 ;3 defs for $0417
Enemy_YMF_Dummy .eq $0417
PiranhaPlantUpYPos .eq $0417
Bubble_YMF_Dummy .eq $042c
Player_Y_MoveForce .eq $0433
SprObject_Y_MoveForce .eq $0433
CheepCheepOrigYPos .eq $0434 ;3 defs for $434
Enemy_Y_MoveForce .eq $0434
PiranhaPlantDownYPos .eq $0434
Block_Y_MoveForce .eq $043c {addr/3}
MaximumLeftSpeed .eq $0450
MaximumRightSpeed .eq $0456
Cannon_Offset .eq $046a
Whirlpool_Offset .eq $046a
Cannon_PageLoc .eq $046b ;2 defs for $046b
Whirlpool_PageLoc .eq $046b
Cannon_X_Position .eq $0471 ;2 defs for $0471
Whirlpool_LeftExtent .eq $0471
Cannon_Y_Position .eq $0477 ;2 defs for $0477
Whirlpool_Length .eq $0477
Cannon_Timer .eq $047d ;2 defs for $047d
Whirlpool_Flag .eq $047d
BowserHitPoints .eq $0483
StompChainCounter .eq $0484
Player_CollisionBits .eq $0490
Enemy_CollisionBits .eq $0491
Player_BoundBoxCtrl .eq $0499 ;2 defs for $0499
SprObj_BoundBoxCtrl .eq $0499
Enemy_BoundBoxCtrl .eq $049a {addr/6}
Fireball_BoundBoxCtrl .eq $04a0
Misc_BoundBoxCtrl .eq $04a2
BoundingBox_UL_XPos .eq $04ac
BoundingBox_UL_YPos .eq $04ad
BoundingBox_DR_XPos .eq $04ae
BoundingBox_DR_YPos .eq $04af
EnemyBoundingBoxCoord .eq $04b0 {addr/4}
Block_Buffer_1 .eq $0500
Block_Buffer_2 .eq $05d0
BlockBufferColumnPos .eq $06a0
MetatileBuffer .eq $06a1 {addr/11}
HammerEnemyOffset .eq $06ae
JumpCoinMiscOffset .eq $06b7
BrickCoinTimerFlag .eq $06bc
Misc_Collision_Flag .eq $06be
unused_06c9 .eq $06c9
EnemyFrenzyBuffer .eq $06cb
SecondaryHardMode .eq $06cc
EnemyFrenzyQueue .eq $06cd
FireballCounter .eq $06ce
DuplicateObj_Offset .eq $06cf
LakituReappearTimer .eq $06d1
NumberofGroupEnemies .eq $06d3
ColorRotateOffset .eq $06d4
PlayerGfxOffset .eq $06d5
WarpZoneControl .eq $06d6
FireworksCounter .eq $06d7
MultiLoopCorrectCntr .eq $06d9
MultiLoopPassCntr .eq $06da
JumpspringForce .eq $06db
MaxRangeFromOrigin .eq $06dc
BitMFilter .eq $06dd
ChangeAreaTimer .eq $06de
SprShuffleAmtOffset .eq $06e0
SprShuffleAmt .eq $06e1 {addr/3}
SprDataOffset .eq $06e4 {addr/15}
Enemy_SprDataOffset .eq $06e5
Alt_SprDataOffset .eq $06ec ;2 defs for $06ec
Block_SprDataOffset .eq $06ec
Bubble_SprDataOffset .eq $06ee
FBall_SprDataOffset .eq $06f1
Misc_SprDataOffset .eq $06f3
SavedJoypad1Bits .eq $06fc
SavedJoypad2Bits .eq $06fd
Player_X_Scroll .eq $06ff
Player_XSpeedAbsolute .eq $0700
FrictionAdderHigh .eq $0701
FrictionAdderLow .eq $0702
RunningSpeed .eq $0703
SwimmingFlag .eq $0704
Player_X_MoveForce .eq $0705
DiffToHaltJump .eq $0706
JumpOrigin_Y_HighPos .eq $0707
JumpOrigin_Y_Position .eq $0708
VerticalForce .eq $0709
VerticalForceDown .eq $070a
PlayerChangeSizeFlag .eq $070b
PlayerAnimTimerSet .eq $070c
PlayerAnimCtrl .eq $070d
JumpspringAnimCtrl .eq $070e
FlagpoleCollisionYPos .eq $070f
PlayerEntranceCtrl .eq $0710
FireballThrowingTimer .eq $0711
DeathMusicLoaded .eq $0712
FlagpoleSoundQueue .eq $0713
CrouchingFlag .eq $0714
GameTimerSetting .eq $0715
DisableCollisionDet .eq $0716
DemoAction .eq $0717
DemoActionTimer .eq $0718
PrimaryMsgCounter .eq $0719
ScreenLeft_PageLoc .eq $071a
ScreenRight_PageLoc .eq $071b
ScreenLeft_X_Pos .eq $071c
ScreenRight_X_Pos .eq $071d
ColumnSets .eq $071e
AreaParserTaskNum .eq $071f
CurrentNTAddr_High .eq $0720
CurrentNTAddr_Low .eq $0721
Sprite0HitDetectFlag .eq $0722
ScrollLock .eq $0723
CurrentPageLoc .eq $0725
CurrentColumnPos .eq $0726
TerrainControl .eq $0727
BackloadingFlag .eq $0728
BehindAreaParserFlag .eq $0729
AreaObjectPageLoc .eq $072a
AreaObjectPageSel .eq $072b
AreaDataOffset .eq $072c
AreaObjOffsetBuffer .eq $072d
AreaObjectLength .eq $0730 {addr/3}
AreaStyle .eq $0733
StaircaseControl .eq $0734
AreaObjectHeight .eq $0735
MushroomLedgeHalfLen .eq $0736
EnemyDataOffset .eq $0739
EnemyObjectPageLoc .eq $073a
EnemyObjectPageSel .eq $073b
ScreenRoutineTask .eq $073c
ScrollThirtyTwo .eq $073d
HorizontalScroll .eq $073f
VerticalScroll .eq $0740
ForegroundScenery .eq $0741
BackgroundScenery .eq $0742
CloudTypeOverride .eq $0743
BackgroundColorCtrl .eq $0744
LoopCommand .eq $0745
StarFlagTaskControl .eq $0746
TimerControl .eq $0747
CoinTallyFor1Ups .eq $0748
SecondaryMsgCounter .eq $0749
JoypadBitMask .eq $074a
AreaType .eq $074e
AreaAddrsLOffset .eq $074f
AreaPointer .eq $0750
EntrancePage .eq $0751
AltEntranceControl .eq $0752
CurrentPlayer .eq $0753
PlayerSize .eq $0754
Player_Pos_ForScroll .eq $0755
PlayerStatus .eq $0756
FetchNewGameTimerFlag .eq $0757
JoypadOverride .eq $0758
GameTimerExpiredFlag .eq $0759
OnscreenPlayerInfo .eq $075a {addr/7}
NumberOfLives .eq $075a ;used by current player
HalfwayPage .eq $075b
LevelNumber .eq $075c ;the actual dash number
Hidden1UpFlag .eq $075d
CoinTally .eq $075e
WorldNumber .eq $075f
AreaNumber .eq $0760 ;internal number used to find areas
OffscreenPlayerInfo .eq $0761 {addr/7}
OffScr_NumberofLives .eq $0761 ;used by offscreen player
OffScr_Hidden1UpFlag .eq $0764
OffScr_WorldNumber .eq $0766
OffScr_AreaNumber .eq $0767
ScrollFractional .eq $0768
DisableIntermediate .eq $0769
PrimaryHardMode .eq $076a
WorldSelectNumber .eq $076b
OperMode .eq $0770
OperMode_Task .eq $0772
VRAM_Buffer_AddrCtrl .eq $0773
DisableScreenFlag .eq $0774
ScrollAmount .eq $0775
GamePauseStatus .eq $0776
GamePauseTimer .eq $0777
Mirror_PPU_CTRL_REG1 .eq $0778
Mirror_PPU_CTRL_REG2 .eq $0779
NumberOfPlayers .eq $077a
IntervalTimerControl .eq $077f
Timers .eq $0780 {addr/36}
SelectTimer .eq $0780
PlayerAnimTimer .eq $0781
JumpSwimTimer .eq $0782
RunningTimer .eq $0783
BlockBounceTimer .eq $0784
SideCollisionTimer .eq $0785
JumpspringTimer .eq $0786
GameTimerCtrlTimer .eq $0787
ClimbSlideTimer .eq $0789
EnemyFrameTimer .eq $078a
FrenzyEnemyTimer .eq $078f
BowserFireBreathTimer .eq $0790
StompTimer .eq $0791
AirBubbleTimer .eq $0792
ScrollIntervalTimer .eq $0795
EnemyIntervalTimer .eq $0796
BrickCoinTimer .eq $079d
InjuryTimer .eq $079e
StarInvincibleTimer .eq $079f
ScreenTimer .eq $07a0
WorldEndTimer .eq $07a1
DemoTimer .eq $07a2
PseudoRandomBitReg .eq $07a7 {addr/3}
SoundMemory .eq $07b0 {addr/32}
MusicOffset_Noise .eq $07b0
EventMusicBuffer .eq $07b1
PauseSoundBuffer .eq $07b2
Squ2_NoteLenBuffer .eq $07b3
Squ2_NoteLenCounter .eq $07b4
Squ2_EnvelopeDataCtrl .eq $07b5
Squ1_NoteLenCounter .eq $07b6
Squ1_EnvelopeDataCtrl .eq $07b7
Tri_NoteLenBuffer .eq $07b8
Tri_NoteLenCounter .eq $07b9
Noise_BeatLenCounter .eq $07ba
Squ1_SfxLenCounter .eq $07bb
Squ2_SfxLenCounter .eq $07bd
Sfx_SecondaryCounter .eq $07be
Noise_SfxLenCounter .eq $07bf
DAC_Counter .eq $07c0
NoiseDataLoopbackOfs .eq $07c1
NoteLengthTblAdder .eq $07c4
AreaMusicBuffer_Alt .eq $07c5
PauseModeFlag .eq $07c6
.eq $07c7
AltRegContentFlag .eq $07ca
WarmBootOffset .eq $07d6
TopScoreDisplay .eq $07d7 {addr/6}
ScoreAndCoinDisplay .eq $07dd
GameTimerDisplay .eq $07f8 {addr/3}
WorldSelectEnableFlag .eq $07fc
ContinueWorld .eq $07fd
ColdBootOffset .eq $07fe
WarmBootValidation .eq $07ff
PPUCTRL .eq $2000 ;W VPHB SINN various
PPUMASK .eq $2001 ;W BGRs bMmG various
PPUSTATUS .eq $2002 ;R VSO- ---- various; read resets $2005/2006
OAMADDR .eq $2003 ;W OAM read/write address
PPUSCROLL .eq $2005 ;WW fine scroll position (two writes: X,Y)
PPUADDR .eq $2006 ;WW PPU read/write address (two writes: MSB, LSB)
PPUDATA .eq $2007 ;RW PPU data read/write
SQ1_VOL .eq $4000 ;DDLC VVVV
SQ1_SWEEP .eq $4001 ;EPPP NSSS
SQ1_LO .eq $4002 ;TTTT TTTT
SQ1_HI .eq $4003 ;LLLL LTTT
SQ2_VOL .eq $4004 ;DDLC VVVV
SQ2_SWEEP .eq $4005 ;EPPP NSSS
SQ2_LO .eq $4006 ;TTTT TTTT
TRI_LINEAR .eq $4008 ;CRRR RRRR
NOISE_VOL .eq $400c ;--LC VVVV
NOISE_LO .eq $400e ;L--- PPPP
NOISE_HI .eq $400f ;LLLL L---
DMC_RAW .eq $4011 ;-DDD DDDD
OAMDMA .eq $4014 ;AAAA AAAA OAM DMA high address
SND_CHN .eq $4015 ;W:---D NT21 R:IF-D NT21
JOY1 .eq $4016 ;joystick 1 data (R) and joystick strobe (W)
JOY2 .eq $4017 ;joystick 2 data (R) and frame counter (W)
;
; iNES file header, for use by emulators.
; (See https://wiki.nesdev.com/w/index.php/INES )
;
.addrs NA
0000: 4e 45 53 .str βNESβ
0003: 1a .dd1 $1a ;Ctrl+Z
0004: 02 .dd1 $02 ;PRG ROM is 2 x 16KB
0005: 01 .dd1 $01 ;CHR ROM is 1 x 8KB
0006: 01 .dd1 %00000001 ;flags 6
0007: 00 .dd1 %00000000 ;flags 7
0008: 00 .dd1 %00000000 ;flags 8
0009: 00 .dd1 %00000000 ;flags 9
000a: 00 .dd1 %00000000 ;flags 10
000b: 00 00 00 00+ .bulk $00,$00,$00,$00,$00 ;padding
.adrend β NA
;
; Start of main program.
;
; The RESET vector points here.
;
.addrs $8000
8000: 78 Start sei ;pretty standard 6502 type init here
8001: d8 cld
8002: a9 10 lda #%00010000 ;init PPU control register 1
8004: 8d 00 20 sta PPUCTRL
8007: a2 ff ldx #$ff ;reset stack pointer
8009: 9a txs
800a: ad 02 20 VBlank1 lda PPUSTATUS ;wait two frames
800d: 10 fb bpl VBlank1
800f: ad 02 20 VBlank2 lda PPUSTATUS
8012: 10 fb bpl VBlank2
8014: a0 fe ldy #<ColdBootOffset ;load default cold boot pointer
8016: a2 05 ldx #$05 ;this is where we check for a warm boot
8018: bd d7 07 WBootCheck lda TopScoreDisplay,x ;check each score digit in the top score
801b: c9 0a cmp #10 ;to see if we have a valid digit
801d: b0 0c bcs ColdBoot ;if not, give up and proceed with cold boot
801f: ca dex
8020: 10 f6 bpl WBootCheck
8022: ad ff 07 lda WarmBootValidation ;second checkpoint, check to see if
8025: c9 a5 cmp #$a5 ; another location has a specific value
8027: d0 02 bne ColdBoot
8029: a0 d6 ldy #<WarmBootOffset ;if passed both, load warm boot pointer
802b: 20 cc 90 ColdBoot jsr InitializeMemory ;clear memory using pointer in Y
802e: 8d 11 40 sta DMC_RAW ;reset delta counter load register
8031: 8d 70 07 sta OperMode ;reset primary mode of operation
8034: a9 a5 lda #$a5 ;set warm boot flag
8036: 8d ff 07 sta WarmBootValidation
8039: 8d a7 07 sta PseudoRandomBitReg ;set seed for pseudorandom register
803c: a9 0f lda #%00001111
803e: 8d 15 40 sta SND_CHN ;enable all sound channels except dmc
8041: a9 06 lda #%00000110
8043: 8d 01 20 sta PPUMASK ;turn off clipping for OAM and background
8046: 20 20 82 jsr MoveAllSpritesOffscreen
8049: 20 19 8e jsr InitializeNameTables ;initialize both name tables
804c: ee 74 07 inc DisableScreenFlag ;set flag to disable screen output
804f: ad 78 07 lda Mirror_PPU_CTRL_REG1
8052: 09 80 ora #%10000000 ;enable NMIs
8054: 20 ed 8e jsr WritePPUReg1
8057: 4c 57 80 EndlessLoop jmp EndlessLoop ;endless loop, need I say more?
; -----------------------------------------------------------------------------
; $00 - vram buffer address table low, also used for pseudorandom bit
; $01 - vram buffer address table high
VRAM_AddrTable_Low
805a: 01 .dd1 <VRAM_Buffer1
805b: a4 .dd1 <WaterPaletteData
805c: c8 .dd1 <GroundPaletteData
805d: ec .dd1 <UndergroundPaletteData
805e: 10 .dd1 <CastlePaletteData
805f: 00 .dd1 <VRAM_Buffer1_Offset
8060: 41 .dd1 <VRAM_Buffer2
8061: 41 .dd1 <VRAM_Buffer2
8062: 4c .dd1 <BowserPaletteData
8063: 34 .dd1 <DaySnowPaletteData
8064: 3c .dd1 <NightSnowPaletteData
8065: 44 .dd1 <MushroomPaletteData
8066: 54 .dd1 <MarioThanksMessage
8067: 68 .dd1 <LuigiThanksMessage
8068: 7c .dd1 <MushroomRetainerSaved
8069: a8 .dd1 <PrincessSaved1
806a: bf .dd1 <PrincessSaved2
806b: de .dd1 <WorldSelectMessage1
806c: ef .dd1 <WorldSelectMessage2
VRAM_AddrTable_High
806d: 03 .dd1 >VRAM_Buffer1
806e: 8c .dd1 >WaterPaletteData
806f: 8c .dd1 >GroundPaletteData
8070: 8c .dd1 >UndergroundPaletteData
8071: 8d .dd1 >CastlePaletteData
8072: 03 .dd1 >VRAM_Buffer1_Offset
8073: 03 .dd1 >VRAM_Buffer2
8074: 03 .dd1 >VRAM_Buffer2
8075: 8d .dd1 >BowserPaletteData
8076: 8d .dd1 >DaySnowPaletteData
8077: 8d .dd1 >NightSnowPaletteData
8078: 8d .dd1 >MushroomPaletteData
8079: 8d .dd1 >MarioThanksMessage
807a: 8d .dd1 >LuigiThanksMessage
807b: 8d .dd1 >MushroomRetainerSaved
807c: 8d .dd1 >PrincessSaved1
807d: 8d .dd1 >PrincessSaved2
807e: 8d .dd1 >WorldSelectMessage1
807f: 8d .dd1 >WorldSelectMessage2
VRAM_Buffer_Offset
8080: 00 .dd1 <VRAM_Buffer1_Offset
8081: 40 .dd1 <VRAM_Buffer2_Offset
NonMaskableInterrupt
8082: ad 78 07 lda Mirror_PPU_CTRL_REG1 ;disable NMIs in mirror reg
8085: 29 7f and #%01111111 ;save all other bits
8087: 8d 78 07 sta Mirror_PPU_CTRL_REG1
808a: 29 7e and #%01111110 ;alter name table address to be $2800
808c: 8d 00 20 sta PPUCTRL ;(essentially $2000) but save other bits
808f: ad 79 07 lda Mirror_PPU_CTRL_REG2 ;disable OAM and background display by default
8092: 29 e6 and #%11100110
8094: ac 74 07 ldy DisableScreenFlag ;get screen disable flag
8097: d0 05 bne ScreenOff ;if set, used bits as-is
8099: ad 79 07 lda Mirror_PPU_CTRL_REG2 ;otherwise reenable bits and save them
809c: 09 1e ora #%00011110
809e: 8d 79 07 ScreenOff sta Mirror_PPU_CTRL_REG2 ;save bits for later but not in register at the moment
80a1: 29 e7 and #%11100111 ;disable screen for now
80a3: 8d 01 20 sta PPUMASK
80a6: ae 02 20 ldx PPUSTATUS ;reset flip-flop and reset scroll registers to zero
80a9: a9 00 lda #$00
80ab: 20 e6 8e jsr InitScroll
80ae: 8d 03 20 sta OAMADDR ;reset spr-ram address register
80b1: a9 02 lda #$02 ;perform spr-ram DMA access on $0200-$02ff
80b3: 8d 14 40 sta OAMDMA
80b6: ae 73 07 ldx VRAM_Buffer_AddrCtrl ;load control for pointer to buffer contents
80b9: bd 5a 80 lda VRAM_AddrTable_Low,x ;set indirect at $00 to pointer
80bc: 85 00 sta $00
80be: bd 6d 80 lda VRAM_AddrTable_High,x
80c1: 85 01 sta $01
80c3: 20 dd 8e jsr UpdateScreen ;update screen with buffer contents
80c6: a0 00 ldy #$00
80c8: ae 73 07 ldx VRAM_Buffer_AddrCtrl ;check for usage of $0341
80cb: e0 06 cpx #$06
80cd: d0 01 bne InitBuffer
80cf: c8 iny ;get offset based on usage
80d0: be 80 80 InitBuffer ldx VRAM_Buffer_Offset,y
80d3: a9 00 lda #$00 ;clear buffer header at last location
80d5: 9d 00 03 sta VRAM_Buffer1_Offset,x
80d8: 9d 01 03 sta VRAM_Buffer1,x
80db: 8d 73 07 sta VRAM_Buffer_AddrCtrl ;reinit address control to $0301
80de: ad 79 07 lda Mirror_PPU_CTRL_REG2 ;copy mirror of $2001 to register
80e1: 8d 01 20 sta PPUMASK
80e4: 20 d0 f2 jsr SoundEngine ;play sound
80e7: 20 5c 8e jsr ReadJoypads ;read joypads
80ea: 20 82 81 jsr PauseRoutine ;handle pause
80ed: 20 97 8f jsr UpdateTopScore
80f0: ad 76 07 lda GamePauseStatus ;check for pause status
80f3: 4a lsr A
80f4: b0 25 bcs PauseSkip
80f6: ad 47 07 lda TimerControl ;if master timer control not set, decrement
80f9: f0 05 beq DecTimers ;all frame and interval timers
80fb: ce 47 07 dec TimerControl
80fe: d0 19 bne NoDecTimers
8100: a2 14 DecTimers ldx #$14 ;load end offset for end of frame timers
8102: ce 7f 07 dec IntervalTimerControl ;decrement interval timer control,
8105: 10 07 bpl DecTimersLoop ; if not expired, only frame timers will decrement
8107: a9 14 lda #$14
8109: 8d 7f 07 sta IntervalTimerControl ;if control for interval timers expired,
810c: a2 23 ldx #$23 ; interval timers will decrement along with frame timers
810e: bd 80 07 DecTimersLoop lda SelectTimer,x ;check current timer
8111: f0 03 beq SkipExpTimer ;if current timer expired, branch to skip,
8113: de 80 07 dec SelectTimer,x ; otherwise decrement the current timer
8116: ca SkipExpTimer dex ;move onto next timer
8117: 10 f5 bpl DecTimersLoop ;do this until all timers are dealt with
8119: e6 09 NoDecTimers inc FrameCounter ;increment frame counter
811b: a2 00 PauseSkip ldx #$00
811d: a0 07 ldy #$07
811f: ad a7 07 lda PseudoRandomBitReg ;get first memory locaion of LSFR bytes
8122: 29 02 and #%00000010 ;mask out all but d1
8124: 85 00 sta $00 ;save here
8126: ad a8 07 lda PseudoRandomBitReg+1 ;get second memory location
8129: 29 02 and #%00000010 ;mask out all but d1
812b: 45 00 eor $00 ;perform exclusive-OR on d1 from first and second bytes
812d: 18 clc ;if neither or both are set, carry will be clear
812e: f0 01 beq RotPRandomBit
8130: 38 sec ;if one or the other is set, carry will be set
8131: 7e a7 07 RotPRandomBit ror PseudoRandomBitReg,x ;rotate carry into d7, and rotate last bit into carry
8134: e8 inx ;increment to next byte
8135: 88 dey ;decrement for loop
8136: d0 f9 bne RotPRandomBit
8138: ad 22 07 lda Sprite0HitDetectFlag ;check for flag here
813b: f0 1f beq SkipSprite0
813d: ad 02 20 Sprite0Clr lda PPUSTATUS ;wait for sprite 0 flag to clear, which will
8140: 29 40 and #%01000000 ; not happen until vblank has ended
8142: d0 f9 bne Sprite0Clr
8144: ad 76 07 lda GamePauseStatus ;if in pause mode, do not bother with sprites at all
8147: 4a lsr A
8148: b0 06 bcs Sprite0Hit
814a: 20 23 82 jsr MoveSpritesOffscreen
814d: 20 c6 81 jsr SpriteShuffler
8150: ad 02 20 Sprite0Hit lda PPUSTATUS ;do sprite #0 hit detection
8153: 29 40 and #%01000000
8155: f0 f9 beq Sprite0Hit
8157: a0 14 ldy #$14 ;small delay, to wait until we hit orizontal blank time
8159: 88 HBlankDelay dey
815a: d0 fd bne HBlankDelay
815c: ad 3f 07 SkipSprite0 lda HorizontalScroll ;set scroll registers from variables
815f: 8d 05 20 sta PPUSCROLL
8162: ad 40 07 lda VerticalScroll
8165: 8d 05 20 sta PPUSCROLL
8168: ad 78 07 lda Mirror_PPU_CTRL_REG1 ;load saved mirror of $2000
816b: 48 pha
816c: 8d 00 20 sta PPUCTRL
816f: ad 76 07 lda GamePauseStatus ;if in pause mode, do not perform operation mode stuff
8172: 4a lsr A
8173: b0 03 bcs SkipMainOper
8175: 20 12 82 jsr OperModeExecutionTree ;otherwise do one of many, many possible subroutines
8178: ad 02 20 SkipMainOper lda PPUSTATUS ;reset flip-flip
817b: 68 pla
817c: 09 80 ora #%10000000 ;reactivate NMIs
817e: 8d 00 20 sta PPUCTRL
8181: 40 rti ;we are done until the next frame!
; -----------------------------------------------------------------------------
8182: ad 70 07 PauseRoutine lda OperMode ;are we in victory mode?
8185: c9 02 cmp #VictoryModeValue ;if so, go ahead
8187: f0 0b beq ChkPauseTimer
8189: c9 01 cmp #GameModeValue ;are we in game mode?
818b: d0 38 bne ExitPause ;if not, leave
818d: ad 72 07 lda OperMode_Task ;if we are in game mode, are we running game engine?
8190: c9 03 cmp #$03
8192: d0 31 bne ExitPause ;if not, leave
8194: ad 77 07 ChkPauseTimer lda GamePauseTimer ;check if pause timer is still counting down
8197: f0 04 beq ChkStart
8199: ce 77 07 dec GamePauseTimer ;if so, decrement and leave
819c: 60 rts
819d: ad fc 06 ChkStart lda SavedJoypad1Bits ;check to see if start is pressed
81a0: 29 10 and #Start_Button ;on controller 1
81a2: f0 19 beq ClrPauseTimer
81a4: ad 76 07 lda GamePauseStatus ;check to see if timer flag is set
81a7: 29 80 and #%10000000 ;and if so, do not reset timer (residual,
81a9: d0 1a bne ExitPause ; joypad reading routine makes this unnecessary)
81ab: a9 2b lda #$2b ;set pause timer
81ad: 8d 77 07 sta GamePauseTimer
81b0: ad 76 07 lda GamePauseStatus
81b3: a8 tay
81b4: c8 iny ;set pause sfx queue for next pause mode
81b5: 84 fa sty PauseSoundQueue
81b7: 49 01 eor #%00000001 ;invert d0 and set d7
81b9: 09 80 ora #%10000000
81bb: d0 05 bne SetPause ;unconditional branch
81bd: ad 76 07 ClrPauseTimer lda GamePauseStatus ;clear timer flag if timer is at zero and start button
81c0: 29 7f and #%01111111 ; is not pressed
81c2: 8d 76 07 SetPause sta GamePauseStatus
81c5: 60 ExitPause rts
; -----------------------------------------------------------------------------
; $00 - used for preset value
81c6: ac 4e 07 SpriteShuffler ldy AreaType ;load level type, likely residual code
81c9: a9 28 lda #$28 ;load preset value which will put it at
81cb: 85 00 sta $00 ; sprite #10
81cd: a2 0e ldx #$0e ;start at the end of OAM data offsets
81cf: bd e4 06 ShuffleLoop lda SprDataOffset,x ;check for offset value against
81d2: c5 00 cmp $00 ; the preset value
81d4: 90 0f bcc NextSprOffset ;if less, skip this part
81d6: ac e0 06 ldy SprShuffleAmtOffset ;get current offset to preset value we want to add
81d9: 18 clc
81da: 79 e1 06 adc SprShuffleAmt,y ;get shuffle amount, add to current sprite offset
81dd: 90 03 bcc StrSprOffset ;if not exceeded $ff, skip second add
81df: 18 clc
81e0: 65 00 adc $00 ;otherwise add preset value $28 to offset
81e2: 9d e4 06 StrSprOffset sta SprDataOffset,x ;store new offset here or old one if branched to here
81e5: ca NextSprOffset dex ;move backwards to next one
81e6: 10 e7 bpl ShuffleLoop
81e8: ae e0 06 ldx SprShuffleAmtOffset ;load offset
81eb: e8 inx
81ec: e0 03 cpx #$03 ;check if offset + 1 goes to 3
81ee: d0 02 bne SetAmtOffset ;if offset + 1 not 3, store
81f0: a2 00 ldx #$00 ;otherwise, init to 0
81f2: 8e e0 06 SetAmtOffset stx SprShuffleAmtOffset
81f5: a2 08 ldx #$08 ;load offsets for values and storage
81f7: a0 02 ldy #$02
81f9: b9 e9 06 SetMiscOffset lda SprDataOffset+5,y ;load one of three OAM data offsets
81fc: 9d f1 06 sta Misc_SprDataOffset-2,x ;store first one unmodified, but
81ff: 18 clc ; add eight to the second and eight
8200: 69 08 adc #$08 ; more to the third one
8202: 9d f2 06 sta Misc_SprDataOffset-1,x ;note that due to the way X is set up,
8205: 18 clc ; this code loads into the misc sprite offsets
8206: 69 08 adc #$08
8208: 9d f3 06 sta Misc_SprDataOffset,x
820b: ca dex
820c: ca dex
820d: ca dex
820e: 88 dey
820f: 10 e8 bpl SetMiscOffset ;do this until all misc spr offsets are loaded
8211: 60 rts
; -----------------------------------------------------------------------------
OperModeExecutionTree
8212: ad 70 07 lda OperMode
8215: 20 04 8e jsr JumpEngine
8218: 31 82 .dd2 TitleScreenMode
821a: dc ae .dd2 GameMode
821c: 8b 83 .dd2 VictoryMode
821e: 18 92 .dd2 GameOverMode
; -----------------------------------------------------------------------------
MoveAllSpritesOffscreen
8220: a0 00 ldy #$00 ;this routine moves all sprites off the screen
8222: 2c bit βΌ Fireball_BoundBoxCtrl ;BIT instruction opcode
MoveSpritesOffscreen
8223: a0 04 ldy #$04 ;this routine moves all but sprite 0
8225: a9 f8 lda #$f8 ;off the screen
8227: 99 00 02 SprInitLoop sta Sprite_Y_Position,y ;write 248 into OAM data's Y coordinate
822a: c8 iny ;which will move it off the screen
822b: c8 iny
822c: c8 iny
822d: c8 iny
822e: d0 f7 bne SprInitLoop
8230: 60 rts
; -----------------------------------------------------------------------------
8231: ad 72 07 TitleScreenMode lda OperMode_Task
8234: 20 04 8e jsr JumpEngine
8237: cf 8f .dd2 InitializeGame
8239: 67 85 .dd2 ScreenRoutines
823b: 61 90 .dd2 PrimaryGameSetup
823d: 45 82 .dd2 GameMenuRoutine
; -----------------------------------------------------------------------------
WSelectBufferTemplate
823f: 04 20 73 01+ .bulk $04,$20,$73,$01,$00,$00
8245: a0 00 ldy #$00
8247: ad fc 06 lda SavedJoypad1Bits ;check to see if either player pressed
824a: 0d fd 06 ora SavedJoypad2Bits ; only the start button (either joypad)
824d: c9 10 cmp #Start_Button
824f: f0 04 beq StartGame
8251: c9 90 cmp #$90 ;||check to see if A + start was pressed
8253: d0 03 bne ChkSelect ;if not, branch to check select button
8255: 4c d8 82 StartGame jmp ChkContinue ;if either start or A + start, execute here
8258: c9 20 ChkSelect cmp #Select_Button ;check to see if the select button was pressed
825a: f0 1a beq SelectBLogic ;if so, branch reset demo timer
825c: ae a2 07 ldx DemoTimer ;otherwise check demo timer
825f: d0 0b bne ChkWorldSel ;if demo timer not expired, branch to check world selection
8261: 8d 80 07 sta SelectTimer ;set controller bits here if running demo
8264: 20 6b 83 jsr DemoEngine ;run through the demo actions
8267: b0 60 bcs ResetTitle ;if carry flag set, demo over, thus branch
8269: 4c c0 82 jmp RunDemo ;otherwise, run game engine for demo
826c: ae fc 07 ChkWorldSel ldx WorldSelectEnableFlag ;check to see if world selection has been enabled
826f: f0 4a beq NullJoypad
8271: c9 40 cmp #B_Button ;if so, check to see if the B button was pressed
8273: d0 46 bne NullJoypad
8275: c8 iny ;if so, increment Y and execute same code as select
8276: ad a2 07 SelectBLogic lda DemoTimer ;if select or B pressed, check demo timer one last time
8279: f0 4e beq ResetTitle ;if demo timer expired, branch to reset title screen mode
827b: a9 18 lda #$18 ;otherwise reset demo timer
827d: 8d a2 07 sta DemoTimer
8280: ad 80 07 lda SelectTimer ;check select/B button timer
8283: d0 36 bne NullJoypad ;if not expired, branch
8285: a9 10 lda #$10 ;otherwise reset select button timer
8287: 8d 80 07 sta SelectTimer
828a: c0 01 cpy #$01 ;was the B button pressed earlier? if so, branch
828c: f0 0e beq IncWorldSel ;note this will not be run if world selection is disabled
828e: ad 7a 07 lda NumberOfPlayers ;if no, must have been the select button, therefore
8291: 49 01 eor #%00000001 ; change number of players and draw icon accordingly
8293: 8d 7a 07 sta NumberOfPlayers
8296: 20 25 83 jsr DrawMushroomIcon
8299: 4c bb 82 jmp NullJoypad
829c: ae 6b 07 IncWorldSel ldx WorldSelectNumber ;increment world select number
829f: e8 inx
82a0: 8a txa
82a1: 29 07 and #%00000111 ;mask out higher bits
82a3: 8d 6b 07 sta WorldSelectNumber ;store as current world select number
82a6: 20 0e 83 jsr GoContinue
82a9: bd 3f 82 UpdateShroom lda WSelectBufferTemplate,x ;write template for world select in vram buffer
82ac: 9d 00 03 sta VRAM_Buffer1-1,x ;do this until all bytes are written
82af: e8 inx
82b0: e0 06 cpx #$06
82b2: 30 f5 bmi UpdateShroom
82b4: ac 5f 07 ldy WorldNumber ;get world number from variable and increment for
82b7: c8 iny ; proper display, and put in blank byte before
82b8: 8c 04 03 sty VRAM_Buffer1+3 ; null terminator
82bb: a9 00 NullJoypad lda #$00 ;clear joypad bits for player 1
82bd: 8d fc 06 sta SavedJoypad1Bits
82c0: 20 ea ae RunDemo jsr GameCoreRoutine ;run game engine
82c3: a5 0e lda GameEngineSubroutine ;check to see if we're running lose life routine
82c5: c9 06 cmp #$06
82c7: d0 44 bne ExitMenu ;if not, do not do all the resetting below
82c9: a9 00 ResetTitle lda #$00 ;reset game modes, disable
82cb: 8d 70 07 sta OperMode ;sprite 0 check and disable
82ce: 8d 72 07 sta OperMode_Task ;screen output
82d1: 8d 22 07 sta Sprite0HitDetectFlag
82d4: ee 74 07 inc DisableScreenFlag
82d7: 60 rts
82d8: ac a2 07 ChkContinue ldy DemoTimer ;if timer for demo has expired, reset modes
82db: f0 ec beq ResetTitle
82dd: 0a asl A ;check to see if A button was also pushed
82de: 90 06 bcc StartWorld1 ;if not, don't load continue function's world number
82e0: ad fd 07 lda ContinueWorld ;load previously saved world number for secret
82e3: 20 0e 83 jsr GoContinue ;continue function when pressing A + start
82e6: 20 03 9c StartWorld1 jsr LoadAreaPointer
82e9: ee 5d 07 inc Hidden1UpFlag ;set 1-up box flag for both players
82ec: ee 64 07 inc OffScr_Hidden1UpFlag
82ef: ee 57 07 inc FetchNewGameTimerFlag ;set fetch new game timer flag
82f2: ee 70 07 inc OperMode ;set next game mode
82f5: ad fc 07 lda WorldSelectEnableFlag ;if world select flag is on, then primary
82f8: 8d 6a 07 sta PrimaryHardMode ; hard mode must be on as well
82fb: a9 00 lda #$00
82fd: 8d 72 07 sta OperMode_Task ;set game mode here, and clear demo timer
8300: 8d a2 07 sta DemoTimer
8303: a2 17 ldx #$17
8305: a9 00 lda #$00
8307: 9d dd 07 InitScores sta ScoreAndCoinDisplay,x ;clear player scores and coin displays
830a: ca dex
830b: 10 fa bpl InitScores
830d: 60 rts
830e: 8d 5f 07 GoContinue sta WorldNumber ;start both players at the first area
8311: 8d 66 07 sta OffScr_WorldNumber ; of the previously saved world number
8314: a2 00 ldx #$00 ;note that on power-up using this function
8316: 8e 60 07 stx AreaNumber ; will make no difference
8319: 8e 67 07 stx OffScr_AreaNumber
831c: 60 rts
; -----------------------------------------------------------------------------
MushroomIconData
831d: 07 22 49 83+ .bulk $07,$22,$49,$83,$ce,$24,$24,$00
DrawMushroomIcon
8325: a0 07 ldy #$07 ;read eight bytes to be read by transfer routine
8327: b9 1d 83 IconDataRead lda MushroomIconData,y ;note that the default position is set for a
832a: 99 00 03 sta VRAM_Buffer1-1,y ; 1-player game
832d: 88 dey
832e: 10 f7 bpl IconDataRead
8330: ad 7a 07 lda NumberOfPlayers ;check number of players
8333: f0 0a beq ExitIcon ;if set to 1-player game, we're done
8335: a9 24 lda #$24 ;otherwise, load blank tile in 1-player position
8337: 8d 04 03 sta VRAM_Buffer1+3
833a: a9 ce lda #$ce ;then load shroom icon tile in 2-player position
833c: 8d 06 03 sta VRAM_Buffer1+5
833f: 60 ExitIcon rts
; -----------------------------------------------------------------------------
8340: 01 80 02 81+ DemoActionData .bulk $01,$80,$02,$81,$41,$80,$01,$42,$c2,$02,$80,$41,$c1,$41,$c1,$01
+ $c1,$01,$02,$80,$00
8355: 9b 10 18 05+ DemoTimingData .bulk $9b,$10,$18,$05,$2c,$20,$24,$15,$5a,$10,$20,$28,$30,$20,$10,$80
+ $20,$30,$30,$01,$ff,$00
836b: ae 17 07 DemoEngine ldx DemoAction ;load current demo action
836e: ad 18 07 lda DemoActionTimer ;load current action timer
8371: d0 0d bne DoAction ;if timer still counting down, skip
8373: e8 inx
8374: ee 17 07 inc DemoAction ;if expired, increment action, X, and
8377: 38 sec ; set carry by default for demo over
8378: bd 54 83 lda DemoTimingData-1,x ;get next timer
837b: 8d 18 07 sta DemoActionTimer ;store as current timer
837e: f0 0a beq DemoOver ;if timer already at zero, skip
8380: bd 3f 83 DoAction lda DemoActionData-1,x ;get and perform action (current or next)
8383: 8d fc 06 sta SavedJoypad1Bits
8386: ce 18 07 dec DemoActionTimer ;decrement action timer
8389: 18 clc ;clear carry if demo still going
838a: 60 DemoOver rts
; -----------------------------------------------------------------------------
838b: 20 a0 83 VictoryMode jsr VictoryModeSubroutines ;run victory mode subroutines
838e: ad 72 07 lda OperMode_Task ;get current task of victory mode
8391: f0 07 beq AutoPlayer ;if on bridge collapse, skip enemy processing
8393: a2 00 ldx #$00
8395: 86 08 stx ObjectOffset ;otherwise reset enemy object offset
8397: 20 47 c0 jsr EnemiesAndLoopsCore ; and run enemy code
839a: 20 2a f1 AutoPlayer jsr RelativePlayerPosition ;get player's relative coordinates
839d: 4c e9 ee jmp PlayerGfxHandler ;draw the player, then leave
VictoryModeSubroutines
83a0: ad 72 07 lda OperMode_Task
83a3: 20 04 8e jsr JumpEngine
83a6: ec cf .dd2 BridgeCollapse
83a8: b0 83 .dd2 SetupVictoryMode
83aa: bd 83 .dd2 PlayerVictoryWalk
83ac: f6 83 .dd2 PrintVictoryMessages
83ae: 61 84 .dd2 PlayerEndWorld
; -----------------------------------------------------------------------------
SetupVictoryMode
83b0: ae 1b 07 ldx ScreenRight_PageLoc ;get page location of right side of screen
83b3: e8 inx ;increment to next page
83b4: 86 34 stx DestinationPageLoc ;store here
83b6: a9 08 lda #EndOfCastleMusic
83b8: 85 fc sta EventMusicQueue ;play win castle music
83ba: 4c 4e 87 jmp IncModeTask_B ;jump to set next major task in victory mode
; -----------------------------------------------------------------------------
PlayerVictoryWalk
83bd: a0 00 ldy #$00 ;set value here to not walk player by default
83bf: 84 35 sty VictoryWalkControl
83c1: a5 6d lda Player_PageLoc ;get player's page location
83c3: c5 34 cmp DestinationPageLoc ;compare with destination page location
83c5: d0 06 bne PerformWalk ;if page locations don't match, branch
83c7: a5 86 lda Player_X_Position ;otherwise get player's horizontal position
83c9: c9 60 cmp #$60 ;compare with preset horizontal position
83cb: b0 03 bcs DontWalk ;if still on other page, branch ahead
83cd: e6 35 PerformWalk inc VictoryWalkControl ;otherwise increment value and Y
83cf: c8 iny ;note Y will be used to walk the player
83d0: 98 DontWalk tya ;put contents of Y in A and
83d1: 20 e6 b0 jsr AutoControlPlayer ; use A to mvoe player to the right or not
83d4: ad 1a 07 lda ScreenLeft_PageLoc ;check page location of left side of screen
83d7: c5 34 cmp DestinationPageLoc ;against set value here
83d9: f0 16 beq ExitVWalk ;branch if equal to change modes if necessary
83db: ad 68 07 lda ScrollFractional
83de: 18 clc ;do fixed point math on fractional part of scroll
83df: 69 80 adc #$80
83e1: 8d 68 07 sta ScrollFractional ;save fractional movement amount
83e4: a9 01 lda #$01 ;set 1 pixel per frame
83e6: 69 00 adc #$00 ;add carry from previous addition
83e8: a8 tay ;use as scroll amount
83e9: 20 c4 af jsr ScrollScreen ;do sub to scroll the screen
83ec: 20 6f af jsr UpdScrollVar ;do another sub to update screen and scroll variables
83ef: e6 35 inc VictoryWalkControl ;increment value to stay in this routine
83f1: a5 35 ExitVWalk lda VictoryWalkControl ;load value set here
83f3: f0 68 beq IncModeTask_A ;if zero, branch to change modes
83f5: 60 rts ;otherwise leave
; -----------------------------------------------------------------------------
PrintVictoryMessages
83f6: ad 49 07 lda SecondaryMsgCounter ;load secondary message counter
83f9: d0 48 bne IncMsgCounter ;if set, branch to increment message counters
83fb: ad 19 07 lda PrimaryMsgCounter ;otherwise load primary message counter
83fe: f0 18 beq ThankPlayer ;if set to zero, branch to print first message
8400: c9 09 cmp #$09 ;if at 9 or above, branch elsewhere (this comparison
8402: b0 3f bcs IncMsgCounter ; is residual code, counter never reaches 9)
8404: ac 5f 07 ldy WorldNumber ;check world number
8407: c0 07 cpy #World8
8409: d0 09 bne MRetainerMsg ;if not at world 8, skip to next part
840b: c9 03 cmp #$03 ;check primary message counter again
840d: 90 34 bcc IncMsgCounter ;if not at 3 yet (world 8 only), branch to increment
840f: e9 01 sbc #$01 ;otherwise subtract one
8411: 4c 18 84 jmp ThankPlayer ;and skip to next part
8414: c9 02 MRetainerMsg cmp #$02 ;check primary message counter
8416: 90 2b bcc IncMsgCounter ;if not at 2 yet (world 1-7 only), branch
8418: a8 ThankPlayer tay ;put primary message counter into Y
8419: d0 08 bne SecondPartMsg ;if counter nonzero, skip this part, do not print first message
841b: ad 53 07 lda CurrentPlayer ;otherwise get player currently on the screen
841e: f0 14 beq EvalForMusic ;if mario, branch
8420: c8 iny ;otherwise increment Y once for luigi and
8421: d0 11 bne EvalForMusic ;do an unconditional branch to the same place
8423: c8 SecondPartMsg iny ;increment Y to do world 8's message
8424: ad 5f 07 lda WorldNumber
8427: c9 07 cmp #World8 ;check world number
8429: f0 09 beq EvalForMusic ;if at world 8, branch to next part
842b: 88 dey ;otherwise decrement Y for world 1-7's message
842c: c0 04 cpy #$04 ;if counter at 4 (world 1-7) only
842e: b0 26 bcs SetEndTimer ; branch to set victory end timer
8430: c0 03 cpy #$03 ;if counter at 3 (world 1-7 only)
8432: b0 0f bcs IncMsgCounter ; branch to keep counting
8434: c0 03 EvalForMusic cpy #$03 ;if counter not yet at 3 (world 8 only), branch
8436: d0 04 bne PrintMsg ; to print message only (note world 1-7 will only
8438: a9 04 lda #VictoryMusic ; reach this code if counter = 0, and will always branch)
843a: 85 fc sta EventMusicQueue ;otherwise load victory music first (world 8 only)
843c: 98 PrintMsg tya ;put primary message counter in A
843d: 18 clc ;add $0c or 12 to counter thus giving an appropriate value,
843e: 69 0c adc #$0c ; ($0c-$0d = first), ($0e = world 1-7's), ($0f-$12 = world 8's)
8440: 8d 73 07 sta VRAM_Buffer_AddrCtrl ;write message counter to vram address controller
8443: ad 49 07 IncMsgCounter lda SecondaryMsgCounter
8446: 18 clc
8447: 69 04 adc #$04 ;add four to secondary message counter
8449: 8d 49 07 sta SecondaryMsgCounter
844c: ad 19 07 lda PrimaryMsgCounter
844f: 69 00 adc #$00 ;add carry to primary message counter
8451: 8d 19 07 sta PrimaryMsgCounter
8454: c9 07 cmp #$07 ;check primary counter one more time
8456: 90 08 SetEndTimer bcc ExitMsgs ;if not reached value yet, branch to leave
8458: a9 06 lda #$06
845a: 8d a1 07 sta WorldEndTimer ;otherwise set world end timer
845d: ee 72 07 IncModeTask_A inc OperMode_Task ;move onto next task in mode
8460: 60 ExitMsgs rts ;leave
; -----------------------------------------------------------------------------
8461: ad a1 07 PlayerEndWorld lda WorldEndTimer ;check to see if world end timer expired
8464: d0 20 bne EndExitOne ;branch to leave if not
8466: ac 5f 07 ldy WorldNumber ;check world number
8469: c0 07 cpy #World8 ;if on world 8, player is done with game,
846b: b0 1a bcs EndChkBButton ; thus branch to read controller
846d: a9 00 lda #$00
846f: 8d 60 07 sta AreaNumber ;otherwise initialize area number used as offset
8472: 8d 5c 07 sta LevelNumber ; and level number control to start at area 1
8475: 8d 72 07 sta OperMode_Task ;initialize secondary mode of operation
8478: ee 5f 07 inc WorldNumber ;increment world number to move onto the next world
847b: 20 03 9c jsr LoadAreaPointer ;get area address offset for the next area
847e: ee 57 07 inc FetchNewGameTimerFlag ;set flag to load game timer from header
8481: a9 01 lda #GameModeValue
8483: 8d 70 07 sta OperMode ;set mode of operation to game mode
8486: 60 EndExitOne rts ;and leave
8487: ad fc 06 EndChkBButton lda SavedJoypad1Bits
848a: 0d fd 06 ora SavedJoypad2Bits ;check to see if B button was pressed on
848d: 29 40 and #B_Button ; either controller
848f: f0 0d beq EndExitTwo ;branch to leave if not
8491: a9 01 lda #$01 ;otherwise set world selection flag
8493: 8d fc 07 sta WorldSelectEnableFlag
8496: a9 ff lda #$ff ;remove onscreen player's lives
8498: 8d 5a 07 sta NumberOfLives
849b: 20 48 92 jsr TerminateGame ;do sub to continue other player or end game
849e: 60 EndExitTwo rts ;leave
; -----------------------------------------------------------------------------
;
; Data is used as tiles for numbers that appear when you defeat enemies.
FloateyNumTileData
849f: ff ff .bulk $ff,$ff ;dummy
84a1: f6 fb .bulk $f6,$fb ;"100"
84a3: f7 fb .bulk $f7,$fb ;"200"
84a5: f8 fb .bulk $f8,$fb ;"400"
84a7: f9 fb .bulk $f9,$fb ;"500"
84a9: fa fb .bulk $fa,$fb ;"800"
84ab: f6 50 .bulk $f6,$50 ;"1000"
84ad: f7 50 .bulk $f7,$50 ;"2000"
84af: f8 50 .bulk $f8,$50 ;"4000"
84b1: f9 50 .bulk $f9,$50 ;"5000"
84b3: fa 50 .bulk $fa,$50 ;"8000"
84b5: fd fe .bulk $fd,$fe ;"1-UP"
;
; High nybble is digit number, low nybble is number to add to the digit of the
; player's score.
84b7: ff ScoreUpdateData .dd1 $ff ;dummy
84b8: 41 42 44 45+ .bulk $41,$42,$44,$45,$48,$31,$32,$34,$35,$38,$00
FloateyNumbersRoutine
84c3: bd 10 01 lda FloateyNum_Control,x ;load control for floatey number
84c6: f0 be beq EndExitOne ;if zero, branch to leave
84c8: c9 0b cmp #$0b ;if less than $0b, branch
84ca: 90 05 bcc ChkNumTimer
84cc: a9 0b lda #$0b ;otherwise set to $0b, thus keeping
84ce: 9d 10 01 sta FloateyNum_Control,x ; it in range
84d1: a8 ChkNumTimer tay ;use as Y
84d2: bd 2c 01 lda FloateyNum_Timer,x ;check value here
84d5: d0 04 bne DecNumTimer ;if nonzero, branch ahead
84d7: 9d 10 01 sta FloateyNum_Control,x ;initialize floatey number control and leave
84da: 60 rts
84db: de 2c 01 DecNumTimer dec FloateyNum_Timer,x ;decrement value here
84de: c9 2b cmp #$2b ;if not reached a certain point, branch
84e0: d0 1e bne ChkTallEnemy
84e2: c0 0b cpy #$0b ;check offset for $0b
84e4: d0 07 bne LoadNumTiles ;branch ahead if not found
84e6: ee 5a 07 inc NumberOfLives ;give player one extra life (1-up)
84e9: a9 40 lda #Sfx_ExtraLife
84eb: 85 fe sta Square2SoundQueue ;and play the 1-up sound
84ed: b9 b7 84 LoadNumTiles lda ScoreUpdateData,y ;load point value here
84f0: 4a lsr A ;move high nybble to low
84f1: 4a lsr A
84f2: 4a lsr A
84f3: 4a lsr A
84f4: aa tax ;use as X offset, essentially the digit
84f5: b9 b7 84 lda ScoreUpdateData,y ;load again and this time
84f8: 29 0f and #%00001111 ;mask out the high nybble
84fa: 9d 34 01 sta DigitModifier,x ;store as amount to add to the digit
84fd: 20 27 bc jsr AddToScore ;update the score accordingly
8500: bc e5 06 ChkTallEnemy ldy Enemy_SprDataOffset,x ;get OAM data offset for enemy object
8503: b5 16 lda Enemy_ID,x ;get enemy object identifier
8505: c9 12 cmp #Spiny
8507: f0 22 beq FloateyPart ;branch if spiny
8509: c9 0d cmp #PiranhaPlant
850b: f0 1e beq FloateyPart ;branch if piranha plant
850d: c9 05 cmp #HammerBro
850f: f0 12 beq GetAltOffset ;branch elsewhere if hammer bro
8511: c9 0a cmp #GreyCheepCheep
8513: f0 16 beq FloateyPart ;branch if cheep-cheep of either color
8515: c9 0b cmp #RedCheepCheep
8517: f0 12 beq FloateyPart
8519: c9 09 cmp #TallEnemy
851b: b0 06 bcs GetAltOffset ;branch elsewhere if enemy object => $09
851d: b5 1e lda Enemy_State,x
851f: c9 02 cmp #$02 ;if enemy state defeated or otherwise
8521: b0 08 bcs FloateyPart ;$02 or greater, branch beyond this part
8523: ae ee 03 GetAltOffset ldx SprDataOffset_Ctrl ;load some kind of control bit
8526: bc ec 06 ldy Alt_SprDataOffset,x ;get alternate OAM data offset
8529: a6 08 ldx ObjectOffset ;get enemy object offset again
852b: bd 1e 01 FloateyPart lda FloateyNum_Y_Pos,x ;get vertical coordinate for
852e: c9 18 cmp #$18 ; floatey number, if coordinate in the
8530: 90 05 bcc SetupNumSpr ; status bar, branch
8532: e9 01 sbc #$01
8534: 9d 1e 01 sta FloateyNum_Y_Pos,x ;otherwise subtract one and store as new
8537: bd 1e 01 SetupNumSpr lda FloateyNum_Y_Pos,x ;get vertical coordinate
853a: e9 08 sbc #$08 ;subtract eight and dump into the
853c: 20 c1 e5 jsr DumpTwoSpr ; left and right sprite's Y coordinates
853f: bd 17 01 lda FloateyNum_X_Pos,x ;get horizontal coordinate
8542: 99 03 02 sta Sprite_X_Position,y ;store into X coordinate of left sprite
8545: 18 clc
8546: 69 08 adc #$08 ;add eight pixels and store into X
8548: 99 07 02 sta Sprite_X_Position+4,y ; coordinate of right sprite
854b: a9 02 lda #$02
854d: 99 02 02 sta Sprite_Attributes,y ;set palette control in attribute bytes
8550: 99 06 02 sta Sprite_Attributes+4,y ; of left and right sprites
8553: bd 10 01 lda FloateyNum_Control,x
8556: 0a asl A ;multiply our floatey number control by 2
8557: aa tax ; and use as offset for look-up table
8558: bd 9f 84 lda FloateyNumTileData,x
855b: 99 01 02 sta Sprite_Tilenumber,y ;display first half of number of points
855e: bd a0 84 lda FloateyNumTileData+1,x
8561: 99 05 02 sta Sprite_Tilenumber+4,y ;display the second half
8564: a6 08 ldx ObjectOffset ;get enemy object offset and leave
8566: 60 rts
; -----------------------------------------------------------------------------
8567: ad 3c 07 ScreenRoutines lda ScreenRoutineTask ;run one of the following subroutines
856a: 20 04 8e jsr JumpEngine
856d: 8b 85 .dd2 InitScreen
856f: 9b 85 .dd2 SetupIntermediate
8571: 52 86 .dd2 WriteTopStatusLine
8573: 5a 86 .dd2 WriteBottomStatusLine
8575: 93 86 .dd2 DisplayTimeUp
8577: 9d 88 .dd2 ResetSpritesAndScreenTimer
8579: a8 86 .dd2 DisplayIntermediate
857b: 9d 88 .dd2 ResetSpritesAndScreenTimer
857d: e6 86 .dd2 AreaParserTaskControl
857f: bf 85 .dd2 GetAreaPalette
8581: e3 85 .dd2 GetBackgroundColor
8583: 43 86 .dd2 GetAlternatePalette1
8585: ff 86 .dd2 DrawTitleScreen
8587: 32 87 .dd2 ClearBuffersDrawIcon
8589: 49 87 .dd2 WriteTopScore
; -----------------------------------------------------------------------------
858b: 20 20 82 InitScreen jsr MoveAllSpritesOffscreen ;initialize all sprites including sprite #0
858e: 20 19 8e jsr InitializeNameTables ; and erase both name and attribute tables
8591: ad 70 07 lda OperMode
8594: f0 32 beq NextSubtask ;if mode still 0, do not load
8596: a2 03 ldx #$03 ;into buffer pointer
8598: 4c c5 85 jmp SetVRAMAddr_A
; -----------------------------------------------------------------------------
SetupIntermediate
859b: ad 44 07 lda BackgroundColorCtrl ;save current background color control
859e: 48 pha ; and player status to stack
859f: ad 56 07 lda PlayerStatus
85a2: 48 pha
85a3: a9 00 lda #$00 ;set background color to black
85a5: 8d 56 07 sta PlayerStatus ; and player status to not fiery
85a8: a9 02 lda #$02 ;this is the ONLY time background color control
85aa: 8d 44 07 sta BackgroundColorCtrl ; is set to less than 4
85ad: 20 f1 85 jsr GetPlayerColors
85b0: 68 pla ;we only execute this routine for
85b1: 8d 56 07 sta PlayerStatus ; the intermediate lives display
85b4: 68 pla ; and once we're done, we return bg
85b5: 8d 44 07 sta BackgroundColorCtrl ; color ctrl and player status from stack
85b8: 4c 45 87 jmp IncSubtask ; then move into the next task
; -----------------------------------------------------------------------------
85bb: 01 02 03 04 AreaPalette .bulk $01,$02,$03,$04
85bf: ac 4e 07 GetAreaPalette ldy AreaType ;select appropriate palette to load
85c2: be bb 85 ldx AreaPalette,y ; based on area type
85c5: 8e 73 07 SetVRAMAddr_A stx VRAM_Buffer_AddrCtrl ;store offset into buffer control
85c8: 4c 45 87 NextSubtask jmp IncSubtask ;move onto next task
; -----------------------------------------------------------------------------
; $00 - used as temp counter in GetPlayerColors
BGColorCtrl_Addr
85cb: 00 09 0a 04 .bulk $00,$09,$0a,$04
BackgroundColors
85cf: 22 22 0f 0f .bulk $22,$22,$0f,$0f ;used by area type if bg color ctrl not set
85d3: 0f 22 0f 0f .bulk $0f,$22,$0f,$0f ;used by background color control if set
85d7: 22 16 27 18 PlayerColors .bulk $22,$16,$27,$18 ;mario's colors
85db: 22 30 27 19 .bulk $22,$30,$27,$19 ;luigi's colors
85df: 22 37 27 16 .bulk $22,$37,$27,$16 ;fiery (used by both)
GetBackgroundColor
85e3: ac 44 07 ldy BackgroundColorCtrl ;check background color control
85e6: f0 06 beq NoBGColor ;if not set, increment task and fetch palette
85e8: b9 c7 85 lda BGColorCtrl_Addr-4,y ;put appropriate palette into vram
85eb: 8d 73 07 sta VRAM_Buffer_AddrCtrl ;note that if set to 5-7, $0301 will not be read
85ee: ee 3c 07 NoBGColor inc ScreenRoutineTask ;increment to next subtask and plod on through
;
85f1: ae 00 03 GetPlayerColors ldx VRAM_Buffer1_Offset ;get current buffer offset
85f4: a0 00 ldy #$00
85f6: ad 53 07 lda CurrentPlayer ;check which player is on the screen
85f9: f0 02 beq ChkFiery
85fb: a0 04 ldy #$04 ;load offset for luigi
85fd: ad 56 07 ChkFiery lda PlayerStatus ;check player status
8600: c9 02 cmp #$02
8602: d0 02 bne StartClrGet ;if fiery, load alternate offset for fiery player
8604: a0 08 ldy #$08
8606: a9 03 StartClrGet lda #$03 ;do four colors
8608: 85 00 sta $00
860a: b9 d7 85 ClrGetLoop lda PlayerColors,y ;fetch player colors and store them
860d: 9d 04 03 sta VRAM_Buffer1+3,x ; in the buffer
8610: c8 iny
8611: e8 inx
8612: c6 00 dec $00
8614: 10 f4 bpl ClrGetLoop
8616: ae 00 03 ldx VRAM_Buffer1_Offset ;load original offset from before
8619: ac 44 07 ldy BackgroundColorCtrl ;if this value is four or greater, it will be set
861c: d0 03 bne SetBGColor ;therefore use it as offset to background color
861e: ac 4e 07 ldy AreaType ;otherwise use area type bits from area offset as offset
8621: b9 cf 85 SetBGColor lda BackgroundColors,y ; to background color instead
8624: 9d 04 03 sta VRAM_Buffer1+3,x
8627: a9 3f lda #$3f ;set for sprite palette address
8629: 9d 01 03 sta VRAM_Buffer1,x ;save to buffer
862c: a9 10 lda #$10
862e: 9d 02 03 sta VRAM_Buffer1+1,x
8631: a9 04 lda #$04 ;write length byte to buffer
8633: 9d 03 03 sta VRAM_Buffer1+2,x
8636: a9 00 lda #$00 ;now the null terminator
8638: 9d 08 03 sta VRAM_Buffer1+7,x
863b: 8a txa ;move the buffer pointer ahead 7 bytes
863c: 18 clc ;in case we want to write anything else later
863d: 69 07 adc #$07
863f: 8d 00 03 SetVRAMOffset sta VRAM_Buffer1_Offset ;store as new vram buffer offset
8642: 60 rts
; -----------------------------------------------------------------------------
GetAlternatePalette1
8643: ad 33 07 lda AreaStyle ;check for mushroom level style
8646: c9 01 cmp #$01
8648: d0 05 bne NoAltPal
864a: a9 0b lda #$0b ;if found, load appropriate palette
864c: 8d 73 07 SetVRAMAddr_B sta VRAM_Buffer_AddrCtrl
864f: 4c 45 87 NoAltPal jmp IncSubtask ;now onto the next task
; -----------------------------------------------------------------------------
WriteTopStatusLine
8652: a9 00 lda #$00 ;select main status bar
8654: 20 08 88 jsr WriteGameText ;output it
8657: 4c 45 87 jmp IncSubtask ;onto the next task
; -----------------------------------------------------------------------------
WriteBottomStatusLine
865a: 20 30 bc jsr GetSBNybbles ;write player's score and coin tally to screen
865d: ae 00 03 ldx VRAM_Buffer1_Offset
8660: a9 20 lda #$20 ;write address for world-area number on screen
8662: 9d 01 03 sta VRAM_Buffer1,x
8665: a9 73 lda #$73
8667: 9d 02 03 sta VRAM_Buffer1+1,x
866a: a9 03 lda #$03 ;write length for it
866c: 9d 03 03 sta VRAM_Buffer1+2,x
866f: ac 5f 07 ldy WorldNumber ;first the world number
8672: c8 iny
8673: 98 tya
8674: 9d 04 03 sta VRAM_Buffer1+3,x
8677: a9 28 lda #$28 ;next the dash
8679: 9d 05 03 sta VRAM_Buffer1+4,x
867c: ac 5c 07 ldy LevelNumber ;next the level number
867f: c8 iny ;increment for proper number display
8680: 98 tya
8681: 9d 06 03 sta VRAM_Buffer1+5,x
8684: a9 00 lda #$00 ;put null terminator on
8686: 9d 07 03 sta VRAM_Buffer1+6,x
8689: 8a txa ;move the buffer offset up by 6 bytes
868a: 18 clc
868b: 69 06 adc #$06
868d: 8d 00 03 sta VRAM_Buffer1_Offset
8690: 4c 45 87 jmp IncSubtask
; -----------------------------------------------------------------------------
8693: ad 59 07 DisplayTimeUp lda GameTimerExpiredFlag ;if game timer not expired, increment task
8696: f0 0a beq NoTimeUp ;control 2 tasks forward, otherwise, stay here
8698: a9 00 lda #$00
869a: 8d 59 07 sta GameTimerExpiredFlag ;reset timer expiration flag
869d: a9 02 lda #$02 ;output time-up screen to buffer
869f: 4c c7 86 jmp OutputInter
86a2: ee 3c 07 NoTimeUp inc ScreenRoutineTask ;increment control task 2 tasks forward
86a5: 4c 45 87 jmp IncSubtask
; -----------------------------------------------------------------------------
DisplayIntermediate
86a8: ad 70 07 lda OperMode ;check primary mode of operation
86ab: f0 33 beq NoInter ;if in title screen mode, skip this
86ad: c9 03 cmp #GameOverModeValue ;are we in game over mode?
86af: f0 22 beq GameOverInter ;if so, proceed to display game over screen
86b1: ad 52 07 lda AltEntranceControl ;otherwise check for mode of alternate entry
86b4: d0 2a bne NoInter ; and branch if found
86b6: ac 4e 07 ldy AreaType ;check if we are on castle level
86b9: c0 03 cpy #$03 ;and if so, branch (possibly residual)
86bb: f0 05 beq PlayerInter
86bd: ad 69 07 lda DisableIntermediate ;if this flag is set, skip intermediate lives display
86c0: d0 1e bne NoInter ; and jump to specific task, otherwise
86c2: 20 a4 ef PlayerInter jsr DrawPlayer_Intermediate ;put player in appropriate place for
86c5: a9 01 lda #$01 ; lives display, then output lives display to buffer
86c7: 20 08 88 OutputInter jsr WriteGameText
86ca: 20 a5 88 jsr ResetScreenTimer
86cd: a9 00 lda #$00
86cf: 8d 74 07 sta DisableScreenFlag ;reenable screen output
86d2: 60 rts
86d3: a9 12 GameOverInter lda #$12 ;set screen timer
86d5: 8d a0 07 sta ScreenTimer
86d8: a9 03 lda #$03 ;output game over screen to buffer
86da: 20 08 88 jsr WriteGameText
86dd: 4c 4e 87 jmp IncModeTask_B
86e0: a9 08 NoInter lda #$08 ;set for specific task and leave
86e2: 8d 3c 07 sta ScreenRoutineTask
86e5: 60 rts
; -----------------------------------------------------------------------------
AreaParserTaskControl
86e6: ee 74 07 inc DisableScreenFlag ;turn off screen
86e9: 20 b0 92 TaskLoop jsr AreaParserTaskHandler ;render column set of current area
86ec: ad 1f 07 lda AreaParserTaskNum ;check number of tasks
86ef: d0 f8 bne TaskLoop ;if tasks still not all done, do another one
86f1: ce 1e 07 dec ColumnSets ;do we need to render more column sets?
86f4: 10 03 bpl OutputCol
86f6: ee 3c 07 inc ScreenRoutineTask ;if not, move on to the next task
86f9: a9 06 OutputCol lda #$06 ;set vram buffer to output rendered column set
86fb: 8d 73 07 sta VRAM_Buffer_AddrCtrl ; on next NMI
86fe: 60 rts
; -----------------------------------------------------------------------------
; $00 - vram buffer address table low
; $01 - vram buffer address table high
86ff: ad 70 07 DrawTitleScreen lda OperMode ;are we in title screen mode?
8702: d0 4a bne IncModeTask_B ;if not, exit
8704: a9 1e lda #>TitleScreenDataOffset ;load address $1ec0 into
8706: 8d 06 20 sta PPUADDR ; the vram address register
8709: a9 c0 lda #<TitleScreenDataOffset
870b: 8d 06 20 sta PPUADDR
870e: a9 03 lda #$03 ;put address $0300 into
8710: 85 01 sta $01 ; the indirect at $00
8712: a0 00 ldy #$00
8714: 84 00 sty $00
8716: ad 07 20 lda PPUDATA ;do one garbage read
8719: ad 07 20 OutputTScr lda PPUDATA ;get title screen from chr-rom
871c: 91 00 sta ($00),y ;store 256 bytes into buffer
871e: c8 iny
871f: d0 02 bne ChkHiByte ;if not past 256 bytesw, do not increment
8721: e6 01 inc $01 ;otherwise increment high byte of indirect
8723: a5 01 ChkHiByte lda $01 ;heck high byte?
8725: c9 04 cmp #$04 ;at $0400?
8727: d0 f0 bne OutputTScr ;if not, loop back and do another
8729: c0 3a cpy #$3a ;check if offset points past end of data
872b: 90 ec bcc OutputTScr ;if not, loop back and do another
872d: a9 05 lda #$05 ;set buffer transfer control to $0300,
872f: 4c 4c 86 jmp SetVRAMAddr_B ; increment task and exit
; -----------------------------------------------------------------------------
ClearBuffersDrawIcon
8732: ad 70 07 lda OperMode ;check game mode
8735: d0 17 bne IncModeTask_B ;if not title screen mnode, leave
8737: a2 00 ldx #$00 ;otherwise, clear buffer space
8739: 9d 00 03 TScrClear sta VRAM_Buffer1-1,x
873c: 9d 00 04 sta VRAM_Buffer1+255,x
873f: ca dex
8740: d0 f7 bne TScrClear
8742: 20 25 83 jsr DrawMushroomIcon ;draw player select icon
8745: ee 3c 07 IncSubtask inc ScreenRoutineTask ;move onto next task
8748: 60 rts
; -----------------------------------------------------------------------------
8749: a9 fa WriteTopScore lda #$fa ;run display routine to display top score on title
874b: 20 36 bc jsr UpdateNumber
874e: ee 72 07 IncModeTask_B inc OperMode_Task ;move onto next mode
8751: 60 rts
; -----------------------------------------------------------------------------
; ||TopStatusBarLine
8752: 20 43 05 16+ GameText .bulk $20,$43,$05,$16,$0a,$1b,$12,$18 ;"MARIO"
875a: 20 52 0b 20+ .bulk $20,$52,$0b,$20,$18,$1b,$15,$0d ;"WORLD TIME"
8762: 24 24 1d 12+ .bulk $24,$24,$1d,$12,$16,$0e
8768: 20 68 05 00+ .bulk $20,$68,$05,$00,$24,$24,$2e,$29 ;score trailing digit and coin display
8770: 23 c0 7f aa .bulk $23,$c0,$7f,$aa ;attribute table data, clears name table 0 to palette 2
8774: 23 c2 01 ea .bulk $23,$c2,$01,$ea ;attribute table data, used for coin icon in status bar
8778: ff .dd1 $ff ;end of data block
WorldLivesDisplay
8779: 21 cd 07 24+ .bulk $21,$cd,$07,$24,$24 ;cross with spaces used on
877e: 29 24 24 24+ .bulk $29,$24,$24,$24,$24 ; lives display
8783: 21 4b 09 20+ .bulk $21,$4b,$09,$20,$18 ;"WORLD - " used on lives display
8788: 1b 15 0d 24+ .bulk $1b,$15,$0d,$24,$24,$28,$24
878f: 22 0c 47 24 .bulk $22,$0c,$47,$24 ;possibly used to clear time up
8793: 23 dc 01 ba .bulk $23,$dc,$01,$ba ;attribute table data for crown if more than 9 lives
8797: ff .dd1 $ff
8798: 21 cd 05 16+ TwoPlayerTimeUp .bulk $21,$cd,$05,$16,$0a,$1b,$12,$18 ;"MARIO"
87a0: 22 0c 07 1d+ .bulk $22,$0c,$07,$1d,$12,$16,$0e,$24,$1e,$19 ;"TIME UP"
87aa: ff .dd1 $ff
TwoPlayerGameOver
87ab: 21 cd 05 16+ .bulk $21,$cd,$05,$16,$0a,$1b,$12,$18 ;"MARIO"
OnePlayerGameOver
87b3: 22 0b 09 10+ .bulk $22,$0b,$09,$10,$0a,$16,$0e,$24 ;"GAME OVER"
87bb: 18 1f 0e 1b .bulk $18,$1f,$0e,$1b
87bf: ff .dd1 $ff
87c0: 25 84 15 20+ WarpZoneWelcome .bulk $25,$84,$15,$20,$0e,$15,$0c,$18,$16 ;"WELCOME TO WARP ZONE!"
87c9: 0e 24 1d 18+ .bulk $0e,$24,$1d,$18,$24,$20,$0a,$1b,$19
87d2: 24 23 18 17+ .bulk $24,$23,$18,$17,$0e,$2b
87d8: 26 25 01 24 .bulk $26,$25,$01,$24 ;placeholder for left pipe
87dc: 26 2d 01 24 .bulk $26,$2d,$01,$24 ;placeholder for middle pipe
87e0: 26 35 01 24 .bulk $26,$35,$01,$24 ;placeholder for right pipe
87e4: 27 d9 46 aa .bulk $27,$d9,$46,$aa ;attribute data
87e8: 27 e1 45 aa .bulk $27,$e1,$45,$aa
87ec: ff .dd1 $ff
87ed: 15 1e 12 10+ LuigiName .bulk $15,$1e,$12,$10,$12 ;"LUIGI", no address or length
87f2: 04 03 02 00 WarpZoneNumbers .bulk $04,$03,$02,$00 ;warp zone numbers, note spaces on middle
87f6: 24 05 24 00 .bulk $24,$05,$24,$00 ; zone, partly responsible for
87fa: 08 07 06 00 .bulk $08,$07,$06,$00 ; the minus world
; || (should be table of single-byte offsets, e.g. TopStatusBarLine-GameText and
; WorldLivesDisplay-GameText)
87fe: 00 00 27 27+ GameTextOffsets .bulk $00,$00,$27,$27,$46,$4e,$59,$61,$6e,$6e
8808: 48 WriteGameText pha ;save text number to stack
8809: 0a asl A
880a: a8 tay ;multiply by 2 and use as offset
880b: c0 04 cpy #$04 ;if set to do top status bar on world/lives display,
880d: 90 0c bcc LdGameText ; branch to use current offset as-is
880f: c0 08 cpy #$08 ;if set to do time-up or game over,
8811: 90 02 bcc Chk2Players ;branch to check players
8813: a0 08 ldy #$08 ;otherwise warp zone, therefore set offset
8815: ad 7a 07 Chk2Players lda NumberOfPlayers ;check for number of players
8818: d0 01 bne LdGameText ;if there are two, use current offset to also print name
881a: c8 iny ;otherwise increment offset by one to not print name
881b: be fe 87 LdGameText ldx GameTextOffsets,y ;get offset to message we want to print
881e: a0 00 ldy #$00
8820: bd 52 87 GameTextLoop lda GameText,x ;load message data
8823: c9 ff cmp #$ff ;check for terminator
8825: f0 07 beq EndGameText ;branch to end text if found
8827: 99 01 03 sta VRAM_Buffer1,y ;otherwise write data to buffer
882a: e8 inx ;and increment increment
882b: c8 iny
882c: d0 f2 bne GameTextLoop ;do this for 256 bytes if no terminator found
882e: a9 00 EndGameText lda #$00 ;put null terminator at end
8830: 99 01 03 sta VRAM_Buffer1,y
8833: 68 pla ;pull original text number from stack
8834: aa tax
8835: c9 04 cmp #$04 ;are we printing warp zone?
8837: b0 49 bcs PrintWarpZoneNumbers
8839: ca dex ;are we printing the world/lives display?
883a: d0 23 bne CheckPlayerName ;if not, branch to check player's name
883c: ad 5a 07 lda NumberOfLives ;otherwise, check number of lives
883f: 18 clc ; and increment by one for display
8840: 69 01 adc #$01
8842: c9 0a cmp #10 ;more than 9 lives?
8844: 90 07 bcc PutLives
8846: e9 0a sbc #10 ;if so, subtract 10 and put a crown tile
8848: a0 9f ldy #$9f ; next to the difference...strange things happen if
884a: 8c 08 03 sty VRAM_Buffer1+7 ; the number of lives exceeds 19
884d: 8d 09 03 PutLives sta VRAM_Buffer1+8
8850: ac 5f 07 ldy WorldNumber ;write world and level numbers (incremented for display)
8853: c8 iny ; to the buffer in the spaces surrounding the dash
8854: 8c 14 03 sty VRAM_Buffer1+19
8857: ac 5c 07 ldy LevelNumber
885a: c8 iny
885b: 8c 16 03 sty VRAM_Buffer1+21 ;we're done here
885e: 60 rts
885f: ad 7a 07 CheckPlayerName lda NumberOfPlayers ;check number of players
8862: f0 1d beq ExitChkName ;if only 1 player, leave
8864: ad 53 07 lda CurrentPlayer ;load current player
8867: ca dex ;check to see if current message number is for time up
8868: d0 09 bne ChkLuigi
886a: ac 70 07 ldy OperMode ;check for game over mode
886d: c0 03 cpy #GameOverModeValue
886f: f0 02 beq ChkLuigi
8871: 49 01 eor #%00000001 ;if not, must be time up, invert d0 to do other player
8873: 4a ChkLuigi lsr A
8874: 90 0b bcc ExitChkName ;if mario is current player, do not change the name
8876: a0 04 ldy #$04
8878: b9 ed 87 NameLoop lda LuigiName,y ;otherwise, replace "MARIO" with "LUIGI"
887b: 99 04 03 sta VRAM_Buffer1+3,y
887e: 88 dey
887f: 10 f7 bpl NameLoop ;do this until each letter is replaced
8881: 60 ExitChkName rts
PrintWarpZoneNumbers
8882: e9 04 sbc #$04 ;subtract 4 and then shift to the left
8884: 0a asl A ; twice to get proper warp zone number
8885: 0a asl A ;offset
8886: aa tax
8887: a0 00 ldy #$00
8889: bd f2 87 WarpNumLoop lda WarpZoneNumbers,x ;print warp zone numbers into the
888c: 99 1c 03 sta VRAM_Buffer1+27,y ; placeholders from earlier
888f: e8 inx
8890: c8 iny ;put a number in every fourth space
8891: c8 iny
8892: c8 iny
8893: c8 iny
8894: c0 0c cpy #$0c
8896: 90 f1 bcc WarpNumLoop
8898: a9 2c lda #$2c ;load new buffer pointer at end of message
889a: 4c 3f 86 jmp SetVRAMOffset
; -----------------------------------------------------------------------------
ResetSpritesAndScreenTimer
889d: ad a0 07 lda ScreenTimer ;check if screen timer has expired
88a0: d0 0b bne NoReset ;if not, branch to leave
88a2: 20 20 82 jsr MoveAllSpritesOffscreen ;otherwise reset sprites now
ResetScreenTimer
88a5: a9 07 lda #$07 ;reset timer again
88a7: 8d a0 07 sta ScreenTimer
88aa: ee 3c 07 inc ScreenRoutineTask ;move onto next task
88ad: 60 NoReset rts
; -----------------------------------------------------------------------------
; $00 - temp vram buffer offset
; $01 - temp metatile buffer offset
; $02 - temp metatile graphics table offset
; $03 - used to store attribute bits
; $04 - used to determine attribute table row
; $05 - used to determine attribute table column
; $06 - metatile graphics table address low
; $07 - metatile graphics table address high
RenderAreaGraphics
88ae: ad 26 07 lda CurrentColumnPos ;store LSB of where we're at
88b1: 29 01 and #$01
88b3: 85 05 sta $05
88b5: ac 40 03 ldy VRAM_Buffer2_Offset ;store vram buffer offset
88b8: 84 00 sty $00
88ba: ad 21 07 lda CurrentNTAddr_Low ;get current name table address we're supposed to render
88bd: 99 42 03 sta VRAM_Buffer2+1,y
88c0: ad 20 07 lda CurrentNTAddr_High
88c3: 99 41 03 sta VRAM_Buffer2,y
88c6: a9 9a lda #$9a ;store length byte of 26 here with d7 set
88c8: 99 43 03 sta VRAM_Buffer2+2,y ; to increment by 32 (in columns)
88cb: a9 00 lda #$00 ;init attribute row
88cd: 85 04 sta $04
88cf: aa tax
88d0: 86 01 DrawMTLoop stx $01 ;tore init value of 0 or incremented offset for buffer
88d2: bd a1 06 lda MetatileBuffer,x ;get first metatile number, and mask out all but 2 MSB
88d5: 29 c0 and #%11000000
88d7: 85 03 sta $03 ;store attribute table bits here
88d9: 0a asl A ;note that metatile format is:
88da: 2a rol A ;%xx000000 - attribute table bits
88db: 2a rol A ;%00xxxxxx - metatile number
88dc: a8 tay ;rotate bits to d1-d0 and use as offset here
88dd: b9 08 8b lda MetatileGraphics_Low,y ;get address to graphics table from here
88e0: 85 06 sta $06
88e2: b9 0c 8b lda MetatileGraphics_High,y
88e5: 85 07 sta $07
88e7: bd a1 06 lda MetatileBuffer,x ;get metatile number again
88ea: 0a asl A ;multiply by 4 and use as tile offset
88eb: 0a asl A
88ec: 85 02 sta $02
88ee: ad 1f 07 lda AreaParserTaskNum ;get current task number for level processing and
88f1: 29 01 and #%00000001 ; mask out all but LSB, then invert LSB, multiply by 2
88f3: 49 01 eor #%00000001 ; to get the correct column position in the metatile,
88f5: 0a asl A ; then add to the tile offset so we can draw either side
88f6: 65 02 adc $02 ; of the metatiles
88f8: a8 tay
88f9: a6 00 ldx $00 ;use vram buffer offset from before as X
88fb: b1 06 lda ($06),y
88fd: 9d 44 03 sta VRAM_Buffer2+3,x ;get first tile number (top left or top right) and store
8900: c8 iny
8901: b1 06 lda ($06),y ;now get the second (bottom left or bottom right) and store
8903: 9d 45 03 sta VRAM_Buffer2+4,x
8906: a4 04 ldy $04 ;get current attribute row
8908: a5 05 lda $05 ;get LSB of current column where we're at, and
890a: d0 0e bne RightCheck ; branch if set (clear = left attrib, set = right)
890c: a5 01 lda $01 ;get current row we're rendering
890e: 4a lsr A ;branch if LSB set (clear = top left, set = bottom left)
890f: b0 19 bcs LLeft
8911: 26 03 rol $03 ;rotate attribute bits 3 to the left
8913: 26 03 rol $03 ;this in d1-d0, for upper left square
8915: 26 03 rol $03
8917: 4c 30 89 jmp SetAttrib
891a: a5 01 RightCheck lda $01 ;get LSB of current row we're rendering
891c: 4a lsr A ;branch if set (clear = top right, set = bottom right)
891d: b0 0f bcs NextMTRow
891f: 46 03 lsr $03 ;shift attribute bits 4 to the right
8921: 46 03 lsr $03
8923: 46 03 lsr $03
8925: 46 03 lsr $03
8927: 4c 30 89 jmp SetAttrib
892a: 46 03 LLeft lsr $03 ;shift attribute bits 2 to the right
892c: 46 03 lsr $03 ;this in d5-d4 for lower left square
892e: e6 04 NextMTRow inc $04 ;move onto next attribute row
8930: b9 f9 03 SetAttrib lda AttributeBuffer,y ;get previously saved bits from before
8933: 05 03 ora $03 ; if any, and put new bits, if any
8935: 99 f9 03 sta AttributeBuffer,y ; onto the old, and store
8938: e6 00 inc $00 ;increment vram buffer offset by 2
893a: e6 00 inc $00
893c: a6 01 ldx $01 ;get current gfx buffer row, and check for
893e: e8 inx ; the bottom of the screen
893f: e0 0d cpx #$0d
8941: 90 8d bcc DrawMTLoop ;if not there yet, loop back
8943: a4 00 ldy $00 ;get current vram buffer offset, increment by 3
8945: c8 iny ;(for name table address and length bytes)
8946: c8 iny
8947: c8 iny
8948: a9 00 lda #$00
894a: 99 41 03 sta VRAM_Buffer2,y ;put null terminator at end of data for name table
894d: 8c 40 03 sty VRAM_Buffer2_Offset ;store new buffer offset
8950: ee 21 07 inc CurrentNTAddr_Low ;increment name table address low
8953: ad 21 07 lda CurrentNTAddr_Low ;check current low byte
8956: 29 1f and #%00011111 ;if no wraparound, just skip this part
8958: d0 0d bne ExitDrawM
895a: a9 80 lda #$80 ;if wraparound occurs, make sure low byte stays
895c: 8d 21 07 sta CurrentNTAddr_Low ; just under the status bar
895f: ad 20 07 lda CurrentNTAddr_High ; and then invert d2 of the name table address high
8962: 49 04 eor #%00000100 ; to move onto the next appropriate name table
8964: 8d 20 07 sta CurrentNTAddr_High
8967: 4c bd 89 ExitDrawM jmp SetVRAMCtrl ;jump to set buffer to $0341 and leave
; -----------------------------------------------------------------------------
; $00 - temp attribute table address high (big endian order this time!)
; $01 - temp attribute table address low
RenderAttributeTables
896a: ad 21 07 lda CurrentNTAddr_Low ;get low byte of next name table address
896d: 29 1f and #%00011111 ; to be written to, mask out all but 5 LSB,
896f: 38 sec ; subtract four
8970: e9 04 sbc #$04
8972: 29 1f and #%00011111 ;mask out bits again and store
8974: 85 01 sta $01
8976: ad 20 07 lda CurrentNTAddr_High ;get high byte and branch if borrow not set
8979: b0 02 bcs SetATHigh
897b: 49 04 eor #%00000100 ;otherwise invert d2
897d: 29 04 SetATHigh and #%00000100 ;mask out all other bits
897f: 09 23 ora #$23 ;add $2300 to the high byte and store
8981: 85 00 sta $00
8983: a5 01 lda $01 ;get low byte - 4, divide by 4, add offset for
8985: 4a lsr A ; attribute table and store
8986: 4a lsr A
8987: 69 c0 adc #$c0 ;we should now have the appropriate block of
8989: 85 01 sta $01 ; attribute table in our temp address
898b: a2 00 ldx #$00
898d: ac 40 03 ldy VRAM_Buffer2_Offset ;get buffer offset
8990: a5 00 AttribLoop lda $00
8992: 99 41 03 sta VRAM_Buffer2,y ;store high byte of attribute table address
8995: a5 01 lda $01
8997: 18 clc ;get low byte, add 8 because we want to start
8998: 69 08 adc #$08 ; below the status bar, and store
899a: 99 42 03 sta VRAM_Buffer2+1,y
899d: 85 01 sta $01 ;also store in temp again
899f: bd f9 03 lda AttributeBuffer,x ;fetch current attribute table byte and store
89a2: 99 44 03 sta VRAM_Buffer2+3,y ; in the buffer
89a5: a9 01 lda #$01
89a7: 99 43 03 sta VRAM_Buffer2+2,y ;store length of 1 in buffer
89aa: 4a lsr A
89ab: 9d f9 03 sta AttributeBuffer,x ;clear current byte in attribute buffer
89ae: c8 iny ;increment buffer offset by 4 bytes
89af: c8 iny
89b0: c8 iny
89b1: c8 iny
89b2: e8 inx ;increment attribute offset and check to see
89b3: e0 07 cpx #$07 ; if we're at the end yet
89b5: 90 d9 bcc AttribLoop
89b7: 99 41 03 sta VRAM_Buffer2,y ;put null terminator at the end
89ba: 8c 40 03 sty VRAM_Buffer2_Offset ;store offset in case we want to do any more
89bd: a9 06 SetVRAMCtrl lda #$06
89bf: 8d 73 07 sta VRAM_Buffer_AddrCtrl ;set buffer to $0341 and leave
89c2: 60 rts
; -----------------------------------------------------------------------------
; $00 - used as temporary counter in ColorRotation
ColorRotatePalette
89c3: 27 27 27 17+ .bulk $27,$27,$27,$17,$07,$17
89c9: 3f 0c 04 ff+ BlankPalette .bulk $3f,$0c,$04,$ff,$ff,$ff,$ff,$00
; used based on area type
89d1: 0f 07 12 0f Palette3Data .bulk $0f,$07,$12,$0f
89d5: 0f 07 17 0f .bulk $0f,$07,$17,$0f
89d9: 0f 07 17 1c .bulk $0f,$07,$17,$1c
89dd: 0f 07 17 00 .bulk $0f,$07,$17,$00
89e1: a5 09 ColorRotation lda FrameCounter ;get frame counter
89e3: 29 07 and #$07 ;mask out all but three LSB
89e5: d0 51 bne ExitColorRot ;branch if not set to zero to do this every eighth frame
89e7: ae 00 03 ldx VRAM_Buffer1_Offset ;check vram buffer offset
89ea: e0 31 cpx #$31
89ec: b0 4a bcs ExitColorRot ;if offset over 48 bytes, branch to leave
89ee: a8 tay ;otherwise use frame counter's 3 LSB as offset here
89ef: b9 c9 89 GetBlankPal lda BlankPalette,y ;get blank palette for palette 3
89f2: 9d 01 03 sta VRAM_Buffer1,x ;store it in the vram buffer
89f5: e8 inx ;increment offsets
89f6: c8 iny
89f7: c0 08 cpy #$08
89f9: 90 f4 bcc GetBlankPal ;do this until all bytes are copied
89fb: ae 00 03 ldx VRAM_Buffer1_Offset ;get current vram buffer offset
89fe: a9 03 lda #$03
8a00: 85 00 sta $00 ;set counter here
8a02: ad 4e 07 lda AreaType ;get area type
8a05: 0a asl A ;multiply by 4 to get proper offset
8a06: 0a asl A
8a07: a8 tay ;save as offset here
8a08: b9 d1 89 GetAreaPal lda Palette3Data,y ;fetch palette to be written based on area type
8a0b: 9d 04 03 sta VRAM_Buffer1+3,x ;store it to overwrite blank palette in vram buffer
8a0e: c8 iny
8a0f: e8 inx
8a10: c6 00 dec $00 ;decrement counter
8a12: 10 f4 bpl GetAreaPal ;do this until the palette is all copied
8a14: ae 00 03 ldx VRAM_Buffer1_Offset ;get current vram buffer offset
8a17: ac d4 06 ldy ColorRotateOffset ;get color cycling offset
8a1a: b9 c3 89 lda ColorRotatePalette,y
8a1d: 9d 05 03 sta VRAM_Buffer1+4,x ;get and store current color in second slot of palette
8a20: ad 00 03 lda VRAM_Buffer1_Offset
8a23: 18 clc ;add seven bytes to vram buffer offset
8a24: 69 07 adc #$07
8a26: 8d 00 03 sta VRAM_Buffer1_Offset
8a29: ee d4 06 inc ColorRotateOffset ;increment color cycling offset
8a2c: ad d4 06 lda ColorRotateOffset
8a2f: c9 06 cmp #$06 ;check to see if it's still in range
8a31: 90 05 bcc ExitColorRot ;if so, branch to leave
8a33: a9 00 lda #$00
8a35: 8d d4 06 sta ColorRotateOffset ;otherwise, init to keep it in range
8a38: 60 ExitColorRot rts ;leave
; -----------------------------------------------------------------------------
; $00 - temp store for offset control bit
; $01 - temp vram buffer offset
; $02 - temp store for vertical high nybble in block buffer routine
; $03 - temp adder for high byte of name table address
; $04, $05 - name table address low/high
; $06, $07 - block buffer address low/high
8a39: 45 45 47 47 BlockGfxData .bulk $45,$45,$47,$47
8a3d: 47 47 47 47 .bulk $47,$47,$47,$47
8a41: 57 58 59 5a .bulk $57,$58,$59,$5a
8a45: 24 24 24 24 .bulk $24,$24,$24,$24
8a49: 26 26 26 26 .bulk $26,$26,$26,$26
8a4d: a0 41 RemoveCoin_Axe ldy #$41 ;set low byte so offset points to $0341
8a4f: a9 03 lda #$03 ;load offset for default blank metatile
8a51: ae 4e 07 ldx AreaType ;check area type
8a54: d0 02 bne WriteBlankMT ;if not water type, use offset
8a56: a9 04 lda #$04 ;otherwise load offset for blank metatile used in water
8a58: 20 97 8a WriteBlankMT jsr PutBlockMetatile ;do a sub to write blank metatile to vram buffer
8a5b: a9 06 lda #$06
8a5d: 8d 73 07 sta VRAM_Buffer_AddrCtrl ;set vram address controller to $0341 and leave
8a60: 60 rts
ReplaceBlockMetatile
8a61: 20 6d 8a jsr WriteBlockMetatile ;write metatile to vram buffer to replace block object
8a64: ee f0 03 inc Block_ResidualCounter ;increment unused counter (residual code)
8a67: de ec 03 dec Block_RepFlag,x ;decrement flag (residual code)
8a6a: 60 rts ;leave
DestroyBlockMetatile
8a6b: a9 00 lda #$00 ;force blank metatile if branched/jumped to this point
WriteBlockMetatile
8a6d: a0 03 ldy #$03 ;load offset for blank metatile
8a6f: c9 00 cmp #$00 ;check contents of A for blank metatile
8a71: f0 14 beq UseBOffset ;branch if found (unconditional if branched from 8a6b)
8a73: a0 00 ldy #$00 ;load offset for brick metatile w/ line
8a75: c9 58 cmp #$58
8a77: f0 0e beq UseBOffset ;use offset if metatile is brick with coins (w/ line)
8a79: c9 51 cmp #$51
8a7b: f0 0a beq UseBOffset ;use offset if metatile is breakable brick w/ line
8a7d: c8 iny ;increment offset for brick metatile w/o line
8a7e: c9 5d cmp #$5d
8a80: f0 05 beq UseBOffset ;use offset if metatile is brick with coins (w/o line)
8a82: c9 52 cmp #$52
8a84: f0 01 beq UseBOffset ;use offset if metatile is breakable brick w/o line
8a86: c8 iny ;if any other metatile, increment offset for empty block
8a87: 98 UseBOffset tya ;put Y in A
8a88: ac 00 03 ldy VRAM_Buffer1_Offset ;get vram buffer offset
8a8b: c8 iny ;move onto next byte
8a8c: 20 97 8a jsr PutBlockMetatile ;get appropriate block data and write to vram buffer
8a8f: 88 MoveVOffset dey ;decrement vram buffer offset
8a90: 98 tya ;add 10 bytes to it
8a91: 18 clc
8a92: 69 0a adc #10
8a94: 4c 3f 86 jmp SetVRAMOffset ;branch to store as new vram buffer offset
PutBlockMetatile
8a97: 86 00 stx $00 ;store control bit from SprDataOffset_Ctrl
8a99: 84 01 sty $01 ;store vram buffer offset for next byte
8a9b: 0a asl A
8a9c: 0a asl A ;multiply A by four and use as X
8a9d: aa tax
8a9e: a0 20 ldy #$20 ;load high byte for name table 0
8aa0: a5 06 lda $06 ;get low byte of block buffer pointer
8aa2: c9 d0 cmp #$d0 ;check to see if we're on odd-page block buffer
8aa4: 90 02 bcc SaveHAddr ;if not, use current high byte
8aa6: a0 24 ldy #$24 ;otherwise load high byte for name table 1
8aa8: 84 03 SaveHAddr sty $03 ;save high byte here
8aaa: 29 0f and #$0f ;mask out high nybble of block buffer pointer
8aac: 0a asl A ;multiply by 2 to get appropriate name table low byte
8aad: 85 04 sta $04 ;and then store it here
8aaf: a9 00 lda #$00
8ab1: 85 05 sta $05 ;initialize temp high byte
8ab3: a5 02 lda $02 ;get vertical high nybble offset used in block buffer routine
8ab5: 18 clc
8ab6: 69 20 adc #$20 ;add 32 pixels for the status bar
8ab8: 0a asl A
8ab9: 26 05 rol $05 ;shift and rotate d7 onto d0 and d6 into carry
8abb: 0a asl A
8abc: 26 05 rol $05 ;shift and rotate d6 onto d0 and d5 into carry
8abe: 65 04 adc $04 ;add low byte of name table and carry to vertical high nybble
8ac0: 85 04 sta $04 ;and store here
8ac2: a5 05 lda $05 ;get whatever was in d7 and d6 of vertical high nybble
8ac4: 69 00 adc #$00 ;add carry
8ac6: 18 clc
8ac7: 65 03 adc $03 ;then add high byte of name table
8ac9: 85 05 sta $05 ;store here
8acb: a4 01 ldy $01 ;get vram buffer offset to be used
8acd: bd 39 8a RemBridge lda BlockGfxData,x ;write top left and top right
8ad0: 99 03 03 sta VRAM_Buffer1+2,y ; tile numbers into first spot
8ad3: bd 3a 8a lda BlockGfxData+1,x
8ad6: 99 04 03 sta VRAM_Buffer1+3,y
8ad9: bd 3b 8a lda BlockGfxData+2,x ;write bottom left and bottom
8adc: 99 08 03 sta VRAM_Buffer1+7,y ; right tiles numbers into
8adf: bd 3c 8a lda BlockGfxData+3,x ; second spot
8ae2: 99 09 03 sta VRAM_Buffer1+8,y
8ae5: a5 04 lda $04
8ae7: 99 01 03 sta VRAM_Buffer1,y ;write low byte of name table
8aea: 18 clc ; into first slot as read
8aeb: 69 20 adc #$20 ;add 32 bytes to value
8aed: 99 06 03 sta VRAM_Buffer1+5,y ;write low byte of name table
8af0: a5 05 lda $05 ; plus 32 bytes into second slot
8af2: 99 00 03 sta VRAM_Buffer1-1,y ;write high byte of name
8af5: 99 05 03 sta VRAM_Buffer1+4,y ; table address to both slots
8af8: a9 02 lda #$02
8afa: 99 02 03 sta VRAM_Buffer1+1,y ;put length of 2 in
8afd: 99 07 03 sta VRAM_Buffer1+6,y ; both slots
8b00: a9 00 lda #$00
8b02: 99 0a 03 sta VRAM_Buffer1+9,y ;put null terminator at end
8b05: a6 00 ldx $00 ;get offset control bit here
8b07: 60 rts ;and leave
; -----------------------------------------------------------------------------
; METATILE GRAPHICS TABLE
MetatileGraphics_Low
8b08: 10 .dd1 <Palette0_MTiles
8b09: ac .dd1 <Palette1_MTiles
8b0a: 64 .dd1 <Palette2_MTiles
8b0b: 8c .dd1 <Palette3_MTiles
MetatileGraphics_High
8b0c: 8b .dd1 >Palette0_MTiles
8b0d: 8b .dd1 >Palette1_MTiles
8b0e: 8c .dd1 >Palette2_MTiles
8b0f: 8c .dd1 >Palette3_MTiles
8b10: 24 24 24 24 Palette0_MTiles .bulk $24,$24,$24,$24 ;blank
8b14: 27 27 27 27 .bulk $27,$27,$27,$27 ;black metatile
8b18: 24 24 24 35 .bulk $24,$24,$24,$35 ;bush left
8b1c: 36 25 37 25 .bulk $36,$25,$37,$25 ;bush middle
8b20: 24 38 24 24 .bulk $24,$38,$24,$24 ;bush right
8b24: 24 30 30 26 .bulk $24,$30,$30,$26 ;mountain left
8b28: 26 26 34 26 .bulk $26,$26,$34,$26 ;mountain left bottom/middle center
8b2c: 24 31 24 32 .bulk $24,$31,$24,$32 ;mountain middle top
8b30: 33 26 24 33 .bulk $33,$26,$24,$33 ;mountain right
8b34: 34 26 26 26 .bulk $34,$26,$26,$26 ;mountain right bottom
8b38: 26 26 26 26 .bulk $26,$26,$26,$26 ;mountain middle bottom
8b3c: 24 c0 24 c0 .bulk $24,$c0,$24,$c0 ;bridge guardrail
8b40: 24 7f 7f 24 .bulk $24,$7f,$7f,$24 ;chain
8b44: b8 ba b9 bb .bulk $b8,$ba,$b9,$bb ;tall tree, top half
8b48: b8 bc b9 bd .bulk $b8,$bc,$b9,$bd ;short tree top
8b4c: ba bc bb bd .bulk $ba,$bc,$bb,$bd ;tall tree top, bottom half
8b50: 60 64 61 65 .bulk $60,$64,$61,$65 ;warp pipe end left, points up
8b54: 62 66 63 67 .bulk $62,$66,$63,$67 ;warp pipe end right, points up
8b58: 60 64 61 65 .bulk $60,$64,$61,$65 ;decoration pipe end left, points up
8b5c: 62 66 63 67 .bulk $62,$66,$63,$67 ;decoration pipe end right, points up
8b60: 68 68 69 69 .bulk $68,$68,$69,$69 ;pipe shaft left
8b64: 26 26 6a 6a .bulk $26,$26,$6a,$6a ;pipe shaft right
8b68: 4b 4c 4d 4e .bulk $4b,$4c,$4d,$4e ;tree ledge left edge
8b6c: 4d 4f 4d 4f .bulk $4d,$4f,$4d,$4f ;tree ledge middle
8b70: 4d 4e 50 51 .bulk $4d,$4e,$50,$51 ;tree ledge right edge
8b74: 6b 70 2c 2d .bulk $6b,$70,$2c,$2d ;mushroom left edge
8b78: 6c 71 6d 72 .bulk $6c,$71,$6d,$72 ;mushroom middle
8b7c: 6e 73 6f 74 .bulk $6e,$73,$6f,$74 ;mushroom right edge
8b80: 86 8a 87 8b .bulk $86,$8a,$87,$8b ;sideways pipe end top
8b84: 88 8c 88 8c .bulk $88,$8c,$88,$8c ;sideways pipe shaft top
8b88: 89 8d 69 69 .bulk $89,$8d,$69,$69 ;sideways pipe joint top
8b8c: 8e 91 8f 92 .bulk $8e,$91,$8f,$92 ;sideways pipe end bottom
8b90: 26 93 26 93 .bulk $26,$93,$26,$93 ;sideways pipe shaft bottom
8b94: 90 94 69 69 .bulk $90,$94,$69,$69 ;sideways pipe joint bottom
8b98: a4 e9 ea eb .bulk $a4,$e9,$ea,$eb ;seaplant
8b9c: 24 24 24 24 .bulk $24,$24,$24,$24 ;blank, used on bricks or blocks that are hit
8ba0: 24 2f 24 3d .bulk $24,$2f,$24,$3d ;flagpole ball
8ba4: a2 a2 a3 a3 .bulk $a2,$a2,$a3,$a3 ;flagpole shaft
8ba8: 24 24 24 24 .bulk $24,$24,$24,$24 ;blank, used in conjunction with vines
8bac: a2 a2 a3 a3 Palette1_MTiles .bulk $a2,$a2,$a3,$a3 ;vertical rope
8bb0: 99 24 99 24 .bulk $99,$24,$99,$24 ;horizontal rope
8bb4: 24 a2 3e 3f .bulk $24,$a2,$3e,$3f ;left pulley
8bb8: 5b 5c 24 a3 .bulk $5b,$5c,$24,$a3 ;right pulley
8bbc: 24 24 24 24 .bulk $24,$24,$24,$24 ;blank used for balance rope
8bc0: 9d 47 9e 47 .bulk $9d,$47,$9e,$47 ;castle top
8bc4: 47 47 27 27 .bulk $47,$47,$27,$27 ;castle window left
8bc8: 47 47 47 47 .bulk $47,$47,$47,$47 ;castle brick wall
8bcc: 27 27 47 47 .bulk $27,$27,$47,$47 ;castle window right
8bd0: a9 47 aa 47 .bulk $a9,$47,$aa,$47 ;castle top w/ brick
8bd4: 9b 27 9c 27 .bulk $9b,$27,$9c,$27 ;entrance top
8bd8: 27 27 27 27 .bulk $27,$27,$27,$27 ;entrance bottom
8bdc: 52 52 52 52 .bulk $52,$52,$52,$52 ;green ledge stump
8be0: 80 a0 81 a1 .bulk $80,$a0,$81,$a1 ;fence
8be4: be be bf bf .bulk $be,$be,$bf,$bf ;tree trunk
8be8: 75 ba 76 bb .bulk $75,$ba,$76,$bb ;mushroom stump top
8bec: ba ba bb bb .bulk $ba,$ba,$bb,$bb ;mushroom stump bottom
8bf0: 45 47 45 47 .bulk $45,$47,$45,$47 ;breakable brick w/ line
8bf4: 47 47 47 47 .bulk $47,$47,$47,$47 ;breakable brick
8bf8: 45 47 45 47 .bulk $45,$47,$45,$47 ;breakable brick (not used)
8bfc: b4 b6 b5 b7 .bulk $b4,$b6,$b5,$b7 ;cracked rock terrain
8c00: 45 47 45 47 .bulk $45,$47,$45,$47 ;brick with line (power-up)
8c04: 45 47 45 47 .bulk $45,$47,$45,$47 ;brick with line (vine)
8c08: 45 47 45 47 .bulk $45,$47,$45,$47 ;brick with line (star)
8c0c: 45 47 45 47 .bulk $45,$47,$45,$47 ;brick with line (coins)
8c10: 45 47 45 47 .bulk $45,$47,$45,$47 ;brick with line (1-up)
8c14: 47 47 47 47 .bulk $47,$47,$47,$47 ;brick (power-up)
8c18: 47 47 47 47 .bulk $47,$47,$47,$47 ;brick (vine)
8c1c: 47 47 47 47 .bulk $47,$47,$47,$47 ;brick (star)
8c20: 47 47 47 47 .bulk $47,$47,$47,$47 ;brick (coins)
8c24: 47 47 47 47 .bulk $47,$47,$47,$47 ;brick (1-up)
8c28: 24 24 24 24 .bulk $24,$24,$24,$24 ;hidden block (1 coin)
8c2c: 24 24 24 24 .bulk $24,$24,$24,$24 ;hidden block (1-up)
8c30: ab ac ad ae .bulk $ab,$ac,$ad,$ae ;solid block (3-d block)
8c34: 5d 5e 5d 5e .bulk $5d,$5e,$5d,$5e ;solid block (white wall)
8c38: c1 24 c1 24 .bulk $c1,$24,$c1,$24 ;bridge
8c3c: c6 c8 c7 c9 .bulk $c6,$c8,$c7,$c9 ;bullet bill cannon barrel
8c40: ca cc cb cd .bulk $ca,$cc,$cb,$cd ;bullet bill cannon top
8c44: 2a 2a 40 40 .bulk $2a,$2a,$40,$40 ;bullet bill cannon bottom
8c48: 24 24 24 24 .bulk $24,$24,$24,$24 ;blank used for jumpspring
8c4c: 24 47 24 47 .bulk $24,$47,$24,$47 ;half brick used for jumpspring
8c50: 82 83 84 85 .bulk $82,$83,$84,$85 ;solid block (water level, green rock)
8c54: 24 47 24 47 .bulk $24,$47,$24,$47 ;half brick (???)
8c58: 86 8a 87 8b .bulk $86,$8a,$87,$8b ;water pipe top
8c5c: 8e 91 8f 92 .bulk $8e,$91,$8f,$92 ;water pipe bottom
8c60: 24 2f 24 3d .bulk $24,$2f,$24,$3d ;flag ball (residual object)
8c64: 24 24 24 35 Palette2_MTiles .bulk $24,$24,$24,$35 ;cloud left
8c68: 36 25 37 25 .bulk $36,$25,$37,$25 ;cloud middle
8c6c: 24 38 24 24 .bulk $24,$38,$24,$24 ;cloud right
8c70: 24 24 39 24 .bulk $24,$24,$39,$24 ;cloud bottom left
8c74: 3a 24 3b 24 .bulk $3a,$24,$3b,$24 ;cloud bottom middle
8c78: 3c 24 24 24 .bulk $3c,$24,$24,$24 ;cloud bottom right
8c7c: 41 26 41 26 .bulk $41,$26,$41,$26 ;water/lava top
8c80: 26 26 26 26 .bulk $26,$26,$26,$26 ;water/lava
8c84: b0 b1 b2 b3 .bulk $b0,$b1,$b2,$b3 ;cloud level terrain
8c88: 77 79 77 79 .bulk $77,$79,$77,$79 ;bowser's bridge
8c8c: 53 55 54 56 Palette3_MTiles .bulk $53,$55,$54,$56 ;question block (coin)
8c90: 53 55 54 56 .bulk $53,$55,$54,$56 ;question block (power-up)
8c94: a5 a7 a6 a8 .bulk $a5,$a7,$a6,$a8 ;coin
8c98: c2 c4 c3 c5 .bulk $c2,$c4,$c3,$c5 ;underwater coin
8c9c: 57 59 58 5a .bulk $57,$59,$58,$5a ;empty block
8ca0: 7b 7d 7c 7e .bulk $7b,$7d,$7c,$7e ;axe
; -----------------------------------------------------------------------------
; VRAM BUFFER DATA FOR LOCATIONS IN PRG-ROM
WaterPaletteData
8ca4: 3f 00 20 .bulk $3f,$00,$20
8ca7: 0f 15 12 25 .bulk $0f,$15,$12,$25
8cab: 0f 3a 1a 0f .bulk $0f,$3a,$1a,$0f
8caf: 0f 30 12 0f .bulk $0f,$30,$12,$0f
8cb3: 0f 27 12 0f .bulk $0f,$27,$12,$0f
8cb7: 22 16 27 18 .bulk $22,$16,$27,$18
8cbb: 0f 10 30 27 .bulk $0f,$10,$30,$27
8cbf: 0f 16 30 27 .bulk $0f,$16,$30,$27
8cc3: 0f 0f 30 10 .bulk $0f,$0f,$30,$10
8cc7: 00 .bulk $00
GroundPaletteData
8cc8: 3f 00 20 .bulk $3f,$00,$20
8ccb: 0f 29 1a 0f .bulk $0f,$29,$1a,$0f
8ccf: 0f 36 17 0f .bulk $0f,$36,$17,$0f
8cd3: 0f 30 21 0f .bulk $0f,$30,$21,$0f
8cd7: 0f 27 17 0f .bulk $0f,$27,$17,$0f
8cdb: 0f 16 27 18 .bulk $0f,$16,$27,$18
8cdf: 0f 1a 30 27 .bulk $0f,$1a,$30,$27
8ce3: 0f 16 30 27 .bulk $0f,$16,$30,$27
8ce7: 0f 0f 36 17 .bulk $0f,$0f,$36,$17
8ceb: 00 .bulk $00
UndergroundPaletteData
8cec: 3f 00 20 .bulk $3f,$00,$20
8cef: 0f 29 1a 09 .bulk $0f,$29,$1a,$09
8cf3: 0f 3c 1c 0f .bulk $0f,$3c,$1c,$0f
8cf7: 0f 30 21 1c .bulk $0f,$30,$21,$1c
8cfb: 0f 27 17 1c .bulk $0f,$27,$17,$1c
8cff: 0f 16 27 18 .bulk $0f,$16,$27,$18
8d03: 0f 1c 36 17 .bulk $0f,$1c,$36,$17
8d07: 0f 16 30 27 .bulk $0f,$16,$30,$27
8d0b: 0f 0c 3c 1c .bulk $0f,$0c,$3c,$1c
8d0f: 00 .bulk $00
CastlePaletteData
8d10: 3f 00 20 .bulk $3f,$00,$20
8d13: 0f 30 10 00 .bulk $0f,$30,$10,$00
8d17: 0f 30 10 00 .bulk $0f,$30,$10,$00
8d1b: 0f 30 16 00 .bulk $0f,$30,$16,$00
8d1f: 0f 27 17 00 .bulk $0f,$27,$17,$00
8d23: 0f 16 27 18 .bulk $0f,$16,$27,$18
8d27: 0f 1c 36 17 .bulk $0f,$1c,$36,$17
8d2b: 0f 16 30 27 .bulk $0f,$16,$30,$27
8d2f: 0f 00 30 10 .bulk $0f,$00,$30,$10
8d33: 00 .bulk $00
DaySnowPaletteData
8d34: 3f 00 04 .bulk $3f,$00,$04
8d37: 22 30 00 10 .bulk $22,$30,$00,$10
8d3b: 00 .bulk $00
NightSnowPaletteData
8d3c: 3f 00 04 .bulk $3f,$00,$04
8d3f: 0f 30 00 10 .bulk $0f,$30,$00,$10
8d43: 00 .bulk $00
MushroomPaletteData
8d44: 3f 00 04 .bulk $3f,$00,$04
8d47: 22 27 16 0f .bulk $22,$27,$16,$0f
8d4b: 00 .bulk $00
BowserPaletteData
8d4c: 3f 14 04 .bulk $3f,$14,$04
8d4f: 0f 1a 30 27+ .bulk $0f,$1a,$30,$27,$00
; "THANK YOU MARIO"
MarioThanksMessage
8d54: 25 48 10 .bulk $25,$48,$10
8d57: 1d 11 0a 17+ .bulk $1d,$11,$0a,$17,$14,$24
8d5d: 22 18 1e 24 .bulk $22,$18,$1e,$24
8d61: 16 0a 1b 12+ .bulk $16,$0a,$1b,$12,$18,$2b
8d67: 00 .dd1 $00
; THANK YOU LUIGI
LuigiThanksMessage
8d68: 25 48 10 .bulk $25,$48,$10
8d6b: 1d 11 0a 17+ .bulk $1d,$11,$0a,$17,$14,$24
8d71: 22 18 1e 24 .bulk $22,$18,$1e,$24
8d75: 15 1e 12 10+ .bulk $15,$1e,$12,$10,$12,$2b
8d7b: 00 .dd1 $00
; "BUT OUR PRINCESS IS IN"
MushroomRetainerSaved
8d7c: 25 c5 16 .bulk $25,$c5,$16
8d7f: 0b 1e 1d 24+ .bulk $0b,$1e,$1d,$24,$18,$1e,$1b,$24
8d87: 19 1b 12 17+ .bulk $19,$1b,$12,$17,$0c,$0e,$1c,$1c,$24
8d90: 12 1c 24 12+ .bulk $12,$1c,$24,$12,$17
; "ANOTHER CASTLE!"
8d95: 26 05 0f .bulk $26,$05,$0f
8d98: 0a 17 18 1d+ .bulk $0a,$17,$18,$1d,$11,$0e,$1b,$24
8da0: 0c 0a 1c 1d+ .bulk $0c,$0a,$1c,$1d,$15,$0e,$2b,$00
; "YOUR QUEST IS OVER."
8da8: 25 a7 13 PrincessSaved1 .bulk $25,$a7,$13
8dab: 22 18 1e 1b+ .bulk $22,$18,$1e,$1b,$24
8db0: 1a .dd1 $1a
8db1: 1e 0e 1c 1d+ .bulk $1e,$0e,$1c,$1d,$24
8db6: 12 1c 24 18+ .bulk $12,$1c,$24,$18,$1f,$0e,$1b,$af
8dbe: 00 .dd1 $00
; "WE PRESENT YOU A NEW QUEST."
8dbf: 25 e3 1b PrincessSaved2 .bulk $25,$e3,$1b
8dc2: 20 0e 24 .bulk $20,$0e,$24
8dc5: 19 1b 0e 1c+ .bulk $19,$1b,$0e,$1c,$0e,$17,$1d,$24
8dcd: 22 18 1e 24+ .bulk $22,$18,$1e,$24,$0a,$24,$17,$0e,$20,$24
8dd7: 1a 1e 0e 1c+ .bulk $1a,$1e,$0e,$1c,$1d,$af
8ddd: 00 .dd1 $00
; "PUSH BUTTON B"
WorldSelectMessage1
8dde: 26 4a 0d .bulk $26,$4a,$0d
8de1: 19 1e 1c 11+ .bulk $19,$1e,$1c,$11,$24
8de6: 0b 1e 1d 1d+ .bulk $0b,$1e,$1d,$1d,$18,$17,$24,$0b
8dee: 00 .dd1 $00
; "TO SELECT A WORLD"
WorldSelectMessage2
8def: 26 88 11 .bulk $26,$88,$11
8df2: 1d 18 24 1c+ .bulk $1d,$18,$24,$1c,$0e,$15,$0e,$0c,$1d,$24
8dfc: 0a 24 20 18+ .bulk $0a,$24,$20,$18,$1b,$15,$0d
8e03: 00 .dd1 $00
; -----------------------------------------------------------------------------
; $04 - address low to jump address
; $05 - address high to jump address
; $06 - jump address low
; $07 - jump address high
8e04: 0a JumpEngine asl A ;shift bit from contents of A
8e05: a8 tay
8e06: 68 pla ;pull saved return address from stack
8e07: 85 04 sta $04 ;save to indirect
8e09: 68 pla
8e0a: 85 05 sta $05
8e0c: c8 iny
8e0d: b1 04 lda ($04),y ;load pointer from indirect
8e0f: 85 06 sta $06 ;note that if an RTS is performed in next routine
8e11: c8 iny ;it will return to the execution before the sub
8e12: b1 04 lda ($04),y ; that called this routine
8e14: 85 07 sta $07
8e16: 6c 06 00 jmp ($0006) ;jump to the address we loaded
; -----------------------------------------------------------------------------
InitializeNameTables
8e19: ad 02 20 lda PPUSTATUS ;reset flip-flop
8e1c: ad 78 07 lda Mirror_PPU_CTRL_REG1 ;load mirror of ppu reg $2000
8e1f: 09 10 ora #%00010000 ;set sprites for first 4k and background for second 4k
8e21: 29 f0 and #%11110000 ;clear rest of lower nybble, leave higher alone
8e23: 20 ed 8e jsr WritePPUReg1
8e26: a9 24 lda #$24 ;set vram address to start of name table 1
8e28: 20 2d 8e jsr WriteNTAddr
8e2b: a9 20 lda #$20 ;and then set it to name table 0
8e2d: 8d 06 20 WriteNTAddr sta PPUADDR
8e30: a9 00 lda #$00
8e32: 8d 06 20 sta PPUADDR
8e35: a2 04 ldx #$04 ;clear name table with blank tile #24
8e37: a0 c0 ldy #$c0
8e39: a9 24 lda #$24
8e3b: 8d 07 20 InitNTLoop sta PPUDATA ;count out exactly 768 tiles
8e3e: 88 dey
8e3f: d0 fa bne InitNTLoop
8e41: ca dex
8e42: d0 f7 bne InitNTLoop
8e44: a0 40 ldy #64 ;now to clear the attribute table (with zero this time)
8e46: 8a txa
8e47: 8d 00 03 sta VRAM_Buffer1_Offset ;init vram buffer 1 offset
8e4a: 8d 01 03 sta VRAM_Buffer1 ;init vram buffer 1
8e4d: 8d 07 20 InitATLoop sta PPUDATA
8e50: 88 dey
8e51: d0 fa bne InitATLoop
8e53: 8d 3f 07 sta HorizontalScroll ;reset scroll variables
8e56: 8d 40 07 sta VerticalScroll
8e59: 4c e6 8e jmp InitScroll ;initialize scroll registers to zero
; -----------------------------------------------------------------------------
; $00 - temp joypad bit
8e5c: a9 01 ReadJoypads lda #$01 ;reset and clear strobe of joypad ports
8e5e: 8d 16 40 sta JOY1
8e61: 4a lsr A
8e62: aa tax ;start with joypad 1's port
8e63: 8d 16 40 sta JOY1
8e66: 20 6a 8e jsr ReadPortBits
8e69: e8 inx ;increment for joypad 2's port
8e6a: a0 08 ReadPortBits ldy #$08
8e6c: 48 PortLoop pha ;push previous bit onto stack
8e6d: bd 16 40 lda JOY1,x ;read current bit on joypad port
8e70: 85 00 sta $00 ;check d1 and d0 of port output
8e72: 4a lsr A ;this is necessary on the old
8e73: 05 00 ora $00 ; famicom systems in japan
8e75: 4a lsr A
8e76: 68 pla ;read bits from stack
8e77: 2a rol A ;rotate bit from carry flag
8e78: 88 dey
8e79: d0 f1 bne PortLoop ;count down bits left
8e7b: 9d fc 06 sta SavedJoypad1Bits,x ;save controller status here always
8e7e: 48 pha
8e7f: 29 30 and #%00110000 ;check for select or start
8e81: 3d 4a 07 and JoypadBitMask,x ;if neither saved state nor current state
8e84: f0 07 beq Save8Bits ; have any of these two set, branch
8e86: 68 pla
8e87: 29 cf and #%11001111 ;otherwise store without select
8e89: 9d fc 06 sta SavedJoypad1Bits,x ; or start bits and leave
8e8c: 60 rts
8e8d: 68 Save8Bits pla
8e8e: 9d 4a 07 sta JoypadBitMask,x ;save with all bits in another place and leave
8e91: 60 rts
; -----------------------------------------------------------------------------
; $00 - vram buffer address table low
; $01 - vram buffer address table high
WriteBufferToScreen
8e92: 8d 06 20 sta PPUADDR ;store high byte of vram address
8e95: c8 iny
8e96: b1 00 lda ($00),y ;load next byte (second)
8e98: 8d 06 20 sta PPUADDR ;store low byte of vram address
8e9b: c8 iny
8e9c: b1 00 lda ($00),y ;load next byte (third)
8e9e: 0a asl A ;shift to left and save in stack
8e9f: 48 pha
8ea0: ad 78 07 lda Mirror_PPU_CTRL_REG1 ;load mirror of $2000,
8ea3: 09 04 ora #%00000100 ;set ppu to increment by 32 by default
8ea5: b0 02 bcs SetupWrites ;if d7 of third byte was clear, ppu will
8ea7: 29 fb and #%11111011 ;only increment by 1
8ea9: 20 ed 8e SetupWrites jsr WritePPUReg1 ;write to register
8eac: 68 pla ;pull from stack and shift to left again
8ead: 0a asl A
8eae: 90 03 bcc GetLength ;if d6 of third byte was clear, do not repeat byte
8eb0: 09 02 ora #%00000010 ;otherwise set d1 and increment Y
8eb2: c8 iny
8eb3: 4a GetLength lsr A ;shift back to the right to get proper length
8eb4: 4a lsr A ;note that d1 will now be in carry
8eb5: aa tax
8eb6: b0 01 OutputToVRAM bcs RepeatByte ;if carry set, repeat loading the same byte
8eb8: c8 iny ;otherwise increment Y to load next byte
8eb9: b1 00 RepeatByte lda ($00),y ;load more data from buffer and write to vram
8ebb: 8d 07 20 sta PPUDATA
8ebe: ca dex ;done writing?
8ebf: d0 f5 bne OutputToVRAM
8ec1: 38 sec
8ec2: 98 tya
8ec3: 65 00 adc $00 ;add end length plus one to the indirect at $00
8ec5: 85 00 sta $00 ; to allow this routine to read another set of updates
8ec7: a9 00 lda #$00
8ec9: 65 01 adc $01
8ecb: 85 01 sta $01
8ecd: a9 3f lda #$3f ;sets vram address to $3f00
8ecf: 8d 06 20 sta PPUADDR
8ed2: a9 00 lda #$00
8ed4: 8d 06 20 sta PPUADDR
8ed7: 8d 06 20 sta PPUADDR ;then reinitializes it for some reason
8eda: 8d 06 20 sta PPUADDR
8edd: ae 02 20 UpdateScreen ldx PPUSTATUS ;reset flip-flop
8ee0: a0 00 ldy #$00 ;load first byte from indirect as a pointer
8ee2: b1 00 lda ($00),y
8ee4: d0 ac bne WriteBufferToScreen ;if byte is zero we have no further updates to make here
8ee6: 8d 05 20 InitScroll sta PPUSCROLL ;store contents of A into scroll registers
8ee9: 8d 05 20 sta PPUSCROLL ;and end whatever subroutine led us here
8eec: 60 rts
; -----------------------------------------------------------------------------
8eed: 8d 00 20 WritePPUReg1 sta PPUCTRL ;write contents of A to PPU register 1
8ef0: 8d 78 07 sta Mirror_PPU_CTRL_REG1 ;and its mirror
8ef3: 60 rts
; -----------------------------------------------------------------------------
; $00 - used to store status bar nybbles
; $02 - used as temp vram offset
; $03 - used to store length of status bar number
;
; status bar name table offset and length data
8ef4: f0 06 StatusBarData .bulk $f0,$06 ;top score display on title screen
8ef6: 62 06 .bulk $62,$06 ;player score
8ef8: 62 06 .bulk $62,$06
8efa: 6d 02 .bulk $6d,$02 ;coin tally
8efc: 6d 02 .bulk $6d,$02
8efe: 7a 03 .bulk $7a,$03 ;game timer
8f00: 06 0c 12 18+ StatusBarOffset .bulk $06,$0c,$12,$18,$1e,$24
PrintStatusBarNumbers
8f06: 85 00 sta $00 ;store player-specific offset
8f08: 20 11 8f jsr OutputNumbers ;use first nybble to print the coin display
8f0b: a5 00 lda $00 ;move high nybble to low
8f0d: 4a lsr A ;and print to score display
8f0e: 4a lsr A
8f0f: 4a lsr A
8f10: 4a lsr A
8f11: 18 OutputNumbers clc ;add 1 to low nybble
8f12: 69 01 adc #$01
8f14: 29 0f and #%00001111 ;mask out high nybble
8f16: c9 06 cmp #$06
8f18: b0 44 bcs ExitOutputN
8f1a: 48 pha ;save incremented value to stack for now and
8f1b: 0a asl A ;shift to left and use as offset
8f1c: a8 tay
8f1d: ae 00 03 ldx VRAM_Buffer1_Offset ;get current buffer pointer
8f20: a9 20 lda #$20 ;put at top of screen by default
8f22: c0 00 cpy #$00 ;are we writing top score on title screen?
8f24: d0 02 bne SetupNums
8f26: a9 22 lda #$22 ;if so, put further down on the screen
8f28: 9d 01 03 SetupNums sta VRAM_Buffer1,x
8f2b: b9 f4 8e lda StatusBarData,y ;write low vram address and length of thing
8f2e: 9d 02 03 sta VRAM_Buffer1+1,x ;we're printing to the buffer
8f31: b9 f5 8e lda StatusBarData+1,y
8f34: 9d 03 03 sta VRAM_Buffer1+2,x
8f37: 85 03 sta $03 ;save length byte in counter
8f39: 86 02 stx $02 ;and buffer pointer elsewhere for now
8f3b: 68 pla ;pull original incremented value from stack
8f3c: aa tax
8f3d: bd 00 8f lda StatusBarOffset,x ;load offset to value we want to write
8f40: 38 sec
8f41: f9 f5 8e sbc StatusBarData+1,y ;subtract from length byte we read before
8f44: a8 tay ;use value as offset to display digits
8f45: a6 02 ldx $02
8f47: b9 d7 07 DigitPLoop lda TopScoreDisplay,y ;write digits to the buffer
8f4a: 9d 04 03 sta VRAM_Buffer1+3,x
8f4d: e8 inx
8f4e: c8 iny
8f4f: c6 03 dec $03 ;do this until all the digits are written
8f51: d0 f4 bne DigitPLoop
8f53: a9 00 lda #$00 ;put null terminator at end
8f55: 9d 04 03 sta VRAM_Buffer1+3,x
8f58: e8 inx ;increment buffer pointer by 3
8f59: e8 inx
8f5a: e8 inx
8f5b: 8e 00 03 stx VRAM_Buffer1_Offset ;store it in case we want to use it again
8f5e: 60 ExitOutputN rts
; -----------------------------------------------------------------------------
DigitsMathRoutine
8f5f: ad 70 07 lda OperMode ;check mode of operation
8f62: c9 00 cmp #$00
8f64: f0 16 beq EraseDMods ;if in title screen mode, branch to lock score
8f66: a2 05 ldx #$05
8f68: bd 34 01 AddModLoop lda DigitModifier,x ;load digit amount to increment
8f6b: 18 clc
8f6c: 79 d7 07 adc TopScoreDisplay,y ;add to current digit
8f6f: 30 16 bmi BorrowOne ;if result is a negative number, branch to subtract
8f71: c9 0a cmp #$0a
8f73: b0 19 bcs CarryOne ;if digit greater than $09, branch to add
8f75: 99 d7 07 StoreNewD sta TopScoreDisplay,y ;store as new score or game timer digit
8f78: 88 dey ;move onto next digits in score or game timer
8f79: ca dex ;and digit amounts to increment
8f7a: 10 ec bpl AddModLoop ;loop back if we're not done yet
8f7c: a9 00 EraseDMods lda #$00 ;store zero here
8f7e: a2 06 ldx #$06 ;start with the last digit
8f80: 9d 33 01 EraseMLoop sta DigitModifier-1,x ;initialize the digit amounts to increment
8f83: ca dex
8f84: 10 fa bpl EraseMLoop ;do this until they're all reset, then leave
8f86: 60 rts
8f87: de 33 01 BorrowOne dec DigitModifier-1,x ;decrement the previous digit, then put $09 in
8f8a: a9 09 lda #$09 ; the game timer digit we're currently on to "borrow
8f8c: d0 e7 bne StoreNewD ; the one", then do an unconditional branch back
8f8e: 38 CarryOne sec ;subtract ten from our digit to make it a
8f8f: e9 0a sbc #$0a ; proper BCD number, then increment the digit
8f91: fe 33 01 inc DigitModifier-1,x ; preceding current digit to "carry the one" properly
8f94: 4c 75 8f jmp StoreNewD ;go back to just after we branched here
; -----------------------------------------------------------------------------
8f97: a2 05 UpdateTopScore ldx #$05 ;start with mario's score
8f99: 20 9e 8f jsr TopScoreCheck
8f9c: a2 0b ldx #$0b ;now do luigi's score
8f9e: a0 05 TopScoreCheck ldy #$05 ;start with the lowest digit
8fa0: 38 sec
8fa1: bd dd 07 GetScoreDiff lda ScoreAndCoinDisplay,x ;subtract each player digit from each high score digit
8fa4: f9 d7 07 sbc TopScoreDisplay,y ; from lowest to highest, if any top score digit exceeds
8fa7: ca dex ; any player digit, borrow will be set until a subsequent
8fa8: 88 dey ; subtraction clears it (player digit is higher than top)
8fa9: 10 f6 bpl GetScoreDiff
8fab: 90 0e bcc NoTopSc ;check to see if borrow is still set, if so, no new high score
8fad: e8 inx ;increment X and Y once to the start of the score
8fae: c8 iny
8faf: bd dd 07 CopyScore lda ScoreAndCoinDisplay,x ;store player's score digits into high score memory area
8fb2: 99 d7 07 sta TopScoreDisplay,y
8fb5: e8 inx
8fb6: c8 iny
8fb7: c0 06 cpy #$06 ;do this until we have stored them all
8fb9: 90 f4 bcc CopyScore
8fbb: 60 NoTopSc rts
; -----------------------------------------------------------------------------
DefaultSprOffsets
8fbc: 04 30 48 60+ .bulk $04,$30,$48,$60,$78,$90,$a8,$c0,$d8,$e8,$24,$f8,$fc,$28,$2c
8fcb: 18 ff 23 58 Sprite0Data .bulk $18,$ff,$23,$58
; -----------------------------------------------------------------------------
8fcf: a0 6f InitializeGame ldy #$6f ;clear all memory as in initialization procedure,
8fd1: 20 cc 90 jsr InitializeMemory ; but this time, clear only as far as $076f
8fd4: a0 1f ldy #$1f
8fd6: 99 b0 07 ClrSndLoop sta SoundMemory,y ;clear out memory used
8fd9: 88 dey ; by the sound engines
8fda: 10 fa bpl ClrSndLoop
8fdc: a9 18 lda #$18 ;set demo timer
8fde: 8d a2 07 sta DemoTimer
8fe1: 20 03 9c jsr LoadAreaPointer
;
8fe4: a0 4b InitializeArea ldy #$4b ;clear all memory again, only as far as $074b
8fe6: 20 cc 90 jsr InitializeMemory ;this is only necessary if branching from
8fe9: a2 21 ldx #$21
8feb: a9 00 lda #$00
8fed: 9d 80 07 ClrTimersLoop sta Timers,x ;clear out memory between
8ff0: ca dex ; $0780 and $07a1
8ff1: 10 fa bpl ClrTimersLoop
8ff3: ad 5b 07 lda HalfwayPage
8ff6: ac 52 07 ldy AltEntranceControl ;if AltEntranceControl not set, use halfway page, if any found
8ff9: f0 03 beq StartPage
8ffb: ad 51 07 lda EntrancePage ;otherwise use saved entry page number here
8ffe: 8d 1a 07 StartPage sta ScreenLeft_PageLoc ;set as value here
9001: 8d 25 07 sta CurrentPageLoc ;also set as current page
9004: 8d 28 07 sta BackloadingFlag ;set flag here if halfway page or saved entry page number found
9007: 20 38 b0 jsr GetScreenPosition ;get pixel coordinates for screen borders
900a: a0 20 ldy #$20 ;if on odd numbered page, use $2480 as start of rendering
900c: 29 01 and #%00000001 ;otherwise use $2080, this address used later as name table
900e: f0 02 beq SetInitNTHigh ; address for rendering of game area
9010: a0 24 ldy #$24
9012: 8c 20 07 SetInitNTHigh sty CurrentNTAddr_High ;store name table address
9015: a0 80 ldy #$80
9017: 8c 21 07 sty CurrentNTAddr_Low
901a: 0a asl A ;store LSB of page number in high nybble
901b: 0a asl A ; of block buffer column position
901c: 0a asl A
901d: 0a asl A
901e: 8d a0 06 sta BlockBufferColumnPos
9021: ce 30 07 dec AreaObjectLength ;set area object lengths for all empty
9024: ce 31 07 dec AreaObjectLength+1
9027: ce 32 07 dec AreaObjectLength+2
902a: a9 0b lda #$0b ;set value for renderer to update 12 column sets
902c: 8d 1e 07 sta ColumnSets ;12 column sets = 24 metatile columns = 1 1/2 screens
902f: 20 22 9c jsr GetAreaDataAddrs ;get enemy and level addresses and load header
9032: ad 6a 07 lda PrimaryHardMode ;check to see if primary hard mode has been activated
9035: d0 10 bne SetSecHard ;if so, activate the secondary no matter where we're at
9037: ad 5f 07 lda WorldNumber ;otherwise check world number
903a: c9 04 cmp #World5 ;if less than 5, do not activate secondary
903c: 90 0c bcc CheckHalfway
903e: d0 07 bne SetSecHard ;if not equal to, then world > 5, thus activate
9040: ad 5c 07 lda LevelNumber ;otherwise, world 5, so check level number
9043: c9 02 cmp #Level3 ;if 1 or 2, do not set secondary hard mode flag
9045: 90 03 bcc CheckHalfway
9047: ee cc 06 SetSecHard inc SecondaryHardMode ;set secondary hard mode flag for areas 5-3 and beyond
904a: ad 5b 07 CheckHalfway lda HalfwayPage
904d: f0 05 beq DoneInitArea
904f: a9 02 lda #$02 ;if halfway page set, overwrite start position from header
9051: 8d 10 07 sta PlayerEntranceCtrl
9054: a9 80 DoneInitArea lda #Silence ;silence music
9056: 85 fb sta AreaMusicQueue
9058: a9 01 lda #$01 ;disable screen output
905a: 8d 74 07 sta DisableScreenFlag
905d: ee 72 07 inc OperMode_Task ;increment one of the modes
9060: 60 rts
; -----------------------------------------------------------------------------
PrimaryGameSetup
9061: a9 01 lda #$01
9063: 8d 57 07 sta FetchNewGameTimerFlag ;set flag to load game timer from header
9066: 8d 54 07 sta PlayerSize ;set player's size to small
9069: a9 02 lda #$02
906b: 8d 5a 07 sta NumberOfLives ;give each player three lives
906e: 8d 61 07 sta OffScr_NumberofLives
;
SecondaryGameSetup
9071: a9 00 lda #$00
9073: 8d 74 07 sta DisableScreenFlag ;enable screen output
9076: a8 tay
9077: 99 00 03 ClearVRLoop sta VRAM_Buffer1-1,y ;clear buffer at $0300-$03ff
907a: c8 iny
907b: d0 fa bne ClearVRLoop
907d: 8d 59 07 sta GameTimerExpiredFlag ;clear game timer exp flag
9080: 8d 69 07 sta DisableIntermediate ;clear skip lives display flag
9083: 8d 28 07 sta BackloadingFlag ;clear value here
9086: a9 ff lda #$ff
9088: 8d a0 03 sta BalPlatformAlignment ;initialize balance platform assignment flag
908b: ad 1a 07 lda ScreenLeft_PageLoc ;get left side page location
908e: 4e 78 07 lsr Mirror_PPU_CTRL_REG1 ;shift LSB of ppu register #1 mirror out
9091: 29 01 and #$01 ;mask out all but LSB of page location
9093: 6a ror A ;rotate LSB of page location into carry then onto mirror
9094: 2e 78 07 rol Mirror_PPU_CTRL_REG1 ;this is to set the proper PPU name table
9097: 20 ed 90 jsr GetAreaMusic ;load proper music into queue
909a: a9 38 lda #$38 ;load sprite shuffle amounts to be used later
909c: 8d e3 06 sta SprShuffleAmt+2
909f: a9 48 lda #$48
90a1: 8d e2 06 sta SprShuffleAmt+1
90a4: a9 58 lda #$58
90a6: 8d e1 06 sta SprShuffleAmt
90a9: a2 0e ldx #$0e ;load default OAM offsets into $06e4-$06f2
90ab: bd bc 8f ShufAmtLoop lda DefaultSprOffsets,x
90ae: 9d e4 06 sta SprDataOffset,x
90b1: ca dex ;do this until they're all set
90b2: 10 f7 bpl ShufAmtLoop
90b4: a0 03 ldy #$03 ;set up sprite #0
90b6: b9 cb 8f ISpr0Loop lda Sprite0Data,y
90b9: 99 00 02 sta Sprite_Data,y
90bc: 88 dey
90bd: 10 f7 bpl ISpr0Loop
90bf: 20 af 92 jsr DoNothing2 ;these jsrs doesn't do anything useful
90c2: 20 aa 92 jsr DoNothing1
90c5: ee 22 07 inc Sprite0HitDetectFlag ;set sprite #0 check flag
90c8: ee 72 07 inc OperMode_Task ;increment to next task
90cb: 60 rts
; -----------------------------------------------------------------------------
; $06 - RAM address low
; $07 - RAM address high
InitializeMemory
90cc: a2 07 ldx #$07 ;set initial high byte to $0700-$07ff
90ce: a9 00 lda #$00 ;set initial low byte to start of page (at $00 of page)
90d0: 85 06 sta $06
90d2: 86 07 InitPageLoop stx $07
90d4: e0 01 InitByteLoop cpx #$01 ;check to see if we're on the stack ($0100-$01ff)
90d6: d0 04 bne InitByte ;if not, go ahead anyway
90d8: c0 60 cpy #$60 ;otherwise, check to see if we're at $0160-$01ff
90da: b0 02 bcs SkipByte ;if so, skip write
90dc: 91 06 InitByte sta ($06),y ;otherwise, initialize byte with current low byte in Y
90de: 88 SkipByte dey
90df: c0 ff cpy #$ff ;do this until all bytes in page have been erased
90e1: d0 f1 bne InitByteLoop
90e3: ca dex ;go onto the next page
90e4: 10 ec bpl InitPageLoop ;do this until all pages of memory have been erased
90e6: 60 rts
; -----------------------------------------------------------------------------
90e7: 02 MusicSelectData .dd1 WaterMusic
90e8: 01 .dd1 GroundMusic
90e9: 04 .dd1 UndergroundMusic
90ea: 08 .dd1 CastleMusic
90eb: 10 .dd1 CloudMusic
90ec: 20 .dd1 PipeIntroMusic
90ed: ad 70 07 GetAreaMusic lda OperMode ;if in title screen mode, leave
90f0: f0 23 beq ExitGetM
90f2: ad 52 07 lda AltEntranceControl ;check for specific alternate mode of entry
90f5: c9 02 cmp #$02 ;if found, branch without checking starting position
90f7: f0 0d beq ChkAreaType ; from area object data header
90f9: a0 05 ldy #$05 ;select music for pipe intro scene by default
90fb: ad 10 07 lda PlayerEntranceCtrl ;check value from level header for certain values
90fe: c9 06 cmp #$06
9100: f0 0e beq StoreMusic ;load music for pipe intro scene if header
9102: c9 07 cmp #$07 ;start position either value $06 or $07
9104: f0 0a beq StoreMusic
9106: ac 4e 07 ChkAreaType ldy AreaType ;load area type as offset for music bit
9109: ad 43 07 lda CloudTypeOverride
910c: f0 02 beq StoreMusic ;check for cloud type override
910e: a0 04 ldy #$04 ;select music for cloud type level if found
9110: b9 e7 90 StoreMusic lda MusicSelectData,y ;otherwise select appropriate music for level type
9113: 85 fb sta AreaMusicQueue ;store in queue and leave
9115: 60 ExitGetM rts
; -----------------------------------------------------------------------------
PlayerStarting_X_Pos
9116: 28 18 38 28 .bulk $28,$18,$38,$28
911a: 08 00 AltYPosOffset .bulk $08,$00
PlayerStarting_Y_Pos
911c: 00 20 b0 50+ .bulk $00,$20,$b0,$50,$00,$00,$b0,$b0,$f0
PlayerBGPriorityData
9125: 00 20 00 00+ .bulk $00,$20,$00,$00,$00,$00,$00,$00
912d: 20 GameTimerData .dd1 $20 ;dummy byte, used as part of bg priority data
912e: 04 03 02 .bulk $04,$03,$02
Entrance_GameTimerSetup
9131: ad 1a 07 lda ScreenLeft_PageLoc ;set current page for area objects
9134: 85 6d sta Player_PageLoc ; as page location for player
9136: a9 28 lda #$28 ;store value here
9138: 8d 0a 07 sta VerticalForceDown ;for fractional movement downwards if necessary
913b: a9 01 lda #$01 ;set high byte of player position and
913d: 85 33 sta PlayerFacingDir ;set facing direction so that player faces right
913f: 85 b5 sta Player_Y_HighPos
9141: a9 00 lda #$00 ;set player state to on the ground by default
9143: 85 1d sta Player_State
9145: ce 90 04 dec Player_CollisionBits ;initialize player's collision bits
9148: a0 00 ldy #$00 ;initialize halfway page
914a: 8c 5b 07 sty HalfwayPage
914d: ad 4e 07 lda AreaType ;check area type
9150: d0 01 bne ChkStPos ;if water type, set swimming flag, otherwise do not set
9152: c8 iny
9153: 8c 04 07 ChkStPos sty SwimmingFlag
9156: ae 10 07 ldx PlayerEntranceCtrl ;get starting position loaded from header
9159: ac 52 07 ldy AltEntranceControl ;check alternate mode of entry flag for 0 or 1
915c: f0 07 beq SetStPos
915e: c0 01 cpy #$01
9160: f0 03 beq SetStPos
9162: be 18 91 ldx AltYPosOffset-2,y ;if not 0 or 1, override $0710 with new offset in X
9165: b9 16 91 SetStPos lda PlayerStarting_X_Pos,y ;load appropriate horizontal position
9168: 85 86 sta Player_X_Position ; and vertical positions for the player, using
916a: bd 1c 91 lda PlayerStarting_Y_Pos,x ; AltEntranceControl as offset for horizontal and either $0710
916d: 85 ce sta Player_Y_Position ; or value that overwrote $0710 as offset for vertical
916f: bd 25 91 lda PlayerBGPriorityData,x
9172: 8d c4 03 sta Player_SprAttrib ;set player sprite attributes using offset in X
9175: 20 f1 85 jsr GetPlayerColors ;get appropriate player palette
9178: ac 15 07 ldy GameTimerSetting ;get timer control value from header
917b: f0 1a beq ChkOverR ;if set to zero, branch (do not use dummy byte for this)
917d: ad 57 07 lda FetchNewGameTimerFlag ;do we need to set the game timer? if not, use
9180: f0 15 beq ChkOverR ; old game timer setting
9182: b9 2d 91 lda GameTimerData,y ;if game timer is set and game timer flag is also set,
9185: 8d f8 07 sta GameTimerDisplay ; use value of game timer control for first digit of game timer
9188: a9 01 lda #$01
918a: 8d fa 07 sta GameTimerDisplay+2 ;set last digit of game timer to 1
918d: 4a lsr A
918e: 8d f9 07 sta GameTimerDisplay+1 ;set second digit of game timer
9191: 8d 57 07 sta FetchNewGameTimerFlag ;clear flag for game timer reset
9194: 8d 9f 07 sta StarInvincibleTimer ;clear star mario timer
9197: ac 58 07 ChkOverR ldy JoypadOverride ;if controller bits not set, branch to skip this part
919a: f0 14 beq ChkSwimE
919c: a9 03 lda #$03 ;set player state to climbing
919e: 85 1d sta Player_State
91a0: a2 00 ldx #$00 ;set offset for first slot, for block object
91a2: 20 84 bd jsr InitBlock_XY_Pos
91a5: a9 f0 lda #$f0 ;set vertical coordinate for block object
91a7: 85 d7 sta Block_Y_Position
91a9: a2 05 ldx #$05 ;set offset in X for last enemy object buffer slot
91ab: a0 00 ldy #$00 ;set offset in Y for object coordinates used earlier
91ad: 20 1e b9 jsr Setup_Vine ;do a sub to grow vine
91b0: ac 4e 07 ChkSwimE ldy AreaType ;if level not water-type,
91b3: d0 03 bne SetPESub ; skip this subroutine
91b5: 20 0b b7 jsr SetupBubble ;otherwise, execute sub to set up air bubbles
91b8: a9 07 SetPESub lda #$07 ;set to run player entrance subroutine
91ba: 85 0e sta GameEngineSubroutine ; on the next frame of game engine
91bc: 60 rts
; -----------------------------------------------------------------------------
;
; page numbers are in order from -1 to -4
HalfwayPageNybbles
91bd: 56 40 .bulk $56,$40
91bf: 65 70 .bulk $65,$70
91c1: 66 40 .bulk $66,$40
91c3: 66 40 .bulk $66,$40
91c5: 66 40 .bulk $66,$40
91c7: 66 60 .bulk $66,$60
91c9: 65 70 .bulk $65,$70
91cb: 00 00 .bulk $00,$00
91cd: ee 74 07 PlayerLoseLife inc DisableScreenFlag ;disable screen and sprite 0 check
91d0: a9 00 lda #$00
91d2: 8d 22 07 sta Sprite0HitDetectFlag
91d5: a9 80 lda #Silence ;silence music
91d7: 85 fc sta EventMusicQueue
91d9: ce 5a 07 dec NumberOfLives ;take one life from player
91dc: 10 0b bpl StillInGame ;if player still has lives, branch
91de: a9 00 lda #$00
91e0: 8d 72 07 sta OperMode_Task ;initialize mode task,
91e3: a9 03 lda #GameOverModeValue ;switch to game over mode
91e5: 8d 70 07 sta OperMode ;and leave
91e8: 60 rts
91e9: ad 5f 07 StillInGame lda WorldNumber ;multiply world number by 2 and use
91ec: 0a asl A ; as offset
91ed: aa tax
91ee: ad 5c 07 lda LevelNumber ;if in area -3 or -4, increment
91f1: 29 02 and #$02 ; offset by one byte, otherwise
91f3: f0 01 beq GetHalfway ; leave offset alone
91f5: e8 inx
91f6: bc bd 91 GetHalfway ldy HalfwayPageNybbles,x ;get halfway page number with offset
91f9: ad 5c 07 lda LevelNumber ;check area number's LSB
91fc: 4a lsr A
91fd: 98 tya ;if in area -2 or -4, use lower nybble
91fe: b0 04 bcs MaskHPNyb
9200: 4a lsr A ;move higher nybble to lower if area
9201: 4a lsr A ; number is -1 or -3
9202: 4a lsr A
9203: 4a lsr A
9204: 29 0f MaskHPNyb and #%00001111 ;mask out all but lower nybble
9206: cd 1a 07 cmp ScreenLeft_PageLoc
9209: f0 04 beq SetHalfway ;left side of screen must be at the halfway page,
920b: 90 02 bcc SetHalfway ; otherwise player must start at the
920d: a9 00 lda #$00 ;beginning of the level
920f: 8d 5b 07 SetHalfway sta HalfwayPage ;store as halfway page for player
9212: 20 82 92 jsr TransposePlayers ;switch players around if 2-player game
9215: 4c 64 92 jmp ContinueGame ;continue the game
; -----------------------------------------------------------------------------
9218: ad 72 07 GameOverMode lda OperMode_Task
921b: 20 04 8e jsr JumpEngine
921e: 24 92 .dd2 SetupGameOver
9220: 67 85 .dd2 ScreenRoutines
9222: 37 92 .dd2 RunGameOver
; -----------------------------------------------------------------------------
9224: a9 00 SetupGameOver lda #$00 ;reset screen routine task control for title screen, game,
9226: 8d 3c 07 sta ScreenRoutineTask ; and game over modes
9229: 8d 22 07 sta Sprite0HitDetectFlag ;disable sprite 0 check
922c: a9 02 lda #GameOverMusic
922e: 85 fc sta EventMusicQueue ;put game over music in secondary queue
9230: ee 74 07 inc DisableScreenFlag ;disable screen output
9233: ee 72 07 inc OperMode_Task ;set secondary mode to 1
9236: 60 rts
; -----------------------------------------------------------------------------
9237: a9 00 RunGameOver lda #$00 ;reenable screen
9239: 8d 74 07 sta DisableScreenFlag
923c: ad fc 06 lda SavedJoypad1Bits ;check controller for start pressed
923f: 29 10 and #Start_Button
9241: d0 05 bne TerminateGame
9243: ad a0 07 lda ScreenTimer ;if not pressed, wait for
9246: d0 39 bne GameIsOn ; screen timer to expire
9248: a9 80 TerminateGame lda #Silence ;silence music
924a: 85 fc sta EventMusicQueue
924c: 20 82 92 jsr TransposePlayers ;check if other player can keep
924f: 90 13 bcc ContinueGame ; going, and do so if possible
9251: ad 5f 07 lda WorldNumber ;otherwise put world number of current
9254: 8d fd 07 sta ContinueWorld ; player into secret continue function variable
9257: a9 00 lda #$00
9259: 0a asl A ;residual ASL instruction
925a: 8d 72 07 sta OperMode_Task ;reset all modes to title screen and
925d: 8d a0 07 sta ScreenTimer ; leave
9260: 8d 70 07 sta OperMode
9263: 60 rts
9264: 20 03 9c ContinueGame jsr LoadAreaPointer ;update level pointer with
9267: a9 01 lda #$01 ; actual world and area numbers, then
9269: 8d 54 07 sta PlayerSize ; reset player's size, status, and
926c: ee 57 07 inc FetchNewGameTimerFlag ; set game timer flag to reload
926f: a9 00 lda #$00 ; game timer from header
9271: 8d 47 07 sta TimerControl ;also set flag for timers to count again
9274: 8d 56 07 sta PlayerStatus
9277: 85 0e sta GameEngineSubroutine ;reset task for game core
9279: 8d 72 07 sta OperMode_Task ;set modes and leave
927c: a9 01 lda #$01 ;if in game over mode, switch back to
927e: 8d 70 07 sta OperMode ; game mode, because game is still on
9281: 60 GameIsOn rts
TransposePlayers
9282: 38 sec ;set carry flag by default to end game
9283: ad 7a 07 lda NumberOfPlayers ;if only a 1 player game, leave
9286: f0 21 beq ExTrans
9288: ad 61 07 lda OffScr_NumberofLives ;does offscreen player have any lives left?
928b: 30 1c bmi ExTrans ;branch if not
928d: ad 53 07 lda CurrentPlayer ;invert bit to update
9290: 49 01 eor #%00000001 ; which player is on the screen
9292: 8d 53 07 sta CurrentPlayer
9295: a2 06 ldx #$06
9297: bd 5a 07 TransLoop lda OnscreenPlayerInfo,x ;transpose the information
929a: 48 pha ; of the onscreen player
929b: bd 61 07 lda OffscreenPlayerInfo,x ; with that of the offscreen player
929e: 9d 5a 07 sta OnscreenPlayerInfo,x
92a1: 68 pla
92a2: 9d 61 07 sta OffscreenPlayerInfo,x
92a5: ca dex
92a6: 10 ef bpl TransLoop
92a8: 18 clc
92a9: 60 rts
; -----------------------------------------------------------------------------
92aa: a9 ff DoNothing1 lda #$ff ;this is residual code, this value is
92ac: 8d c9 06 sta unused_06c9 ; not used anywhere in the program
92af: 60 DoNothing2 rts
; -----------------------------------------------------------------------------
AreaParserTaskHandler
92b0: ac 1f 07 ldy AreaParserTaskNum ;check number of tasks here
92b3: d0 05 bne DoAPTasks ;if already set, go ahead
92b5: a0 08 ldy #$08
92b7: 8c 1f 07 sty AreaParserTaskNum ;otherwise, set eight by default
92ba: 88 DoAPTasks dey
92bb: 98 tya
92bc: 20 c8 92 jsr AreaParserTasks
92bf: ce 1f 07 dec AreaParserTaskNum ;if all tasks not complete do not
92c2: d0 03 bne SkipATRender ; render attribute table yet
92c4: 20 6a 89 jsr RenderAttributeTables
92c7: 60 SkipATRender rts
92c8: 20 04 8e AreaParserTasks jsr JumpEngine
92cb: db 92 .dd2 IncrementColumnPos
92cd: ae 88 .dd2 RenderAreaGraphics
92cf: ae 88 .dd2 RenderAreaGraphics
92d1: fc 93 .dd2 AreaParserCore
92d3: db 92 .dd2 IncrementColumnPos
92d5: ae 88 .dd2 RenderAreaGraphics
92d7: ae 88 .dd2 RenderAreaGraphics
92d9: fc 93 .dd2 AreaParserCore
; -----------------------------------------------------------------------------
IncrementColumnPos
92db: ee 26 07 inc CurrentColumnPos ;increment column where we're at
92de: ad 26 07 lda CurrentColumnPos
92e1: 29 0f and #%00001111 ;mask out higher nybble
92e3: d0 06 bne NoColWrap
92e5: 8d 26 07 sta CurrentColumnPos ;if no bits left set, wrap back to zero (0-f)
92e8: ee 25 07 inc CurrentPageLoc ; and increment page number where we're at
92eb: ee a0 06 NoColWrap inc BlockBufferColumnPos ;increment column offset where we're at
92ee: ad a0 06 lda BlockBufferColumnPos
92f1: 29 1f and #%00011111 ;mask out all but 5 LSB (0-1f)
92f3: 8d a0 06 sta BlockBufferColumnPos ;and save
92f6: 60 rts
; -----------------------------------------------------------------------------
; $00 - used as counter, store for low nybble for background, ceiling byte for
; terrain
; $01 - used to store floor byte for terrain
; $07 - used to store terrain metatile
; $06-$07 - used to store block buffer address
BSceneDataOffsets
92f7: 00 30 60 .bulk $00,$30,$60
92fa: 93 00 00 11+ BackSceneryData .bulk $93,$00,$00,$11,$12,$12,$13,$00,$00,$51,$52,$53,$00,$00,$00,$00 ;clouds
+ $00,$00,$01,$02,$02,$03,$00,$00,$00,$00,$00,$00,$91,$92,$93,$00
+ $00,$00,$00,$51,$52,$53,$41,$42,$43,$00,$00,$00,$00,$00,$91,$92
932a: 97 87 88 89+ .bulk $97,$87,$88,$89,$99,$00,$00,$00,$11,$12,$13,$a4,$a5,$a5,$a5,$a6 ;mountains and bushes
+ $97,$98,$99,$01,$02,$03,$00,$a4,$a5,$a6,$00,$11,$12,$12,$12,$13
+ $00,$00,$00,$00,$01,$02,$02,$03,$00,$a4,$a5,$a5,$a6,$00,$00,$00
935a: 11 12 12 13+ .bulk $11,$12,$12,$13,$00,$00,$00,$00,$00,$00,$00,$9c,$00,$8b,$aa,$aa ;trees and fences
+ $aa,$aa,$11,$12,$13,$8b,$00,$9c,$9c,$00,$00,$01,$02,$03,$11,$12
+ $12,$13,$00,$00,$00,$00,$aa,$aa,$9c,$aa,$00,$8b,$00,$01,$02,$03
BackSceneryMetatiles
938a: 80 83 00 .bulk $80,$83,$00 ;cloud left
938d: 81 84 00 .bulk $81,$84,$00 ;cloud middle
9390: 82 85 00 .bulk $82,$85,$00 ;cloud right
9393: 02 00 00 .bulk $02,$00,$00 ;bush left
9396: 03 00 00 .bulk $03,$00,$00 ;bush middle
9399: 04 00 00 .bulk $04,$00,$00 ;bush right
939c: 00 05 06 .bulk $00,$05,$06 ;mountain left
939f: 07 06 0a .bulk $07,$06,$0a ;mountain middle
93a2: 00 08 09 .bulk $00,$08,$09 ;mountain right
93a5: 4d 00 00 .bulk $4d,$00,$00 ;fence
93a8: 0d 0f 4e .bulk $0d,$0f,$4e ;tall tree
93ab: 0e 4e 4e .bulk $0e,$4e,$4e ;short tree
FSceneDataOffsets
93ae: 00 0d 1a .bulk $00,$0d,$1a
93b1: 86 87 87 87+ ForeSceneryData .bulk $86,$87,$87,$87,$87,$87,$87,$87,$87,$87,$87,$69,$69 ;in water
93be: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$45,$47,$47,$47,$47,$47,$00,$00 ;wall
93cb: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$86,$87 ;over water
TerrainMetatiles
93d8: 69 54 52 62 .bulk $69,$54,$52,$62
TerrainRenderBits
93dc: 00 00 .dbd2 %0000000000000000 ;no ceiling or floor
93de: 00 18 .dbd2 %0000000000011000 ;no ceiling, floor 2
93e0: 01 18 .dbd2 %0000000100011000 ;ceiling 1, floor 2
93e2: 07 18 .dbd2 %0000011100011000 ;ceiling 3, floor 2
93e4: 0f 18 .dbd2 %0000111100011000 ;ceiling 4, floor 2
93e6: ff 18 .dbd2 %1111111100011000 ;ceiling 8, floor 2
93e8: 01 1f .dbd2 %0000000100011111 ;ceiling 1, floor 5
93ea: 07 1f .dbd2 %0000011100011111 ;ceiling 3, floor 5
93ec: 0f 1f .dbd2 %0000111100011111 ;ceiling 4, floor 5
93ee: 81 1f .dbd2 %1000000100011111 ;ceiling 1, floor 6
93f0: 01 00 .dbd2 %0000000100000000 ;ceiling 1, no floor
93f2: 8f 1f .dbd2 %1000111100011111 ;ceiling 4, floor 6
93f4: f1 1f .dbd2 %1111000100011111 ;ceiling 1, floor 9
93f6: f9 18 .dbd2 %1111100100011000 ;ceiling 1, middle 5, floor 2
93f8: f1 18 .dbd2 %1111000100011000 ;ceiling 1, middle 4, floor 2
93fa: ff 1f .dbd2 %1111111100011111 ;completely solid top to bottom
93fc: ad 28 07 AreaParserCore lda BackloadingFlag ;check to see if we are starting right of start
93ff: f0 03 beq RenderSceneryTerrain ;if not, go ahead and render background, foreground and terrain
9401: 20 08 95 jsr ProcessAreaData ;otherwise skip ahead and load level data
;
RenderSceneryTerrain
9404: a2 0c ldx #$0c
9406: a9 00 lda #$00
9408: 9d a1 06 ClrMTBuf sta MetatileBuffer,x ;clear out metatile buffer
940b: ca dex
940c: 10 fa bpl ClrMTBuf
940e: ac 42 07 ldy BackgroundScenery ;do we need to render the background scenery?
9411: f0 42 beq RendFore ;if not, skip to check the foreground
9413: ad 25 07 lda CurrentPageLoc ;otherwise check for every third page
9416: c9 03 ThirdP cmp #$03
9418: 30 05 bmi RendBack ;if less than three we're there
941a: 38 sec
941b: e9 03 sbc #$03 ;if 3 or more, subtract 3 and
941d: 10 f7 bpl ThirdP ;do an unconditional branch
941f: 0a RendBack asl A ;move results to higher nybble
9420: 0a asl A
9421: 0a asl A
9422: 0a asl A
9423: 79 f6 92 adc BSceneDataOffsets-1,y ;add to it offset loaded from here
9426: 6d 26 07 adc CurrentColumnPos ;add to the result our current column position
9429: aa tax
942a: bd fa 92 lda BackSceneryData,x ;load data from sum of offsets
942d: f0 26 beq RendFore ;if zero, no scenery for that part
942f: 48 pha
9430: 29 0f and #$0f ;save to stack and clear high nybble
9432: 38 sec
9433: e9 01 sbc #$01 ;subtract one (because low nybble is $01-$0c)
9435: 85 00 sta $00 ;save low nybble
9437: 0a asl A ;multiply by three (shift to left and add result to old one)
9438: 65 00 adc $00 ;note that since d7 was nulled, the carry flag is always clear
943a: aa tax ;save as offset for background scenery metatile data
943b: 68 pla ;get high nybble from stack, move low
943c: 4a lsr A
943d: 4a lsr A
943e: 4a lsr A
943f: 4a lsr A
9440: a8 tay ;use as second offset (used to determine height)
9441: a9 03 lda #$03 ;use previously saved memory location for counter
9443: 85 00 sta $00
9445: bd 8a 93 SceLoop1 lda BackSceneryMetatiles,x ;load metatile data from offset of (lsb - 1) * 3
9448: 99 a1 06 sta MetatileBuffer,y ;store into buffer from offset of (msb / 16)
944b: e8 inx
944c: c8 iny
944d: c0 0b cpy #$0b ;if at this location, leave loop
944f: f0 04 beq RendFore
9451: c6 00 dec $00 ;decrement until counter expires, barring exception
9453: d0 f0 bne SceLoop1
9455: ae 41 07 RendFore ldx ForegroundScenery ;check for foreground data needed or not
9458: f0 13 beq RendTerr ;if not, skip this part
945a: bc ad 93 ldy FSceneDataOffsets-1,x ;load offset from location offset by header value, then
945d: a2 00 ldx #$00 ; reinit X
945f: b9 b1 93 SceLoop2 lda ForeSceneryData,y ;load data until counter expires
9462: f0 03 beq NoFore ;do not store if zero found
9464: 9d a1 06 sta MetatileBuffer,x
9467: c8 NoFore iny
9468: e8 inx
9469: e0 0d cpx #$0d ;store up to end of metatile buffer
946b: d0 f2 bne SceLoop2
946d: ac 4e 07 RendTerr ldy AreaType ;check world type for water level
9470: d0 0c bne TerMTile ;if not water level, skip this part
9472: ad 5f 07 lda WorldNumber ;check world number, if not world number eight
9475: c9 07 cmp #World8 ; then skip this part
9477: d0 05 bne TerMTile
9479: a9 62 lda #$62 ;if set as water level and world number eight,
947b: 4c 88 94 jmp StoreMT ; use castle wall metatile as terrain type
947e: b9 d8 93 TerMTile lda TerrainMetatiles,y ;otherwise get appropriate metatile for area type
9481: ac 43 07 ldy CloudTypeOverride ;check for cloud type override
9484: f0 02 beq StoreMT ;if not set, keep value otherwise
9486: a9 88 lda #$88 ;use cloud block terrain
9488: 85 07 StoreMT sta $07 ;store value here
948a: a2 00 ldx #$00 ;initialize X, use as metatile buffer offset
948c: ad 27 07 lda TerrainControl ;use yet another value from the header
948f: 0a asl A ;multiply by 2 and use as yet another offset
9490: a8 tay
9491: b9 dc 93 TerrLoop lda TerrainRenderBits,y ;get one of the terrain rendering bit data
9494: 85 00 sta $00
9496: c8 iny ;increment Y and use as offset next time around
9497: 84 01 sty $01
9499: ad 43 07 lda CloudTypeOverride ;skip if value here is zero
949c: f0 0a beq NoCloud2
949e: e0 00 cpx #$00 ;otherwise, check if we're doing the ceiling byte
94a0: f0 06 beq NoCloud2
94a2: a5 00 lda $00 ;if not, mask out all but d3
94a4: 29 08 and #%00001000
94a6: 85 00 sta $00
94a8: a0 00 NoCloud2 ldy #$00 ;start at beginning of bitmasks
94aa: b9 8a c6 TerrBChk lda Bitmasks,y ;load bitmask, then perform AND on contents of first byte
94ad: 24 00 bit $00
94af: f0 05 beq NextTBit ;if not set, skip this part (do not write terrain to buffer)
94b1: a5 07 lda $07
94b3: 9d a1 06 sta MetatileBuffer,x ;load terrain type metatile number and store into buffer here
94b6: e8 NextTBit inx ;continue until end of buffer
94b7: e0 0d cpx #$0d
94b9: f0 18 beq RendBBuf ;if we're at the end, break out of this loop
94bb: ad 4e 07 lda AreaType ;check world type for underground area
94be: c9 02 cmp #$02
94c0: d0 08 bne EndUChk ;if not underground, skip this part
94c2: e0 0b cpx #$0b
94c4: d0 04 bne EndUChk ;if we're at the bottom of the screen, override
94c6: a9 54 lda #$54 ; old terrain type with ground level terrain type
94c8: 85 07 sta $07
94ca: c8 EndUChk iny ;increment bitmasks offset in Y
94cb: c0 08 cpy #$08
94cd: d0 db bne TerrBChk ;if not all bits checked, loop back
94cf: a4 01 ldy $01
94d1: d0 be bne TerrLoop ;unconditional branch, use Y to load next byte
94d3: 20 08 95 RendBBuf jsr ProcessAreaData ;do the area data loading routine now
94d6: ad a0 06 lda BlockBufferColumnPos
94d9: 20 e1 9b jsr GetBlockBufferAddr ;get block buffer address from where we're at
94dc: a2 00 ldx #$00
94de: a0 00 ldy #$00 ;init index regs and start at beginning of smaller buffer
94e0: 84 00 ChkMTLow sty $00
94e2: bd a1 06 lda MetatileBuffer,x ;load stored metatile number
94e5: 29 c0 and #%11000000 ;mask out all but 2 MSB
94e7: 0a asl A
94e8: 2a rol A ;make %xx000000 into %000000xx
94e9: 2a rol A
94ea: a8 tay ;use as offset in Y
94eb: bd a1 06 lda MetatileBuffer,x ;reload original unmasked value here
94ee: d9 04 95 cmp BlockBuffLowBounds,y ;check for certain values depending on bits set
94f1: b0 02 bcs StrBlock ;if equal or greater, branch
94f3: a9 00 lda #$00 ;if less, init value before storing
94f5: a4 00 StrBlock ldy $00 ;get offset for block buffer
94f7: 91 06 sta ($06),y ;store value into block buffer
94f9: 98 tya
94fa: 18 clc ;add 16 (move down one row) to offset
94fb: 69 10 adc #$10
94fd: a8 tay
94fe: e8 inx ;increment column value
94ff: e0 0d cpx #$0d
9501: 90 dd bcc ChkMTLow ;continue until we pass last row, then leave
9503: 60 rts
; numbers lower than these with the same attribute bits will not be stored in
; the block buffer
BlockBuffLowBounds
9504: 10 51 88 c0 .bulk $10,$51,$88,$c0
; -----------------------------------------------------------------------------
; $00 - used to store area object identifier
; $07 - used as adder to find proper area object code
9508: a2 02 ProcessAreaData ldx #$02 ;start at the end of area object buffer
950a: 86 08 ProcADLoop stx ObjectOffset
950c: a9 00 lda #$00 ;reset flag
950e: 8d 29 07 sta BehindAreaParserFlag
9511: ac 2c 07 ldy AreaDataOffset ;get offset of area data pointer
9514: b1 e7 lda (AreaData),y ;get first byte of area object
9516: c9 fd cmp #$fd ;if end-of-area, skip all this crap
9518: f0 4b beq RdyDecode
951a: bd 30 07 lda AreaObjectLength,x ;check area object buffer flag
951d: 10 46 bpl RdyDecode ;if buffer not negative, branch, otherwise
951f: c8 iny
9520: b1 e7 lda (AreaData),y ;get second byte of area object
9522: 0a asl A ;check for page select bit (d7), branch if not set
9523: 90 0b bcc Chk1Row13
9525: ad 2b 07 lda AreaObjectPageSel ;check page select
9528: d0 06 bne Chk1Row13
952a: ee 2b 07 inc AreaObjectPageSel ;if not already set, set it now
952d: ee 2a 07 inc AreaObjectPageLoc ;and increment page location
9530: 88 Chk1Row13 dey
9531: b1 e7 lda (AreaData),y ;reread first byte of level object
9533: 29 0f and #$0f ;mask out high nybble
9535: c9 0d cmp #$0d ;row 13?
9537: d0 1b bne Chk1Row14
9539: c8 iny ;if so, reread second byte of level object
953a: b1 e7 lda (AreaData),y
953c: 88 dey ;decrement to get ready to read first byte
953d: 29 40 and #%01000000 ;check for d6 set (if not, object is page control)
953f: d0 1c bne CheckRear
9541: ad 2b 07 lda AreaObjectPageSel ;if page select is set, do not reread
9544: d0 17 bne CheckRear
9546: c8 iny ;if d6 not set, reread second byte
9547: b1 e7 lda (AreaData),y
9549: 29 1f and #%00011111 ;mask out all but 5 LSB and store in page control
954b: 8d 2a 07 sta AreaObjectPageLoc
954e: ee 2b 07 inc AreaObjectPageSel ;increment page select
9551: 4c 6e 95 jmp NextAObj
9554: c9 0e Chk1Row14 cmp #$0e ;row 14?
9556: d0 05 bne CheckRear
9558: ad 28 07 lda BackloadingFlag ;check flag for saved page number and branch if set
955b: d0 08 bne RdyDecode ; to render the object (otherwise bg might not look right)
955d: ad 2a 07 CheckRear lda AreaObjectPageLoc ;check to see if current page of level object is
9560: cd 25 07 cmp CurrentPageLoc ;behind current page of renderer
9563: 90 06 bcc SetBehind ;if so branch
9565: 20 95 95 RdyDecode jsr DecodeAreaData ;do sub and do not turn on flag
9568: 4c 71 95 jmp ChkLength
956b: ee 29 07 SetBehind inc BehindAreaParserFlag ;turn on flag if object is behind renderer
956e: 20 89 95 NextAObj jsr IncAreaObjOffset ;increment buffer offset and move on
9571: a6 08 ChkLength ldx ObjectOffset ;get buffer offset
9573: bd 30 07 lda AreaObjectLength,x ;check object length for anything stored here
9576: 30 03 bmi ProcLoopb ;if not, branch to handle loopback
9578: de 30 07 dec AreaObjectLength,x ;otherwise decrement length or get rid of it
957b: ca ProcLoopb dex ;decrement buffer offset
957c: 10 8c bpl ProcADLoop ; and loopback unless exceeded buffer
957e: ad 29 07 lda BehindAreaParserFlag ;check for flag set if objects were behind renderer
9581: d0 85 bne ProcessAreaData ;branch if true to load more level data, otherwise
9583: ad 28 07 lda BackloadingFlag ;check for flag set if starting right of page $00
9586: d0 80 bne ProcessAreaData ;branch if true to load more level data, otherwise leave
9588: 60 EndAParse rts
IncAreaObjOffset
9589: ee 2c 07 inc AreaDataOffset ;increment offset of level pointer
958c: ee 2c 07 inc AreaDataOffset
958f: a9 00 lda #$00 ;reset page select
9591: 8d 2b 07 sta AreaObjectPageSel
9594: 60 rts
9595: bd 30 07 DecodeAreaData lda AreaObjectLength,x ;check current buffer flag
9598: 30 03 bmi Chk1stB
959a: bc 2d 07 ldy AreaObjOffsetBuffer,x ;if not, get offset from buffer
959d: a2 10 Chk1stB ldx #$10 ;load offset of 16 for special row 15
959f: b1 e7 lda (AreaData),y ;get first byte of level object again
95a1: c9 fd cmp #$fd
95a3: f0 e3 beq EndAParse ;if end of level, leave this routine
95a5: 29 0f and #$0f ;otherwise, mask out low nybble
95a7: c9 0f cmp #$0f ;row 15?
95a9: f0 08 beq ChkRow14 ;if so, keep the offset of 16
95ab: a2 08 ldx #$08 ;otherwise load offset of 8 for special row 12
95ad: c9 0c cmp #$0c ;row 12?
95af: f0 02 beq ChkRow14 ;if so, keep the offset value of 8
95b1: a2 00 ldx #$00 ;otherwise nullify value by default
95b3: 86 07 ChkRow14 stx $07 ;store whatever value we just loaded here
95b5: a6 08 ldx ObjectOffset ;get object offset again
95b7: c9 0e cmp #$0e ;row 14?
95b9: d0 08 bne ChkRow13
95bb: a9 00 lda #$00 ;if so, load offset with $00
95bd: 85 07 sta $07
95bf: a9 2e lda #$2e ;and load A with another value
95c1: d0 53 bne NormObj ;unconditional branch
95c3: c9 0d ChkRow13 cmp #$0d ;row 13?
95c5: d0 1b bne ChkSRows
95c7: a9 22 lda #$22 ;if so, load offset with 34
95c9: 85 07 sta $07
95cb: c8 iny ;get next byte
95cc: b1 e7 lda (AreaData),y
95ce: 29 40 and #%01000000 ;mask out all but d6 (page control obj bit)
95d0: f0 63 beq LeavePar ;if d6 clear, branch to leave (we handled this earlier)
95d2: b1 e7 lda (AreaData),y ;otherwise, get byte again
95d4: 29 7f and #%01111111 ;mask out d7
95d6: c9 4b cmp #$4b ;check for loop command in low nybble
95d8: d0 03 bne Mask2MSB ;(plus d6 set for object other than page control)
95da: ee 45 07 inc LoopCommand ;if loop command, set loop command flag
95dd: 29 3f Mask2MSB and #%00111111 ;mask out d7 and d6
95df: 4c 16 96 jmp NormObj ;and jump
95e2: c9 0c ChkSRows cmp #$0c ;row 12-15?
95e4: b0 27 bcs SpecObj
95e6: c8 iny ;if not, get second byte of level object
95e7: b1 e7 lda (AreaData),y
95e9: 29 70 and #%01110000 ;mask out all but d6-d4
95eb: d0 0b bne LrgObj ;if any bits set, branch to handle large object
95ed: a9 16 lda #$16
95ef: 85 07 sta $07 ;otherwise set offset of 24 for small object
95f1: b1 e7 lda (AreaData),y ;reload second byte of level object
95f3: 29 0f and #%00001111 ;mask out higher nybble and jump
95f5: 4c 16 96 jmp NormObj
95f8: 85 00 LrgObj sta $00 ;store value here (branch for large objects)
95fa: c9 70 cmp #$70 ;check for vertical pipe object
95fc: d0 0a bne NotWPipe
95fe: b1 e7 lda (AreaData),y ;if not, reload second byte
9600: 29 08 and #%00001000 ;mask out all but d3 (usage control bit)
9602: f0 04 beq NotWPipe ;if d3 clear, branch to get original value
9604: a9 00 lda #$00 ;otherwise, nullify value for warp pipe
9606: 85 00 sta $00
9608: a5 00 NotWPipe lda $00 ;get value and jump ahead
960a: 4c 12 96 jmp MoveAOId
960d: c8 SpecObj iny ;branch here for rows 12-15
960e: b1 e7 lda (AreaData),y
9610: 29 70 and #%01110000 ;get next byte and mask out all but d6-d4
9612: 4a MoveAOId lsr A ;move d6-d4 to lower nybble
9613: 4a lsr A
9614: 4a lsr A
9615: 4a lsr A
9616: 85 00 NormObj sta $00 ;store value here (branch for small objects and rows 13 and 14)
9618: bd 30 07 lda AreaObjectLength,x ;is there something stored here already?
961b: 10 42 bpl RunAObj ;if so, branch to do its particular sub
961d: ad 2a 07 lda AreaObjectPageLoc ;otherwise check to see if the object we've loaded is on the
9620: cd 25 07 cmp CurrentPageLoc ;same page as the renderer, and if so, branch
9623: f0 11 beq InitRear
9625: ac 2c 07 ldy AreaDataOffset ;if not, get old offset of level pointer
9628: b1 e7 lda (AreaData),y ;and reload first byte
962a: 29 0f and #%00001111
962c: c9 0e cmp #$0e ;row 14?
962e: d0 05 bne LeavePar
9630: ad 28 07 lda BackloadingFlag ;if so, check backloading flag
9633: d0 21 bne StarAObj ;if set, branch to render object, else leave
9635: 60 LeavePar rts
9636: ad 28 07 InitRear lda BackloadingFlag ;check backloading flag to see if it's been initialized
9639: f0 0b beq BackColC ;branch to column-wise check
963b: a9 00 lda #$00 ;if not, initialize both backloading and
963d: 8d 28 07 sta BackloadingFlag ;behind-renderer flags and leave
9640: 8d 29 07 sta BehindAreaParserFlag
9643: 85 08 sta ObjectOffset
9645: 60 LoopCmdE rts
9646: ac 2c 07 BackColC ldy AreaDataOffset ;get first byte again
9649: b1 e7 lda (AreaData),y
964b: 29 f0 and #%11110000 ;mask out low nybble and move high to low
964d: 4a lsr A
964e: 4a lsr A
964f: 4a lsr A
9650: 4a lsr A
9651: cd 26 07 cmp CurrentColumnPos ;is this where we're at?
9654: d0 df bne LeavePar ;if not, branch to leave
9656: ad 2c 07 StarAObj lda AreaDataOffset ;if so, load area obj offset and store in buffer
9659: 9d 2d 07 sta AreaObjOffsetBuffer,x
965c: 20 89 95 jsr IncAreaObjOffset ;do sub to increment to next object data
965f: a5 00 RunAObj lda $00 ;get stored value and add offset to it
9661: 18 clc ;then use the jump engine with current contents of A
9662: 65 07 adc $07
9664: 20 04 8e jsr JumpEngine
; large objects (rows $00-$0b or 00-11, d6-d4 set)
9667: e5 98 .dd2 VerticalPipe
9669: 40 97 .dd2 AreaStyleObject ;used by warp pipes
966b: 2e 9a .dd2 RowOfBricks
966d: 3e 9a .dd2 RowOfSolidBlocks
966f: f2 99 .dd2 RowOfCoins
9671: 50 9a .dd2 ColumnOfBricks
9673: 59 9a .dd2 ColumnOfSolidBlocks
9675: e5 98 .dd2 VerticalPipe ;used by decoration pipes
; objects for special row $0c or 12
9677: 41 9b .dd2 Hole_Empty
9679: ba 97 .dd2 PulleyRopeObject
967b: 79 99 .dd2 Bridge_High
967d: 7c 99 .dd2 Bridge_Middle
967f: 7f 99 .dd2 Bridge_Low
9681: 57 99 .dd2 Hole_Water
9683: 68 99 .dd2 QuestionBlockRow_High
9685: 6b 99 .dd2 QuestionBlockRow_Low
; objects for special row $0f or 15
9687: d0 99 .dd2 EndlessRope
9689: d7 99 .dd2 BalancePlatRope
968b: 06 98 .dd2 CastleObject
968d: b7 9a .dd2 StaircaseObject
968f: ab 98 .dd2 ExitPipe
9691: 94 99 .dd2 FlagBalls_Residual
; small objects (rows $00-$0b or 00-11, d6-d4 all clear)
9693: 0e 9b .dd2 QuestionBlock ;power-up
9695: 0e 9b .dd2 QuestionBlock ;coin
9697: 0e 9b .dd2 QuestionBlock ;hidden, coin
9699: 01 9b .dd2 Hidden1UpBlock ;hidden, 1-up
969b: 19 9b .dd2 BrickWithItem ;brick, power-up
969d: 19 9b .dd2 BrickWithItem ;brick, vine
969f: 19 9b .dd2 BrickWithItem ;brick, star
96a1: 14 9b .dd2 BrickWithCoins ;brick, coins
96a3: 19 9b .dd2 BrickWithItem ;brick, 1-up
96a5: 6f 98 .dd2 WaterPipe
96a7: 19 9a .dd2 EmptyBlock
96a9: d3 9a .dd2 JumpSpring
; objects for special row $0d or 13 (d6 set)
96ab: 82 98 .dd2 IntroPipe
96ad: 9e 99 .dd2 FlagpoleObject
96af: 09 9a .dd2 AxeObj
96b1: 0e 9a .dd2 ChainObj
96b3: 01 9a .dd2 CastleBridgeObj
96b5: f2 96 .dd2 ScrollLockObject_Warp
96b7: 0d 97 .dd2 ScrollLockObject
96b9: 0d 97 .dd2 ScrollLockObject
96bb: 2b 97 .dd2 AreaFrenzy ;flying cheep-cheeps
96bd: 2b 97 .dd2 AreaFrenzy ;bullet bills or swimming cheep-cheeps
96bf: 2b 97 .dd2 AreaFrenzy ;stop frenzy
96c1: 45 96 .dd2 LoopCmdE
; object for special row $0e or 14
96c3: c5 96 .dd2 AlterAreaAttributes
; -----------------------------------------------------------------------------
; (these apply to all area object subroutines in this section unless otherwise
; stated)
; $00 - used to store offset used to find object code
; $07 - starts with adder from area parser, used to store row offset
AlterAreaAttributes
96c5: bc 2d 07 ldy AreaObjOffsetBuffer,x ;load offset for level object data saved in buffer
96c8: c8 iny ;load second byte
96c9: b1 e7 lda (AreaData),y
96cb: 48 pha ;save in stack for now
96cc: 29 40 and #%01000000
96ce: d0 12 bne Alter2 ;branch if d6 is set
96d0: 68 pla
96d1: 48 pha ;pull and push offset to copy to A
96d2: 29 0f and #%00001111 ;mask out high nybble and store as
96d4: 8d 27 07 sta TerrainControl ; new terrain height type bits
96d7: 68 pla
96d8: 29 30 and #%00110000 ;pull and mask out all but d5 and d4
96da: 4a lsr A ;move bits to lower nybble and store
96db: 4a lsr A ; as new background scenery bits
96dc: 4a lsr A
96dd: 4a lsr A
96de: 8d 42 07 sta BackgroundScenery ;then leave
96e1: 60 rts
96e2: 68 Alter2 pla
96e3: 29 07 and #%00000111 ;mask out all but 3 LSB
96e5: c9 04 cmp #$04 ;if four or greater, set color control bits
96e7: 90 05 bcc SetFore ; and nullify foreground scenery bits
96e9: 8d 44 07 sta BackgroundColorCtrl
96ec: a9 00 lda #$00
96ee: 8d 41 07 SetFore sta ForegroundScenery ;otherwise set new foreground scenery bits
96f1: 60 rts
; -----------------------------------------------------------------------------
ScrollLockObject_Warp
96f2: a2 04 ldx #$04 ;load value of 4 for game text routine as default
96f4: ad 5f 07 lda WorldNumber ; warp zone (4-3-2), then check world number
96f7: f0 08 beq WarpNum
96f9: e8 inx ;if world number > 1, increment for next warp zone (5)
96fa: ac 4e 07 ldy AreaType ;check area type
96fd: 88 dey
96fe: d0 01 bne WarpNum ;if ground area type, increment for last warp zone
9700: e8 inx ; (8-7-6) and move on
9701: 8a WarpNum txa
9702: 8d d6 06 sta WarpZoneControl ;store number here to be used by warp zone routine
9705: 20 08 88 jsr WriteGameText ;print text and warp zone numbers
9708: a9 0d lda #PiranhaPlant
970a: 20 16 97 jsr KillEnemies ;load identifier for piranha plants and do sub
ScrollLockObject
970d: ad 23 07 lda ScrollLock ;invert scroll lock to turn it on
9710: 49 01 eor #%00000001
9712: 8d 23 07 sta ScrollLock
9715: 60 rts
; -----------------------------------------------------------------------------
; $00 - used to store enemy identifier in KillEnemies
9716: 85 00 KillEnemies sta $00 ;store identifier here
9718: a9 00 lda #$00
971a: a2 04 ldx #$04 ;check for identifier in enemy object buffer
971c: b4 16 KillELoop ldy Enemy_ID,x
971e: c4 00 cpy $00 ;if not found, branch
9720: d0 02 bne NoKillE
9722: 95 0f sta Enemy_Flag,x
9724: ca NoKillE dex ;do this until all slots are checked
9725: 10 f5 bpl KillELoop
9727: 60 rts
; -----------------------------------------------------------------------------
9728: 14 FrenzyIDData .dd1 FlyCheepCheepFrenzy
9729: 17 .dd1 BBill_CCheep_Frenzy
972a: 18 .dd1 Stop_Frenzy
972b: a6 00 AreaFrenzy ldx $00 ;use area object identifier bit as offset
972d: bd 20 97 lda FrenzyIDData-8,x ;note that it starts at 8, thus weird address here
9730: a0 05 ldy #$05
9732: 88 FreCompLoop dey ;check regular slots of enemy object buffer
9733: 30 07 bmi ExitAFrenzy ;if all slots checked and enemy object not found, branch to store
9735: d9 16 00 cmp Enemy_ID,y ;check for enemy object in buffer versus frenzy object
9738: d0 f8 bne FreCompLoop
973a: a9 00 lda #$00 ;if enemy object already present, nullify queue and leave
973c: 8d cd 06 ExitAFrenzy sta EnemyFrenzyQueue ;store enemy into frenzy queue
973f: 60 rts
; -----------------------------------------------------------------------------
; $06 - used by MushroomLedge to store length
9740: ad 33 07 AreaStyleObject lda AreaStyle ;load level object style and jump to the right sub
9743: 20 04 8e jsr JumpEngine
9746: 4c 97 .dd2 TreeLedge ;also used for cloud type levels
9748: 78 97 .dd2 MushroomLedge
974a: 69 9a .dd2 BulletBillCannon
974c: 20 bb 9b TreeLedge jsr GetLrgObjAttrib ;get row and length of green ledge
974f: bd 30 07 lda AreaObjectLength,x ;check length counter for expiration
9752: f0 1f beq EndTreeL
9754: 10 11 bpl MidTreeL
9756: 98 tya
9757: 9d 30 07 sta AreaObjectLength,x ;store lower nybble into buffer flag as length of ledge
975a: ad 25 07 lda CurrentPageLoc
975d: 0d 26 07 ora CurrentColumnPos ;are we at the start of the level?
9760: f0 05 beq MidTreeL
9762: a9 16 lda #$16 ;render start of tree ledge
9764: 4c b0 97 jmp NoUnder
9767: a6 07 MidTreeL ldx $07
9769: a9 17 lda #$17 ;render middle of tree ledge
976b: 9d a1 06 sta MetatileBuffer,x ;note that this is also used if ledge position is
976e: a9 4c lda #$4c ; at the start of level for continuous effect
9770: 4c aa 97 jmp AllUnder ;now render the part underneath
9773: a9 18 EndTreeL lda #$18 ;render end of tree ledge
9775: 4c b0 97 jmp NoUnder
9778: 20 ac 9b MushroomLedge jsr ChkLrgObjLength ;get shroom dimensions
977b: 84 06 sty $06 ;store length here for now
977d: 90 0c bcc EndMushL
977f: bd 30 07 lda AreaObjectLength,x ;divide length by 2 and store elsewhere
9782: 4a lsr A
9783: 9d 36 07 sta MushroomLedgeHalfLen,x
9786: a9 19 lda #$19 ;render start of mushroom
9788: 4c b0 97 jmp NoUnder
978b: a9 1b EndMushL lda #$1b ;if at the end, render end of mushroom
978d: bc 30 07 ldy AreaObjectLength,x
9790: f0 1e beq NoUnder
9792: bd 36 07 lda MushroomLedgeHalfLen,x ;get divided length and store where length
9795: 85 06 sta $06 ; was stored originally
9797: a6 07 ldx $07
9799: a9 1a lda #$1a
979b: 9d a1 06 sta MetatileBuffer,x ;render middle of mushroom
979e: c4 06 cpy $06 ;are we smack dab in the center?
97a0: d0 2c bne MushLExit ;if not, branch to leave
97a2: e8 inx
97a3: a9 4f lda #$4f
97a5: 9d a1 06 sta MetatileBuffer,x ;render stem top of mushroom underneath the middle
97a8: a9 50 lda #$50
97aa: e8 AllUnder inx
97ab: a0 0f ldy #$0f ;set $0f to render all way down
97ad: 4c 7d 9b jmp RenderUnderPart ;now render the stem of mushroom
97b0: a6 07 NoUnder ldx $07 ;load row of ledge
97b2: a0 00 ldy #$00 ;set 0 for no bottom on this part
97b4: 4c 7d 9b jmp RenderUnderPart
; -----------------------------------------------------------------------------
; tiles used by pulleys and rope object
PulleyRopeMetatiles
97b7: 42 41 43 .bulk $42,$41,$43
PulleyRopeObject
97ba: 20 ac 9b jsr ChkLrgObjLength ;get length of pulley/rope object
97bd: a0 00 ldy #$00 ;initialize metatile offset
97bf: b0 07 bcs RenderPul ;if starting, render left pulley
97c1: c8 iny
97c2: bd 30 07 lda AreaObjectLength,x ;if not at the end, render rope
97c5: d0 01 bne RenderPul
97c7: c8 iny ;otherwise render right pulley
97c8: b9 b7 97 RenderPul lda PulleyRopeMetatiles,y
97cb: 8d a1 06 sta MetatileBuffer ;render at the top of the screen
97ce: 60 MushLExit rts ;and leave
; -----------------------------------------------------------------------------
; $06 - used to store upper limit of rows for CastleObject
97cf: 00 45 45 45+ CastleMetatiles .bulk $00,$45,$45,$45,$00
97d4: 00 48 47 46+ .bulk $00,$48,$47,$46,$00
97d9: 45 49 49 49+ .bulk $45,$49,$49,$49,$45
97de: 47 47 4a 47+ .bulk $47,$47,$4a,$47,$47
97e3: 47 47 4b 47+ .bulk $47,$47,$4b,$47,$47
97e8: 49 49 49 49+ .bulk $49,$49,$49,$49,$49
97ed: 47 4a 47 4a+ .bulk $47,$4a,$47,$4a,$47
97f2: 47 4b 47 4b+ .bulk $47,$4b,$47,$4b,$47
97f7: 47 47 47 47+ .bulk $47,$47,$47,$47,$47
97fc: 4a 47 4a 47+ .bulk $4a,$47,$4a,$47,$4a
9801: 4b 47 4b 47+ .bulk $4b,$47,$4b,$47,$4b
9806: 20 bb 9b CastleObject jsr GetLrgObjAttrib ;save lower nybble as starting row
9809: 84 07 sty $07 ;if starting row is above $0a, game will crash!!!
980b: a0 04 ldy #$04
980d: 20 af 9b jsr ChkLrgObjFixedLength ;load length of castle if not already loaded
9810: 8a txa
9811: 48 pha ;save obj buffer offset to stack
9812: bc 30 07 ldy AreaObjectLength,x ;use current length as offset for castle data
9815: a6 07 ldx $07 ;begin at starting row
9817: a9 0b lda #$0b
9819: 85 06 sta $06 ;load upper limit of number of rows to print
981b: b9 cf 97 CRendLoop lda CastleMetatiles,y ;load current byte using offset
981e: 9d a1 06 sta MetatileBuffer,x
9821: e8 inx ;store in buffer and increment buffer offset
9822: a5 06 lda $06
9824: f0 07 beq ChkCFloor ;have we reached upper limit yet?
9826: c8 iny ;if not, increment column-wise
9827: c8 iny ; to byte in next row
9828: c8 iny
9829: c8 iny
982a: c8 iny
982b: c6 06 dec $06 ;move closer to upper limit
982d: e0 0b ChkCFloor cpx #$0b ;have we reached the row just before floor?
982f: d0 ea bne CRendLoop ;if not, go back and do another row
9831: 68 pla
9832: aa tax ;get obj buffer offset from before
9833: ad 25 07 lda CurrentPageLoc
9836: f0 36 beq ExitCastle ;if we're at page 0, we do not need to do anything else
9838: bd 30 07 lda AreaObjectLength,x ;check length
983b: c9 01 cmp #$01 ;if length almost about to expire, put brick at floor
983d: f0 2a beq PlayerStop
983f: a4 07 ldy $07 ;check starting row for tall castle ($00)
9841: d0 04 bne NotTall
9843: c9 03 cmp #$03 ;if found, then check to see if we're at the second column
9845: f0 22 beq PlayerStop
9847: c9 02 NotTall cmp #$02 ;if not tall castle, check to see if we're at the third column
9849: d0 23 bne ExitCastle ;if we aren't and the castle is tall, don't create flag yet
984b: 20 cb 9b jsr GetAreaObjXPosition ;otherwise, obtain and save horizontal pixel coordinate
984e: 48 pha
984f: 20 4a 99 jsr FindEmptyEnemySlot ;find an empty place on the enemy object buffer
9852: 68 pla
9853: 95 87 sta Enemy_X_Position,x ;then write horizontal coordinate for star flag
9855: ad 25 07 lda CurrentPageLoc
9858: 95 6e sta Enemy_PageLoc,x ;set page location for star flag
985a: a9 01 lda #$01
985c: 95 b6 sta Enemy_Y_HighPos,x ;set vertical high byte
985e: 95 0f sta Enemy_Flag,x ;set flag for buffer
9860: a9 90 lda #$90
9862: 95 cf sta Enemy_Y_Position,x ;set vertical coordinate
9864: a9 31 lda #StarFlagObject ;set star flag value in buffer itself
9866: 95 16 sta Enemy_ID,x
9868: 60 rts
9869: a0 52 PlayerStop ldy #$52 ;put brick at floor to stop player at end of level
986b: 8c ab 06 sty MetatileBuffer+10 ;this is only done if we're on the second column
986e: 60 ExitCastle rts
; -----------------------------------------------------------------------------
986f: 20 bb 9b WaterPipe jsr GetLrgObjAttrib ;get row and lower nybble
9872: bc 30 07 ldy AreaObjectLength,x ;get length (residual code, water pipe is 1 col thick)
9875: a6 07 ldx $07 ;get row
9877: a9 6b lda #$6b
9879: 9d a1 06 sta MetatileBuffer,x ;draw something here and below it
987c: a9 6c lda #$6c
987e: 9d a2 06 sta MetatileBuffer+1,x
9881: 60 rts
; -----------------------------------------------------------------------------
; $05 - used to store length of vertical shaft in RenderSidewaysPipe
; $06 - used to store leftover horizontal length in RenderSidewaysPipe and
; vertical length in VerticalPipe and GetPipeHeight
9882: a0 03 IntroPipe ldy #$03 ;check if length set, if not set, set it
9884: 20 af 9b jsr ChkLrgObjFixedLength
9887: a0 0a ldy #$0a ;set fixed value and render the sideways part
9889: 20 b3 98 jsr RenderSidewaysPipe
988c: b0 10 bcs NoBlankP ;if carry flag set, not time to draw vertical pipe part
988e: a2 06 ldx #$06 ;blank everything above the vertical pipe part
9890: a9 00 VPipeSectLoop lda #$00 ; all the way to the top of the screen
9892: 9d a1 06 sta MetatileBuffer,x ; because otherwise it will look like exit pipe
9895: ca dex
9896: 10 f8 bpl VPipeSectLoop
9898: b9 dd 98 lda VerticalPipeData,y ;draw the end of the vertical pipe part
989b: 8d a8 06 sta MetatileBuffer+7
989e: 60 NoBlankP rts
SidePipeShaftData
989f: 15 14 .bulk $15,$14 ;used to control whether or not vertical pipe shaft
98a1: 00 00 .bulk $00,$00 ; is drawn, and if so, controls the metatile number
98a3: 15 1e SidePipeTopPart .bulk $15,$1e ;top part of sideways part of pipe
98a5: 1d 1c .bulk $1d,$1c
SidePipeBottomPart
98a7: 15 21 .bulk $15,$21 ;bottom part of sideways part of pipe
98a9: 20 1f .bulk $20,$1f
98ab: a0 03 ExitPipe ldy #$03 ;check if length set, if not set, set it
98ad: 20 af 9b jsr ChkLrgObjFixedLength
98b0: 20 bb 9b jsr GetLrgObjAttrib ;get vertical length, then plow on through RenderSidewaysPipe
RenderSidewaysPipe
98b3: 88 dey ;decrement twice to make room for shaft at bottom
98b4: 88 dey ; and store here for now as vertical length
98b5: 84 05 sty $05
98b7: bc 30 07 ldy AreaObjectLength,x ;get length left over and store here
98ba: 84 06 sty $06
98bc: a6 05 ldx $05 ;get vertical length plus one, use as buffer offset
98be: e8 inx
98bf: b9 9f 98 lda SidePipeShaftData,y ;check for value $00 based on horizontal offset
98c2: c9 00 cmp #$00
98c4: f0 08 beq DrawSidePart ;if found, do not draw the vertical pipe shaft
98c6: a2 00 ldx #$00
98c8: a4 05 ldy $05 ;init buffer offset and get vertical length
98ca: 20 7d 9b jsr RenderUnderPart ; and render vertical shaft using tile number in A
98cd: 18 clc ;clear carry flag to be used by IntroPipe
98ce: a4 06 DrawSidePart ldy $06 ;render side pipe part at the bottom
98d0: b9 a3 98 lda SidePipeTopPart,y
98d3: 9d a1 06 sta MetatileBuffer,x ;note that the pipe parts are stored
98d6: b9 a7 98 lda SidePipeBottomPart,y ; backwards horizontally
98d9: 9d a2 06 sta MetatileBuffer+1,x
98dc: 60 rts
VerticalPipeData
98dd: 11 10 .bulk $11,$10 ;used by pipes that lead somewhere
98df: 15 14 .bulk $15,$14
98e1: 13 12 .bulk $13,$12 ;used by decoration pipes
98e3: 15 14 .bulk $15,$14
98e5: 20 39 99 VerticalPipe jsr GetPipeHeight
98e8: a5 00 lda $00 ;check to see if value was nullified earlier
98ea: f0 04 beq WarpPipe ;(if d3, the usage control bit of second byte, was set)
98ec: c8 iny
98ed: c8 iny
98ee: c8 iny
98ef: c8 iny ;add four if usage control bit was not set
98f0: 98 WarpPipe tya ;save value in stack
98f1: 48 pha
98f2: ad 60 07 lda AreaNumber
98f5: 0d 5f 07 ora WorldNumber ;if at world 1-1, do not add piranha plant ever
98f8: f0 2b beq DrawPipe
98fa: bc 30 07 ldy AreaObjectLength,x ;if on second column of pipe, branch
98fd: f0 26 beq DrawPipe ;(because we only need to do this once)
98ff: 20 4a 99 jsr FindEmptyEnemySlot ;check for an empty moving data buffer space
9902: b0 21 bcs DrawPipe ;if not found, too many enemies, thus skip
9904: 20 cb 9b jsr GetAreaObjXPosition ;get horizontal pixel coordinate
9907: 18 clc
9908: 69 08 adc #$08 ;add eight to put the piranha plant in the center
990a: 95 87 sta Enemy_X_Position,x ;store as enemy's horizontal coordinate
990c: ad 25 07 lda CurrentPageLoc ;add carry to current page number
990f: 69 00 adc #$00
9911: 95 6e sta Enemy_PageLoc,x ;store as enemy's page coordinate
9913: a9 01 lda #$01
9915: 95 b6 sta Enemy_Y_HighPos,x
9917: 95 0f sta Enemy_Flag,x ;activate enemy flag
9919: 20 d3 9b jsr GetAreaObjYPosition ;get piranha plant's vertical coordinate and store here
991c: 95 cf sta Enemy_Y_Position,x
991e: a9 0d lda #PiranhaPlant ;write piranha plant's value into buffer
9920: 95 16 sta Enemy_ID,x
9922: 20 87 c7 jsr InitPiranhaPlant
9925: 68 DrawPipe pla ;get value saved earlier and use as Y
9926: a8 tay
9927: a6 07 ldx $07 ;get buffer offset
9929: b9 dd 98 lda VerticalPipeData,y ;draw the appropriate pipe with the Y we loaded earlier
992c: 9d a1 06 sta MetatileBuffer,x ;render the top of the pipe
992f: e8 inx
9930: b9 df 98 lda VerticalPipeData+2,y ;render the rest of the pipe
9933: a4 06 ldy $06 ;subtract one from length and render the part underneath
9935: 88 dey
9936: 4c 7d 9b jmp RenderUnderPart
9939: a0 01 GetPipeHeight ldy #$01 ;check for length loaded, if not, load
993b: 20 af 9b jsr ChkLrgObjFixedLength ;pipe length of 2 (horizontal)
993e: 20 bb 9b jsr GetLrgObjAttrib
9941: 98 tya ;get saved lower nybble as height
9942: 29 07 and #$07 ;save only the three lower bits as
9944: 85 06 sta $06 ; vertical length, then load Y with
9946: bc 30 07 ldy AreaObjectLength,x ; length left over
9949: 60 rts
FindEmptyEnemySlot
994a: a2 00 ldx #$00 ;start at first enemy slot
994c: 18 EmptyChkLoop clc ;clear carry flag by default
994d: b5 0f lda Enemy_Flag,x ;check enemy buffer for nonzero
994f: f0 05 beq ExitEmptyChk ;if zero, leave
9951: e8 inx
9952: e0 05 cpx #$05 ;if nonzero, check next value
9954: d0 f6 bne EmptyChkLoop
9956: 60 ExitEmptyChk rts ;if all values nonzero, carry flag is set
; -----------------------------------------------------------------------------
9957: 20 ac 9b Hole_Water jsr ChkLrgObjLength ;get low nybble and save as length
995a: a9 86 lda #$86 ;render waves
995c: 8d ab 06 sta MetatileBuffer+10
995f: a2 0b ldx #$0b
9961: a0 01 ldy #$01 ;now render the water underneath
9963: a9 87 lda #$87
9965: 4c 7d 9b jmp RenderUnderPart
; -----------------------------------------------------------------------------
QuestionBlockRow_High
9968: a9 03 lda #$03 ;start on the fourth row
996a: 2c bit βΌ PseudoRandomBitReg+2 ;BIT instruction opcode
QuestionBlockRow_Low
996b: a9 07 lda #$07 ;start on the eighth row
996d: 48 pha ;save whatever row to the stack for now
996e: 20 ac 9b jsr ChkLrgObjLength ;get low nybble and save as length
9971: 68 pla
9972: aa tax ;render question boxes with coins
9973: a9 c0 lda #$c0
9975: 9d a1 06 sta MetatileBuffer,x
9978: 60 rts
; -----------------------------------------------------------------------------
9979: a9 06 Bridge_High lda #$06 ;start on the seventh row from top of screen
997b: 2c bit βΌ PseudoRandomBitReg+2 ;BIT instruction opcode
997c: a9 07 Bridge_Middle lda #$07 ;start on the eighth row
997e: 2c bit βΌ $09a9 ;BIT instruction opcode
997f: a9 09 Bridge_Low lda #$09 ;start on the tenth row
9981: 48 pha ;save whatever row to the stack for now
9982: 20 ac 9b jsr ChkLrgObjLength ;get low nybble and save as length
9985: 68 pla
9986: aa tax ;render bridge railing
9987: a9 0b lda #$0b
9989: 9d a1 06 sta MetatileBuffer,x
998c: e8 inx
998d: a0 00 ldy #$00 ;now render the bridge itself
998f: a9 63 lda #$63
9991: 4c 7d 9b jmp RenderUnderPart
; -----------------------------------------------------------------------------
FlagBalls_Residual
9994: 20 bb 9b jsr GetLrgObjAttrib ;get low nybble from object byte
9997: a2 02 ldx #$02 ;render flag balls on third row from top
9999: a9 6d lda #$6d ; of screen downwards based on low nybble
999b: 4c 7d 9b jmp RenderUnderPart
; -----------------------------------------------------------------------------
999e: a9 24 FlagpoleObject lda #$24 ;render flagpole ball on top
99a0: 8d a1 06 sta MetatileBuffer
99a3: a2 01 ldx #$01 ;now render the flagpole shaft
99a5: a0 08 ldy #$08
99a7: a9 25 lda #$25
99a9: 20 7d 9b jsr RenderUnderPart
99ac: a9 61 lda #$61 ;render solid block at the bottom
99ae: 8d ab 06 sta MetatileBuffer+10
99b1: 20 cb 9b jsr GetAreaObjXPosition
99b4: 38 sec ;get pixel coordinate of where the flagpole is,
99b5: e9 08 sbc #$08 ; subtract eight pixels and use as horizontal
99b7: 85 8c sta Enemy_X_Position+5 ; coordinate for the flag
99b9: ad 25 07 lda CurrentPageLoc
99bc: e9 00 sbc #$00 ;subtract borrow from page location and use as
99be: 85 73 sta Enemy_PageLoc+5 ; page location for the flag
99c0: a9 30 lda #$30
99c2: 85 d4 sta Enemy_Y_Position+5 ;set vertical coordinate for flag
99c4: a9 b0 lda #$b0
99c6: 8d 0d 01 sta FlagpoleFNum_Y_Pos ;set initial vertical coordinate for flagpole's floatey number
99c9: a9 30 lda #FlagpoleFlagObject
99cb: 85 1b sta Enemy_ID+5 ;set flag identifier, note that identifier and coordinates
99cd: e6 14 inc Enemy_Flag+5 ;use last space in enemy object buffer
99cf: 60 rts
; -----------------------------------------------------------------------------
99d0: a2 00 EndlessRope ldx #$00 ;render rope from the top to the bottom of screen
99d2: a0 0f ldy #$0f
99d4: 4c e9 99 jmp DrawRope
99d7: 8a BalancePlatRope txa ;save object buffer offset for now
99d8: 48 pha
99d9: a2 01 ldx #$01 ;blank out all from second row to the bottom
99db: a0 0f ldy #$0f ; with blank used for balance platform rope
99dd: a9 44 lda #$44
99df: 20 7d 9b jsr RenderUnderPart
99e2: 68 pla ;get back object buffer offset
99e3: aa tax
99e4: 20 bb 9b jsr GetLrgObjAttrib ;get vertical length from lower nybble
99e7: a2 01 ldx #$01
99e9: a9 40 DrawRope lda #$40 ;render the actual rope
99eb: 4c 7d 9b jmp RenderUnderPart
; -----------------------------------------------------------------------------
CoinMetatileData
99ee: c3 c2 c2 c2 .bulk $c3,$c2,$c2,$c2
99f2: ac 4e 07 RowOfCoins ldy AreaType ;get area type
99f5: b9 ee 99 lda CoinMetatileData,y ;load appropriate coin metatile
99f8: 4c 44 9a jmp GetRow
; -----------------------------------------------------------------------------
99fb: 06 07 08 C_ObjectRow .bulk $06,$07,$08
C_ObjectMetatile
99fe: c5 0c 89 .bulk $c5,$0c,$89
9a01: a0 0c CastleBridgeObj ldy #$0c ;load length of 13 columns
9a03: 20 af 9b jsr ChkLrgObjFixedLength
9a06: 4c 0e 9a jmp ChainObj
9a09: a9 08 AxeObj lda #$08 ;load bowser's palette into sprite portion of palette
9a0b: 8d 73 07 sta VRAM_Buffer_AddrCtrl
9a0e: a4 00 ChainObj ldy $00 ;get value loaded earlier from decoder
9a10: be f9 99 ldx C_ObjectRow-2,y ;get appropriate row and metatile for object
9a13: b9 fc 99 lda C_ObjectMetatile-2,y
9a16: 4c 20 9a jmp ColObj
9a19: 20 bb 9b EmptyBlock jsr GetLrgObjAttrib ;get row location
9a1c: a6 07 ldx $07
9a1e: a9 c4 lda #$c4
9a20: a0 00 ColObj ldy #$00 ;column length of 1
9a22: 4c 7d 9b jmp RenderUnderPart
SolidBlockMetatiles
9a25: 69 61 61 62 .bulk $69,$61,$61,$62
9a29: 22 51 52 52 BrickMetatiles .bulk $22,$51,$52,$52
9a2d: 88 .dd1 $88 ;used only by row of bricks object
9a2e: ac 4e 07 RowOfBricks ldy AreaType ;load area type obtained from area offset pointer
9a31: ad 43 07 lda CloudTypeOverride ;check for cloud type override
9a34: f0 02 beq DrawBricks
9a36: a0 04 ldy #$04 ;if cloud type, override area type
9a38: b9 29 9a DrawBricks lda BrickMetatiles,y ;get appropriate metatile
9a3b: 4c 44 9a jmp GetRow ;and go render it
RowOfSolidBlocks
9a3e: ac 4e 07 ldy AreaType ;load area type obtained from area offset pointer
9a41: b9 25 9a lda SolidBlockMetatiles,y ;get metatile
9a44: 48 GetRow pha ;store metatile here
9a45: 20 ac 9b jsr ChkLrgObjLength ;get row number, load length
9a48: a6 07 DrawRow ldx $07
9a4a: a0 00 ldy #$00 ;set vertical height of 1
9a4c: 68 pla
9a4d: 4c 7d 9b jmp RenderUnderPart ;render object
9a50: ac 4e 07 ColumnOfBricks ldy AreaType ;load area type obtained from area offset
9a53: b9 29 9a lda BrickMetatiles,y ;get metatile (no cloud override as for row)
9a56: 4c 5f 9a jmp GetRow2
ColumnOfSolidBlocks
9a59: ac 4e 07 ldy AreaType ;load area type obtained from area offset
9a5c: b9 25 9a lda SolidBlockMetatiles,y ;get metatile
9a5f: 48 GetRow2 pha ;save metatile to stack for now
9a60: 20 bb 9b jsr GetLrgObjAttrib ;get length and row
9a63: 68 pla ;restore metatile
9a64: a6 07 ldx $07 ;get starting row
9a66: 4c 7d 9b jmp RenderUnderPart ;now render the column
; -----------------------------------------------------------------------------
BulletBillCannon
9a69: 20 bb 9b jsr GetLrgObjAttrib ;get row and length of bullet bill cannon
9a6c: a6 07 ldx $07 ;start at first row
9a6e: a9 64 lda #$64 ;render bullet bill cannon
9a70: 9d a1 06 sta MetatileBuffer,x
9a73: e8 inx
9a74: 88 dey ;done yet?
9a75: 30 0e bmi SetupCannon
9a77: a9 65 lda #$65 ;if not, render middle part
9a79: 9d a1 06 sta MetatileBuffer,x
9a7c: e8 inx
9a7d: 88 dey ;done yet?
9a7e: 30 05 bmi SetupCannon
9a80: a9 66 lda #$66 ;if not, render bottom until length expires
9a82: 20 7d 9b jsr RenderUnderPart
9a85: ae 6a 04 SetupCannon ldx Cannon_Offset ;get offset for data used by cannons and whirlpools
9a88: 20 d3 9b jsr GetAreaObjYPosition ;get proper vertical coordinate for cannon
9a8b: 9d 77 04 sta Cannon_Y_Position,x ;and store it here
9a8e: ad 25 07 lda CurrentPageLoc
9a91: 9d 6b 04 sta Cannon_PageLoc,x ;store page number for cannon here
9a94: 20 cb 9b jsr GetAreaObjXPosition ;get proper horizontal coordinate for cannon
9a97: 9d 71 04 sta Cannon_X_Position,x ; and store it here
9a9a: e8 inx
9a9b: e0 06 cpx #$06 ;increment and check offset
9a9d: 90 02 bcc StrCOffset ;if not yet reached sixth cannon, branch to save offset
9a9f: a2 00 ldx #$00 ;otherwise initialize it
9aa1: 8e 6a 04 StrCOffset stx Cannon_Offset ;save new offset and leave
9aa4: 60 rts
; -----------------------------------------------------------------------------
StaircaseHeightData
9aa5: 07 07 06 05+ .bulk $07,$07,$06,$05,$04,$03,$02,$01,$00
StaircaseRowData
9aae: 03 03 04 05+ .bulk $03,$03,$04,$05,$06,$07,$08,$09,$0a
9ab7: 20 ac 9b StaircaseObject jsr ChkLrgObjLength ;check and load length
9aba: 90 05 bcc NextStair ;if length already loaded, skip init part
9abc: a9 09 lda #$09 ;start past the end for the bottom
9abe: 8d 34 07 sta StaircaseControl ; of the staircase
9ac1: ce 34 07 NextStair dec StaircaseControl ;move onto next step (or first if starting)
9ac4: ac 34 07 ldy StaircaseControl
9ac7: be ae 9a ldx StaircaseRowData,y ;get starting row and height to render
9aca: b9 a5 9a lda StaircaseHeightData,y
9acd: a8 tay
9ace: a9 61 lda #$61 ;now render solid block staircase
9ad0: 4c 7d 9b jmp RenderUnderPart
; -----------------------------------------------------------------------------
9ad3: 20 bb 9b JumpSpring jsr GetLrgObjAttrib
9ad6: 20 4a 99 jsr FindEmptyEnemySlot ;find empty space in enemy object buffer
9ad9: 20 cb 9b jsr GetAreaObjXPosition ;get horizontal coordinate for jumpspring
9adc: 95 87 sta Enemy_X_Position,x ;and store
9ade: ad 25 07 lda CurrentPageLoc ;store page location of jumpspring
9ae1: 95 6e sta Enemy_PageLoc,x
9ae3: 20 d3 9b jsr GetAreaObjYPosition ;get vertical coordinate for jumpspring
9ae6: 95 cf sta Enemy_Y_Position,x ;and store
9ae8: 95 58 sta Jumpspring_FixedYPos,x ;store as permanent coordinate here
9aea: a9 32 lda #JumpspringObject
9aec: 95 16 sta Enemy_ID,x ;write jumpspring object to enemy object buffer
9aee: a0 01 ldy #$01
9af0: 94 b6 sty Enemy_Y_HighPos,x ;store vertical high byte
9af2: f6 0f inc Enemy_Flag,x ;set flag for enemy object buffer
9af4: a6 07 ldx $07
9af6: a9 67 lda #$67 ;draw metatiles in two rows where jumpspring is
9af8: 9d a1 06 sta MetatileBuffer,x
9afb: a9 68 lda #$68
9afd: 9d a2 06 sta MetatileBuffer+1,x
9b00: 60 rts
; -----------------------------------------------------------------------------
; $07 - used to save ID of brick object
9b01: ad 5d 07 Hidden1UpBlock lda Hidden1UpFlag ;if flag not set, do not render object
9b04: f0 36 beq ExitDecBlock
9b06: a9 00 lda #$00 ;if set, init for the next one
9b08: 8d 5d 07 sta Hidden1UpFlag
9b0b: 4c 19 9b jmp BrickWithItem ;jump to code shared with unbreakable bricks
9b0e: 20 36 9b QuestionBlock jsr GetAreaObjectID ;get value from level decoder routine
9b11: 4c 2c 9b jmp DrawQBlk ;go to render it
9b14: a9 00 BrickWithCoins lda #$00 ;initialize multi-coin timer flag
9b16: 8d bc 06 sta BrickCoinTimerFlag
9b19: 20 36 9b BrickWithItem jsr GetAreaObjectID ;save area object ID
9b1c: 84 07 sty $07
9b1e: a9 00 lda #$00 ;load default adder for bricks with lines
9b20: ac 4e 07 ldy AreaType ;check level type for ground level
9b23: 88 dey
9b24: f0 02 beq BWithL ;if ground type, do not start with 5
9b26: a9 05 lda #$05 ;otherwise use adder for bricks without lines
9b28: 18 BWithL clc ;add object ID to adder
9b29: 65 07 adc $07
9b2b: a8 tay ;use as offset for metatile
9b2c: b9 e8 bd DrawQBlk lda BrickQBlockMetatiles,y ;get appropriate metatile for brick (question block
9b2f: 48 pha ; if branched to here from question block routine)
9b30: 20 bb 9b jsr GetLrgObjAttrib ;get row from location byte
9b33: 4c 48 9a jmp DrawRow ;now render the object
9b36: a5 00 GetAreaObjectID lda $00 ;get value saved from area parser routine
9b38: 38 sec
9b39: e9 00 sbc #$00 ;possibly residual code
9b3b: a8 tay ;save to Y
9b3c: 60 ExitDecBlock rts
; -----------------------------------------------------------------------------
9b3d: 87 00 00 00 HoleMetatiles .bulk $87,$00,$00,$00
9b41: 20 ac 9b Hole_Empty jsr ChkLrgObjLength ;get lower nybble and save as length
9b44: 90 2d bcc NoWhirlP ;skip this part if length already loaded
9b46: ad 4e 07 lda AreaType ;check for water type level
9b49: d0 28 bne NoWhirlP ;if not water type, skip this part
9b4b: ae 6a 04 ldx Whirlpool_Offset ;get offset for data used by cannons and whirlpools
9b4e: 20 cb 9b jsr GetAreaObjXPosition ;get proper vertical coordinate of where we're at
9b51: 38 sec
9b52: e9 10 sbc #$10 ;subtract 16 pixels
9b54: 9d 71 04 sta Whirlpool_LeftExtent,x ;store as left extent of whirlpool
9b57: ad 25 07 lda CurrentPageLoc ;get page location of where we're at
9b5a: e9 00 sbc #$00 ;subtract borrow
9b5c: 9d 6b 04 sta Whirlpool_PageLoc,x ;save as page location of whirlpool
9b5f: c8 iny
9b60: c8 iny ;increment length by 2
9b61: 98 tya
9b62: 0a asl A ;multiply by 16 to get size of whirlpool
9b63: 0a asl A ;note that whirlpool will always be
9b64: 0a asl A ; two blocks bigger than actual size of hole
9b65: 0a asl A ; and extend one block beyond each edge
9b66: 9d 77 04 sta Whirlpool_Length,x ; save size of whirlpool here
9b69: e8 inx
9b6a: e0 05 cpx #$05 ;increment and check offset
9b6c: 90 02 bcc StrWOffset ;if not yet reached fifth whirlpool, branch to save offset
9b6e: a2 00 ldx #$00 ;otherwise initialize it
9b70: 8e 6a 04 StrWOffset stx Whirlpool_Offset ;save new offset here
9b73: ae 4e 07 NoWhirlP ldx AreaType ;get appropriate metatile, then
9b76: bd 3d 9b lda HoleMetatiles,x ; render the hole proper
9b79: a2 08 ldx #$08
9b7b: a0 0f ldy #$0f ;start at ninth row and go to bottom, run RenderUnderPart
;
9b7d: 8c 35 07 RenderUnderPart sty AreaObjectHeight ;store vertical length to render
9b80: bc a1 06 ldy MetatileBuffer,x ;check current spot to see if there's something
9b83: f0 18 beq DrawThisRow ;we need to keep, if nothing, go ahead
9b85: c0 17 cpy #$17
9b87: f0 17 beq WaitOneRow ;if middle part (tree ledge), wait until next row
9b89: c0 1a cpy #$1a
9b8b: f0 13 beq WaitOneRow ;if middle part (mushroom ledge), wait until next row
9b8d: c0 c0 cpy #$c0
9b8f: f0 0c beq DrawThisRow ;if question block w/ coin, overwrite
9b91: c0 c0 cpy #$c0
9b93: b0 0b bcs WaitOneRow ;if any other metatile with palette 3, wait until next row
9b95: c0 54 cpy #$54
9b97: d0 04 bne DrawThisRow ;if cracked rock terrain, overwrite
9b99: c9 50 cmp #$50
9b9b: f0 03 beq WaitOneRow ;if stem top of mushroom, wait until next row
9b9d: 9d a1 06 DrawThisRow sta MetatileBuffer,x ;render contents of A from routine that called this
9ba0: e8 WaitOneRow inx
9ba1: e0 0d cpx #$0d ;stop rendering if we're at the bottom of the screen
9ba3: b0 06 bcs ExitUPartR
9ba5: ac 35 07 ldy AreaObjectHeight ;decrement, and stop rendering if there is no more length
9ba8: 88 dey
9ba9: 10 d2 bpl RenderUnderPart
9bab: 60 ExitUPartR rts
; -----------------------------------------------------------------------------
9bac: 20 bb 9b ChkLrgObjLength jsr GetLrgObjAttrib ;get row location and size (length if branched to from here)
ChkLrgObjFixedLength
9baf: bd 30 07 lda AreaObjectLength,x ;check for set length counter
9bb2: 18 clc ;clear carry flag for not just starting
9bb3: 10 05 bpl LenSet ;if counter not set, load it, otherwise leave alone
9bb5: 98 tya ;save length into length counter
9bb6: 9d 30 07 sta AreaObjectLength,x
9bb9: 38 sec ;set carry flag if just starting
9bba: 60 LenSet rts
9bbb: bc 2d 07 GetLrgObjAttrib ldy AreaObjOffsetBuffer,x ;get offset saved from area obj decoding routine
9bbe: b1 e7 lda (AreaData),y ;get first byte of level object
9bc0: 29 0f and #%00001111
9bc2: 85 07 sta $07 ;save row location
9bc4: c8 iny
9bc5: b1 e7 lda (AreaData),y ;get next byte, save lower nybble (length or height)
9bc7: 29 0f and #%00001111 ; as Y, then leave
9bc9: a8 tay
9bca: 60 rts
; -----------------------------------------------------------------------------
GetAreaObjXPosition
9bcb: ad 26 07 lda CurrentColumnPos ;multiply current offset where we're at by 16
9bce: 0a asl A ; to obtain horizontal pixel coordinate
9bcf: 0a asl A
9bd0: 0a asl A
9bd1: 0a asl A
9bd2: 60 rts
; -----------------------------------------------------------------------------
GetAreaObjYPosition
9bd3: a5 07 lda $07 ;multiply value by 16
9bd5: 0a asl A
9bd6: 0a asl A ;this will give us the proper vertical pixel coordinate
9bd7: 0a asl A
9bd8: 0a asl A
9bd9: 18 clc
9bda: 69 20 adc #32 ;add 32 pixels for the status bar
9bdc: 60 rts
; -----------------------------------------------------------------------------
; $06-$07 - used to store block buffer address used as indirect
9bdd: 00 BlockBufferAddr .dd1 <Block_Buffer_1
9bde: d0 .dd1 <Block_Buffer_2
9bdf: 05 .dd1 >Block_Buffer_1
9be0: 05 .dd1 >Block_Buffer_2
GetBlockBufferAddr
9be1: 48 pha ;take value of A, save
9be2: 4a lsr A ;move high nybble to low
9be3: 4a lsr A
9be4: 4a lsr A
9be5: 4a lsr A
9be6: a8 tay ;use nybble as pointer to high byte
9be7: b9 df 9b lda BlockBufferAddr+2,y ; of indirect here
9bea: 85 07 sta $07
9bec: 68 pla
9bed: 29 0f and #%00001111 ;pull from stack, mask out high nybble
9bef: 18 clc
9bf0: 79 dd 9b adc BlockBufferAddr,y ;add to low byte
9bf3: 85 06 sta $06 ;store here and leave
9bf5: 60 rts
; -----------------------------------------------------------------------------
; unused space
9bf6: ff .dd1 $ff
9bf7: ff .dd1 $ff
; -----------------------------------------------------------------------------
AreaDataOfsLoopback
9bf8: 12 36 0e 0e+ .bulk $12,$36,$0e,$0e,$0e,$32,$32,$32,$0a,$26,$40
; -----------------------------------------------------------------------------
9c03: 20 13 9c LoadAreaPointer jsr FindAreaPointer ;find it and store it here
9c06: 8d 50 07 sta AreaPointer
9c09: 29 60 GetAreaType and #%01100000 ;mask out all but d6 and d5
9c0b: 0a asl A
9c0c: 2a rol A
9c0d: 2a rol A
9c0e: 2a rol A ;make %0xx00000 into %000000xx
9c0f: 8d 4e 07 sta AreaType ;save 2 MSB as area type
9c12: 60 rts
9c13: ac 5f 07 FindAreaPointer ldy WorldNumber ;load offset from world variable
9c16: b9 b4 9c lda WorldAddrOffsets,y
9c19: 18 clc ;add area number used to find data
9c1a: 6d 60 07 adc AreaNumber
9c1d: a8 tay
9c1e: b9 bc 9c lda AreaAddrOffsets,y ;from there we have our area pointer
9c21: 60 rts
GetAreaDataAddrs
9c22: ad 50 07 lda AreaPointer ;use 2 MSB for Y
9c25: 20 09 9c jsr GetAreaType
9c28: a8 tay
9c29: ad 50 07 lda AreaPointer ;mask out all but 5 LSB
9c2c: 29 1f and #%00011111
9c2e: 8d 4f 07 sta AreaAddrsLOffset ;save as low offset
9c31: b9 e0 9c lda EnemyAddrHOffsets,y ;load base value with 2 altered MSB,
9c34: 18 clc ; then add base value to 5 LSB, result
9c35: 6d 4f 07 adc AreaAddrsLOffset ; becomes offset for level data
9c38: a8 tay
9c39: b9 e4 9c lda EnemyDataAddrLow,y ;use offset to load pointer
9c3c: 85 e9 sta EnemyData
9c3e: b9 06 9d lda EnemyDataAddrHigh,y
9c41: 85 ea sta EnemyData+1
9c43: ac 4e 07 ldy AreaType ;use area type as offset
9c46: b9 28 9d lda AreaDataHOffsets,y ;do the same thing but with different base value
9c49: 18 clc
9c4a: 6d 4f 07 adc AreaAddrsLOffset
9c4d: a8 tay
9c4e: b9 2c 9d lda AreaDataAddrLow,y ;use this offset to load another pointer
9c51: 85 e7 sta AreaData
9c53: b9 4e 9d lda AreaDataAddrHigh,y
9c56: 85 e8 sta AreaData+1
9c58: a0 00 ldy #$00 ;load first byte of header
9c5a: b1 e7 lda (AreaData),y
9c5c: 48 pha ;save it to the stack for now
9c5d: 29 07 and #%00000111 ;save 3 LSB for foreground scenery or bg color control
9c5f: c9 04 cmp #$04
9c61: 90 05 bcc StoreFore
9c63: 8d 44 07 sta BackgroundColorCtrl ;if 4 or greater, save value here as bg color control
9c66: a9 00 lda #$00
9c68: 8d 41 07 StoreFore sta ForegroundScenery ;if less, save value here as foreground scenery
9c6b: 68 pla ;pull byte from stack and push it back
9c6c: 48 pha
9c6d: 29 38 and #%00111000 ;save player entrance control bits
9c6f: 4a lsr A ;shift bits over to LSBs
9c70: 4a lsr A
9c71: 4a lsr A
9c72: 8d 10 07 sta PlayerEntranceCtrl ;save value here as player entrance control
9c75: 68 pla ;pull byte again but do not push it back
9c76: 29 c0 and #%11000000 ;save 2 MSB for game timer setting
9c78: 18 clc
9c79: 2a rol A ;rotate bits over to LSBs
9c7a: 2a rol A
9c7b: 2a rol A
9c7c: 8d 15 07 sta GameTimerSetting ;save value here as game timer setting
9c7f: c8 iny
9c80: b1 e7 lda (AreaData),y ;load second byte of header
9c82: 48 pha ;save to stack
9c83: 29 0f and #%00001111 ;mask out all but lower nybble
9c85: 8d 27 07 sta TerrainControl
9c88: 68 pla ;pull and push byte to copy it to A
9c89: 48 pha
9c8a: 29 30 and #%00110000 ;save 2 MSB for background scenery type
9c8c: 4a lsr A
9c8d: 4a lsr A ;shift bits to LSBs
9c8e: 4a lsr A
9c8f: 4a lsr A
9c90: 8d 42 07 sta BackgroundScenery ;save as background scenery
9c93: 68 pla
9c94: 29 c0 and #%11000000
9c96: 18 clc
9c97: 2a rol A ;rotate bits over to LSBs
9c98: 2a rol A
9c99: 2a rol A
9c9a: c9 03 cmp #%00000011 ;if set to 3, store here
9c9c: d0 05 bne StoreStyle ;and nullify other value
9c9e: 8d 43 07 sta CloudTypeOverride ;otherwise store value in other place
9ca1: a9 00 lda #$00
9ca3: 8d 33 07 StoreStyle sta AreaStyle
9ca6: a5 e7 lda AreaData ;increment area data address by 2 bytes
9ca8: 18 clc
9ca9: 69 02 adc #$02
9cab: 85 e7 sta AreaData
9cad: a5 e8 lda AreaData+1
9caf: 69 00 adc #$00
9cb1: 85 e8 sta AreaData+1
9cb3: 60 rts
; -----------------------------------------------------------------------------
;
; GAME LEVELS DATA
;
WorldAddrOffsets
9cb4: 00 05 0a 0e+ .bulk $00,$05,$0a,$0e,$13,$17,$1b,$20 ;||offsets from AreaAddrOffsets
9cbc: 25 29 c0 26+ AreaAddrOffsets .bulk $25,$29,$c0,$26,$60 ;World1Areas
9cc1: 28 29 01 27+ World2Areas .bulk $28,$29,$01,$27,$62
9cc6: 24 35 20 63 World3Areas .bulk $24,$35,$20,$63
9cca: 22 29 41 2c+ World4Areas .bulk $22,$29,$41,$2c,$61
9ccf: 2a 31 26 62 World5Areas .bulk $2a,$31,$26,$62
9cd3: 2e 23 2d 60 World6Areas .bulk $2e,$23,$2d,$60
9cd7: 33 29 01 27+ World7Areas .bulk $33,$29,$01,$27,$64
9cdc: 30 32 21 65 World8Areas .bulk $30,$32,$21,$65
;
; bonus area data offsets, included here for comparison purposes
;
; underground bonus area - c2
; cloud area 1 (day) - 2b
; cloud area 2 (night) - 34
; water area (5-2/6-2) - 00
; water area (8-4) - 02
; warp zone area (4-2) - 2f
EnemyAddrHOffsets
9ce0: 1f 06 1c 00 .bulk $1f,$06,$1c,$00
EnemyDataAddrLow
9ce4: 70 .dd1 <E_CastleArea1
9ce5: 97 .dd1 <E_CastleArea2
9ce6: b0 .dd1 <E_CastleArea3
9ce7: df .dd1 <E_CastleArea4
9ce8: 0a .dd1 <E_CastleArea5
9ce9: 1f .dd1 <E_CastleArea6
9cea: 59 .dd1 <E_GroundArea1
9ceb: 7e .dd1 <E_GroundArea2
9cec: 9b .dd1 <E_GroundArea3
9ced: a9 .dd1 <E_GroundArea4
9cee: d0 .dd1 <E_GroundArea5
9cef: 01 .dd1 <E_GroundArea6
9cf0: 1f .dd1 <E_GroundArea7
9cf1: 3c .dd1 <E_GroundArea8
9cf2: 51 .dd1 <E_GroundArea9
9cf3: 7b .dd1 <E_GroundArea10
9cf4: 7c .dd1 <E_GroundArea11
9cf5: a0 .dd1 <E_GroundArea12
9cf6: a9 .dd1 <E_GroundArea13
9cf7: ce .dd1 <E_GroundArea14
9cf8: f1 .dd1 <E_GroundArea15
9cf9: fa .dd1 <E_GroundArea16
9cfa: fb .dd1 <E_GroundArea17
9cfb: 35 .dd1 <E_GroundArea18
9cfc: 60 .dd1 <E_GroundArea19
9cfd: 8e .dd1 <E_GroundArea20
9cfe: aa .dd1 <E_GroundArea21
9cff: b3 .dd1 <E_GroundArea22
9d00: d8 .dd1 <E_UndergroundArea1
9d01: 05 .dd1 <E_UndergroundArea2
9d02: 33 .dd1 <E_UndergroundArea3
9d03: 60 .dd1 <E_WaterArea1
9d04: 71 .dd1 <E_WaterArea2
9d05: 9b .dd1 <E_WaterArea3
EnemyDataAddrHigh
9d06: 9d .dd1 >E_CastleArea1
9d07: 9d .dd1 >E_CastleArea2
9d08: 9d .dd1 >E_CastleArea3
9d09: 9d .dd1 >E_CastleArea4
9d0a: 9e .dd1 >E_CastleArea5
9d0b: 9e .dd1 >E_CastleArea6
9d0c: 9e .dd1 >E_GroundArea1
9d0d: 9e .dd1 >E_GroundArea2
9d0e: 9e .dd1 >E_GroundArea3
9d0f: 9e .dd1 >E_GroundArea4
9d10: 9e .dd1 >E_GroundArea5
9d11: 9f .dd1 >E_GroundArea6
9d12: 9f .dd1 >E_GroundArea7
9d13: 9f .dd1 >E_GroundArea8
9d14: 9f .dd1 >E_GroundArea9
9d15: 9f .dd1 >E_GroundArea10
9d16: 9f .dd1 >E_GroundArea11
9d17: 9f .dd1 >E_GroundArea12
9d18: 9f .dd1 >E_GroundArea13
9d19: 9f .dd1 >E_GroundArea14
9d1a: 9f .dd1 >E_GroundArea15
9d1b: 9f .dd1 >E_GroundArea16
9d1c: 9f .dd1 >E_GroundArea17
9d1d: a0 .dd1 >E_GroundArea18
9d1e: a0 .dd1 >E_GroundArea19
9d1f: a0 .dd1 >E_GroundArea20
9d20: a0 .dd1 >E_GroundArea21
9d21: a0 .dd1 >E_GroundArea22
9d22: a0 .dd1 >E_UndergroundArea1
9d23: a1 .dd1 >E_UndergroundArea2
9d24: a1 .dd1 >E_UndergroundArea3
9d25: a1 .dd1 >E_WaterArea1
9d26: a1 .dd1 >E_WaterArea2
9d27: a1 .dd1 >E_WaterArea3
AreaDataHOffsets
9d28: 00 03 19 1c .bulk $00,$03,$19,$1c
9d2c: 06 AreaDataAddrLow .dd1 <L_WaterArea1
9d2d: 45 .dd1 <L_WaterArea2
9d2e: c0 .dd1 <L_WaterArea3
9d2f: 6b .dd1 <L_GroundArea1
9d30: ce .dd1 <L_GroundArea2
9d31: 37 .dd1 <L_GroundArea3
9d32: 8a .dd1 <L_GroundArea4
9d33: 19 .dd1 <L_GroundArea5
9d34: 8e .dd1 <L_GroundArea6
9d35: f3 .dd1 <L_GroundArea7
9d36: 48 .dd1 <L_GroundArea8
9d37: cd .dd1 <L_GroundArea9
9d38: 32 .dd1 <L_GroundArea10
9d39: 3b .dd1 <L_GroundArea11
9d3a: 7a .dd1 <L_GroundArea12
9d3b: 8f .dd1 <L_GroundArea13
9d3c: f6 .dd1 <L_GroundArea14
9d3d: 5b .dd1 <L_GroundArea15
9d3e: ce .dd1 <L_GroundArea16
9d3f: ff .dd1 <L_GroundArea17
9d40: 92 .dd1 <L_GroundArea18
9d41: 05 .dd1 <L_GroundArea19
9d42: 7e .dd1 <L_GroundArea20
9d43: d7 .dd1 <L_GroundArea21
9d44: 02 .dd1 <L_GroundArea22
9d45: 35 .dd1 <L_UndergroundArea1
9d46: d8 .dd1 <L_UndergroundArea2
9d47: 79 .dd1 <L_UndergroundArea3
9d48: af .dd1 <L_CastleArea1
9d49: 10 .dd1 <L_CastleArea2
9d4a: 8f .dd1 <L_CastleArea3
9d4b: 02 .dd1 <L_CastleArea4
9d4c: 6f .dd1 <L_CastleArea5
9d4d: fa .dd1 <L_CastleArea6
AreaDataAddrHigh
9d4e: ae .dd1 >L_WaterArea1
9d4f: ae .dd1 >L_WaterArea2
9d50: ae .dd1 >L_WaterArea3
9d51: a4 .dd1 >L_GroundArea1
9d52: a4 .dd1 >L_GroundArea2
9d53: a5 .dd1 >L_GroundArea3
9d54: a5 .dd1 >L_GroundArea4
9d55: a6 .dd1 >L_GroundArea5
9d56: a6 .dd1 >L_GroundArea6
9d57: a6 .dd1 >L_GroundArea7
9d58: a7 .dd1 >L_GroundArea8
9d59: a7 .dd1 >L_GroundArea9
9d5a: a8 .dd1 >L_GroundArea10
9d5b: a8 .dd1 >L_GroundArea11
9d5c: a8 .dd1 >L_GroundArea12
9d5d: a8 .dd1 >L_GroundArea13
9d5e: a8 .dd1 >L_GroundArea14
9d5f: a9 .dd1 >L_GroundArea15
9d60: a9 .dd1 >L_GroundArea16
9d61: a9 .dd1 >L_GroundArea17
9d62: aa .dd1 >L_GroundArea18
9d63: ab .dd1 >L_GroundArea19
9d64: ab .dd1 >L_GroundArea20
9d65: ab .dd1 >L_GroundArea21
9d66: ac .dd1 >L_GroundArea22
9d67: ac .dd1 >L_UndergroundArea1
9d68: ac .dd1 >L_UndergroundArea2
9d69: ad .dd1 >L_UndergroundArea3
9d6a: a1 .dd1 >L_CastleArea1
9d6b: a2 .dd1 >L_CastleArea2
9d6c: a2 .dd1 >L_CastleArea3
9d6d: a3 .dd1 >L_CastleArea4
9d6e: a3 .dd1 >L_CastleArea5
9d6f: a3 .dd1 >L_CastleArea6
;
; ENEMY OBJECT DATA
;
; level 1-4/6-4
9d70: 76 dd bb 4c+ E_CastleArea1 .bulk $76,$dd,$bb,$4c,$ea,$1d,$1b,$cc,$56,$5d,$16,$9d,$c6,$1d,$36,$9d
+ $c9,$1d,$04,$db,$49,$1d,$84,$1b,$c9,$5d,$88,$95,$0f,$08,$30,$4c
+ $78,$2d,$a6,$28,$90,$b5
9d96: ff .dd1 $ff
; level 4-4
9d97: 0f 03 56 1b+ E_CastleArea2 .bulk $0f,$03,$56,$1b,$c9,$1b,$0f,$07,$36,$1b,$aa,$1b,$48,$95,$0f,$0a
+ $2a,$1b,$5b,$0c,$78,$2d,$90,$b5
9daf: ff .dd1 $ff
; level 2-4/5-4
9db0: 0b 8c 4b 4c+ E_CastleArea3 .bulk $0b,$8c,$4b,$4c,$77,$5f,$eb,$0c,$bd,$db,$19,$9d,$75,$1d,$7d,$5b
+ $d9,$1d,$3d,$dd,$99,$1d,$26,$9d,$5a,$2b,$8a,$2c,$ca,$1b,$20,$95
+ $7b,$5c,$db,$4c,$1b,$cc,$3b,$cc,$78,$2d,$a6,$28,$90,$b5
9dde: ff .dd1 $ff
; level 3-4
9ddf: 0b 8c 3b 1d+ E_CastleArea4 .bulk $0b,$8c,$3b,$1d,$8b,$1d,$ab,$0c,$db,$1d,$0f,$03,$65,$1d,$6b,$1b
+ $05,$9d,$0b,$1b,$05,$9b,$0b,$1d,$8b,$0c,$1b,$8c,$70,$15,$7b,$0c
+ $db,$0c,$0f,$08,$78,$2d,$a6,$28,$90,$b5
9e09: ff .dd1 $ff
; level 7-4
9e0a: 27 a9 4b 0c+ E_CastleArea5 .bulk $27,$a9,$4b,$0c,$68,$29,$0f,$06,$77,$1b,$0f,$0b,$60,$15,$4b,$8c
+ $78,$2d,$90,$b5
9e1e: ff .dd1 $ff
; level 8-4
9e1f: 0f 03 8e 65+ E_CastleArea6 .bulk $0f,$03,$8e,$65,$e1,$bb,$38,$6d,$a8,$3e,$e5,$e7,$0f,$08,$0b,$02
+ $2b,$02,$5e,$65,$e1,$bb,$0e,$db,$0e,$bb,$8e,$db,$0e,$fe,$65,$ec
+ $0f,$0d,$4e,$65,$e1,$0f,$0e,$4e,$02,$e0,$0f,$10,$fe,$e5,$e1,$1b
+ $85,$7b,$0c,$5b,$95,$78,$2d,$90,$b5
9e58: ff .dd1 $ff
; level 3-3
9e59: a5 86 e4 28+ E_GroundArea1 .bulk $a5,$86,$e4,$28,$18,$a8,$45,$83,$69,$03,$c6,$29,$9b,$83,$16,$a4
+ $88,$24,$e9,$28,$05,$a8,$7b,$28,$24,$8f,$c8,$03,$e8,$03,$46,$a8
+ $85,$24,$c8,$24
9e7d: ff .dd1 $ff
; level 8-3
9e7e: eb 8e 0f 03+ E_GroundArea2 .bulk $eb,$8e,$0f,$03,$fb,$05,$17,$85,$db,$8e,$0f,$07,$57,$05,$7b,$05
+ $9b,$80,$2b,$85,$fb,$05,$0f,$0b,$1b,$05,$9b,$05
9e9a: ff .dd1 $ff
; level 4-1
9e9b: 2e c2 66 e2+ E_GroundArea3 .bulk $2e,$c2,$66,$e2,$11,$0f,$07,$02,$11,$0f,$0c,$12,$11
9ea8: ff .dd1 $ff
; level 6-2
9ea9: 0e c2 a8 ab+ E_GroundArea4 .bulk $0e,$c2,$a8,$ab,$00,$bb,$8e,$6b,$82,$de,$00,$a0,$33,$86,$43,$06
+ $3e,$b4,$a0,$cb,$02,$0f,$07,$7e,$42,$a6,$83,$02,$0f,$0a,$3b,$02
+ $cb,$37,$0f,$0c,$e3,$0e
9ecf: ff .dd1 $ff
; level 3-1
9ed0: 9b 8e ca 0e+ E_GroundArea5 .bulk $9b,$8e,$ca,$0e,$ee,$42,$44,$5b,$86,$80,$b8,$1b,$80,$50,$ba,$10
+ $b7,$5b,$00,$17,$85,$4b,$05,$fe,$34,$40,$b7,$86,$c6,$06,$5b,$80
+ $83,$00,$d0,$38,$5b,$8e,$8a,$0e,$a6,$00,$bb,$0e,$c5,$80,$f3,$00
9f00: ff .dd1 $ff
; level 1-1
9f01: 1e c2 00 6b+ E_GroundArea6 .bulk $1e,$c2,$00,$6b,$06,$8b,$86,$63,$b7,$0f,$05,$03,$06,$23,$06,$4b
+ $b7,$bb,$00,$5b,$b7,$fb,$37,$3b,$b7,$0f,$0b,$1b,$37
9f1e: ff .dd1 $ff
; level 1-3/5-3
9f1f: 2b d7 e3 03+ E_GroundArea7 .bulk $2b,$d7,$e3,$03,$c2,$86,$e2,$06,$76,$a5,$a3,$8f,$03,$86,$2b,$57
+ $68,$28,$e9,$28,$e5,$83,$24,$8f,$36,$a8,$5b,$03
9f3b: ff .dd1 $ff
; level 2-3/7-3
9f3c: 0f 02 78 40+ E_GroundArea8 .bulk $0f,$02,$78,$40,$48,$ce,$f8,$c3,$f8,$c3,$0f,$07,$7b,$43,$c6,$d0
+ $0f,$8a,$c8,$50
9f50: ff .dd1 $ff
; level 2-1
9f51: 85 86 0b 80+ E_GroundArea9 .bulk $85,$86,$0b,$80,$1b,$00,$db,$37,$77,$80,$eb,$37,$fe,$2b,$20,$2b
+ $80,$7b,$38,$ab,$b8,$77,$86,$fe,$42,$20,$49,$86,$8b,$06,$9b,$80
+ $7b,$8e,$5b,$b7,$9b,$0e,$bb,$0e,$9b,$80
; end of data terminator here is also used by pipe intro area
9f7b: ff E_GroundArea10 .dd1 $ff
; level 5-1
9f7c: 0b 80 60 38+ E_GroundArea11 .bulk $0b,$80,$60,$38,$10,$b8,$c0,$3b,$db,$8e,$40,$b8,$f0,$38,$7b,$8e
+ $a0,$b8,$c0,$b8,$fb,$00,$a0,$b8,$30,$bb,$ee,$42,$88,$0f,$0b,$2b
+ $0e,$67,$0e
9f9f: ff .dd1 $ff
; cloud level used in levels 2-1 and 5-2
9fa0: 0a aa 0e 28+ E_GroundArea12 .bulk $0a,$aa,$0e,$28,$2a,$0e,$31,$88
9fa8: ff .dd1 $ff
; level 4-3
9fa9: c7 83 d7 03+ E_GroundArea13 .bulk $c7,$83,$d7,$03,$42,$8f,$7a,$03,$05,$a4,$78,$24,$a6,$25,$e4,$25
+ $4b,$83,$e3,$03,$05,$a4,$89,$24,$b5,$24,$09,$a4,$65,$24,$c9,$24
+ $0f,$08,$85,$25
9fcd: ff .dd1 $ff
; level 6-3
9fce: cd a5 b5 a8+ E_GroundArea14 .bulk $cd,$a5,$b5,$a8,$07,$a8,$76,$28,$cc,$25,$65,$a4,$a9,$24,$e5,$24
+ $19,$a4,$0f,$07,$95,$28,$e6,$24,$19,$a4,$d7,$29,$16,$a9,$58,$29
+ $97,$29
9ff0: ff .dd1 $ff
; level 6-1
9ff1: 0f 02 02 11+ E_GroundArea15 .bulk $0f,$02,$02,$11,$0f,$07,$02,$11
9ff9: ff .dd1 $ff
; warp zone area used in level 4-2
9ffa: ff E_GroundArea16 .dd1 $ff
; level 8-1
9ffb: 2b 82 ab 38+ E_GroundArea17 .bulk $2b,$82,$ab,$38,$de,$42,$e2,$1b,$b8,$eb,$3b,$db,$80,$8b,$b8,$1b
+ $82,$fb,$b8,$7b,$80,$fb,$3c,$5b,$bc,$7b,$b8,$1b,$8e,$cb,$0e,$1b
+ $8e,$0f,$0d,$2b,$3b,$bb,$b8,$eb,$82,$4b,$b8,$bb,$38,$3b,$b7,$bb
+ $02,$0f,$13,$1b,$00,$cb,$80,$6b,$bc
a034: ff .dd1 $ff
; level 5-2
a035: 7b 80 ae 00+ E_GroundArea18 .bulk $7b,$80,$ae,$00,$80,$8b,$8e,$e8,$05,$f9,$86,$17,$86,$16,$85,$4e
+ $2b,$80,$ab,$8e,$87,$85,$c3,$05,$8b,$82,$9b,$02,$ab,$02,$bb,$86
+ $cb,$06,$d3,$03,$3b,$8e,$6b,$0e,$a7,$8e
a05f: ff .dd1 $ff
; level 8-2
a060: 29 8e 52 11+ E_GroundArea19 .bulk $29,$8e,$52,$11,$83,$0e,$0f,$03,$9b,$0e,$2b,$8e,$5b,$0e,$cb,$8e
+ $fb,$0e,$fb,$82,$9b,$82,$bb,$02,$fe,$42,$e8,$bb,$8e,$0f,$0a,$ab
+ $0e,$cb,$0e,$f9,$0e,$88,$86,$a6,$06,$db,$02,$b6,$8e
a08d: ff .dd1 $ff
; level 7-1
a08e: ab ce de 42+ E_GroundArea20 .bulk $ab,$ce,$de,$42,$c0,$cb,$ce,$5b,$8e,$1b,$ce,$4b,$85,$67,$45,$0f
+ $07,$2b,$00,$7b,$85,$97,$05,$0f,$0a,$92,$02
a0a9: ff .dd1 $ff
; cloud level used in levels 3-1 and 6-2
a0aa: 0a aa 0e 24+ E_GroundArea21 .bulk $0a,$aa,$0e,$24,$4a,$1e,$23,$aa
a0b2: ff .dd1 $ff
; level 3-2
a0b3: 1b 80 bb 38+ E_GroundArea22 .bulk $1b,$80,$bb,$38,$4b,$bc,$eb,$3b,$0f,$04,$2b,$00,$ab,$38,$eb,$00
+ $cb,$8e,$fb,$80,$ab,$b8,$6b,$80,$fb,$3c,$9b,$bb,$5b,$bc,$fb,$00
+ $6b,$b8,$fb,$38
a0d7: ff .dd1 $ff
; level 1-2
E_UndergroundArea1
a0d8: 0b 86 1a 06+ .bulk $0b,$86,$1a,$06,$db,$06,$de,$c2,$02,$f0,$3b,$bb,$80,$eb,$06,$0b
+ $86,$93,$06,$f0,$39,$0f,$06,$60,$b8,$1b,$86,$a0,$b9,$b7,$27,$bd
+ $27,$2b,$83,$a1,$26,$a9,$26,$ee,$25,$0b,$27,$b4
a104: ff .dd1 $ff
; level 4-2
E_UndergroundArea2
a105: 0f 02 1e 2f+ .bulk $0f,$02,$1e,$2f,$60,$e0,$3a,$a5,$a7,$db,$80,$3b,$82,$8b,$02,$fe
+ $42,$68,$70,$bb,$25,$a7,$2c,$27,$b2,$26,$b9,$26,$9b,$80,$a8,$82
+ $b5,$27,$bc,$27,$b0,$bb,$3b,$82,$87,$34,$ee,$25,$6b
a132: ff .dd1 $ff
; underground bonus rooms area used in many levels
E_UndergroundArea3
a133: 1e a5 0a 2e+ .bulk $1e,$a5,$0a,$2e,$28,$27,$2e,$33,$c7,$0f,$03,$1e,$40,$07,$2e,$30
+ $e7,$0f,$05,$1e,$24,$44,$0f,$07,$1e,$22,$6a,$2e,$23,$ab,$0f,$09
+ $1e,$41,$68,$1e,$2a,$8a,$2e,$23,$a2,$2e,$32,$ea
a15f: ff .dd1 $ff
; water area used in levels 5-2 and 6-2
a160: 3b 87 66 27+ E_WaterArea1 .bulk $3b,$87,$66,$27,$cc,$27,$ee,$31,$87,$ee,$23,$a7,$3b,$87,$db,$07
a170: ff .dd1 $ff
; level 2-2/7-2
a171: 0f 01 2e 25+ E_WaterArea2 .bulk $0f,$01,$2e,$25,$2b,$2e,$25,$4b,$4e,$25,$cb,$6b,$07,$97,$47,$e9
+ $87,$47,$c7,$7a,$07,$d6,$c7,$78,$07,$38,$87,$ab,$47,$e3,$07,$9b
+ $87,$0f,$09,$68,$47,$db,$c7,$3b,$c7
a19a: ff .dd1 $ff
; water area used in level 8-4
a19b: 47 9b cb 07+ E_WaterArea3 .bulk $47,$9b,$cb,$07,$fa,$1d,$86,$9b,$3a,$87,$56,$07,$88,$1b,$07,$9d
+ $2e,$65,$f0
a1ae: ff .dd1 $ff
;
; AREA OBJECT DATA
;
; level 1-4/6-4
a1af: 9b 07 L_CastleArea1 .bulk $9b,$07
a1b1: 05 32 06 33+ .bulk $05,$32,$06,$33,$07,$34,$ce,$03,$dc,$51,$ee,$07,$73,$e0,$74,$0a
+ $7e,$06,$9e,$0a,$ce,$06,$e4,$00,$e8,$0a,$fe,$0a,$2e,$89,$4e,$0b
+ $54,$0a,$14,$8a,$c4,$0a,$34,$8a,$7e,$06,$c7,$0a,$01,$e0,$02,$0a
+ $47,$0a,$81,$60,$82,$0a,$c7,$0a,$0e,$87,$7e,$02,$a7,$02,$b3,$02
+ $d7,$02,$e3,$02,$07,$82,$13,$02,$3e,$06,$7e,$02,$ae,$07,$fe,$0a
+ $0d,$c4,$cd,$43,$ce,$09,$de,$0b,$dd,$42,$fe,$02,$5d,$c7
a20f: fd .dd1 $fd
; level 4-4
a210: 5b 07 L_CastleArea2 .bulk $5b,$07
a212: 05 32 06 33+ .bulk $05,$32,$06,$33,$07,$34,$5e,$0a,$68,$64,$98,$64,$a8,$64,$ce,$06
+ $fe,$02,$0d,$01,$1e,$0e,$7e,$02,$94,$63,$b4,$63,$d4,$63,$f4,$63
+ $14,$e3,$2e,$0e,$5e,$02,$64,$35,$88,$72,$be,$0e,$0d,$04,$ae,$02
+ $ce,$08,$cd,$4b,$fe,$02,$0d,$05,$68,$31,$7e,$0a,$96,$31,$a9,$63
+ $a8,$33,$d5,$30,$ee,$02,$e6,$62,$f4,$61,$04,$b1,$08,$3f,$44,$33
+ $94,$63,$a4,$31,$e4,$31,$04,$bf,$08,$3f,$04,$bf,$08,$3f,$cd,$4b
+ $03,$e4,$0e,$03,$2e,$01,$7e,$06,$be,$02,$de,$06,$fe,$0a,$0d,$c4
+ $cd,$43,$ce,$09,$de,$0b,$dd,$42,$fe,$02,$5d,$c7
a28e: fd .dd1 $fd
; level 2-4/5-4
a28f: 9b 07 L_CastleArea3 .bulk $9b,$07
a291: 05 32 06 33+ .bulk $05,$32,$06,$33,$07,$34,$fe,$00,$27,$b1,$65,$32,$75,$0a,$71,$00
+ $b7,$31,$08,$e4,$18,$64,$1e,$04,$57,$3b,$bb,$0a,$17,$8a,$27,$3a
+ $73,$0a,$7b,$0a,$d7,$0a,$e7,$3a,$3b,$8a,$97,$0a,$fe,$08,$24,$8a
+ $2e,$00,$3e,$40,$38,$64,$6f,$00,$9f,$00,$be,$43,$c8,$0a,$c9,$63
+ $ce,$07,$fe,$07,$2e,$81,$66,$42,$6a,$42,$79,$0a,$be,$00,$c8,$64
+ $f8,$64,$08,$e4,$2e,$07,$7e,$03,$9e,$07,$be,$03,$de,$07,$fe,$0a
+ $03,$a5,$0d,$44,$cd,$43,$ce,$09,$dd,$42,$de,$0b,$fe,$02,$5d,$c7
a301: fd .dd1 $fd
; level 3-4
a302: 9b 07 L_CastleArea4 .bulk $9b,$07
a304: 05 32 06 33+ .bulk $05,$32,$06,$33,$07,$34,$fe,$06,$0c,$81,$39,$0a,$5c,$01,$89,$0a
+ $ac,$01,$d9,$0a,$fc,$01,$2e,$83,$a7,$01,$b7,$00,$c7,$01,$de,$0a
+ $fe,$02,$4e,$83,$5a,$32,$63,$0a,$69,$0a,$7e,$02,$ee,$03,$fa,$32
+ $03,$8a,$09,$0a,$1e,$02,$ee,$03,$fa,$32,$03,$8a,$09,$0a,$14,$42
+ $1e,$02,$7e,$0a,$9e,$07,$fe,$0a,$2e,$86,$5e,$0a,$8e,$06,$be,$0a
+ $ee,$07,$3e,$83,$5e,$07,$fe,$0a,$0d,$c4,$41,$52,$51,$52,$cd,$43
+ $ce,$09,$de,$0b,$dd,$42,$fe,$02,$5d,$c7
a36e: fd .dd1 $fd
; level 7-4
a36f: 5b 07 L_CastleArea5 .bulk $5b,$07
a371: 05 32 06 33+ .bulk $05,$32,$06,$33,$07,$34,$fe,$0a,$ae,$86,$be,$07,$fe,$02,$0d,$02
+ $27,$32,$46,$61,$55,$62,$5e,$0e,$1e,$82,$68,$3c,$74,$3a,$7d,$4b
+ $5e,$8e,$7d,$4b,$7e,$82,$84,$62,$94,$61,$a4,$31,$bd,$4b,$ce,$06
+ $fe,$02,$0d,$06,$34,$31,$3e,$0a,$64,$32,$75,$0a,$7b,$61,$a4,$33
+ $ae,$02,$de,$0e,$3e,$82,$64,$32,$78,$32,$b4,$36,$c8,$36,$dd,$4b
+ $44,$b2,$58,$32,$94,$63,$a4,$3e,$ba,$30,$c9,$61,$ce,$06,$dd,$4b
+ $ce,$86,$dd,$4b,$fe,$02,$2e,$86,$5e,$02,$7e,$06,$fe,$02,$1e,$86
+ $3e,$02,$5e,$06,$7e,$02,$9e,$06,$fe,$0a,$0d,$c4,$cd,$43,$ce,$09
+ $de,$0b,$dd,$42,$fe,$02,$5d,$c7
a3f9: fd .dd1 $fd
; level 8-4
a3fa: 5b 06 L_CastleArea6 .bulk $5b,$06
a3fc: 05 32 06 33+ .bulk $05,$32,$06,$33,$07,$34,$5e,$0a,$ae,$02,$0d,$01,$39,$73,$0d,$03
+ $39,$7b,$4d,$4b,$de,$06,$1e,$8a,$ae,$06,$c4,$33,$16,$fe,$a5,$77
+ $fe,$02,$fe,$82,$0d,$07,$39,$73,$a8,$74,$ed,$4b,$49,$fb,$e8,$74
+ $fe,$0a,$2e,$82,$67,$02,$84,$7a,$87,$31,$0d,$0b,$fe,$02,$0d,$0c
+ $39,$73,$5e,$06,$c6,$76,$45,$ff,$be,$0a,$dd,$48,$fe,$06,$3d,$cb
+ $46,$7e,$ad,$4a,$fe,$82,$39,$f3,$a9,$7b,$4e,$8a,$9e,$07,$fe,$0a
+ $0d,$c4,$cd,$43,$ce,$09,$de,$0b,$dd,$42,$fe,$02,$5d,$c7
a46a: fd .dd1 $fd
; level 3-3
a46b: 94 11 L_GroundArea1 .bulk $94,$11
a46d: 0f 26 fe 10+ .bulk $0f,$26,$fe,$10,$28,$94,$65,$15,$eb,$12,$fa,$41,$4a,$96,$54,$40
+ $a4,$42,$b7,$13,$e9,$19,$f5,$15,$11,$80,$47,$42,$71,$13,$80,$41
+ $15,$92,$1b,$1f,$24,$40,$55,$12,$64,$40,$95,$12,$a4,$40,$d2,$12
+ $e1,$40,$13,$c0,$2c,$17,$2f,$12,$49,$13,$83,$40,$9f,$14,$a3,$40
+ $17,$92,$83,$13,$92,$41,$b9,$14,$c5,$12,$c8,$40,$d4,$40,$4b,$92
+ $78,$1b,$9c,$94,$9f,$11,$df,$14,$fe,$11,$7d,$c1,$9e,$42,$cf,$20
a4cd: fd .dd1 $fd
; level 8-3
a4ce: 90 b1 L_GroundArea2 .bulk $90,$b1
a4d0: 0f 26 29 91+ .bulk $0f,$26,$29,$91,$7e,$42,$fe,$40,$28,$92,$4e,$42,$2e,$c0,$57,$73
+ $c3,$25,$c7,$27,$23,$84,$33,$20,$5c,$01,$77,$63,$88,$62,$99,$61
+ $aa,$60,$bc,$01,$ee,$42,$4e,$c0,$69,$11,$7e,$42,$de,$40,$f8,$62
+ $0e,$c2,$ae,$40,$d7,$63,$e7,$63,$33,$a7,$37,$27,$43,$04,$cc,$01
+ $e7,$73,$0c,$81,$3e,$42,$0d,$0a,$5e,$40,$88,$72,$be,$42,$e7,$87
+ $fe,$40,$39,$e1,$4e,$00,$69,$60,$87,$60,$a5,$60,$c3,$31,$fe,$31
+ $6d,$c1,$be,$42,$ef,$20
a536: fd .dd1 $fd
; level 4-1
a537: 52 21 L_GroundArea3 .bulk $52,$21
a539: 0f 20 6e 40+ .bulk $0f,$20,$6e,$40,$58,$f2,$93,$01,$97,$00,$0c,$81,$97,$40,$a6,$41
+ $c7,$40,$0d,$04,$03,$01,$07,$01,$23,$01,$27,$01,$ec,$03,$ac,$f3
+ $c3,$03,$78,$e2,$94,$43,$47,$f3,$74,$43,$47,$fb,$74,$43,$2c,$f1
+ $4c,$63,$47,$00,$57,$21,$5c,$01,$7c,$72,$39,$f1,$ec,$02,$4c,$81
+ $d8,$62,$ec,$01,$0d,$0d,$0f,$38,$c7,$07,$ed,$4a,$1d,$c1,$5f,$26
a589: fd .dd1 $fd
; level 6-2
a58a: 54 21 L_GroundArea4 .bulk $54,$21
a58c: 0f 26 a7 22+ .bulk $0f,$26,$a7,$22,$37,$fb,$73,$20,$83,$07,$87,$02,$93,$20,$c7,$73
+ $04,$f1,$06,$31,$39,$71,$59,$71,$e7,$73,$37,$a0,$47,$04,$86,$7c
+ $e5,$71,$e7,$31,$33,$a4,$39,$71,$a9,$71,$d3,$23,$08,$f2,$13,$05
+ $27,$02,$49,$71,$75,$75,$e8,$72,$67,$f3,$99,$71,$e7,$20,$f4,$72
+ $f7,$31,$17,$a0,$33,$20,$39,$71,$73,$28,$bc,$05,$39,$f1,$79,$71
+ $a6,$21,$c3,$06,$d3,$20,$dc,$00,$fc,$00,$07,$a2,$13,$21,$5f,$32
+ $8c,$00,$98,$7a,$c7,$63,$d9,$61,$03,$a2,$07,$22,$74,$72,$77,$31
+ $e7,$73,$39,$f1,$58,$72,$77,$73,$d8,$72,$7f,$b1,$97,$73,$b6,$64
+ $c5,$65,$d4,$66,$e3,$67,$f3,$67,$8d,$c1,$cf,$26
a618: fd .dd1 $fd
; level 3-1
a619: 52 31 L_GroundArea5 .bulk $52,$31
a61b: 0f 20 6e 66+ .bulk $0f,$20,$6e,$66,$07,$81,$36,$01,$66,$00,$a7,$22,$08,$f2,$67,$7b
+ $dc,$02,$98,$f2,$d7,$20,$39,$f1,$9f,$33,$dc,$27,$dc,$57,$23,$83
+ $57,$63,$6c,$51,$87,$63,$99,$61,$a3,$06,$b3,$21,$77,$f3,$f3,$21
+ $f7,$2a,$13,$81,$23,$22,$53,$00,$63,$22,$e9,$0b,$0c,$83,$13,$21
+ $16,$22,$33,$05,$8f,$35,$ec,$01,$63,$a0,$67,$20,$73,$01,$77,$01
+ $83,$20,$87,$20,$b3,$20,$b7,$20,$c3,$01,$c7,$00,$d3,$20,$d7,$20
+ $67,$a0,$77,$07,$87,$22,$e8,$62,$f5,$65,$1c,$82,$7f,$38,$8d,$c1
+ $cf,$26
a68d: fd .dd1 $fd
; level 1-1
a68e: 50 21 L_GroundArea6 .bulk $50,$21
a690: 07 81 47 24+ .bulk $07,$81,$47,$24,$57,$00,$63,$01,$77,$01,$c9,$71,$68,$f2,$e7,$73
+ $97,$fb,$06,$83,$5c,$01,$d7,$22,$e7,$00,$03,$a7,$6c,$02,$b3,$22
+ $e3,$01,$e7,$07,$47,$a0,$57,$06,$a7,$01,$d3,$00,$d7,$01,$07,$81
+ $67,$20,$93,$22,$03,$a3,$1c,$61,$17,$21,$6f,$33,$c7,$63,$d8,$62
+ $e9,$61,$fa,$60,$4f,$b3,$87,$63,$9c,$01,$b7,$63,$c8,$62,$d9,$61
+ $ea,$60,$39,$f1,$87,$21,$a7,$01,$b7,$20,$39,$f1,$5f,$38,$6d,$c1
+ $af,$26
a6f2: fd .dd1 $fd
; level 1-3/5-3
a6f3: 90 11 L_GroundArea7 .bulk $90,$11
a6f5: 0f 26 fe 10+ .bulk $0f,$26,$fe,$10,$2a,$93,$87,$17,$a3,$14,$b2,$42,$0a,$92,$19,$40
+ $36,$14,$50,$41,$82,$16,$2b,$93,$24,$41,$bb,$14,$b8,$00,$c2,$43
+ $c3,$13,$1b,$94,$67,$12,$c4,$15,$53,$c1,$d2,$41,$12,$c1,$29,$13
+ $85,$17,$1b,$92,$1a,$42,$47,$13,$83,$41,$a7,$13,$0e,$91,$a7,$63
+ $b7,$63,$c5,$65,$d5,$65,$dd,$4a,$e3,$67,$f3,$67,$8d,$c1,$ae,$42
+ $df,$20
a747: fd .dd1 $fd
; level 2-3/7-3
a748: 90 11 L_GroundArea8 .bulk $90,$11
a74a: 0f 26 6e 10+ .bulk $0f,$26,$6e,$10,$8b,$17,$af,$32,$d8,$62,$e8,$62,$fc,$3f,$ad,$c8
+ $f8,$64,$0c,$be,$43,$43,$f8,$64,$0c,$bf,$73,$40,$84,$40,$93,$40
+ $a4,$40,$b3,$40,$f8,$64,$48,$e4,$5c,$39,$83,$40,$92,$41,$b3,$40
+ $f8,$64,$48,$e4,$5c,$39,$f8,$64,$13,$c2,$37,$65,$4c,$24,$63,$00
+ $97,$65,$c3,$42,$0b,$97,$ac,$32,$f8,$64,$0c,$be,$53,$45,$9d,$48
+ $f8,$64,$2a,$e2,$3c,$47,$56,$43,$ba,$62,$f8,$64,$0c,$b7,$88,$64
+ $bc,$31,$d4,$45,$fc,$31,$3c,$b1,$78,$64,$8c,$38,$0b,$9c,$1a,$33
+ $18,$61,$28,$61,$39,$60,$5d,$4a,$ee,$11,$0f,$b8,$1d,$c1,$3e,$42
+ $6f,$20
a7cc: fd .dd1 $fd
; level 2-1
a7cd: 52 31 L_GroundArea9 .bulk $52,$31
a7cf: 0f 20 6e 40+ .bulk $0f,$20,$6e,$40,$f7,$20,$07,$84,$17,$20,$4f,$34,$c3,$03,$c7,$02
+ $d3,$22,$27,$e3,$39,$61,$e7,$73,$5c,$e4,$57,$00,$6c,$73,$47,$a0
+ $53,$06,$63,$22,$a7,$73,$fc,$73,$13,$a1,$33,$05,$43,$21,$5c,$72
+ $c3,$23,$cc,$03,$77,$fb,$ac,$02,$39,$f1,$a7,$73,$d3,$04,$e8,$72
+ $e3,$22,$26,$f4,$bc,$02,$8c,$81,$a8,$62,$17,$87,$43,$24,$a7,$01
+ $c3,$04,$08,$f2,$97,$21,$a3,$02,$c9,$0b,$e1,$69,$f1,$69,$8d,$c1
+ $cf,$26
a831: fd .dd1 $fd
; pipe intro area
a832: 38 11 L_GroundArea10 .bulk $38,$11
a834: 0f 26 ad 40+ .bulk $0f,$26,$ad,$40,$3d,$c7
a83a: fd .dd1 $fd
; level 5-1
a83b: 95 b1 L_GroundArea11 .bulk $95,$b1
a83d: 0f 26 0d 02+ .bulk $0f,$26,$0d,$02,$c8,$72,$1c,$81,$38,$72,$0d,$05,$97,$34,$98,$62
+ $a3,$20,$b3,$06,$c3,$20,$cc,$03,$f9,$91,$2c,$81,$48,$62,$0d,$09
+ $37,$63,$47,$03,$57,$21,$8c,$02,$c5,$79,$c7,$31,$f9,$11,$39,$f1
+ $a9,$11,$6f,$b4,$d3,$65,$e3,$65,$7d,$c1,$bf,$26
a879: fd .dd1 $fd
; cloud level used in levels 2-1 and 5-2
a87a: 00 c1 L_GroundArea12 .bulk $00,$c1
a87c: 4c 00 f4 4f+ .bulk $4c,$00,$f4,$4f,$0d,$02,$02,$42,$43,$4f,$52,$c2,$de,$00,$5a,$c2
+ $4d,$c7
a88e: fd .dd1 $fd
; level 4-3
a88f: 90 51 L_GroundArea13 .bulk $90,$51
a891: 0f 26 ee 10+ .bulk $0f,$26,$ee,$10,$0b,$94,$33,$14,$42,$42,$77,$16,$86,$44,$02,$92
+ $4a,$16,$69,$42,$73,$14,$b0,$00,$c7,$12,$05,$c0,$1c,$17,$1f,$11
+ $36,$12,$8f,$14,$91,$40,$1b,$94,$35,$12,$34,$42,$60,$42,$61,$12
+ $87,$12,$96,$40,$a3,$14,$1c,$98,$1f,$11,$47,$12,$9f,$15,$cc,$15
+ $cf,$11,$05,$c0,$1f,$15,$39,$12,$7c,$16,$7f,$11,$82,$40,$98,$12
+ $df,$15,$16,$c4,$17,$14,$54,$12,$9b,$16,$28,$94,$ce,$01,$3d,$c1
+ $5e,$42,$8f,$20
a8f5: fd .dd1 $fd
; level 6-3
a8f6: 97 11 L_GroundArea14 .bulk $97,$11
a8f8: 0f 26 fe 10+ .bulk $0f,$26,$fe,$10,$2b,$92,$57,$12,$8b,$12,$c0,$41,$f7,$13,$5b,$92
+ $69,$0b,$bb,$12,$b2,$46,$19,$93,$71,$00,$17,$94,$7c,$14,$7f,$11
+ $93,$41,$bf,$15,$fc,$13,$ff,$11,$2f,$95,$50,$42,$51,$12,$58,$14
+ $a6,$12,$db,$12,$1b,$93,$46,$43,$7b,$12,$8d,$49,$b7,$14,$1b,$94
+ $49,$0b,$bb,$12,$fc,$13,$ff,$12,$03,$c1,$2f,$15,$43,$12,$4b,$13
+ $77,$13,$9d,$4a,$15,$c1,$a1,$41,$c3,$12,$fe,$01,$7d,$c1,$9e,$42
+ $cf,$20
a95a: fd .dd1 $fd
; level 6-1
a95b: 52 21 L_GroundArea15 .bulk $52,$21
a95d: 0f 20 6e 44+ .bulk $0f,$20,$6e,$44,$0c,$f1,$4c,$01,$aa,$35,$d9,$34,$ee,$20,$08,$b3
+ $37,$32,$43,$04,$4e,$21,$53,$20,$7c,$01,$97,$21,$b7,$07,$9c,$81
+ $e7,$42,$5f,$b3,$97,$63,$ac,$02,$c5,$41,$49,$e0,$58,$61,$76,$64
+ $85,$65,$94,$66,$a4,$22,$a6,$03,$c8,$22,$dc,$02,$68,$f2,$96,$42
+ $13,$82,$17,$02,$af,$34,$f6,$21,$fc,$06,$26,$80,$2a,$24,$36,$01
+ $8c,$00,$ff,$35,$4e,$a0,$55,$21,$77,$20,$87,$07,$89,$22,$ae,$21
+ $4c,$82,$9f,$34,$ec,$01,$03,$e7,$13,$67,$8d,$4a,$ad,$41,$0f,$a6
a9cd: fd .dd1 $fd
; warp zone area used in level 4-2
a9ce: 10 51 L_GroundArea16 .bulk $10,$51
a9d0: 4c 00 c7 12+ .bulk $4c,$00,$c7,$12,$c6,$42,$03,$92,$02,$42,$29,$12,$63,$12,$62,$42
+ $69,$14,$a5,$12,$a4,$42,$e2,$14,$e1,$44,$f8,$16,$37,$c1,$8f,$38
+ $02,$bb,$28,$7a,$68,$7a,$a8,$7a,$e0,$6a,$f0,$6a,$6d,$c5
a9fe: fd .dd1 $fd
; level 8-1
a9ff: 92 31 L_GroundArea17 .bulk $92,$31
aa01: 0f 20 6e 40+ .bulk $0f,$20,$6e,$40,$0d,$02,$37,$73,$ec,$00,$0c,$80,$3c,$00,$6c,$00
+ $9c,$00,$06,$c0,$c7,$73,$06,$83,$28,$72,$96,$40,$e7,$73,$26,$c0
+ $87,$7b,$d2,$41,$39,$f1,$c8,$f2,$97,$e3,$a3,$23,$e7,$02,$e3,$07
+ $f3,$22,$37,$e3,$9c,$00,$bc,$00,$ec,$00,$0c,$80,$3c,$00,$86,$21
+ $a6,$06,$b6,$24,$5c,$80,$7c,$00,$9c,$00,$29,$e1,$dc,$05,$f6,$41
+ $dc,$80,$e8,$72,$0c,$81,$27,$73,$4c,$01,$66,$74,$0d,$11,$3f,$35
+ $b6,$41,$2c,$82,$36,$40,$7c,$02,$86,$40,$f9,$61,$39,$e1,$ac,$04
+ $c6,$41,$0c,$83,$16,$41,$88,$f2,$39,$f1,$7c,$00,$89,$61,$9c,$00
+ $a7,$63,$bc,$00,$c5,$65,$dc,$00,$e3,$67,$f3,$67,$8d,$c1,$cf,$26
aa91: fd .dd1 $fd
; level 5-2
aa92: 55 b1 L_GroundArea18 .bulk $55,$b1
aa94: 0f 26 cf 33+ .bulk $0f,$26,$cf,$33,$07,$b2,$15,$11,$52,$42,$99,$0b,$ac,$02,$d3,$24
+ $d6,$42,$d7,$25,$23,$84,$cf,$33,$07,$e3,$19,$61,$78,$7a,$ef,$33
+ $2c,$81,$46,$64,$55,$65,$65,$65,$ec,$74,$47,$82,$53,$05,$63,$21
+ $62,$41,$96,$22,$9a,$41,$cc,$03,$b9,$91,$39,$f1,$63,$26,$67,$27
+ $d3,$06,$fc,$01,$18,$e2,$d9,$07,$e9,$04,$0c,$86,$37,$22,$93,$24
+ $87,$84,$ac,$02,$c2,$41,$c3,$23,$d9,$71,$fc,$01,$7f,$b1,$9c,$00
+ $a7,$63,$b6,$64,$cc,$00,$d4,$66,$e3,$67,$f3,$67,$8d,$c1,$cf,$26
ab04: fd .dd1 $fd
; level 8-2
ab05: 50 b1 L_GroundArea19 .bulk $50,$b1
ab07: 0f 26 fc 00+ .bulk $0f,$26,$fc,$00,$1f,$b3,$5c,$00,$65,$65,$74,$66,$83,$67,$93,$67
+ $dc,$73,$4c,$80,$b3,$20,$c9,$0b,$c3,$08,$d3,$2f,$dc,$00,$2c,$80
+ $4c,$00,$8c,$00,$d3,$2e,$ed,$4a,$fc,$00,$d7,$a1,$ec,$01,$4c,$80
+ $59,$11,$d8,$11,$da,$10,$37,$a0,$47,$04,$99,$11,$e7,$21,$3a,$90
+ $67,$20,$76,$10,$77,$60,$87,$07,$d8,$12,$39,$f1,$ac,$00,$e9,$71
+ $0c,$80,$2c,$00,$4c,$05,$c7,$7b,$39,$f1,$ec,$00,$f9,$11,$0c,$82
+ $6f,$34,$f8,$11,$fa,$10,$7f,$b2,$ac,$00,$b6,$64,$cc,$01,$e3,$67
+ $f3,$67,$8d,$c1,$cf,$26
ab7d: fd .dd1 $fd
; level 7-1
ab7e: 52 b1 L_GroundArea20 .bulk $52,$b1
ab80: 0f 20 6e 45+ .bulk $0f,$20,$6e,$45,$39,$91,$b3,$04,$c3,$21,$c8,$11,$ca,$10,$49,$91
+ $7c,$73,$e8,$12,$88,$91,$8a,$10,$e7,$21,$05,$91,$07,$30,$17,$07
+ $27,$20,$49,$11,$9c,$01,$c8,$72,$23,$a6,$27,$26,$d3,$03,$d8,$7a
+ $89,$91,$d8,$72,$39,$f1,$a9,$11,$09,$f1,$63,$24,$67,$24,$d8,$62
+ $28,$91,$2a,$10,$56,$21,$70,$04,$79,$0b,$8c,$00,$94,$21,$9f,$35
+ $2f,$b8,$3d,$c1,$7f,$26
abd6: fd .dd1 $fd
; cloud level used in levels 3-1 and 6-2
abd7: 06 c1 L_GroundArea21 .bulk $06,$c1
abd9: 4c 00 f4 4f+ .bulk $4c,$00,$f4,$4f,$0d,$02,$06,$20,$24,$4f,$35,$a0,$36,$20,$53,$46
+ $d5,$20,$d6,$20,$34,$a1,$73,$49,$74,$20,$94,$20,$b4,$20,$d4,$20
+ $f4,$20,$2e,$80,$59,$42,$4d,$c7
ac01: fd .dd1 $fd
; level 3-2
ac02: 96 31 L_GroundArea22 .bulk $96,$31
ac04: 0f 26 0d 03+ .bulk $0f,$26,$0d,$03,$1a,$60,$77,$42,$c4,$00,$c8,$62,$b9,$e1,$d3,$06
+ $d7,$07,$f9,$61,$0c,$81,$4e,$b1,$8e,$b1,$bc,$01,$e4,$50,$e9,$61
+ $0c,$81,$0d,$0a,$84,$43,$98,$72,$0d,$0c,$0f,$38,$1d,$c1,$5f,$26
ac34: fd .dd1 $fd
; level 1-2
L_UndergroundArea1
ac35: 48 0f .bulk $48,$0f
ac37: 0e 01 5e 02+ .bulk $0e,$01,$5e,$02,$a7,$00,$bc,$73,$1a,$e0,$39,$61,$58,$62,$77,$63
+ $97,$63,$b8,$62,$d6,$07,$f8,$62,$19,$e1,$75,$52,$86,$40,$87,$50
+ $95,$52,$93,$43,$a5,$21,$c5,$52,$d6,$40,$d7,$20,$e5,$06,$e6,$51
+ $3e,$8d,$5e,$03,$67,$52,$77,$52,$7e,$02,$9e,$03,$a6,$43,$a7,$23
+ $de,$05,$fe,$02,$1e,$83,$33,$54,$46,$40,$47,$21,$56,$04,$5e,$02
+ $83,$54,$93,$52,$96,$07,$97,$50,$be,$03,$c7,$23,$fe,$02,$0c,$82
+ $43,$45,$45,$24,$46,$24,$90,$08,$95,$51,$78,$fa,$d7,$73,$39,$f1
+ $8c,$01,$a8,$52,$b8,$52,$cc,$01,$5f,$b3,$97,$63,$9e,$00,$0e,$81
+ $16,$24,$66,$04,$8e,$00,$fe,$01,$08,$d2,$0e,$06,$6f,$47,$9e,$0f
+ $0e,$82,$2d,$47,$28,$7a,$68,$7a,$a8,$7a,$ae,$01,$de,$0f,$6d,$c5
acd7: fd .dd1 $fd
; level 4-2
L_UndergroundArea2
acd8: 48 0f .bulk $48,$0f
acda: 0e 01 5e 02+ .bulk $0e,$01,$5e,$02,$bc,$01,$fc,$01,$2c,$82,$41,$52,$4e,$04,$67,$25
+ $68,$24,$69,$24,$ba,$42,$c7,$04,$de,$0b,$b2,$87,$fe,$02,$2c,$e1
+ $2c,$71,$67,$01,$77,$00,$87,$01,$8e,$00,$ee,$01,$f6,$02,$03,$85
+ $05,$02,$13,$21,$16,$02,$27,$02,$2e,$02,$88,$72,$c7,$20,$d7,$07
+ $e4,$76,$07,$a0,$17,$06,$48,$7a,$76,$20,$98,$72,$79,$e1,$88,$62
+ $9c,$01,$b7,$73,$dc,$01,$f8,$62,$fe,$01,$08,$e2,$0e,$00,$6e,$02
+ $73,$20,$77,$23,$83,$04,$93,$20,$ae,$00,$fe,$0a,$0e,$82,$39,$71
+ $a8,$72,$e7,$73,$0c,$81,$8f,$32,$ae,$00,$fe,$04,$04,$d1,$17,$04
+ $26,$49,$27,$29,$df,$33,$fe,$02,$44,$f6,$7c,$01,$8e,$06,$bf,$47
+ $ee,$0f,$4d,$c7,$0e,$82,$68,$7a,$ae,$01,$de,$0f,$6d,$c5
ad78: fd .dd1 $fd
; underground bonus rooms area used in many levels
L_UndergroundArea3
ad79: 48 01 .bulk $48,$01
ad7b: 0e 01 00 5a+ .bulk $0e,$01,$00,$5a,$3e,$06,$45,$46,$47,$46,$53,$44,$ae,$01,$df,$4a
+ $4d,$c7,$0e,$81,$00,$5a,$2e,$04,$37,$28,$3a,$48,$46,$47,$c7,$07
+ $ce,$0f,$df,$4a,$4d,$c7,$0e,$81,$00,$5a,$33,$53,$43,$51,$46,$40
+ $47,$50,$53,$04,$55,$40,$56,$50,$62,$43,$64,$40,$65,$50,$71,$41
+ $73,$51,$83,$51,$94,$40,$95,$50,$a3,$50,$a5,$40,$a6,$50,$b3,$51
+ $b6,$40,$b7,$50,$c3,$53,$df,$4a,$4d,$c7,$0e,$81,$00,$5a,$2e,$02
+ $36,$47,$37,$52,$3a,$49,$47,$25,$a7,$52,$d7,$04,$df,$4a,$4d,$c7
+ $0e,$81,$00,$5a,$3e,$02,$44,$51,$53,$44,$54,$44,$55,$24,$a1,$54
+ $ae,$01,$b4,$21,$df,$4a,$e5,$07,$4d,$c7
ae05: fd .dd1 $fd
; water area used in levels 5-2 and 6-2
ae06: 41 01 L_WaterArea1 .bulk $41,$01
ae08: b4 34 c8 52+ .bulk $b4,$34,$c8,$52,$f2,$51,$47,$d3,$6c,$03,$65,$49,$9e,$07,$be,$01
+ $cc,$03,$fe,$07,$0d,$c9,$1e,$01,$6c,$01,$62,$35,$63,$53,$8a,$41
+ $ac,$01,$b3,$53,$e9,$51,$26,$c3,$27,$33,$63,$43,$64,$33,$ba,$60
+ $c9,$61,$ce,$0b,$e5,$09,$ee,$0f,$7d,$ca,$7d,$47
ae44: fd .dd1 $fd
; level 2-2/7-2
ae45: 41 01 L_WaterArea2 .bulk $41,$01
ae47: b8 52 ea 41+ .bulk $b8,$52,$ea,$41,$27,$b2,$b3,$42,$16,$d4,$4a,$42,$a5,$51,$a7,$31
+ $27,$d3,$08,$e2,$16,$64,$2c,$04,$38,$42,$76,$64,$88,$62,$de,$07
+ $fe,$01,$0d,$c9,$23,$32,$31,$51,$98,$52,$0d,$c9,$59,$42,$63,$53
+ $67,$31,$14,$c2,$36,$31,$87,$53,$17,$e3,$29,$61,$30,$62,$3c,$08
+ $42,$37,$59,$40,$6a,$42,$99,$40,$c9,$61,$d7,$63,$39,$d1,$58,$52
+ $c3,$67,$d3,$31,$dc,$06,$f7,$42,$fa,$42,$23,$b1,$43,$67,$c3,$34
+ $c7,$34,$d1,$51,$43,$b3,$47,$33,$9a,$30,$a9,$61,$b8,$62,$be,$0b
+ $d5,$09,$de,$0f,$0d,$ca,$7d,$47
aebf: fd .dd1 $fd
; water area used in level 8-4
aec0: 49 0f L_WaterArea3 .bulk $49,$0f
aec2: 1e 01 39 73+ .bulk $1e,$01,$39,$73,$5e,$07,$ae,$0b,$1e,$82,$6e,$88,$9e,$02,$0d,$04
+ $2e,$0b,$45,$09,$4e,$0f,$ed,$47
aeda: fd .dd1 $fd
; -----------------------------------------------------------------------------
; unused space
aedb: ff .dd1 $ff
; -----------------------------------------------------------------------------
; indirect jump routine called when $0770 is set to 1
aedc: ad 72 07 GameMode lda OperMode_Task
aedf: 20 04 8e jsr JumpEngine
aee2: e4 8f .dd2 InitializeArea
aee4: 67 85 .dd2 ScreenRoutines
aee6: 71 90 .dd2 SecondaryGameSetup
aee8: ea ae .dd2 GameCoreRoutine
; -----------------------------------------------------------------------------
aeea: ae 53 07 GameCoreRoutine ldx CurrentPlayer ;get which player is on the screen
aeed: bd fc 06 lda SavedJoypad1Bits,x ;use appropriate player's controller bits
aef0: 8d fc 06 sta SavedJoypad1Bits ; as the master controller bits
aef3: 20 4a b0 jsr GameRoutines ;execute one of many possible subs
aef6: ad 72 07 lda OperMode_Task ;check major task of operating mode
aef9: c9 03 cmp #$03 ;if we are supposed to be here,
aefb: b0 01 bcs GameEngine ; branch to the game engine itself
aefd: 60 rts
aefe: 20 24 b6 GameEngine jsr ProcFireball_Bubble ;process fireballs and air bubbles
af01: a2 00 ldx #$00
af03: 86 08 ProcELoop stx ObjectOffset ;put incremented offset in X as enemy object offset
af05: 20 47 c0 jsr EnemiesAndLoopsCore ;process enemy objects
af08: 20 c3 84 jsr FloateyNumbersRoutine ;process floatey numbers
af0b: e8 inx
af0c: e0 06 cpx #$06 ;do these two subroutines until the whole buffer is done
af0e: d0 f3 bne ProcELoop
af10: 20 80 f1 jsr GetPlayerOffscreenBits ;get offscreen bits for player object
af13: 20 2a f1 jsr RelativePlayerPosition ;get relative coordinates for player object
af16: 20 e9 ee jsr PlayerGfxHandler ;draw the player
af19: 20 d4 be jsr BlockObjMT_Updater ;replace block objects with metatiles if necessary
af1c: a2 01 ldx #$01
af1e: 86 08 stx ObjectOffset ;set offset for second
af20: 20 70 be jsr BlockObjectsCore ;process second block object
af23: ca dex
af24: 86 08 stx ObjectOffset ;set offset for first
af26: 20 70 be jsr BlockObjectsCore ;process first block object
af29: 20 96 bb jsr MiscObjectsCore ;process misc objects (hammer, jumping coins)
af2c: 20 bc b9 jsr ProcessCannons ;process bullet bill cannons
af2f: 20 b8 b7 jsr ProcessWhirlpools ;process whirlpools
af32: 20 55 b8 jsr FlagpoleRoutine ;process the flagpole
af35: 20 4f b7 jsr RunGameTimer ;count down the game timer
af38: 20 e1 89 jsr ColorRotation ;cycle one of the background colors
af3b: a5 b5 lda Player_Y_HighPos
af3d: c9 02 cmp #$02 ;if player is below the screen, don't bother with the music
af3f: 10 11 bpl NoChgMus
af41: ad 9f 07 lda StarInvincibleTimer ;if star mario invincibility timer at zero,
af44: f0 1e beq ClrPlrPal ; skip this part
af46: c9 04 cmp #$04
af48: d0 08 bne NoChgMus ;if not yet at a certain point, continue
af4a: ad 7f 07 lda IntervalTimerControl ;if interval timer not yet expired,
af4d: d0 03 bne NoChgMus ; branch ahead, don't bother with the music
af4f: 20 ed 90 jsr GetAreaMusic ;to re-attain appropriate level music
af52: ac 9f 07 NoChgMus ldy StarInvincibleTimer ;get invincibility timer
af55: a5 09 lda FrameCounter ;get frame counter
af57: c0 08 cpy #$08 ;if timer still above certain point,
af59: b0 02 bcs CycleTwo ; branch to cycle player's palette quickly
af5b: 4a lsr A ;otherwise, divide by 8 to cycle every eighth frame
af5c: 4a lsr A
af5d: 4a CycleTwo lsr A ;if branched here, divide by 2 to cycle every other frame
af5e: 20 88 b2 jsr CyclePlayerPalette ;do sub to cycle the palette (note: shares fire flower code)
af61: 4c 67 af jmp SaveAB ; then skip this sub to finish up the game engine
af64: 20 9a b2 ClrPlrPal jsr ResetPalStar ;do sub to clear player's palette bits in attributes
af67: a5 0a SaveAB lda A_B_Buttons ;save current A and B button
af69: 85 0d sta PreviousA_B_Buttons ; into temp variable to be used on next frame
af6b: a9 00 lda #$00
af6d: 85 0c sta Left_Right_Buttons ;nullify left and right buttons temp variable
af6f: ad 73 07 UpdScrollVar lda VRAM_Buffer_AddrCtrl
af72: c9 06 cmp #$06 ;if vram address controller set to 6 (one of two $0341s)
af74: f0 1c beq ExitEng ; then branch to leave
af76: ad 1f 07 lda AreaParserTaskNum ;otherwise check number of tasks
af79: d0 14 bne RunParser
af7b: ad 3d 07 lda ScrollThirtyTwo ;get horizontal scroll in 0-31 or $00-$20 range
af7e: c9 20 cmp #$20 ;check to see if exceeded $21
af80: 30 10 bmi ExitEng ;branch to leave if not
af82: ad 3d 07 lda ScrollThirtyTwo
af85: e9 20 sbc #$20 ;otherwise subtract $20 to set appropriately
af87: 8d 3d 07 sta ScrollThirtyTwo ;and store
af8a: a9 00 lda #$00 ;reset vram buffer offset used in conjunction with
af8c: 8d 40 03 sta VRAM_Buffer2_Offset ; level graphics buffer at $0341-$035f
af8f: 20 b0 92 RunParser jsr AreaParserTaskHandler ;update the name table with more level graphics
af92: 60 ExitEng rts ;and after all that, we're finally done!
; -----------------------------------------------------------------------------
af93: ad ff 06 ScrollHandler lda Player_X_Scroll ;load value saved here
af96: 18 clc
af97: 6d a1 03 adc Platform_X_Scroll ;add value used by left/right platforms
af9a: 8d ff 06 sta Player_X_Scroll ;save as new value here to impose force on scroll
af9d: ad 23 07 lda ScrollLock ;check scroll lock flag
afa0: d0 59 bne InitScrlAmt ;skip a bunch of code here if set
afa2: ad 55 07 lda Player_Pos_ForScroll
afa5: c9 50 cmp #$50 ;check player's horizontal screen position
afa7: 90 52 bcc InitScrlAmt ;if less than 80 pixels to the right, branch
afa9: ad 85 07 lda SideCollisionTimer ;if timer related to player's side collision
afac: d0 4d bne InitScrlAmt ;not expired, branch
afae: ac ff 06 ldy Player_X_Scroll ;get value and decrement by one
afb1: 88 dey ;if value originally set to zero or otherwise
afb2: 30 47 bmi InitScrlAmt ;negative for left movement, branch
afb4: c8 iny
afb5: c0 02 cpy #$02 ;if value $01, branch and do not decrement
afb7: 90 01 bcc ChkNearMid
afb9: 88 dey ;otherwise decrement by one
afba: ad 55 07 ChkNearMid lda Player_Pos_ForScroll
afbd: c9 70 cmp #$70 ;check player's horizontal screen position
afbf: 90 03 bcc ScrollScreen ;if less than 112 pixels to the right, branch
afc1: ac ff 06 ldy Player_X_Scroll ;otherwise get original value undecremented
afc4: 98 ScrollScreen tya
afc5: 8d 75 07 sta ScrollAmount ;save value here
afc8: 18 clc
afc9: 6d 3d 07 adc ScrollThirtyTwo ;add to value already set here
afcc: 8d 3d 07 sta ScrollThirtyTwo ;save as new value here
afcf: 98 tya
afd0: 18 clc
afd1: 6d 1c 07 adc ScreenLeft_X_Pos ;add to left side coordinate
afd4: 8d 1c 07 sta ScreenLeft_X_Pos ;save as new left side coordinate
afd7: 8d 3f 07 sta HorizontalScroll ;save here also
afda: ad 1a 07 lda ScreenLeft_PageLoc
afdd: 69 00 adc #$00 ;add carry to page location for left
afdf: 8d 1a 07 sta ScreenLeft_PageLoc ;side of the screen
afe2: 29 01 and #$01 ;get LSB of page location
afe4: 85 00 sta $00 ;save as temp variable for PPU register 1 mirror
afe6: ad 78 07 lda Mirror_PPU_CTRL_REG1 ;get PPU register 1 mirror
afe9: 29 fe and #%11111110 ;save all bits except d0
afeb: 05 00 ora $00 ;get saved bit here and save in PPU register 1
afed: 8d 78 07 sta Mirror_PPU_CTRL_REG1 ;mirror to be used to set name table later
aff0: 20 38 b0 jsr GetScreenPosition ;figure out where the right side is
aff3: a9 08 lda #$08
aff5: 8d 95 07 sta ScrollIntervalTimer ;set scroll timer (residual, not used elsewhere)
aff8: 4c 00 b0 jmp ChkPOffscr ;skip this part
affb: a9 00 InitScrlAmt lda #$00
affd: 8d 75 07 sta ScrollAmount ;initialize value here
b000: a2 00 ChkPOffscr ldx #$00 ;set X for player offset
b002: 20 f6 f1 jsr GetXOffscreenBits ;get horizontal offscreen bits for player
b005: 85 00 sta $00 ;save them here
b007: a0 00 ldy #$00 ;load default offset (left side)
b009: 0a asl A ;if d7 of offscreen bits are set,
b00a: b0 07 bcs KeepOnscr ;branch with default offset
b00c: c8 iny ;otherwise use different offset (right side)
b00d: a5 00 lda $00
b00f: 29 20 and #%00100000 ;check offscreen bits for d5 set
b011: f0 1b beq InitPlatScrl ;if not set, branch ahead of this part
b013: b9 1c 07 KeepOnscr lda ScreenLeft_X_Pos,y ;get left or right side coordinate based on offset
b016: 38 sec
b017: f9 34 b0 sbc X_SubtracterData,y ;subtract amount based on offset
b01a: 85 86 sta Player_X_Position ;store as player position to prevent movement further
b01c: b9 1a 07 lda ScreenLeft_PageLoc,y ;get left or right page location based on offset
b01f: e9 00 sbc #$00 ;subtract borrow
b021: 85 6d sta Player_PageLoc ;save as player's page location
b023: a5 0c lda Left_Right_Buttons ;check saved controller bits
b025: d9 36 b0 cmp OffscrJoypadBitsData,y ;against bits based on offset
b028: f0 04 beq InitPlatScrl ;if not equal, branch
b02a: a9 00 lda #$00
b02c: 85 57 sta Player_X_Speed ;otherwise nullify horizontal speed of player
b02e: a9 00 InitPlatScrl lda #$00 ;nullify platform force imposed on scroll
b030: 8d a1 03 sta Platform_X_Scroll
b033: 60 rts
X_SubtracterData
b034: 00 10 .bulk $00,$10
OffscrJoypadBitsData
b036: 01 02 .bulk $01,$02
; -----------------------------------------------------------------------------
GetScreenPosition
b038: ad 1c 07 lda ScreenLeft_X_Pos ;get coordinate of screen's left boundary
b03b: 18 clc
b03c: 69 ff adc #$ff ;add 255 pixels
b03e: 8d 1d 07 sta ScreenRight_X_Pos ;store as coordinate of screen's right boundary
b041: ad 1a 07 lda ScreenLeft_PageLoc ;get page number where left boundary is
b044: 69 00 adc #$00 ;add carry from before
b046: 8d 1b 07 sta ScreenRight_PageLoc ;store as page number where right boundary is
b049: 60 rts
; -----------------------------------------------------------------------------
b04a: a5 0e GameRoutines lda GameEngineSubroutine ;run routine based on number (a few of these routines are
b04c: 20 04 8e jsr JumpEngine ; merely placeholders as conditions for other routines)
b04f: 31 91 .dd2 Entrance_GameTimerSetup
b051: c7 b1 .dd2 Vine_AutoClimb
b053: 06 b2 .dd2 SideExitPipeEntry
b055: e5 b1 .dd2 VerticalPipeEntry
b057: a4 b2 .dd2 FlagpoleSlide
b059: ca b2 .dd2 PlayerEndLevel
b05b: cd 91 .dd2 PlayerLoseLife
b05d: 69 b0 .dd2 PlayerEntrance
b05f: e9 b0 .dd2 PlayerCtrlRoutine
b061: 33 b2 .dd2 PlayerChangeSize
b063: 45 b2 .dd2 PlayerInjuryBlink
b065: 69 b2 .dd2 PlayerDeath
b067: 7d b2 .dd2 PlayerFireFlower
b069: ad 52 07 PlayerEntrance lda AltEntranceControl ;check for mode of alternate entry
b06c: c9 02 cmp #$02
b06e: f0 2b beq EntrMode2 ;if found, branch to enter from pipe or with vine
b070: a9 00 lda #$00
b072: a4 ce ldy Player_Y_Position ;if vertical position above a certain
b074: c0 30 cpy #$30 ; point, nullify controller bits and continue
b076: 90 6e bcc AutoControlPlayer ; with player movement code, do not return
b078: ad 10 07 lda PlayerEntranceCtrl ;check player entry bits from header
b07b: c9 06 cmp #$06
b07d: f0 04 beq ChkBehPipe ;if set to 6 or 7, execute pipe intro code
b07f: c9 07 cmp #$07 ;otherwise branch to normal entry
b081: d0 50 bne PlayerRdy
b083: ad c4 03 ChkBehPipe lda Player_SprAttrib ;check for sprite attributes
b086: d0 05 bne IntroEntr ;branch if found
b088: a9 01 lda #$01
b08a: 4c e6 b0 jmp AutoControlPlayer ;force player to walk to the right
b08d: 20 1f b2 IntroEntr jsr EnterSidePipe ;execute sub to move player to the right
b090: ce de 06 dec ChangeAreaTimer ;decrement timer for change of area
b093: d0 50 bne ExitEntr ;branch to exit if not yet expired
b095: ee 69 07 inc DisableIntermediate ;set flag to skip world and lives display
b098: 4c 15 b3 jmp NextArea ;jump to increment to next area and set modes
b09b: ad 58 07 EntrMode2 lda JoypadOverride ;if controller override bits set here,
b09e: d0 0c bne VineEntr ; branch to enter with vine
b0a0: a9 ff lda #$ff ;otherwise, set value here then execute sub
b0a2: 20 00 b2 jsr MovePlayerYAxis ; to move player upwards (note $ff = -1)
b0a5: a5 ce lda Player_Y_Position ;check to see if player is at a specific coordinate
b0a7: c9 91 cmp #$91 ;if player risen to a certain point (this requires pipes
b0a9: 90 28 bcc PlayerRdy ; to be at specific height to look/function right) branch
b0ab: 60 rts ; to the last part, otherwise leave
b0ac: ad 99 03 VineEntr lda VineHeight
b0af: c9 60 cmp #$60 ;check vine height
b0b1: d0 32 bne ExitEntr ;if vine not yet reached maximum height, branch to leave
b0b3: a5 ce lda Player_Y_Position ;get player's vertical coordinate
b0b5: c9 99 cmp #$99 ;check player's vertical coordinate against preset value
b0b7: a0 00 ldy #$00 ;load default values to be written to
b0b9: a9 01 lda #$01 ;this value moves player to the right off the vine
b0bb: 90 0a bcc OffVine ;if vertical coordinate < preset value, use defaults
b0bd: a9 03 lda #$03
b0bf: 85 1d sta Player_State ;otherwise set player state to climbing
b0c1: c8 iny ;increment value in Y
b0c2: a9 08 lda #$08 ;set block in block buffer to cover hole, then
b0c4: 8d b4 05 sta Block_Buffer_1+180 ; use same value to force player to climb
b0c7: 8c 16 07 OffVine sty DisableCollisionDet ;set collision detection disable flag
b0ca: 20 e6 b0 jsr AutoControlPlayer ;use contents of A to move player up or right, execute sub
b0cd: a5 86 lda Player_X_Position
b0cf: c9 48 cmp #$48 ;check player's horizontal position
b0d1: 90 12 bcc ExitEntr ;if not far enough to the right, branch to leave
b0d3: a9 08 PlayerRdy lda #$08 ;set routine to be executed by game engine next frame
b0d5: 85 0e sta GameEngineSubroutine
b0d7: a9 01 lda #$01 ;set to face player to the right
b0d9: 85 33 sta PlayerFacingDir
b0db: 4a lsr A ;init A
b0dc: 8d 52 07 sta AltEntranceControl ;init mode of entry
b0df: 8d 16 07 sta DisableCollisionDet ;init collision detection disable flag
b0e2: 8d 58 07 sta JoypadOverride ;nullify controller override bits
b0e5: 60 ExitEntr rts ;leave!
; -----------------------------------------------------------------------------
; $07 - used to hold upper limit of high byte when player falls down hole
AutoControlPlayer
b0e6: 8d fc 06 sta SavedJoypad1Bits ;override controller bits with contents of A if executing here
PlayerCtrlRoutine
b0e9: a5 0e lda GameEngineSubroutine ;check task here
b0eb: c9 0b cmp #$0b ;if certain value is set, branch to skip controller bit
b0ed: f0 3c beq SizeChk
b0ef: ad 4e 07 lda AreaType ;are we in a water type area?
b0f2: d0 10 bne SaveJoyp ;if not, branch
b0f4: a4 b5 ldy Player_Y_HighPos
b0f6: 88 dey ;if not in vertical area between
b0f7: d0 06 bne DisJoyp ;status bar and bottom, branch
b0f9: a5 ce lda Player_Y_Position
b0fb: c9 d0 cmp #$d0 ;if nearing the bottom of the screen or
b0fd: 90 05 bcc SaveJoyp ; not in the vertical area between status bar or bottom,
b0ff: a9 00 DisJoyp lda #$00 ; disable controller bits
b101: 8d fc 06 sta SavedJoypad1Bits
b104: ad fc 06 SaveJoyp lda SavedJoypad1Bits ;otherwise store A and B buttons in $0a
b107: 29 c0 and #%11000000
b109: 85 0a sta A_B_Buttons
b10b: ad fc 06 lda SavedJoypad1Bits ;store left and right buttons in $0c
b10e: 29 03 and #%00000011
b110: 85 0c sta Left_Right_Buttons
b112: ad fc 06 lda SavedJoypad1Bits ;store up and down buttons in $0b
b115: 29 0c and #%00001100
b117: 85 0b sta Up_Down_Buttons
b119: 29 04 and #%00000100 ;check for pressing down
b11b: f0 0e beq SizeChk ;if not, branch
b11d: a5 1d lda Player_State ;check player's state
b11f: d0 0a bne SizeChk ;if not on the ground, branch
b121: a4 0c ldy Left_Right_Buttons ;check left and right
b123: f0 06 beq SizeChk ;if neither pressed, branch
b125: a9 00 lda #$00
b127: 85 0c sta Left_Right_Buttons ;if pressing down while on the ground,
b129: 85 0b sta Up_Down_Buttons ; nullify directional bits
b12b: 20 29 b3 SizeChk jsr PlayerMovementSubs ;run movement subroutines
b12e: a0 01 ldy #$01 ;is player small?
b130: ad 54 07 lda PlayerSize
b133: d0 09 bne ChkMoveDir
b135: a0 00 ldy #$00 ;check for if crouching
b137: ad 14 07 lda CrouchingFlag
b13a: f0 02 beq ChkMoveDir ;if not, branch ahead
b13c: a0 02 ldy #$02 ;if big and crouching, load y with 2
b13e: 8c 99 04 ChkMoveDir sty Player_BoundBoxCtrl ;set contents of Y as player's bounding box size control
b141: a9 01 lda #$01 ;set moving direction to right by default
b143: a4 57 ldy Player_X_Speed ;check player's horizontal speed
b145: f0 05 beq PlayerSubs ;if not moving at all horizontally, skip this part
b147: 10 01 bpl SetMoveDir ;if moving to the right, use default moving direction
b149: 0a asl A ;otherwise change to move to the left
b14a: 85 45 SetMoveDir sta Player_MovingDir ;set moving direction
b14c: 20 93 af PlayerSubs jsr ScrollHandler ;move the screen if necessary
b14f: 20 80 f1 jsr GetPlayerOffscreenBits ;get player's offscreen bits
b152: 20 2a f1 jsr RelativePlayerPosition ;get coordinates relative to the screen
b155: a2 00 ldx #$00 ;set offset for player object
b157: 20 9c e2 jsr BoundingBoxCore ;get player's bounding box coordinates
b15a: 20 64 dc jsr PlayerBGCollision ;do collision detection and process
b15d: a5 ce lda Player_Y_Position
b15f: c9 40 cmp #$40 ;check to see if player is higher than 64th pixel
b161: 90 16 bcc PlayerHole ;if so, branch ahead
b163: a5 0e lda GameEngineSubroutine
b165: c9 05 cmp #$05 ;if running end-of-level routine, branch ahead
b167: f0 10 beq PlayerHole
b169: c9 07 cmp #$07 ;if running player entrance routine, branch ahead
b16b: f0 0c beq PlayerHole
b16d: c9 04 cmp #$04 ;if running routines $00-$03, branch ahead
b16f: 90 08 bcc PlayerHole
b171: ad c4 03 lda Player_SprAttrib
b174: 29 df and #%11011111 ;otherwise nullify player's
b176: 8d c4 03 sta Player_SprAttrib ; background priority flag
b179: a5 b5 PlayerHole lda Player_Y_HighPos ;check player's vertical high byte
b17b: c9 02 cmp #$02 ; for below the screen
b17d: 30 3b bmi ExitCtrl ;branch to leave if not that far down
b17f: a2 01 ldx #$01
b181: 8e 23 07 stx ScrollLock ;set scroll lock
b184: a0 04 ldy #$04
b186: 84 07 sty $07 ;set value here
b188: a2 00 ldx #$00 ;use X as flag, and clear for cloud level
b18a: ac 59 07 ldy GameTimerExpiredFlag ;check game timer expiration flag
b18d: d0 05 bne HoleDie ;if set, branch
b18f: ac 43 07 ldy CloudTypeOverride ;check for cloud type override
b192: d0 16 bne ChkHoleX ;skip to last part if found
b194: e8 HoleDie inx ;set flag in X for player death
b195: a4 0e ldy GameEngineSubroutine
b197: c0 0b cpy #$0b ;check for some other routine running
b199: f0 0f beq ChkHoleX ;if so, branch ahead
b19b: ac 12 07 ldy DeathMusicLoaded ;check value here
b19e: d0 06 bne HoleBottom ;if already set, branch to next part
b1a0: c8 iny
b1a1: 84 fc sty EventMusicQueue ;otherwise play death music
b1a3: 8c 12 07 sty DeathMusicLoaded ;and set value here
b1a6: a0 06 HoleBottom ldy #$06
b1a8: 84 07 sty $07 ;change value here
b1aa: c5 07 ChkHoleX cmp $07 ;compare vertical high byte with value set here
b1ac: 30 0c bmi ExitCtrl ;if less, branch to leave
b1ae: ca dex ;otherwise decrement flag in X
b1af: 30 0a bmi CloudExit ;if flag was clear, branch to set modes and other values
b1b1: ac b1 07 ldy EventMusicBuffer ;check to see if music is still playing
b1b4: d0 04 bne ExitCtrl ;branch to leave if so
b1b6: a9 06 lda #$06 ;otherwise set to run lose life routine
b1b8: 85 0e sta GameEngineSubroutine ; on next frame
b1ba: 60 ExitCtrl rts ;leave
b1bb: a9 00 CloudExit lda #$00
b1bd: 8d 58 07 sta JoypadOverride ;clear controller override bits if any are set
b1c0: 20 dd b1 jsr SetEntr ;do sub to set secondary mode
b1c3: ee 52 07 inc AltEntranceControl ;set mode of entry to 3
b1c6: 60 rts
; -----------------------------------------------------------------------------
b1c7: a5 b5 Vine_AutoClimb lda Player_Y_HighPos ;check to see whether player reached position
b1c9: d0 06 bne AutoClimb ; above the status bar yet and if so, set modes
b1cb: a5 ce lda Player_Y_Position
b1cd: c9 e4 cmp #$e4
b1cf: 90 0c bcc SetEntr
b1d1: a9 08 AutoClimb lda #%00001000 ;set controller bits override to up
b1d3: 8d 58 07 sta JoypadOverride
b1d6: a0 03 ldy #$03 ;set player state to climbing
b1d8: 84 1d sty Player_State
b1da: 4c e6 b0 jmp AutoControlPlayer
b1dd: a9 02 SetEntr lda #$02 ;set starting position to override
b1df: 8d 52 07 sta AltEntranceControl
b1e2: 4c 13 b2 jmp ChgAreaMode ;set modes
; -----------------------------------------------------------------------------
VerticalPipeEntry
b1e5: a9 01 lda #$01 ;set 1 as movement amount
b1e7: 20 00 b2 jsr MovePlayerYAxis ;do sub to move player downwards
b1ea: 20 93 af jsr ScrollHandler ;do sub to scroll screen with saved force if necessary
b1ed: a0 00 ldy #$00 ;load default mode of entry
b1ef: ad d6 06 lda WarpZoneControl ;check warp zone control variable/flag
b1f2: d0 17 bne ChgAreaPipe ;if set, branch to use mode 0
b1f4: c8 iny
b1f5: ad 4e 07 lda AreaType ;check for castle level type
b1f8: c9 03 cmp #$03
b1fa: d0 0f bne ChgAreaPipe ;if not castle type level, use mode 1
b1fc: c8 iny
b1fd: 4c 0b b2 jmp ChgAreaPipe ;otherwise use mode 2
b200: 18 MovePlayerYAxis clc
b201: 65 ce adc Player_Y_Position ;add contents of A to player position
b203: 85 ce sta Player_Y_Position
b205: 60 rts
; -----------------------------------------------------------------------------
SideExitPipeEntry
b206: 20 1f b2 jsr EnterSidePipe ;execute sub to move player to the right
b209: a0 02 ldy #$02
b20b: ce de 06 ChgAreaPipe dec ChangeAreaTimer ;decrement timer for change of area
b20e: d0 0e bne ExitCAPipe
b210: 8c 52 07 sty AltEntranceControl ;when timer expires set mode of alternate entry
b213: ee 74 07 ChgAreaMode inc DisableScreenFlag ;set flag to disable screen output
b216: a9 00 lda #$00
b218: 8d 72 07 sta OperMode_Task ;set secondary mode of operation
b21b: 8d 22 07 sta Sprite0HitDetectFlag ;disable sprite 0 check
b21e: 60 ExitCAPipe rts ;leave
b21f: a9 08 EnterSidePipe lda #$08 ;set player's horizontal speed
b221: 85 57 sta Player_X_Speed
b223: a0 01 ldy #$01 ;set controller right button by default
b225: a5 86 lda Player_X_Position ;mask out higher nybble of player's
b227: 29 0f and #%00001111 ; horizontal position
b229: d0 03 bne RightPipe
b22b: 85 57 sta Player_X_Speed ;if lower nybble = 0, set as horizontal speed
b22d: a8 tay ;and nullify controller bit override here
b22e: 98 RightPipe tya ;use contents of Y to
b22f: 20 e6 b0 jsr AutoControlPlayer ; execute player control routine with ctrl bits nulled
b232: 60 rts
; -----------------------------------------------------------------------------
PlayerChangeSize
b233: ad 47 07 lda TimerControl ;check master timer control
b236: c9 f8 cmp #$f8 ;for specific moment in time
b238: d0 03 bne EndChgSize ;branch if before or after that point
b23a: 4c 55 b2 jmp InitChangeSize ;otherwise run code to get growing/shrinking going
b23d: c9 c4 EndChgSize cmp #$c4 ;check again for another specific moment
b23f: d0 03 bne ExitChgSize ;and branch to leave if before or after that point
b241: 20 73 b2 jsr DonePlayerTask ;otherwise do sub to init timer control and set routine
b244: 60 ExitChgSize rts ;and then leave
; -----------------------------------------------------------------------------
PlayerInjuryBlink
b245: ad 47 07 lda TimerControl ;check master timer control
b248: c9 f0 cmp #$f0 ; for specific moment in time
b24a: b0 07 bcs ExitBlink ;branch if before that point
b24c: c9 c8 cmp #$c8 ;check again for another specific point
b24e: f0 23 beq DonePlayerTask ;branch if at that point, and not before or after
b250: 4c e9 b0 jmp PlayerCtrlRoutine ;otherwise run player control routine
b253: d0 13 ExitBlink bne ExitBoth ;do unconditional branch to leave
b255: ac 0b 07 InitChangeSize ldy PlayerChangeSizeFlag ;if growing/shrinking flag already set
b258: d0 0e bne ExitBoth ;then branch to leave
b25a: 8c 0d 07 sty PlayerAnimCtrl ;otherwise initialize player's animation frame control
b25d: ee 0b 07 inc PlayerChangeSizeFlag ;set growing/shrinking flag
b260: ad 54 07 lda PlayerSize
b263: 49 01 eor #$01 ;invert player's size
b265: 8d 54 07 sta PlayerSize
b268: 60 ExitBoth rts ;leave
; -----------------------------------------------------------------------------
; $00 - used in CyclePlayerPalette to store current palette to cycle
b269: ad 47 07 PlayerDeath lda TimerControl ;check master timer control
b26c: c9 f0 cmp #$f0 ;for specific moment in time
b26e: b0 33 bcs ExitDeath ;branch to leave if before that point
b270: 4c e9 b0 jmp PlayerCtrlRoutine ;otherwise run player control routine
b273: a9 00 DonePlayerTask lda #$00
b275: 8d 47 07 sta TimerControl ;initialize master timer control to continue timers
b278: a9 08 lda #$08
b27a: 85 0e sta GameEngineSubroutine ;set player control routine to run next frame
b27c: 60 rts ;leave
PlayerFireFlower
b27d: ad 47 07 lda TimerControl ;check master timer control
b280: c9 c0 cmp #$c0 ;for specific moment in time
b282: f0 13 beq ResetPalFireFlower ;branch if at moment, not before or after
b284: a5 09 lda FrameCounter ;get frame counter
b286: 4a lsr A
b287: 4a lsr A ;divide by four to change every four frames
CyclePlayerPalette
b288: 29 03 and #$03 ;mask out all but d1-d0 (previously d3-d2)
b28a: 85 00 sta $00 ;store result here to use as palette bits
b28c: ad c4 03 lda Player_SprAttrib ;get player attributes
b28f: 29 fc and #%11111100 ;save any other bits but palette bits
b291: 05 00 ora $00 ;add palette bits
b293: 8d c4 03 sta Player_SprAttrib ;store as new player attributes
b296: 60 rts ;and leave
ResetPalFireFlower
b297: 20 73 b2 jsr DonePlayerTask ;do sub to init timer control and run player control routine
b29a: ad c4 03 ResetPalStar lda Player_SprAttrib ;get player attributes
b29d: 29 fc and #%11111100 ;mask out palette bits to force palette 0
b29f: 8d c4 03 sta Player_SprAttrib ;store as new player attributes
b2a2: 60 rts ;and leave
b2a3: 60 ExitDeath rts ;leave from death routine
; -----------------------------------------------------------------------------
b2a4: a5 1b FlagpoleSlide lda Enemy_ID+5 ;check special use enemy slot
b2a6: c9 30 cmp #FlagpoleFlagObject ;for flagpole flag object
b2a8: d0 15 bne NoFPObj ;if not found, branch to something residual
b2aa: ad 13 07 lda FlagpoleSoundQueue ;load flagpole sound
b2ad: 85 ff sta Square1SoundQueue ;into square 1's sfx queue
b2af: a9 00 lda #$00
b2b1: 8d 13 07 sta FlagpoleSoundQueue ;init flagpole sound queue
b2b4: a4 ce ldy Player_Y_Position
b2b6: c0 9e cpy #$9e ;check to see if player has slid down
b2b8: b0 02 bcs SlidePlayer ; far enough, and if so, branch with no controller bits set
b2ba: a9 04 lda #$04 ;otherwise force player to climb down (to slide)
b2bc: 4c e6 b0 SlidePlayer jmp AutoControlPlayer ;jump to player control routine
b2bf: e6 0e NoFPObj inc GameEngineSubroutine ;increment to next routine (this may
b2c1: 60 rts ; be residual code)
; -----------------------------------------------------------------------------
Hidden1UpCoinAmts
b2c2: 15 23 16 1b+ .bulk $15,$23,$16,$1b,$17,$18,$23,$63
b2ca: a9 01 PlayerEndLevel lda #$01 ;force player to walk to the right
b2cc: 20 e6 b0 jsr AutoControlPlayer
b2cf: a5 ce lda Player_Y_Position ;check player's vertical position
b2d1: c9 ae cmp #$ae
b2d3: 90 0e bcc ChkStop ;if player is not yet off the flagpole, skip this part
b2d5: ad 23 07 lda ScrollLock ;if scroll lock not set, branch ahead to next part
b2d8: f0 09 beq ChkStop ;because we only need to do this part once
b2da: a9 20 lda #EndOfLevelMusic
b2dc: 85 fc sta EventMusicQueue ;load win level music in event music queue
b2de: a9 00 lda #$00
b2e0: 8d 23 07 sta ScrollLock ;turn off scroll lock to skip this part later
b2e3: ad 90 04 ChkStop lda Player_CollisionBits ;get player collision bits
b2e6: 4a lsr A ;check for d0 set
b2e7: b0 0d bcs RdyNextA ;if d0 set, skip to next part
b2e9: ad 46 07 lda StarFlagTaskControl ;if star flag task control already set,
b2ec: d0 03 bne InCastle ; go ahead with the rest of the code
b2ee: ee 46 07 inc StarFlagTaskControl ;otherwise set task control now (this gets ball rolling!)
b2f1: a9 20 InCastle lda #%00100000 ;set player's background priority bit to
b2f3: 8d c4 03 sta Player_SprAttrib ;give illusion of being inside the castle
b2f6: ad 46 07 RdyNextA lda StarFlagTaskControl
b2f9: c9 05 cmp #$05 ;if star flag task control not yet set
b2fb: d0 2b bne ExitNA ; beyond last valid task number, branch to leave
b2fd: ee 5c 07 inc LevelNumber ;increment level number used for game logic
b300: ad 5c 07 lda LevelNumber
b303: c9 03 cmp #$03 ;check to see if we have yet reached level -4
b305: d0 0e bne NextArea ; and skip this last part here if not
b307: ac 5f 07 ldy WorldNumber ;get world number as offset
b30a: ad 48 07 lda CoinTallyFor1Ups ;check third area coin tally for bonus 1-ups
b30d: d9 c2 b2 cmp Hidden1UpCoinAmts,y ; against minimum value, if player has not collected
b310: 90 03 bcc NextArea ; at least this number of coins, leave flag clear
b312: ee 5d 07 inc Hidden1UpFlag ;otherwise set hidden 1-up box control flag
b315: ee 60 07 NextArea inc AreaNumber ;increment area number used for address loader
b318: 20 03 9c jsr LoadAreaPointer ;get new level pointer
b31b: ee 57 07 inc FetchNewGameTimerFlag ;set flag to load new game timer
b31e: 20 13 b2 jsr ChgAreaMode ;do sub to set secondary mode, disable screen and sprite 0
b321: 8d 5b 07 sta HalfwayPage ;reset halfway page to 0 (beginning)
b324: a9 80 lda #Silence
b326: 85 fc sta EventMusicQueue ;silence music and leave
b328: 60 ExitNA rts
; -----------------------------------------------------------------------------
PlayerMovementSubs
b329: a9 00 lda #$00 ;set A to init crouch flag by default
b32b: ac 54 07 ldy PlayerSize ;is player small?
b32e: d0 08 bne SetCrouch ;if so, branch
b330: a5 1d lda Player_State ;check state of player
b332: d0 07 bne ProcMove ;if not on the ground, branch
b334: a5 0b lda Up_Down_Buttons ;load controller bits for up and down
b336: 29 04 and #%00000100 ;single out bit for down button
b338: 8d 14 07 SetCrouch sta CrouchingFlag ;store value in crouch flag
b33b: 20 50 b4 ProcMove jsr PlayerPhysicsSub ;run sub related to jumping and swimming
b33e: ad 0b 07 lda PlayerChangeSizeFlag ;if growing/shrinking flag set,
b341: d0 16 bne NoMoveSub ; branch to leave
b343: a5 1d lda Player_State
b345: c9 03 cmp #$03 ;get player state
b347: f0 05 beq MoveSubs ;if climbing, branch ahead, leave timer unset
b349: a0 18 ldy #$18
b34b: 8c 89 07 sty ClimbSlideTimer ;otherwise reset timer now
b34e: 20 04 8e MoveSubs jsr JumpEngine
b351: 5a b3 .dd2 OnGroundStateSub
b353: 76 b3 .dd2 JumpSwimSub
b355: 6d b3 .dd2 FallingSub
b357: cf b3 .dd2 ClimbingSub
b359: 60 NoMoveSub rts
; -----------------------------------------------------------------------------
; $00 - used by ClimbingSub to store high vertical adder
OnGroundStateSub
b35a: 20 8f b5 jsr GetPlayerAnimSpeed ;do a sub to set animation frame timing
b35d: a5 0c lda Left_Right_Buttons
b35f: f0 02 beq GndMove ;if left/right controller bits not set, skip instruction
b361: 85 33 sta PlayerFacingDir ;otherwise set new facing direction
b363: 20 cc b5 GndMove jsr ImposeFriction ;do a sub to impose friction on player's walk/run
b366: 20 09 bf jsr MovePlayerHorizontally ;do another sub to move player horizontally
b369: 8d ff 06 sta Player_X_Scroll ;set returned value as player's movement speed for scroll
b36c: 60 rts
; -----------------------------------------------------------------------------
b36d: ad 0a 07 FallingSub lda VerticalForceDown
b370: 8d 09 07 sta VerticalForce ;dump vertical movement force for falling into main one
b373: 4c ac b3 jmp LRAir ;movement force, then skip ahead to process left/right movement
; -----------------------------------------------------------------------------
b376: a4 9f JumpSwimSub ldy Player_Y_Speed ;if player's vertical speed zero
b378: 10 13 bpl DumpFall ; or moving downwards, branch to falling
b37a: a5 0a lda A_B_Buttons
b37c: 29 80 and #A_Button ;check to see if A button is being pressed
b37e: 25 0d and PreviousA_B_Buttons ; and was pressed in previous frame
b380: d0 11 bne ProcSwim ;if so, branch elsewhere
b382: ad 08 07 lda JumpOrigin_Y_Position ;get vertical position player jumped from
b385: 38 sec
b386: e5 ce sbc Player_Y_Position ;subtract current from original vertical coordinate
b388: cd 06 07 cmp DiffToHaltJump ;compare to value set here to see if player is in mid-jump
b38b: 90 06 bcc ProcSwim ;or just starting to jump, if just starting, skip ahead
b38d: ad 0a 07 DumpFall lda VerticalForceDown ;otherwise dump falling into main fractional
b390: 8d 09 07 sta VerticalForce
b393: ad 04 07 ProcSwim lda SwimmingFlag ;if swimming flag not set,
b396: f0 14 beq LRAir ;branch ahead to last part
b398: 20 8f b5 jsr GetPlayerAnimSpeed ;do a sub to get animation frame timing
b39b: a5 ce lda Player_Y_Position
b39d: c9 14 cmp #$14 ;check vertical position against preset value
b39f: b0 05 bcs LRWater ;if not yet reached a certain position, branch ahead
b3a1: a9 18 lda #$18
b3a3: 8d 09 07 sta VerticalForce ;otherwise set fractional
b3a6: a5 0c LRWater lda Left_Right_Buttons ;check left/right controller bits (check for swimming)
b3a8: f0 02 beq LRAir ;if not pressing any, skip
b3aa: 85 33 sta PlayerFacingDir ;otherwise set facing direction accordingly
b3ac: a5 0c LRAir lda Left_Right_Buttons ;check left/right controller bits (check for jumping/falling)
b3ae: f0 03 beq JSMove ;if not pressing any, skip
b3b0: 20 cc b5 jsr ImposeFriction ;otherwise process horizontal movement
b3b3: 20 09 bf JSMove jsr MovePlayerHorizontally ;do a sub to move player horizontally
b3b6: 8d ff 06 sta Player_X_Scroll ;set player's speed here, to be used for scroll later
b3b9: a5 0e lda GameEngineSubroutine
b3bb: c9 0b cmp #$0b ;check for specific routine selected
b3bd: d0 05 bne ExitMov1 ;branch if not set to run
b3bf: a9 28 lda #$28
b3c1: 8d 09 07 sta VerticalForce ;otherwise set fractional
b3c4: 4c 4d bf ExitMov1 jmp MovePlayerVertically ;jump to move player vertically, then leave
; -----------------------------------------------------------------------------
b3c7: 0e 04 fc f2 ClimbAdderLow .bulk $0e,$04,$fc,$f2
b3cb: 00 00 ff ff ClimbAdderHigh .bulk $00,$00,$ff,$ff
b3cf: ad 16 04 ClimbingSub lda Player_YMF_Dummy
b3d2: 18 clc ;add movement force to dummy variable
b3d3: 6d 33 04 adc Player_Y_MoveForce ;save with carry
b3d6: 8d 16 04 sta Player_YMF_Dummy
b3d9: a0 00 ldy #$00 ;set default adder here
b3db: a5 9f lda Player_Y_Speed ;get player's vertical speed
b3dd: 10 01 bpl MoveOnVine ;if not moving upwards, branch
b3df: 88 dey ;otherwise set adder to $ff
b3e0: 84 00 MoveOnVine sty $00 ;store adder here
b3e2: 65 ce adc Player_Y_Position ;add carry to player's vertical position
b3e4: 85 ce sta Player_Y_Position ;and store to move player up or down
b3e6: a5 b5 lda Player_Y_HighPos
b3e8: 65 00 adc $00 ;add carry to player's page location
b3ea: 85 b5 sta Player_Y_HighPos ;and store
b3ec: a5 0c lda Left_Right_Buttons ;compare left/right controller bits
b3ee: 2d 90 04 and Player_CollisionBits ;to collision flag
b3f1: f0 2d beq InitCSTimer ;if not set, skip to end
b3f3: ac 89 07 ldy ClimbSlideTimer ;otherwise check timer
b3f6: d0 27 bne ExitCSub ;if timer not expired, branch to leave
b3f8: a0 18 ldy #$18
b3fa: 8c 89 07 sty ClimbSlideTimer ;otherwise set timer now
b3fd: a2 00 ldx #$00 ;set default offset here
b3ff: a4 33 ldy PlayerFacingDir ;get facing direction
b401: 4a lsr A ;move right button controller bit to carry
b402: b0 02 bcs ClimbFD ;if controller right pressed, branch ahead
b404: e8 inx
b405: e8 inx ;otherwise increment offset by 2 bytes
b406: 88 ClimbFD dey ;check to see if facing right
b407: f0 01 beq CSetFDir ;if so, branch, do not increment
b409: e8 inx ;otherwise increment by 1 byte
b40a: a5 86 CSetFDir lda Player_X_Position
b40c: 18 clc ;add or subtract from player's horizontal position
b40d: 7d c7 b3 adc ClimbAdderLow,x ; using value here as adder and X as offset
b410: 85 86 sta Player_X_Position
b412: a5 6d lda Player_PageLoc ;add or subtract carry or borrow using value here
b414: 7d cb b3 adc ClimbAdderHigh,x ; from the player's page location
b417: 85 6d sta Player_PageLoc
b419: a5 0c lda Left_Right_Buttons ;get left/right controller bits again
b41b: 49 03 eor #%00000011 ;invert them and store them while player
b41d: 85 33 sta PlayerFacingDir ; is on vine to face player in opposite direction
b41f: 60 ExitCSub rts ;then leave
b420: 8d 89 07 InitCSTimer sta ClimbSlideTimer ;initialize timer here
b423: 60 rts
; -----------------------------------------------------------------------------
; $00 - used to store offset to friction data
b424: 20 20 1e 28+ JumpMForceData .bulk $20,$20,$1e,$28,$28,$0d,$04
b42b: 70 70 60 90+ FallMForceData .bulk $70,$70,$60,$90,$90,$0a,$09
b432: fc fc fc fb+ PlayerYSpdData .bulk $fc,$fc,$fc,$fb,$fb,$fe,$ff
b439: 00 00 00 00+ InitMForceData .bulk $00,$00,$00,$00,$00,$80,$00
b440: d8 e8 f0 MaxLeftXSpdData .bulk $d8,$e8,$f0
MaxRightXSpdData
b443: 28 18 10 .bulk $28,$18,$10
b446: 0c .dd1 $0c ;used for pipe intros
b447: e4 98 d0 FrictionData .bulk $e4,$98,$d0
Climb_Y_SpeedData
b44a: 00 ff 01 .bulk $00,$ff,$01
Climb_Y_MForceData
b44d: 00 20 ff .bulk $00,$20,$ff
PlayerPhysicsSub
b450: a5 1d lda Player_State ;check player state
b452: c9 03 cmp #$03
b454: d0 23 bne CheckForJumping ;if not climbing, branch
b456: a0 00 ldy #$00
b458: a5 0b lda Up_Down_Buttons ;get controller bits for up/down
b45a: 2d 90 04 and Player_CollisionBits ;check against player's collision detection bits
b45d: f0 06 beq ProcClimb ;if not pressing up or down, branch
b45f: c8 iny
b460: 29 08 and #%00001000 ;check for pressing up
b462: d0 01 bne ProcClimb
b464: c8 iny
b465: be 4d b4 ProcClimb ldx Climb_Y_MForceData,y ;load value here
b468: 8e 33 04 stx Player_Y_MoveForce ;store as vertical movement force
b46b: a9 08 lda #$08 ;load default animation timing
b46d: be 4a b4 ldx Climb_Y_SpeedData,y ;load some other value here
b470: 86 9f stx Player_Y_Speed ;store as vertical speed
b472: 30 01 bmi SetCAnim ;if climbing down, use default animation timing value
b474: 4a lsr A ;otherwise divide timer setting by 2
b475: 8d 0c 07 SetCAnim sta PlayerAnimTimerSet ;store animation timer setting and leave
b478: 60 rts
b479: ad 0e 07 CheckForJumping lda JumpspringAnimCtrl ;if jumpspring animating,
b47c: d0 0a bne NoJump ;skip ahead to something else
b47e: a5 0a lda A_B_Buttons ;check for A button press
b480: 29 80 and #A_Button
b482: f0 04 beq NoJump ;if not, branch to something else
b484: 25 0d and PreviousA_B_Buttons ;if button not pressed in previous frame, branch
b486: f0 03 beq ProcJumping
b488: 4c 1c b5 NoJump jmp X_Physics ;otherwise, jump to something else
b48b: a5 1d ProcJumping lda Player_State ;check player state
b48d: f0 11 beq InitJS ;if on the ground, branch
b48f: ad 04 07 lda SwimmingFlag ;if swimming flag not set, jump to do something else
b492: f0 f4 beq NoJump ; to prevent midair jumping, otherwise continue
b494: ad 82 07 lda JumpSwimTimer ;if jump/swim timer nonzero, branch
b497: d0 07 bne InitJS
b499: a5 9f lda Player_Y_Speed ;check player's vertical speed
b49b: 10 03 bpl InitJS ;if player's vertical speed motionless or down, branch
b49d: 4c 1c b5 jmp X_Physics ;if timer at zero and player still rising, do not swim
b4a0: a9 20 InitJS lda #$20 ;set jump/swim timer
b4a2: 8d 82 07 sta JumpSwimTimer
b4a5: a0 00 ldy #$00 ;initialize vertical force and dummy variable
b4a7: 8c 16 04 sty Player_YMF_Dummy
b4aa: 8c 33 04 sty Player_Y_MoveForce
b4ad: a5 b5 lda Player_Y_HighPos ;get vertical high and low bytes of jump origin
b4af: 8d 07 07 sta JumpOrigin_Y_HighPos ; and store them next to each other here
b4b2: a5 ce lda Player_Y_Position
b4b4: 8d 08 07 sta JumpOrigin_Y_Position
b4b7: a9 01 lda #$01 ;set player state to jumping/swimming
b4b9: 85 1d sta Player_State
b4bb: ad 00 07 lda Player_XSpeedAbsolute ;check value related to walking/running speed
b4be: c9 09 cmp #$09
b4c0: 90 10 bcc ChkWtr ;branch if below certain values, increment Y
b4c2: c8 iny ;for each amount equal or exceeded
b4c3: c9 10 cmp #$10
b4c5: 90 0b bcc ChkWtr
b4c7: c8 iny
b4c8: c9 19 cmp #$19
b4ca: 90 06 bcc ChkWtr
b4cc: c8 iny
b4cd: c9 1c cmp #$1c
b4cf: 90 01 bcc ChkWtr ;note that for jumping, range is 0-4 for Y
b4d1: c8 iny
b4d2: a9 01 ChkWtr lda #$01 ;set value here (apparently always set to 1)
b4d4: 8d 06 07 sta DiffToHaltJump
b4d7: ad 04 07 lda SwimmingFlag ;if swimming flag disabled, branch
b4da: f0 08 beq GetYPhy
b4dc: a0 05 ldy #$05 ;otherwise set Y to 5, range is 5-6
b4de: ad 7d 04 lda Whirlpool_Flag ;if whirlpool flag not set, branch
b4e1: f0 01 beq GetYPhy
b4e3: c8 iny ;otherwise increment to 6
b4e4: b9 24 b4 GetYPhy lda JumpMForceData,y ;store appropriate jump/swim
b4e7: 8d 09 07 sta VerticalForce ; data here
b4ea: b9 2b b4 lda FallMForceData,y
b4ed: 8d 0a 07 sta VerticalForceDown
b4f0: b9 39 b4 lda InitMForceData,y
b4f3: 8d 33 04 sta Player_Y_MoveForce
b4f6: b9 32 b4 lda PlayerYSpdData,y
b4f9: 85 9f sta Player_Y_Speed
b4fb: ad 04 07 lda SwimmingFlag ;if swimming flag disabled, branch
b4fe: f0 11 beq PJumpSnd
b500: a9 04 lda #Sfx_EnemyStomp ;load swim/goomba stomp sound into
b502: 85 ff sta Square1SoundQueue ;square 1's sfx queue
b504: a5 ce lda Player_Y_Position
b506: c9 14 cmp #$14 ;check vertical low byte of player position
b508: b0 12 bcs X_Physics ;if below a certain point, branch
b50a: a9 00 lda #$00 ;otherwise reset player's vertical speed
b50c: 85 9f sta Player_Y_Speed ; and jump to something else to keep player
b50e: 4c 1c b5 jmp X_Physics ; from swimming above water level
b511: a9 01 PJumpSnd lda #Sfx_BigJump ;load big mario's jump sound by default
b513: ac 54 07 ldy PlayerSize ;is mario big?
b516: f0 02 beq SJumpSnd
b518: a9 80 lda #Sfx_SmallJump ;if not, load small mario's jump sound
b51a: 85 ff SJumpSnd sta Square1SoundQueue ;store appropriate jump sound in square 1 sfx queue
b51c: a0 00 X_Physics ldy #$00
b51e: 84 00 sty $00 ;init value here
b520: a5 1d lda Player_State ;if mario is on the ground, branch
b522: f0 09 beq ProcPRun
b524: ad 00 07 lda Player_XSpeedAbsolute ;check something that seems to be related
b527: c9 19 cmp #$19 ;to mario's speed
b529: b0 33 bcs GetXPhy ;if =>$19 branch here
b52b: 90 18 bcc ChkRFast ;if not branch elsewhere
b52d: c8 ProcPRun iny ;if mario on the ground, increment Y
b52e: ad 4e 07 lda AreaType ;check area type
b531: f0 12 beq ChkRFast ;if water type, branch
b533: 88 dey ;decrement Y by default for non-water type area
b534: a5 0c lda Left_Right_Buttons ;get left/right controller bits
b536: c5 45 cmp Player_MovingDir ;check against moving direction
b538: d0 0b bne ChkRFast ;if controller bits <> moving direction, skip this part
b53a: a5 0a lda A_B_Buttons ;check for b button pressed
b53c: 29 40 and #B_Button
b53e: d0 19 bne SetRTmr ;if pressed, skip ahead to set timer
b540: ad 83 07 lda RunningTimer ;check for running timer set
b543: d0 19 bne GetXPhy ;if set, branch
b545: c8 ChkRFast iny ;if running timer not set or level type is water,
b546: e6 00 inc $00 ; increment Y again and temp variable in memory
b548: ad 03 07 lda RunningSpeed
b54b: d0 07 bne FastXSp ;if running speed set here, branch
b54d: ad 00 07 lda Player_XSpeedAbsolute
b550: c9 21 cmp #$21 ;otherwise check player's walking/running speed
b552: 90 0a bcc GetXPhy ;if less than a certain amount, branch ahead
b554: e6 00 FastXSp inc $00 ;if running speed set or speed => $21 increment $00
b556: 4c 5e b5 jmp GetXPhy ; and jump ahead
b559: a9 0a SetRTmr lda #$0a ;if b button pressed, set running timer
b55b: 8d 83 07 sta RunningTimer
b55e: b9 40 b4 GetXPhy lda MaxLeftXSpdData,y ;get maximum speed to the left
b561: 8d 50 04 sta MaximumLeftSpeed
b564: a5 0e lda GameEngineSubroutine ;check for specific routine running
b566: c9 07 cmp #$07 ;(player entrance)
b568: d0 02 bne GetXPhy2 ;if not running, skip and use old value of Y
b56a: a0 03 ldy #$03 ;otherwise set Y to 3
b56c: b9 43 b4 GetXPhy2 lda MaxRightXSpdData,y ;get maximum speed to the right
b56f: 8d 56 04 sta MaximumRightSpeed
b572: a4 00 ldy $00 ;get other value in memory
b574: b9 47 b4 lda FrictionData,y ;get value using value in memory as offset
b577: 8d 02 07 sta FrictionAdderLow
b57a: a9 00 lda #$00
b57c: 8d 01 07 sta FrictionAdderHigh ;init something here
b57f: a5 33 lda PlayerFacingDir
b581: c5 45 cmp Player_MovingDir ;check facing direction against moving direction
b583: f0 06 beq ExitPhy ;if the same, branch to leave
b585: 0e 02 07 asl FrictionAdderLow ;otherwise shift d7 of friction adder low into carry
b588: 2e 01 07 rol FrictionAdderHigh ; then rotate carry onto d0 of friction adder high
b58b: 60 ExitPhy rts ; and then leave
; -----------------------------------------------------------------------------
PlayerAnimTmrData
b58c: 02 04 07 .bulk $02,$04,$07
GetPlayerAnimSpeed
b58f: a0 00 ldy #$00 ;initialize offset in Y
b591: ad 00 07 lda Player_XSpeedAbsolute ;check player's walking/running speed
b594: c9 1c cmp #$1c ; against preset amount
b596: b0 15 bcs SetRunSpd ;if greater than a certain amount, branch ahead
b598: c8 iny ;otherwise increment Y
b599: c9 0e cmp #$0e ;compare against lower amount
b59b: b0 01 bcs ChkSkid ;if greater than this but not greater than first, skip increment
b59d: c8 iny ;otherwise increment Y again
b59e: ad fc 06 ChkSkid lda SavedJoypad1Bits ;get controller bits
b5a1: 29 7f and #%01111111 ;mask out A button
b5a3: f0 20 beq SetAnimSpd ;if no other buttons pressed, branch ahead of all this
b5a5: 29 03 and #$03 ;mask out all others except left and right
b5a7: c5 45 cmp Player_MovingDir ;check against moving direction
b5a9: d0 08 bne ProcSkid ;if left/right controller bits <> moving direction, branch
b5ab: a9 00 lda #$00 ;otherwise set zero value here
b5ad: 8d 03 07 SetRunSpd sta RunningSpeed ;store zero or running speed here
b5b0: 4c c5 b5 jmp SetAnimSpd
b5b3: ad 00 07 ProcSkid lda Player_XSpeedAbsolute ;check player's walking/running speed
b5b6: c9 0b cmp #$0b ;against one last amount
b5b8: b0 0b bcs SetAnimSpd ;if greater than this amount, branch
b5ba: a5 33 lda PlayerFacingDir
b5bc: 85 45 sta Player_MovingDir ;otherwise use facing direction to set moving direction
b5be: a9 00 lda #$00
b5c0: 85 57 sta Player_X_Speed ;nullify player's horizontal speed
b5c2: 8d 05 07 sta Player_X_MoveForce ; and dummy variable for player
b5c5: b9 8c b5 SetAnimSpd lda PlayerAnimTmrData,y ;get animation timer setting using Y as offset
b5c8: 8d 0c 07 sta PlayerAnimTimerSet
b5cb: 60 rts
; -----------------------------------------------------------------------------
b5cc: 2d 90 04 ImposeFriction and Player_CollisionBits ;perform AND between left/right controller bits and collision flag
b5cf: c9 00 cmp #$00 ;then compare to zero (this instruction is redundant)
b5d1: d0 08 bne JoypFrict ;if any bits set, branch to next part
b5d3: a5 57 lda Player_X_Speed
b5d5: f0 49 beq SetAbsSpd ;if player has no horizontal speed, branch ahead to last part
b5d7: 10 23 bpl RghtFrict ;if player moving to the right, branch to slow
b5d9: 30 03 bmi LeftFrict ;otherwise logic dictates player moving left, branch to slow
b5db: 4a JoypFrict lsr A ;put right controller bit into carry
b5dc: 90 1e bcc RghtFrict ;if left button pressed, carry = 0, thus branch
b5de: ad 05 07 LeftFrict lda Player_X_MoveForce ;load value set here
b5e1: 18 clc
b5e2: 6d 02 07 adc FrictionAdderLow ;add to it another value set here
b5e5: 8d 05 07 sta Player_X_MoveForce ;store here
b5e8: a5 57 lda Player_X_Speed
b5ea: 6d 01 07 adc FrictionAdderHigh ;add value plus carry to horizontal speed
b5ed: 85 57 sta Player_X_Speed ;set as new horizontal speed
b5ef: cd 56 04 cmp MaximumRightSpeed ;compare against maximum value for right movement
b5f2: 30 23 bmi XSpdSign ;if horizontal speed greater negatively, branch
b5f4: ad 56 04 lda MaximumRightSpeed ;otherwise set preset value as horizontal speed
b5f7: 85 57 sta Player_X_Speed ;thus slowing the player's left movement down
b5f9: 4c 20 b6 jmp SetAbsSpd ;skip to the end
b5fc: ad 05 07 RghtFrict lda Player_X_MoveForce ;load value set here
b5ff: 38 sec
b600: ed 02 07 sbc FrictionAdderLow ;subtract from it another value set here
b603: 8d 05 07 sta Player_X_MoveForce ;store here
b606: a5 57 lda Player_X_Speed
b608: ed 01 07 sbc FrictionAdderHigh ;subtract value plus borrow from horizontal speed
b60b: 85 57 sta Player_X_Speed ;set as new horizontal speed
b60d: cd 50 04 cmp MaximumLeftSpeed ;compare against maximum value for left movement
b610: 10 05 bpl XSpdSign ;if horizontal speed greater positively, branch
b612: ad 50 04 lda MaximumLeftSpeed ;otherwise set preset value as horizontal speed
b615: 85 57 sta Player_X_Speed ;thus slowing the player's right movement down
b617: c9 00 XSpdSign cmp #$00 ;if player not moving or moving to the right,
b619: 10 05 bpl SetAbsSpd ; branch and leave horizontal speed value unmodified
b61b: 49 ff eor #$ff
b61d: 18 clc ;otherwise get two's compliment to get absolute
b61e: 69 01 adc #$01 ; unsigned walking/running speed
b620: 8d 00 07 SetAbsSpd sta Player_XSpeedAbsolute ;store walking/running speed here and leave
b623: 60 rts
; -----------------------------------------------------------------------------
; $00 - used to store downward movement force in FireballObjCore
; $02 - used to store maximum vertical speed in FireballObjCore
; $07 - used to store pseudorandom bit in BubbleCheck
ProcFireball_Bubble
b624: ad 56 07 lda PlayerStatus ;check player's status
b627: c9 02 cmp #$02
b629: 90 43 bcc ProcAirBubbles ;if not fiery, branch
b62b: a5 0a lda A_B_Buttons
b62d: 29 40 and #B_Button ;check for b button pressed
b62f: f0 33 beq ProcFireballs ;branch if not pressed
b631: 25 0d and PreviousA_B_Buttons
b633: d0 2f bne ProcFireballs ;if button pressed in previous frame, branch
b635: ad ce 06 lda FireballCounter ;load fireball counter
b638: 29 01 and #%00000001 ;get LSB and use as offset for buffer
b63a: aa tax
b63b: b5 24 lda Fireball_State,x ;load fireball state
b63d: d0 25 bne ProcFireballs ;if not inactive, branch
b63f: a4 b5 ldy Player_Y_HighPos ;if player too high or too low, branch
b641: 88 dey
b642: d0 20 bne ProcFireballs
b644: ad 14 07 lda CrouchingFlag ;if player crouching, branch
b647: d0 1b bne ProcFireballs
b649: a5 1d lda Player_State ;if player's state = climbing, branch
b64b: c9 03 cmp #$03
b64d: f0 15 beq ProcFireballs
b64f: a9 20 lda #Sfx_Fireball ;play fireball sound effect
b651: 85 ff sta Square1SoundQueue
b653: a9 02 lda #$02 ;load state
b655: 95 24 sta Fireball_State,x
b657: ac 0c 07 ldy PlayerAnimTimerSet ;copy animation frame timer setting
b65a: 8c 11 07 sty FireballThrowingTimer ; into fireball throwing timer
b65d: 88 dey
b65e: 8c 81 07 sty PlayerAnimTimer ;decrement and store in player's animation timer
b661: ee ce 06 inc FireballCounter ;increment fireball counter
b664: a2 00 ProcFireballs ldx #$00
b666: 20 89 b6 jsr FireballObjCore ;process first fireball object
b669: a2 01 ldx #$01
b66b: 20 89 b6 jsr FireballObjCore ;process second fireball object, then do air bubbles
b66e: ad 4e 07 ProcAirBubbles lda AreaType ;if not water type level, skip the rest of this
b671: d0 13 bne BublExit
b673: a2 02 ldx #$02 ;otherwise load counter and use as offset
b675: 86 08 BublLoop stx ObjectOffset ;store offset
b677: 20 f9 b6 jsr BubbleCheck ;check timers and coordinates, create air bubble
b67a: 20 31 f1 jsr RelativeBubblePosition ;get relative coordinates
b67d: 20 91 f1 jsr GetBubbleOffscreenBits ;get offscreen information
b680: 20 e1 ed jsr DrawBubble ;draw the air bubble
b683: ca dex
b684: 10 ef bpl BublLoop ;do this until all three are handled
b686: 60 BublExit rts ;then leave
FireballXSpdData
b687: 40 .dd1 $40
b688: c0 .dd1 $c0
b689: 86 08 FireballObjCore stx ObjectOffset ;store offset as current object
b68b: b5 24 lda Fireball_State,x ;check for d7 = 1
b68d: 0a asl A
b68e: b0 63 bcs FireballExplosion ;if so, branch to get relative coordinates and draw explosion
b690: b4 24 ldy Fireball_State,x ;if fireball inactive, branch to leave
b692: f0 5e beq NoFBall
b694: 88 dey ;if fireball state set to 1, skip this part and just run it
b695: f0 27 beq RunFB
b697: a5 86 lda Player_X_Position ;get player's horizontal position
b699: 69 04 adc #$04 ;add four pixels and store as fireball's horizontal position
b69b: 95 8d sta Fireball_X_Position,x
b69d: a5 6d lda Player_PageLoc ;get player's page location
b69f: 69 00 adc #$00 ;add carry and store as fireball's page location
b6a1: 95 74 sta Fireball_PageLoc,x
b6a3: a5 ce lda Player_Y_Position ;get player's vertical position and store
b6a5: 95 d5 sta Fireball_Y_Position,x
b6a7: a9 01 lda #$01 ;set high byte of vertical position
b6a9: 95 bc sta Fireball_Y_HighPos,x
b6ab: a4 33 ldy PlayerFacingDir ;get player's facing direction
b6ad: 88 dey ;decrement to use as offset here
b6ae: b9 87 b6 lda FireballXSpdData,y ;set horizontal speed of fireball accordingly
b6b1: 95 5e sta Fireball_X_Speed,x
b6b3: a9 04 lda #$04 ;set vertical speed of fireball
b6b5: 95 a6 sta Fireball_Y_Speed,x
b6b7: a9 07 lda #$07
b6b9: 9d a0 04 sta Fireball_BoundBoxCtrl,x ;set bounding box size control for fireball
b6bc: d6 24 dec Fireball_State,x ;decrement state to 1 to skip this part from now on
b6be: 8a RunFB txa ;add 7 to offset to use
b6bf: 18 clc ; as fireball offset for next routines
b6c0: 69 07 adc #$07
b6c2: aa tax
b6c3: a9 50 lda #$50 ;set downward movement force here
b6c5: 85 00 sta $00
b6c7: a9 03 lda #$03 ;set maximum speed here
b6c9: 85 02 sta $02
b6cb: a9 00 lda #$00
b6cd: 20 d7 bf jsr ImposeGravity ;do sub here to impose gravity on fireball and move vertically
b6d0: 20 0f bf jsr MoveObjectHorizontally ;do another sub to move it horizontally
b6d3: a6 08 ldx ObjectOffset ;return fireball offset to X
b6d5: 20 3b f1 jsr RelativeFireballPosition ;get relative coordinates
b6d8: 20 87 f1 jsr GetFireballOffscreenBits ;get offscreen information
b6db: 20 2d e2 jsr GetFireballBoundBox ;get bounding box coordinates
b6de: 20 c8 e1 jsr FireballBGCollision ;do fireball to background collision detection
b6e1: ad d2 03 lda FBall_OffscreenBits ;get fireball offscreen bits
b6e4: 29 cc and #%11001100 ;mask out certain bits
b6e6: d0 06 bne EraseFB ;if any bits still set, branch to kill fireball
b6e8: 20 d9 d6 jsr FireballEnemyCollision ;do fireball to enemy collision detection and deal with collisions
b6eb: 4c de ec jmp DrawFireball ;draw fireball appropriately and leave
b6ee: a9 00 EraseFB lda #$00 ;erase fireball state
b6f0: 95 24 sta Fireball_State,x
b6f2: 60 NoFBall rts ;leave
FireballExplosion
b6f3: 20 3b f1 jsr RelativeFireballPosition
b6f6: 4c 09 ed jmp DrawExplosion_Fireball
b6f9: bd a8 07 BubbleCheck lda PseudoRandomBitReg+1,x ;get part of LSFR
b6fc: 29 01 and #$01
b6fe: 85 07 sta $07 ;store pseudorandom bit here
b700: b5 e4 lda Bubble_Y_Position,x ;get vertical coordinate for air bubble
b702: c9 f8 cmp #$f8 ;if offscreen coordinate not set,
b704: d0 2c bne MoveBubl ;branch to move air bubble
b706: ad 92 07 lda AirBubbleTimer ;if air bubble timer not expired,
b709: d0 3f bne ExitBubl ;branch to leave, otherwise create new air bubble
b70b: a0 00 SetupBubble ldy #$00 ;load default value here
b70d: a5 33 lda PlayerFacingDir ;get player's facing direction
b70f: 4a lsr A ;move d0 to carry
b710: 90 02 bcc PosBubl ;branch to use default value if facing left
b712: a0 08 ldy #$08 ;otherwise load alternate value here
b714: 98 PosBubl tya ;use value loaded as adder
b715: 65 86 adc Player_X_Position ;add to player's horizontal position
b717: 95 9c sta Bubble_X_Position,x ;save as horizontal position for airbubble
b719: a5 6d lda Player_PageLoc
b71b: 69 00 adc #$00 ;add carry to player's page location
b71d: 95 83 sta Bubble_PageLoc,x ;save as page location for airbubble
b71f: a5 ce lda Player_Y_Position
b721: 18 clc ;add eight pixels to player's vertical position
b722: 69 08 adc #$08
b724: 95 e4 sta Bubble_Y_Position,x ;save as vertical position for air bubble
b726: a9 01 lda #$01
b728: 95 cb sta Bubble_Y_HighPos,x ;set vertical high byte for air bubble
b72a: a4 07 ldy $07 ;get pseudorandom bit, use as offset
b72c: b9 4d b7 lda BubbleTimerData,y ;get data for air bubble timer
b72f: 8d 92 07 sta AirBubbleTimer ;set air bubble timer
b732: a4 07 MoveBubl ldy $07 ;get pseudorandom bit again, use as offset
b734: bd 2c 04 lda Bubble_YMF_Dummy,x
b737: 38 sec ;subtract pseudorandom amount from dummy variable
b738: f9 4b b7 sbc Bubble_MForceData,y
b73b: 9d 2c 04 sta Bubble_YMF_Dummy,x ;save dummy variable
b73e: b5 e4 lda Bubble_Y_Position,x
b740: e9 00 sbc #$00 ;subtract borrow from airbubble's vertical coordinate
b742: c9 20 cmp #$20 ;if below the status bar,
b744: b0 02 bcs Y_Bubl ;branch to go ahead and use to move air bubble upwards
b746: a9 f8 lda #$f8 ;otherwise set offscreen coordinate
b748: 95 e4 Y_Bubl sta Bubble_Y_Position,x ;store as new vertical coordinate for air bubble
b74a: 60 ExitBubl rts ;leave
Bubble_MForceData
b74b: ff .dd1 $ff
b74c: 50 .dd1 $50
b74d: 40 BubbleTimerData .dd1 $40
b74e: 20 .dd1 $20
; -----------------------------------------------------------------------------
b74f: ad 70 07 RunGameTimer lda OperMode ;get primary mode of operation
b752: f0 4f beq ExGTimer ;branch to leave if in title screen mode
b754: a5 0e lda GameEngineSubroutine
b756: c9 08 cmp #$08 ;if routine number less than eight running,
b758: 90 49 bcc ExGTimer ;branch to leave
b75a: c9 0b cmp #$0b ;if running death routine,
b75c: f0 45 beq ExGTimer ;branch to leave
b75e: a5 b5 lda Player_Y_HighPos
b760: c9 02 cmp #$02 ;if player below the screen,
b762: b0 3f bcs ExGTimer ;branch to leave regardless of level type
b764: ad 87 07 lda GameTimerCtrlTimer ;if game timer control not yet expired,
b767: d0 3a bne ExGTimer ;branch to leave
b769: ad f8 07 lda GameTimerDisplay
b76c: 0d f9 07 ora GameTimerDisplay+1 ;otherwise check game timer digits
b76f: 0d fa 07 ora GameTimerDisplay+2
b772: f0 26 beq TimeUpOn ;if game timer digits at 000, branch to time-up code
b774: ac f8 07 ldy GameTimerDisplay ;otherwise check first digit
b777: 88 dey ;if first digit not on 1,
b778: d0 0c bne ResGTCtrl ;branch to reset game timer control
b77a: ad f9 07 lda GameTimerDisplay+1 ;otherwise check second and third digits
b77d: 0d fa 07 ora GameTimerDisplay+2
b780: d0 04 bne ResGTCtrl ;if timer not at 100, branch to reset game timer control
b782: a9 40 lda #TimeRunningOutMusic
b784: 85 fc sta EventMusicQueue ;otherwise load time running out music
b786: a9 18 ResGTCtrl lda #$18 ;reset game timer control
b788: 8d 87 07 sta GameTimerCtrlTimer
b78b: a0 23 ldy #$23 ;set offset for last digit
b78d: a9 ff lda #$ff ;set value to decrement game timer digit
b78f: 8d 39 01 sta DigitModifier+5
b792: 20 5f 8f jsr DigitsMathRoutine ;do sub to decrement game timer slowly
b795: a9 a4 lda #$a4 ;set status nybbles to update game timer display
b797: 4c 06 8f jmp PrintStatusBarNumbers ;do sub to update the display
b79a: 8d 56 07 TimeUpOn sta PlayerStatus ;init player status (note A will always be zero here)
b79d: 20 31 d9 jsr ForceInjury ;do sub to kill the player (note player is small here)
b7a0: ee 59 07 inc GameTimerExpiredFlag ;set game timer expiration flag
b7a3: 60 ExGTimer rts ;leave
; -----------------------------------------------------------------------------
b7a4: ad 23 07 WarpZoneObject lda ScrollLock ;check for scroll lock flag
b7a7: f0 fa beq ExGTimer ;branch if not set to leave
b7a9: a5 ce lda Player_Y_Position ;check to see if player's vertical coordinate has
b7ab: 25 b5 and Player_Y_HighPos ;same bits set as in vertical high byte (why?)
b7ad: d0 f4 bne ExGTimer ;if so, branch to leave
b7af: 8d 23 07 sta ScrollLock ;otherwise nullify scroll lock flag
b7b2: ee d6 06 inc WarpZoneControl ;increment warp zone flag to make warp pipes for warp zone
b7b5: 4c 98 c9 jmp EraseEnemyObject ;kill this object
; -----------------------------------------------------------------------------
; $00 - used in WhirlpoolActivate to store whirlpool length / 2, page location
; of center of whirlpool and also to store movement force exerted on player
; $01 - used in ProcessWhirlpools to store page location of right extent of
; whirlpool and in WhirlpoolActivate to store center of whirlpool
; $02 - used in ProcessWhirlpools to store right extent of whirlpool and in
; WhirlpoolActivate to store maximum vertical speed
ProcessWhirlpools
b7b8: ad 4e 07 lda AreaType ;check for water type level
b7bb: d0 37 bne ExitWh ;branch to leave if not found
b7bd: 8d 7d 04 sta Whirlpool_Flag ;otherwise initialize whirlpool flag
b7c0: ad 47 07 lda TimerControl ;if master timer control set,
b7c3: d0 2f bne ExitWh ;branch to leave
b7c5: a0 04 ldy #$04 ;otherwise start with last whirlpool data
b7c7: b9 71 04 WhLoop lda Whirlpool_LeftExtent,y ;get left extent of whirlpool
b7ca: 18 clc
b7cb: 79 77 04 adc Whirlpool_Length,y ;add length of whirlpool
b7ce: 85 02 sta $02 ;store result as right extent here
b7d0: b9 6b 04 lda Whirlpool_PageLoc,y ;get page location
b7d3: f0 1c beq NextWh ;if none or page 0, branch to get next data
b7d5: 69 00 adc #$00 ;add carry
b7d7: 85 01 sta $01 ;store result as page location of right extent here
b7d9: a5 86 lda Player_X_Position ;get player's horizontal position
b7db: 38 sec
b7dc: f9 71 04 sbc Whirlpool_LeftExtent,y ;subtract left extent
b7df: a5 6d lda Player_PageLoc ;get player's page location
b7e1: f9 6b 04 sbc Whirlpool_PageLoc,y ;subtract borrow
b7e4: 30 0b bmi NextWh ;if player too far left, branch to get next data
b7e6: a5 02 lda $02 ;otherwise get right extent
b7e8: 38 sec
b7e9: e5 86 sbc Player_X_Position ;subtract player's horizontal coordinate
b7eb: a5 01 lda $01 ;get right extent's page location
b7ed: e5 6d sbc Player_PageLoc ;subtract borrow
b7ef: 10 04 bpl WhirlpoolActivate ;if player within right extent, branch to whirlpool code
b7f1: 88 NextWh dey ;move onto next whirlpool data
b7f2: 10 d3 bpl WhLoop ;do this until all whirlpools are checked
b7f4: 60 ExitWh rts ;leave
WhirlpoolActivate
b7f5: b9 77 04 lda Whirlpool_Length,y ;get length of whirlpool
b7f8: 4a lsr A ;divide by 2
b7f9: 85 00 sta $00 ;save here
b7fb: b9 71 04 lda Whirlpool_LeftExtent,y ;get left extent of whirlpool
b7fe: 18 clc
b7ff: 65 00 adc $00 ;add length divided by 2
b801: 85 01 sta $01 ;save as center of whirlpool
b803: b9 6b 04 lda Whirlpool_PageLoc,y ;get page location
b806: 69 00 adc #$00 ;add carry
b808: 85 00 sta $00 ;save as page location of whirlpool center
b80a: a5 09 lda FrameCounter ;get frame counter
b80c: 4a lsr A ;shift d0 into carry (to run on every other frame)
b80d: 90 2c bcc WhPull ;if d0 not set, branch to last part of code
b80f: a5 01 lda $01 ;get center
b811: 38 sec
b812: e5 86 sbc Player_X_Position ;subtract player's horizontal coordinate
b814: a5 00 lda $00 ;get page location of center
b816: e5 6d sbc Player_PageLoc ;subtract borrow
b818: 10 0e bpl LeftWh ;if player to the left of center, branch
b81a: a5 86 lda Player_X_Position ;otherwise slowly pull player left, towards the center
b81c: 38 sec
b81d: e9 01 sbc #$01 ;subtract one pixel
b81f: 85 86 sta Player_X_Position ;set player's new horizontal coordinate
b821: a5 6d lda Player_PageLoc
b823: e9 00 sbc #$00 ;subtract borrow
b825: 4c 39 b8 jmp SetPWh ;jump to set player's new page location
b828: ad 90 04 LeftWh lda Player_CollisionBits ;get player's collision bits
b82b: 4a lsr A ;shift d0 into carry
b82c: 90 0d bcc WhPull ;if d0 not set, branch
b82e: a5 86 lda Player_X_Position ;otherwise slowly pull player right, towards the center
b830: 18 clc
b831: 69 01 adc #$01 ;add one pixel
b833: 85 86 sta Player_X_Position ;set player's new horizontal coordinate
b835: a5 6d lda Player_PageLoc
b837: 69 00 adc #$00 ;add carry
b839: 85 6d SetPWh sta Player_PageLoc ;set player's new page location
b83b: a9 10 WhPull lda #$10
b83d: 85 00 sta $00 ;set vertical movement force
b83f: a9 01 lda #$01
b841: 8d 7d 04 sta Whirlpool_Flag ;set whirlpool flag to be used later
b844: 85 02 sta $02 ;also set maximum vertical speed
b846: 4a lsr A
b847: aa tax ;set X for player offset
b848: 4c d7 bf jmp ImposeGravity ;jump to put whirlpool effect on player vertically, do not return
; -----------------------------------------------------------------------------
FlagpoleScoreMods
b84b: 05 02 08 04+ .bulk $05,$02,$08,$04,$01
FlagpoleScoreDigits
b850: 03 03 04 04+ .bulk $03,$03,$04,$04,$04
b855: a2 05 FlagpoleRoutine ldx #$05 ;set enemy object offset
b857: 86 08 stx ObjectOffset ; to special use slot
b859: b5 16 lda Enemy_ID,x
b85b: c9 30 cmp #FlagpoleFlagObject ;if flagpole flag not found,
b85d: d0 56 bne ExitFlagP ;branch to leave
b85f: a5 0e lda GameEngineSubroutine
b861: c9 04 cmp #$04 ;if flagpole slide routine not running,
b863: d0 31 bne SkipScore ;branch to near the end of code
b865: a5 1d lda Player_State
b867: c9 03 cmp #$03 ;if player state not climbing,
b869: d0 2b bne SkipScore ;branch to near the end of code
b86b: b5 cf lda Enemy_Y_Position,x ;check flagpole flag's vertical coordinate
b86d: c9 aa cmp #$aa ;if flagpole flag down to a certain point,
b86f: b0 28 bcs GiveFPScr ;branch to end the level
b871: a5 ce lda Player_Y_Position ;check player's vertical coordinate
b873: c9 a2 cmp #$a2 ;if player down to a certain point,
b875: b0 22 bcs GiveFPScr ;branch to end the level
b877: bd 17 04 lda Enemy_YMF_Dummy,x
b87a: 69 ff adc #$ff ;add movement amount to dummy variable
b87c: 9d 17 04 sta Enemy_YMF_Dummy,x ;save dummy variable
b87f: b5 cf lda Enemy_Y_Position,x ;get flag's vertical coordinate
b881: 69 01 adc #$01 ;add 1 plus carry to move flag, and
b883: 95 cf sta Enemy_Y_Position,x ; store vertical coordinate
b885: ad 0e 01 lda FlagpoleFNum_YMFDummy
b888: 38 sec ;subtract movement amount from dummy variable
b889: e9 ff sbc #$ff
b88b: 8d 0e 01 sta FlagpoleFNum_YMFDummy ;save dummy variable
b88e: ad 0d 01 lda FlagpoleFNum_Y_Pos
b891: e9 01 sbc #$01 ;subtract one plus borrow to move floatey number,
b893: 8d 0d 01 sta FlagpoleFNum_Y_Pos ; and store vertical coordinate here
b896: 4c ac b8 SkipScore jmp FPGfx ;jump to skip ahead and draw flag and floatey number
b899: ac 0f 01 GiveFPScr ldy FlagpoleScore ;get score offset from earlier (when player touched flagpole)
b89c: b9 4b b8 lda FlagpoleScoreMods,y ;get amount to award player points
b89f: be 50 b8 ldx FlagpoleScoreDigits,y ;get digit with which to award points
b8a2: 9d 34 01 sta DigitModifier,x ;store in digit modifier
b8a5: 20 27 bc jsr AddToScore ;do sub to award player points depending on height of collision
b8a8: a9 05 lda #$05
b8aa: 85 0e sta GameEngineSubroutine ;set to run end-of-level subroutine on next frame
b8ac: 20 af f1 FPGfx jsr GetEnemyOffscreenBits ;get offscreen information
b8af: 20 52 f1 jsr RelativeEnemyPosition ;get relative coordinates
b8b2: 20 4b e5 jsr FlagpoleGfxHandler ;draw flagpole flag and floatey number
b8b5: 60 ExitFlagP rts
; -----------------------------------------------------------------------------
Jumpspring_Y_PosData
b8b6: 08 10 08 00 .bulk $08,$10,$08,$00
JumpspringHandler
b8ba: 20 af f1 jsr GetEnemyOffscreenBits ;get offscreen information
b8bd: ad 47 07 lda TimerControl ;check master timer control
b8c0: d0 40 bne DrawJSpr ;branch to last section if set
b8c2: ad 0e 07 lda JumpspringAnimCtrl ;check jumpspring frame control
b8c5: f0 3b beq DrawJSpr ;branch to last section if not set
b8c7: a8 tay
b8c8: 88 dey ;subtract one from frame control,
b8c9: 98 tya ; the only way a poor nmos 6502 can
b8ca: 29 02 and #%00000010 ; mask out all but d1, original value still in Y
b8cc: d0 07 bne DownJSpr ;if set, branch to move player up
b8ce: e6 ce inc Player_Y_Position
b8d0: e6 ce inc Player_Y_Position ;move player's vertical position down two pixels
b8d2: 4c d9 b8 jmp PosJSpr ;skip to next part
b8d5: c6 ce DownJSpr dec Player_Y_Position ;move player's vertical position up two pixels
b8d7: c6 ce dec Player_Y_Position
b8d9: b5 58 PosJSpr lda Jumpspring_FixedYPos,x ;get permanent vertical position
b8db: 18 clc
b8dc: 79 b6 b8 adc Jumpspring_Y_PosData,y ;add value using frame control as offset
b8df: 95 cf sta Enemy_Y_Position,x ;store as new vertical position
b8e1: c0 01 cpy #$01 ;check frame control offset (second frame is $00)
b8e3: 90 0f bcc BounceJS ;if offset not yet at third frame ($01), skip to next part
b8e5: a5 0a lda A_B_Buttons
b8e7: 29 80 and #A_Button ;check saved controller bits for A button press
b8e9: f0 09 beq BounceJS ;skip to next part if A not pressed
b8eb: 25 0d and PreviousA_B_Buttons ;check for A button pressed in previous frame
b8ed: d0 05 bne BounceJS ;skip to next part if so
b8ef: a9 f4 lda #$f4
b8f1: 8d db 06 sta JumpspringForce ;otherwise write new jumpspring force here
b8f4: c0 03 BounceJS cpy #$03 ;check frame control offset again
b8f6: d0 0a bne DrawJSpr ;skip to last part if not yet at fifth frame ($03)
b8f8: ad db 06 lda JumpspringForce
b8fb: 85 9f sta Player_Y_Speed ;store jumpspring force as player's new vertical speed
b8fd: a9 00 lda #$00
b8ff: 8d 0e 07 sta JumpspringAnimCtrl ;initialize jumpspring frame control
b902: 20 52 f1 DrawJSpr jsr RelativeEnemyPosition ;get jumpspring's relative coordinates
b905: 20 7d e8 jsr EnemyGfxHandler ;draw jumpspring
b908: 20 7a d6 jsr OffscreenBoundsCheck ;check to see if we need to kill it
b90b: ad 0e 07 lda JumpspringAnimCtrl ;if frame control at zero, don't bother
b90e: f0 0d beq ExJSPring ;trying to animate it, just leave
b910: ad 86 07 lda JumpspringTimer
b913: d0 08 bne ExJSPring ;if jumpspring timer not expired yet, leave
b915: a9 04 lda #$04
b917: 8d 86 07 sta JumpspringTimer ;otherwise initialize jumpspring timer
b91a: ee 0e 07 inc JumpspringAnimCtrl ;increment frame control to animate jumpspring
b91d: 60 ExJSPring rts ;leave
; -----------------------------------------------------------------------------
b91e: a9 2f Setup_Vine lda #VineObject ;load identifier for vine object
b920: 95 16 sta Enemy_ID,x ;store in buffer
b922: a9 01 lda #$01
b924: 95 0f sta Enemy_Flag,x ;set flag for enemy object buffer
b926: b9 76 00 lda Block_PageLoc,y
b929: 95 6e sta Enemy_PageLoc,x ;copy page location from previous object
b92b: b9 8f 00 lda Block_X_Position,y
b92e: 95 87 sta Enemy_X_Position,x ;copy horizontal coordinate from previous object
b930: b9 d7 00 lda Block_Y_Position,y
b933: 95 cf sta Enemy_Y_Position,x ;copy vertical coordinate from previous object
b935: ac 98 03 ldy VineFlagOffset ;load vine flag/offset to next available vine slot
b938: d0 03 bne NextVO ;if set at all, don't bother to store vertical
b93a: 8d 9d 03 sta VineStart_Y_Position ;otherwise store vertical coordinate here
b93d: 8a NextVO txa ;store object offset to next available vine slot
b93e: 99 9a 03 sta VineObjOffset,y ;using vine flag as offset
b941: ee 98 03 inc VineFlagOffset ;increment vine flag offset
b944: a9 04 lda #Sfx_GrowVine
b946: 85 fe sta Square2SoundQueue ;load vine grow sound
b948: 60 rts
; -----------------------------------------------------------------------------
; $06-$07 - used as address to block buffer data
; $02 - used as vertical high nybble of block buffer offset
b949: 30 60 VineHeightData .bulk $30,$60
VineObjectHandler
b94b: e0 05 cpx #$05 ;check enemy offset for special use slot
b94d: d0 68 bne ExitVH ;if not in last slot, branch to leave
b94f: ac 98 03 ldy VineFlagOffset
b952: 88 dey ;decrement vine flag in Y, use as offset
b953: ad 99 03 lda VineHeight
b956: d9 49 b9 cmp VineHeightData,y ;if vine has reached certain height,
b959: f0 0f beq RunVSubs ;branch ahead to skip this part
b95b: a5 09 lda FrameCounter ;get frame counter
b95d: 4a lsr A ;shift d1 into carry
b95e: 4a lsr A
b95f: 90 09 bcc RunVSubs ;if d1 not set (2 frames every 4) skip this part
b961: a5 d4 lda Enemy_Y_Position+5
b963: e9 01 sbc #$01 ;subtract vertical position of vine
b965: 85 d4 sta Enemy_Y_Position+5 ;one pixel every frame it's time
b967: ee 99 03 inc VineHeight ;increment vine height
b96a: ad 99 03 RunVSubs lda VineHeight ;if vine still very small,
b96d: c9 08 cmp #$08 ;branch to leave
b96f: 90 46 bcc ExitVH
b971: 20 52 f1 jsr RelativeEnemyPosition ;get relative coordinates of vine,
b974: 20 af f1 jsr GetEnemyOffscreenBits ; and any offscreen bits
b977: a0 00 ldy #$00 ;initialize offset used in draw vine sub
b979: 20 35 e4 VDrawLoop jsr DrawVine ;draw vine
b97c: c8 iny ;increment offset
b97d: cc 98 03 cpy VineFlagOffset ;if offset in Y and offset here
b980: d0 f7 bne VDrawLoop ;do not yet match, loop back to draw more vine
b982: ad d1 03 lda Enemy_OffscreenBits
b985: 29 0c and #%00001100 ;mask offscreen bits
b987: f0 10 beq WrCMTile ;if none of the saved offscreen bits set, skip ahead
b989: 88 dey ;otherwise decrement Y to get proper offset again
b98a: be 9a 03 KillVine ldx VineObjOffset,y ;get enemy object offset for this vine object
b98d: 20 98 c9 jsr EraseEnemyObject ;kill this vine object
b990: 88 dey ;decrement Y
b991: 10 f7 bpl KillVine ;if any vine objects left, loop back to kill it
b993: 8d 98 03 sta VineFlagOffset ;initialize vine flag/offset
b996: 8d 99 03 sta VineHeight ;initialize vine height
b999: ad 99 03 WrCMTile lda VineHeight ;check vine height
b99c: c9 20 cmp #$20 ;if vine small (less than 32 pixels tall)
b99e: 90 17 bcc ExitVH ;then branch ahead to leave
b9a0: a2 06 ldx #$06 ;set offset in X to last enemy slot
b9a2: a9 01 lda #$01 ;set A to obtain horizontal in $04, but we don't care
b9a4: a0 1b ldy #$1b ;set Y to offset to get block at ($04, $10) of coordinates
b9a6: 20 f0 e3 jsr BlockBufferCollision ;do a sub to get block buffer address set, return contents
b9a9: a4 02 ldy $02
b9ab: c0 d0 cpy #$d0 ;if vertical high nybble offset beyond extent of
b9ad: b0 08 bcs ExitVH ; current block buffer, branch to leave, do not write
b9af: b1 06 lda ($06),y ;otherwise check contents of block buffer at
b9b1: d0 04 bne ExitVH ; current offset, if not empty, branch to leave
b9b3: a9 26 lda #$26
b9b5: 91 06 sta ($06),y ;otherwise, write climbing metatile to block buffer
b9b7: a6 08 ExitVH ldx ObjectOffset ;get enemy object offset and leave
b9b9: 60 rts
; -----------------------------------------------------------------------------
b9ba: 0f CannonBitMasks .dd1 %00001111
b9bb: 07 .dd1 %00000111
b9bc: ad 4e 07 ProcessCannons lda AreaType ;get area type
b9bf: f0 6f beq ExCannon ;if water type area, branch to leave
b9c1: a2 02 ldx #$02
b9c3: 86 08 ThreeSChk stx ObjectOffset ;start at third enemy slot
b9c5: b5 0f lda Enemy_Flag,x ;check enemy buffer flag
b9c7: d0 51 bne Chk_BB ;if set, branch to check enemy
b9c9: bd a8 07 lda PseudoRandomBitReg+1,x ;otherwise get part of LSFR
b9cc: ac cc 06 ldy SecondaryHardMode ;get secondary hard mode flag, use as offset
b9cf: 39 ba b9 and CannonBitMasks,y ;mask out bits of LSFR as decided by flag
b9d2: c9 06 cmp #$06 ;check to see if lower nybble is above certain value
b9d4: b0 44 bcs Chk_BB ;if so, branch to check enemy
b9d6: a8 tay ;transfer masked contents of LSFR to Y as pseudorandom offset
b9d7: b9 6b 04 lda Cannon_PageLoc,y ;get page location
b9da: f0 3e beq Chk_BB ;if not set or on page 0, branch to check enemy
b9dc: b9 7d 04 lda Cannon_Timer,y ;get cannon timer
b9df: f0 08 beq FireCannon ;if expired, branch to fire cannon
b9e1: e9 00 sbc #$00 ;otherwise subtract borrow (note carry will always be clear here)
b9e3: 99 7d 04 sta Cannon_Timer,y ; to count timer down
b9e6: 4c 1a ba jmp Chk_BB
b9e9: ad 47 07 FireCannon lda TimerControl ;if master timer control set,
b9ec: d0 2c bne Chk_BB ;branch to check enemy
b9ee: a9 0e lda #$0e ;otherwise we start creating one
b9f0: 99 7d 04 sta Cannon_Timer,y ;first, reset cannon timer
b9f3: b9 6b 04 lda Cannon_PageLoc,y ;get page location of cannon
b9f6: 95 6e sta Enemy_PageLoc,x ;save as page location of bullet bill
b9f8: b9 71 04 lda Cannon_X_Position,y ;get horizontal coordinate of cannon
b9fb: 95 87 sta Enemy_X_Position,x ;save as horizontal coordinate of bullet bill
b9fd: b9 77 04 lda Cannon_Y_Position,y ;get vertical coordinate of cannon
ba00: 38 sec
ba01: e9 08 sbc #$08 ;subtract eight pixels (because enemies are 24 pixels tall)
ba03: 95 cf sta Enemy_Y_Position,x ;save as vertical coordinate of bullet bill
ba05: a9 01 lda #$01
ba07: 95 b6 sta Enemy_Y_HighPos,x ;set vertical high byte of bullet bill
ba09: 95 0f sta Enemy_Flag,x ;set buffer flag
ba0b: 4a lsr A ;shift right once to init A
ba0c: 95 1e sta Enemy_State,x ;then initialize enemy's state
ba0e: a9 09 lda #$09
ba10: 9d 9a 04 sta Enemy_BoundBoxCtrl,x ;set bounding box size control for bullet bill
ba13: a9 33 lda #BulletBill_CannonVar
ba15: 95 16 sta Enemy_ID,x ;load identifier for bullet bill (cannon variant)
ba17: 4c 2d ba jmp Next3Slt ;move onto next slot
ba1a: b5 16 Chk_BB lda Enemy_ID,x ;check enemy identifier for bullet bill (cannon variant)
ba1c: c9 33 cmp #BulletBill_CannonVar
ba1e: d0 0d bne Next3Slt ;if not found, branch to get next slot
ba20: 20 7a d6 jsr OffscreenBoundsCheck ;otherwise, check to see if it went offscreen
ba23: b5 0f lda Enemy_Flag,x ;check enemy buffer flag
ba25: f0 06 beq Next3Slt ;if not set, branch to get next slot
ba27: 20 af f1 jsr GetEnemyOffscreenBits ;otherwise, get offscreen information
ba2a: 20 33 ba jsr BulletBillHandler ;then do sub to handle bullet bill
ba2d: ca Next3Slt dex ;move onto next slot
ba2e: 10 93 bpl ThreeSChk ;do this until first three slots are checked
ba30: 60 ExCannon rts ;then leave
; -----------------------------------------------------------------------------
BulletBillXSpdData
ba31: 18 e8 .bulk $18,$e8
BulletBillHandler
ba33: ad 47 07 lda TimerControl ;if master timer control set,
ba36: d0 3e bne RunBBSubs ;branch to run subroutines except movement sub
ba38: b5 1e lda Enemy_State,x
ba3a: d0 2e bne ChkDSte ;if bullet bill's state set, branch to check defeated state
ba3c: ad d1 03 lda Enemy_OffscreenBits ;otherwise load offscreen bits
ba3f: 29 0c and #%00001100 ;mask out bits
ba41: c9 0c cmp #%00001100 ;check to see if all bits are set
ba43: f0 40 beq KillBB ;if so, branch to kill this object
ba45: a0 01 ldy #$01 ;set to move right by default
ba47: 20 43 e1 jsr PlayerEnemyDiff ;get horizontal difference between player and bullet bill
ba4a: 30 01 bmi SetupBB ;if enemy to the left of player, branch
ba4c: c8 iny ;otherwise increment to move left
ba4d: 94 46 SetupBB sty Enemy_MovingDir,x ;set bullet bill's moving direction
ba4f: 88 dey ;decrement to use as offset
ba50: b9 31 ba lda BulletBillXSpdData,y ;get horizontal speed based on moving direction
ba53: 95 58 sta BlooperMoveSpeed,x ;and store it
ba55: a5 00 lda $00 ;get horizontal difference
ba57: 69 28 adc #$28 ;add 40 pixels
ba59: c9 50 cmp #$50 ;if less than a certain amount, player is too close
ba5b: 90 28 bcc KillBB ;to cannon either on left or right side, thus branch
ba5d: a9 01 lda #$01
ba5f: 95 1e sta Enemy_State,x ;otherwise set bullet bill's state
ba61: a9 0a lda #$0a
ba63: 9d 8a 07 sta EnemyFrameTimer,x ;set enemy frame timer
ba66: a9 08 lda #$08
ba68: 85 fe sta Square2SoundQueue ;play fireworks/gunfire sound
ba6a: b5 1e ChkDSte lda Enemy_State,x ;check enemy state for d5 set
ba6c: 29 20 and #%00100000
ba6e: f0 03 beq BBFly ;if not set, skip to move horizontally
ba70: 20 63 bf jsr MoveD_EnemyVertically ;otherwise do sub to move bullet bill vertically
ba73: 20 02 bf BBFly jsr MoveEnemyHorizontally ;do sub to move bullet bill horizontally
ba76: 20 af f1 RunBBSubs jsr GetEnemyOffscreenBits ;get offscreen information
ba79: 20 52 f1 jsr RelativeEnemyPosition ;get relative coordinates
ba7c: 20 43 e2 jsr GetEnemyBoundBox ;get bounding box coordinates
ba7f: 20 53 d8 jsr PlayerEnemyCollision ;handle player to enemy collisions
ba82: 4c 7d e8 jmp EnemyGfxHandler ;draw the bullet bill and leave
ba85: 20 98 c9 KillBB jsr EraseEnemyObject ;kill bullet bill and leave
ba88: 60 rts
; -----------------------------------------------------------------------------
HammerEnemyOfsData
ba89: 04 04 04 05+ .bulk $04,$04,$04,$05,$05,$05,$06,$06,$06
ba92: 10 f0 HammerXSpdData .bulk $10,$f0
ba94: ad a8 07 SpawnHammerObj lda PseudoRandomBitReg+1 ;get pseudorandom bits from
ba97: 29 07 and #$07 ; second part of LSFR
ba99: d0 05 bne SetMOfs ;if any bits are set, branch and use as offset
ba9b: ad a8 07 lda PseudoRandomBitReg+1
ba9e: 29 08 and #%00001000 ;get d3 from same part of LSFR
baa0: a8 SetMOfs tay ;use either d3 or d2-d0 for offset here
baa1: b9 2a 00 lda Misc_State,y ;if any values loaded in
baa4: d0 19 bne NoHammer ; $2a-$32 where offset is then leave with carry clear
baa6: be 89 ba ldx HammerEnemyOfsData,y ;get offset of enemy slot to check using Y as offset
baa9: b5 0f lda Enemy_Flag,x ;check enemy buffer flag at offset
baab: d0 12 bne NoHammer ;if buffer flag set, branch to leave with carry clear
baad: a6 08 ldx ObjectOffset ;get original enemy object offset
baaf: 8a txa
bab0: 99 ae 06 sta HammerEnemyOffset,y ;save here
bab3: a9 90 lda #$90
bab5: 99 2a 00 sta Misc_State,y ;save hammer's state here
bab8: a9 07 lda #$07
baba: 99 a2 04 sta Misc_BoundBoxCtrl,y ;set something else entirely, here
babd: 38 sec ;return with carry set
babe: 60 rts
babf: a6 08 NoHammer ldx ObjectOffset ;get original enemy object offset
bac1: 18 clc ;return with carry clear
bac2: 60 rts
; -----------------------------------------------------------------------------
; $00 - used to set downward force
; $01 - used to set upward force (residual)
; $02 - used to set maximum speed
bac3: ad 47 07 ProcHammerObj lda TimerControl ;if master timer control set
bac6: d0 63 bne RunHSubs ; skip all of this code and go to last subs at the end
bac8: b5 2a lda Misc_State,x ;otherwise get hammer's state
baca: 29 7f and #%01111111 ;mask out d7
bacc: bc ae 06 ldy HammerEnemyOffset,x ;get enemy object offset that spawned this hammer
bacf: c9 02 cmp #$02 ;check hammer's state
bad1: f0 20 beq SetHSpd ;if currently at 2, branch
bad3: b0 34 bcs SetHPos ;if greater than 2, branch elsewhere
bad5: 8a txa
bad6: 18 clc ;add 13 bytes to use
bad7: 69 0d adc #$0d ; proper misc object
bad9: aa tax ;return offset to X
bada: a9 10 lda #$10
badc: 85 00 sta $00 ;set downward movement force
bade: a9 0f lda #$0f
bae0: 85 01 sta $01 ;set upward movement force (not used)
bae2: a9 04 lda #$04
bae4: 85 02 sta $02 ;set maximum vertical speed
bae6: a9 00 lda #$00 ;set A to impose gravity on hammer
bae8: 20 d7 bf jsr ImposeGravity ;do sub to impose gravity on hammer and move vertically
baeb: 20 0f bf jsr MoveObjectHorizontally ;do sub to move it horizontally
baee: a6 08 ldx ObjectOffset ;get original misc object offset
baf0: 4c 28 bb jmp RunAllH ;branch to essential subroutines
baf3: a9 fe SetHSpd lda #$fe
baf5: 95 ac sta Misc_Y_Speed,x ;set hammer's vertical speed
baf7: b9 1e 00 lda Enemy_State,y ;get enemy object state
bafa: 29 f7 and #%11110111 ;mask out d3
bafc: 99 1e 00 sta Enemy_State,y ;store new state
baff: b6 46 ldx Enemy_MovingDir,y ;get enemy's moving direction
bb01: ca dex ;decrement to use as offset
bb02: bd 92 ba lda HammerXSpdData,x ;get proper speed to use based on moving direction
bb05: a6 08 ldx ObjectOffset ;reobtain hammer's buffer offset
bb07: 95 64 sta Misc_X_Speed,x ;set hammer's horizontal speed
bb09: d6 2a SetHPos dec Misc_State,x ;decrement hammer's state
bb0b: b9 87 00 lda Enemy_X_Position,y ;get enemy's horizontal position
bb0e: 18 clc
bb0f: 69 02 adc #$02 ;set position 2 pixels to the right
bb11: 95 93 sta Misc_X_Position,x ;store as hammer's horizontal position
bb13: b9 6e 00 lda Enemy_PageLoc,y ;get enemy's page location
bb16: 69 00 adc #$00 ;add carry
bb18: 95 7a sta Misc_PageLoc,x ;store as hammer's page location
bb1a: b9 cf 00 lda Enemy_Y_Position,y ;get enemy's vertical position
bb1d: 38 sec
bb1e: e9 0a sbc #$0a ;move position 10 pixels upward
bb20: 95 db sta Misc_Y_Position,x ;store as hammer's vertical position
bb22: a9 01 lda #$01
bb24: 95 c2 sta Misc_Y_HighPos,x ;set hammer's vertical high byte
bb26: d0 03 bne RunHSubs ;unconditional branch to skip first routine
bb28: 20 c4 d7 RunAllH jsr PlayerHammerCollision ;handle collisions
bb2b: 20 9b f1 RunHSubs jsr GetMiscOffscreenBits ;get offscreen information
bb2e: 20 48 f1 jsr RelativeMiscPosition ;get relative coordinates
bb31: 20 36 e2 jsr GetMiscBoundBox ;get bounding box coordinates
bb34: 20 dc e4 jsr DrawHammer ;draw the hammer
bb37: 60 rts ;and we are done here
; -----------------------------------------------------------------------------
; $02 - used to store vertical high nybble offset from block buffer routine
; $06 - used to store low byte of block buffer address
bb38: 20 84 bb CoinBlock jsr FindEmptyMiscSlot ;set offset for empty or last misc object buffer slot
bb3b: b5 76 lda Block_PageLoc,x ;get page location of block object
bb3d: 99 7a 00 sta Misc_PageLoc,y ;store as page location of misc object
bb40: b5 8f lda Block_X_Position,x ;get horizontal coordinate of block object
bb42: 09 05 ora #$05 ;add 5 pixels
bb44: 99 93 00 sta Misc_X_Position,y ;store as horizontal coordinate of misc object
bb47: b5 d7 lda Block_Y_Position,x ;get vertical coordinate of block object
bb49: e9 10 sbc #$10 ;subtract 16 pixels
bb4b: 99 db 00 sta Misc_Y_Position,y ;store as vertical coordinate of misc object
bb4e: 4c 6c bb jmp JCoinC ;jump to rest of code as applies to this misc object
bb51: 20 84 bb SetupJumpCoin jsr FindEmptyMiscSlot ;set offset for empty or last misc object buffer slot
bb54: bd ea 03 lda Block_PageLoc2,x ;get page location saved earlier
bb57: 99 7a 00 sta Misc_PageLoc,y ;and save as page location for misc object
bb5a: a5 06 lda $06 ;get low byte of block buffer offset
bb5c: 0a asl A
bb5d: 0a asl A ;multiply by 16 to use lower nybble
bb5e: 0a asl A
bb5f: 0a asl A
bb60: 09 05 ora #$05 ;add five pixels
bb62: 99 93 00 sta Misc_X_Position,y ;save as horizontal coordinate for misc object
bb65: a5 02 lda $02 ;get vertical high nybble offset from earlier
bb67: 69 20 adc #$20 ;add 32 pixels for the status bar
bb69: 99 db 00 sta Misc_Y_Position,y ;store as vertical coordinate
bb6c: a9 fb JCoinC lda #$fb
bb6e: 99 ac 00 sta Misc_Y_Speed,y ;set vertical speed
bb71: a9 01 lda #$01
bb73: 99 c2 00 sta Misc_Y_HighPos,y ;set vertical high byte
bb76: 99 2a 00 sta Misc_State,y ;set state for misc object
bb79: 85 fe sta Square2SoundQueue ;load coin grab sound
bb7b: 86 08 stx ObjectOffset ;store current control bit as misc object offset
bb7d: 20 fe bb jsr GiveOneCoin ;update coin tally on the screen and coin amount variable
bb80: ee 48 07 inc CoinTallyFor1Ups ;increment coin tally used to activate 1-up block flag
bb83: 60 rts
FindEmptyMiscSlot
bb84: a0 08 ldy #$08 ;start at end of misc objects buffer
bb86: b9 2a 00 FMiscLoop lda Misc_State,y ;get misc object state
bb89: f0 07 beq UseMiscS ;branch if none found to use current offset
bb8b: 88 dey ;decrement offset
bb8c: c0 05 cpy #$05 ;do this for three slots
bb8e: d0 f6 bne FMiscLoop ;do this until all slots are checked
bb90: a0 08 ldy #$08 ;if no empty slots found, use last slot
bb92: 8c b7 06 UseMiscS sty JumpCoinMiscOffset ;store offset of misc object buffer here (residual)
bb95: 60 rts
; -----------------------------------------------------------------------------
bb96: a2 08 MiscObjectsCore ldx #$08 ;set at end of misc object buffer
bb98: 86 08 MiscLoop stx ObjectOffset ;store misc object offset here
bb9a: b5 2a lda Misc_State,x ;check misc object state
bb9c: f0 56 beq MiscLoopBack ;branch to check next slot
bb9e: 0a asl A ;otherwise shift d7 into carry
bb9f: 90 06 bcc ProcJumpCoin ;if d7 not set, jumping coin, thus skip to rest of code here
bba1: 20 c3 ba jsr ProcHammerObj ;otherwise go to process hammer,
bba4: 4c f4 bb jmp MiscLoopBack ;then check next slot
; -----------------------------------------------------------------------------
; $00 - used to set downward force
; $01 - used to set upward force (residual)
; $02 - used to set maximum speed
bba7: b4 2a ProcJumpCoin ldy Misc_State,x ;check misc object state
bba9: 88 dey ;decrement to see if it's set to 1
bbaa: f0 1d beq JCoinRun ;if so, branch to handle jumping coin
bbac: f6 2a inc Misc_State,x ;otherwise increment state to either start off or as timer
bbae: b5 93 lda Misc_X_Position,x ;get horizontal coordinate for misc object
bbb0: 18 clc ;whether its jumping coin (state 0 only) or floatey number
bbb1: 6d 75 07 adc ScrollAmount ;add current scroll speed
bbb4: 95 93 sta Misc_X_Position,x ;store as new horizontal coordinate
bbb6: b5 7a lda Misc_PageLoc,x ;get page location
bbb8: 69 00 adc #$00 ;add carry
bbba: 95 7a sta Misc_PageLoc,x ;store as new page location
bbbc: b5 2a lda Misc_State,x
bbbe: c9 30 cmp #$30 ;check state of object for preset value
bbc0: d0 26 bne RunJCSubs ;if not yet reached, branch to subroutines
bbc2: a9 00 lda #$00
bbc4: 95 2a sta Misc_State,x ;otherwise nullify object state
bbc6: 4c f4 bb jmp MiscLoopBack ;and move onto next slot
bbc9: 8a JCoinRun txa
bbca: 18 clc ;add 13 bytes to offset for next subroutine
bbcb: 69 0d adc #$0d
bbcd: aa tax
bbce: a9 50 lda #$50 ;set downward movement amount
bbd0: 85 00 sta $00
bbd2: a9 06 lda #$06 ;set maximum vertical speed
bbd4: 85 02 sta $02
bbd6: 4a lsr A ;divide by 2 and set
bbd7: 85 01 sta $01 ;as upward movement amount (apparently residual)
bbd9: a9 00 lda #$00 ;set A to impose gravity on jumping coin
bbdb: 20 d7 bf jsr ImposeGravity ;do sub to move coin vertically and impose gravity on it
bbde: a6 08 ldx ObjectOffset ;get original misc object offset
bbe0: b5 ac lda Misc_Y_Speed,x ;check vertical speed
bbe2: c9 05 cmp #$05
bbe4: d0 02 bne RunJCSubs ;if not moving downward fast enough, keep state as-is
bbe6: f6 2a inc Misc_State,x ;otherwise increment state to change to floatey number
bbe8: 20 48 f1 RunJCSubs jsr RelativeMiscPosition ;get relative coordinates
bbeb: 20 9b f1 jsr GetMiscOffscreenBits ;get offscreen information
bbee: 20 36 e2 jsr GetMiscBoundBox ;get bounding box coordinates (why?)
bbf1: 20 86 e6 jsr JCoinGfxHandler ;draw the coin or floatey number
bbf4: ca MiscLoopBack dex ;decrement misc object offset
bbf5: 10 a1 bpl MiscLoop ;loop back until all misc objects handled
bbf7: 60 rts ;then leave
; -----------------------------------------------------------------------------
CoinTallyOffsets
bbf8: 17 1d .bulk $17,$1d
bbfa: 0b 11 ScoreOffsets .bulk $0b,$11
StatusBarNybbles
bbfc: 02 13 .bulk $02,$13
bbfe: a9 01 GiveOneCoin lda #$01 ;set digit modifier to add 1 coin
bc00: 8d 39 01 sta DigitModifier+5 ; to the current player's coin tally
bc03: ae 53 07 ldx CurrentPlayer ;get current player on the screen
bc06: bc f8 bb ldy CoinTallyOffsets,x ;get offset for player's coin tally
bc09: 20 5f 8f jsr DigitsMathRoutine ;update the coin tally
bc0c: ee 5e 07 inc CoinTally ;increment onscreen player's coin amount
bc0f: ad 5e 07 lda CoinTally
bc12: c9 64 cmp #100 ;does player have 100 coins yet?
bc14: d0 0c bne CoinPoints ;if not, skip all of this
bc16: a9 00 lda #$00
bc18: 8d 5e 07 sta CoinTally ;otherwise, reinitialize coin amount
bc1b: ee 5a 07 inc NumberOfLives ;give the player an extra life
bc1e: a9 40 lda #Sfx_ExtraLife
bc20: 85 fe sta Square2SoundQueue ;play 1-up sound
bc22: a9 02 CoinPoints lda #$02 ;set digit modifier to award
bc24: 8d 38 01 sta DigitModifier+4 ;200 points to the player
bc27: ae 53 07 AddToScore ldx CurrentPlayer ;get current player
bc2a: bc fa bb ldy ScoreOffsets,x ;get offset for player's score
bc2d: 20 5f 8f jsr DigitsMathRoutine ;update the score internally with value in digit modifier
bc30: ac 53 07 GetSBNybbles ldy CurrentPlayer ;get current player
bc33: b9 fc bb lda StatusBarNybbles,y ;get nybbles based on player, use to update score and coins
bc36: 20 06 8f UpdateNumber jsr PrintStatusBarNumbers ;print status bar numbers based on nybbles, whatever they be
bc39: ac 00 03 ldy VRAM_Buffer1_Offset
bc3c: b9 fb 02 lda VRAM_Buffer1-6,y ;check highest digit of score
bc3f: d0 05 bne NoZSup ;if zero, overwrite with space tile for zero suppression
bc41: a9 24 lda #$24
bc43: 99 fb 02 sta VRAM_Buffer1-6,y
bc46: a6 08 NoZSup ldx ObjectOffset ;get enemy object buffer offset
bc48: 60 rts
; -----------------------------------------------------------------------------
bc49: a9 2e SetupPowerUp lda #PowerUpObject ;load power-up identifier into
bc4b: 85 1b sta Enemy_ID+5 ;special use slot of enemy object buffer
bc4d: b5 76 lda Block_PageLoc,x ;store page location of block object
bc4f: 85 73 sta Enemy_PageLoc+5 ;as page location of power-up object
bc51: b5 8f lda Block_X_Position,x ;store horizontal coordinate of block object
bc53: 85 8c sta Enemy_X_Position+5 ;as horizontal coordinate of power-up object
bc55: a9 01 lda #$01
bc57: 85 bb sta Enemy_Y_HighPos+5 ;set vertical high byte of power-up object
bc59: b5 d7 lda Block_Y_Position,x ;get vertical coordinate of block object
bc5b: 38 sec
bc5c: e9 08 sbc #$08 ;subtract 8 pixels
bc5e: 85 d4 sta Enemy_Y_Position+5 ;and use as vertical coordinate of power-up object
bc60: a9 01 PwrUpJmp lda #$01 ;this is a residual jump point in enemy object jump table
bc62: 85 23 sta Enemy_State+5 ;set power-up object's state
bc64: 85 14 sta Enemy_Flag+5 ;set buffer flag
bc66: a9 03 lda #$03
bc68: 8d 9f 04 sta Enemy_BoundBoxCtrl+5 ;set bounding box size control for power-up object
bc6b: a5 39 lda PowerUpType
bc6d: c9 02 cmp #$02 ;check currently loaded power-up type
bc6f: b0 0a bcs PutBehind ;if star or 1-up, branch ahead
bc71: ad 56 07 lda PlayerStatus ;otherwise check player's current status
bc74: c9 02 cmp #$02
bc76: 90 01 bcc StrType ;if player not fiery, use status as power-up type
bc78: 4a lsr A ;otherwise shift right to force fire flower type
bc79: 85 39 StrType sta PowerUpType ;store type here
bc7b: a9 20 PutBehind lda #%00100000
bc7d: 8d ca 03 sta Enemy_SprAttrib+5 ;set background priority bit
bc80: a9 02 lda #Sfx_GrowPowerUp
bc82: 85 fe sta Square2SoundQueue ;load power-up reveal sound and leave
bc84: 60 rts
; -----------------------------------------------------------------------------
PowerUpObjHandler
bc85: a2 05 ldx #$05 ;set object offset for last slot in enemy object buffer
bc87: 86 08 stx ObjectOffset
bc89: a5 23 lda Enemy_State+5 ;check power-up object's state
bc8b: f0 5d beq ExitPUp ;if not set, branch to leave
bc8d: 0a asl A ;shift to check if d7 was set in object state
bc8e: 90 23 bcc GrowThePowerUp ;if not set, branch ahead to skip this part
bc90: ad 47 07 lda TimerControl ;if master timer control set,
bc93: d0 43 bne RunPUSubs ;branch ahead to enemy object routines
bc95: a5 39 lda PowerUpType ;check power-up type
bc97: f0 11 beq ShroomM ;if normal mushroom, branch ahead to move it
bc99: c9 03 cmp #$03
bc9b: f0 0d beq ShroomM ;if 1-up mushroom, branch ahead to move it
bc9d: c9 02 cmp #$02
bc9f: d0 37 bne RunPUSubs ;if not star, branch elsewhere to skip movement
bca1: 20 f9 ca jsr MoveJumpingEnemy ;otherwise impose gravity on star power-up and make it jump
bca4: 20 63 e1 jsr EnemyJump ;note that green paratroopa shares the same code here
bca7: 4c d8 bc jmp RunPUSubs ;then jump to other power-up subroutines
bcaa: 20 77 ca ShroomM jsr MoveNormalEnemy ;do sub to make mushrooms move
bcad: 20 c1 df jsr EnemyToBGCollisionDet ;deal with collisions
bcb0: 4c d8 bc jmp RunPUSubs ;run the other subroutines
bcb3: a5 09 GrowThePowerUp lda FrameCounter ;get frame counter
bcb5: 29 03 and #$03 ;mask out all but 2 LSB
bcb7: d0 19 bne ChkPUSte ;if any bits set here, branch
bcb9: c6 d4 dec Enemy_Y_Position+5 ;otherwise decrement vertical coordinate slowly
bcbb: a5 23 lda Enemy_State+5 ;load power-up object state
bcbd: e6 23 inc Enemy_State+5 ;increment state for next frame (to make power-up rise)
bcbf: c9 11 cmp #$11 ;if power-up object state not yet past 16th pixel,
bcc1: 90 0f bcc ChkPUSte ;branch ahead to last part here
bcc3: a9 10 lda #$10
bcc5: 95 58 sta Enemy_X_Speed,x ;otherwise set horizontal speed
bcc7: a9 80 lda #%10000000
bcc9: 85 23 sta Enemy_State+5 ;and then set d7 in power-up object's state
bccb: 0a asl A ;shift once to init A
bccc: 8d ca 03 sta Enemy_SprAttrib+5 ;initialize background priority bit set here
bccf: 2a rol A ;rotate A to set right moving direction
bcd0: 95 46 sta Enemy_MovingDir,x ;set moving direction
bcd2: a5 23 ChkPUSte lda Enemy_State+5 ;check power-up object's state
bcd4: c9 06 cmp #$06 ;for if power-up has risen enough
bcd6: 90 12 bcc ExitPUp ;if not, don't even bother running these routines
bcd8: 20 52 f1 RunPUSubs jsr RelativeEnemyPosition ;get coordinates relative to screen
bcdb: 20 af f1 jsr GetEnemyOffscreenBits ;get offscreen bits
bcde: 20 43 e2 jsr GetEnemyBoundBox ;get bounding box coordinates
bce1: 20 d2 e6 jsr DrawPowerUp ;draw the power-up object
bce4: 20 53 d8 jsr PlayerEnemyCollision ;check for collision with player
bce7: 20 7a d6 jsr OffscreenBoundsCheck ;check to see if it went offscreen
bcea: 60 ExitPUp rts ;and we're done
; -----------------------------------------------------------------------------
; $00 - used to store metatile from block buffer routine
; $02 - used to store vertical high nybble offset from block buffer routine
; $05 - used to store metatile stored in A at beginning of PlayerHeadCollision
; $06-$07 - used as block buffer address indirect
BlockYPosAdderData
bceb: 04 12 .bulk $04,$12
PlayerHeadCollision
bced: 48 pha ;store metatile number to stack
bcee: a9 11 lda #$11 ;load unbreakable block object state by default
bcf0: ae ee 03 ldx SprDataOffset_Ctrl ;load offset control bit here
bcf3: ac 54 07 ldy PlayerSize ;check player's size
bcf6: d0 02 bne DBlockSte ;if small, branch
bcf8: a9 12 lda #$12 ;otherwise load breakable block object state
bcfa: 95 26 DBlockSte sta Block_State,x ;store into block object buffer
bcfc: 20 6b 8a jsr DestroyBlockMetatile ;store blank metatile in vram buffer to write to name table
bcff: ae ee 03 ldx SprDataOffset_Ctrl ;load offset control bit
bd02: a5 02 lda $02 ;get vertical high nybble offset used in block buffer routine
bd04: 9d e4 03 sta Block_Orig_YPos,x ;set as vertical coordinate for block object
bd07: a8 tay
bd08: a5 06 lda $06 ;get low byte of block buffer address used in same routine
bd0a: 9d e6 03 sta Block_BBuf_Low,x ;save as offset here to be used later
bd0d: b1 06 lda ($06),y ;get contents of block buffer at old address at $06, $07
bd0f: 20 f6 bd jsr BlockBumpedChk ;do a sub to check which block player bumped head on
bd12: 85 00 sta $00 ;store metatile here
bd14: ac 54 07 ldy PlayerSize ;check player's size
bd17: d0 01 bne ChkBrick ;if small, use metatile itself as contents of A
bd19: 98 tya ;otherwise init A (note: big = 0)
bd1a: 90 25 ChkBrick bcc PutMTileB ;if no match was found in previous sub, skip ahead
bd1c: a0 11 ldy #$11 ;otherwise load unbreakable state into block object buffer
bd1e: 94 26 sty Block_State,x ;note this applies to both player sizes
bd20: a9 c4 lda #$c4 ;load empty block metatile into A for now
bd22: a4 00 ldy $00 ;get metatile from before
bd24: c0 58 cpy #$58 ;is it brick with coins (with line)?
bd26: f0 04 beq StartBTmr ;if so, branch
bd28: c0 5d cpy #$5d ;is it brick with coins (without line)?
bd2a: d0 15 bne PutMTileB ;if not, branch ahead to store empty block metatile
bd2c: ad bc 06 StartBTmr lda BrickCoinTimerFlag ;check brick coin timer flag
bd2f: d0 08 bne ContBTmr ;if set, timer expired or counting down, thus branch
bd31: a9 0b lda #$0b
bd33: 8d 9d 07 sta BrickCoinTimer ;if not set, set brick coin timer
bd36: ee bc 06 inc BrickCoinTimerFlag ;and set flag linked to it
bd39: ad 9d 07 ContBTmr lda BrickCoinTimer ;check brick coin timer
bd3c: d0 02 bne PutOldMT ;if not yet expired, branch to use current metatile
bd3e: a0 c4 ldy #$c4 ;otherwise use empty block metatile
bd40: 98 PutOldMT tya ;put metatile into A
bd41: 9d e8 03 PutMTileB sta Block_Metatile,x ;store whatever metatile be appropriate here
bd44: 20 84 bd jsr InitBlock_XY_Pos ;get block object horizontal coordinates saved
bd47: a4 02 ldy $02 ;get vertical high nybble offset
bd49: a9 23 lda #$23
bd4b: 91 06 sta ($06),y ;write blank metatile $23 to block buffer
bd4d: a9 10 lda #$10
bd4f: 8d 84 07 sta BlockBounceTimer ;set block bounce timer
bd52: 68 pla ;pull original metatile from stack
bd53: 85 05 sta $05 ;and save here
bd55: a0 00 ldy #$00 ;set default offset
bd57: ad 14 07 lda CrouchingFlag ;is player crouching?
bd5a: d0 05 bne SmallBP ;if so, branch to increment offset
bd5c: ad 54 07 lda PlayerSize ;is player big?
bd5f: f0 01 beq BigBP ;if so, branch to use default offset
bd61: c8 SmallBP iny ;increment for small or big and crouching
bd62: a5 ce BigBP lda Player_Y_Position ;get player's vertical coordinate
bd64: 18 clc
bd65: 79 eb bc adc BlockYPosAdderData,y ;add value determined by size
bd68: 29 f0 and #$f0 ;mask out low nybble to get 16-pixel correspondence
bd6a: 95 d7 sta Block_Y_Position,x ;save as vertical coordinate for block object
bd6c: b4 26 ldy Block_State,x ;get block object state
bd6e: c0 11 cpy #$11
bd70: f0 06 beq Unbreak ;if set to value loaded for unbreakable, branch
bd72: 20 02 be jsr BrickShatter ;execute code for breakable brick
bd75: 4c 7b bd jmp InvOBit ;skip subroutine to do last part of code here
bd78: 20 9b bd Unbreak jsr BumpBlock ;execute code for unbreakable brick or question block
bd7b: ad ee 03 InvOBit lda SprDataOffset_Ctrl ;invert control bit used by block objects
bd7e: 49 01 eor #$01 ; and floatey numbers
bd80: 8d ee 03 sta SprDataOffset_Ctrl
bd83: 60 rts ;leave!
; -----------------------------------------------------------------------------
InitBlock_XY_Pos
bd84: a5 86 lda Player_X_Position ;get player's horizontal coordinate
bd86: 18 clc
bd87: 69 08 adc #$08 ;add eight pixels
bd89: 29 f0 and #$f0 ;mask out low nybble to give 16-pixel correspondence
bd8b: 95 8f sta Block_X_Position,x ;save as horizontal coordinate for block object
bd8d: a5 6d lda Player_PageLoc
bd8f: 69 00 adc #$00 ;add carry to page location of player
bd91: 95 76 sta Block_PageLoc,x ;save as page location of block object
bd93: 9d ea 03 sta Block_PageLoc2,x ;save elsewhere to be used later
bd96: a5 b5 lda Player_Y_HighPos
bd98: 95 be sta Block_Y_HighPos,x ;save vertical high byte of player into
bd9a: 60 rts ;vertical high byte of block object and leave
; -----------------------------------------------------------------------------
bd9b: 20 1f be BumpBlock jsr CheckTopOfBlock ;check to see if there's a coin directly above this block
bd9e: a9 02 lda #Sfx_Bump
bda0: 85 ff sta Square1SoundQueue ;play bump sound
bda2: a9 00 lda #$00
bda4: 95 60 sta Block_X_Speed,x ;initialize horizontal speed for block object
bda6: 9d 3c 04 sta Block_Y_MoveForce,x ;init fractional movement force
bda9: 85 9f sta Player_Y_Speed ;init player's vertical speed
bdab: a9 fe lda #$fe
bdad: 95 a8 sta Block_Y_Speed,x ;set vertical speed for block object
bdaf: a5 05 lda $05 ;get original metatile from stack
bdb1: 20 f6 bd jsr BlockBumpedChk ;do a sub to check which block player bumped head on
bdb4: 90 31 bcc ExitBlockChk ;if no match was found, branch to leave
bdb6: 98 tya ;move block number to A
bdb7: c9 09 cmp #$09 ;if block number was within 0-8 range,
bdb9: 90 02 bcc BlockCode ;branch to use current number
bdbb: e9 05 sbc #$05 ;otherwise subtract 5 for second set to get proper number
bdbd: 20 04 8e BlockCode jsr JumpEngine ;run appropriate subroutine depending on block number
bdc0: d2 bd .dd2 MushFlowerBlock
bdc2: 38 bb .dd2 CoinBlock
bdc4: 38 bb .dd2 CoinBlock
bdc6: d8 bd .dd2 ExtraLifeMushBlock
bdc8: d2 bd .dd2 MushFlowerBlock
bdca: df bd .dd2 VineBlock
bdcc: d5 bd .dd2 StarBlock
bdce: 38 bb .dd2 CoinBlock
bdd0: d8 bd .dd2 ExtraLifeMushBlock
; -----------------------------------------------------------------------------
bdd2: a9 00 MushFlowerBlock lda #$00 ;load mushroom/fire flower into power-up type
bdd4: 2c bit βΌ $02a9 ;BIT instruction opcode
bdd5: a9 02 StarBlock lda #$02 ;load star into power-up type
bdd7: 2c bit βΌ $03a9 ;BIT instruction opcode
bdd8: a9 03 lda #$03 ;load 1-up mushroom into power-up type
bdda: 85 39 sta PowerUpType ;store correct power-up type
bddc: 4c 49 bc jmp SetupPowerUp
bddf: a2 05 VineBlock ldx #$05 ;load last slot for enemy object buffer
bde1: ac ee 03 ldy SprDataOffset_Ctrl ;get control bit
bde4: 20 1e b9 jsr Setup_Vine ;set up vine object
bde7: 60 ExitBlockChk rts ;leave
; -----------------------------------------------------------------------------
BrickQBlockMetatiles
bde8: c1 c0 5f 60 .bulk $c1,$c0,$5f,$60 ;used by question blocks
; these two sets are functionally identical, but look different
bdec: 55 56 57 58+ .bulk $55,$56,$57,$58,$59 ;used by ground level types
bdf1: 5a 5b 5c 5d+ .bulk $5a,$5b,$5c,$5d,$5e ;used by other level types
bdf6: a0 0d BlockBumpedChk ldy #$0d ;start at end of metatile data
bdf8: d9 e8 bd BumpChkLoop cmp BrickQBlockMetatiles,y ;check to see if current metatile matches
bdfb: f0 04 beq MatchBump ;metatile found in block buffer, branch if so
bdfd: 88 dey ;otherwise move onto next metatile
bdfe: 10 f8 bpl BumpChkLoop ;do this until all metatiles are checked
be00: 18 clc ;if none match, return with carry clear
be01: 60 MatchBump rts ;note carry is set if found match
; -----------------------------------------------------------------------------
be02: 20 1f be BrickShatter jsr CheckTopOfBlock ;check to see if there's a coin directly above this block
be05: a9 01 lda #Sfx_BrickShatter
be07: 9d ec 03 sta Block_RepFlag,x ;set flag for block object to immediately replace metatile
be0a: 85 fd sta NoiseSoundQueue ;load brick shatter sound
be0c: 20 41 be jsr SpawnBrickChunks ;create brick chunk objects
be0f: a9 fe lda #$fe
be11: 85 9f sta Player_Y_Speed ;set vertical speed for player
be13: a9 05 lda #$05
be15: 8d 39 01 sta DigitModifier+5 ;set digit modifier to give player 50 points
be18: 20 27 bc jsr AddToScore ;do sub to update the score
be1b: ae ee 03 ldx SprDataOffset_Ctrl ;load control bit and leave
be1e: 60 rts
; -----------------------------------------------------------------------------
be1f: ae ee 03 CheckTopOfBlock ldx SprDataOffset_Ctrl ;load control bit
be22: a4 02 ldy $02 ;get vertical high nybble offset used in block buffer
be24: f0 1a beq TopEx ;branch to leave if set to zero, because we're at the top
be26: 98 tya ;otherwise set to A
be27: 38 sec
be28: e9 10 sbc #$10 ;subtract $10 to move up one row in the block buffer
be2a: 85 02 sta $02 ;store as new vertical high nybble offset
be2c: a8 tay
be2d: b1 06 lda ($06),y ;get contents of block buffer in same column, one row up
be2f: c9 c2 cmp #$c2 ;is it a coin? (not underwater)
be31: d0 0d bne TopEx ;if not, branch to leave
be33: a9 00 lda #$00
be35: 91 06 sta ($06),y ;otherwise put blank metatile where coin was
be37: 20 4d 8a jsr RemoveCoin_Axe ;write blank metatile to vram buffer
be3a: ae ee 03 ldx SprDataOffset_Ctrl ;get control bit
be3d: 20 51 bb jsr SetupJumpCoin ;create jumping coin object and update coin variables
be40: 60 TopEx rts ;leave!
; -----------------------------------------------------------------------------
SpawnBrickChunks
be41: b5 8f lda Block_X_Position,x ;set horizontal coordinate of block object
be43: 9d f1 03 sta Block_Orig_XPos,x ; as original horizontal coordinate here
be46: a9 f0 lda #$f0
be48: 95 60 sta Block_X_Speed,x ;set horizontal speed for brick chunk objects
be4a: 95 62 sta Block_X_Speed+2,x
be4c: a9 fa lda #$fa
be4e: 95 a8 sta Block_Y_Speed,x ;set vertical speed for one
be50: a9 fc lda #$fc
be52: 95 aa sta Block_Y_Speed+2,x ;set lower vertical speed for the other
be54: a9 00 lda #$00
be56: 9d 3c 04 sta Block_Y_MoveForce,x ;init fractional movement force for both
be59: 9d 3e 04 sta Block_Y_MoveForce+2,x
be5c: b5 76 lda Block_PageLoc,x
be5e: 95 78 sta Block_PageLoc+2,x ;copy page location
be60: b5 8f lda Block_X_Position,x
be62: 95 91 sta Block_X_Position+2,x ;copy horizontal coordinate
be64: b5 d7 lda Block_Y_Position,x
be66: 18 clc ;add 8 pixels to vertical coordinate
be67: 69 08 adc #$08 ;and save as vertical coordinate for one of them
be69: 95 d9 sta Block_Y_Position+2,x
be6b: a9 fa lda #$fa
be6d: 95 a8 sta Block_Y_Speed,x ;set vertical speed...again??? (redundant)
be6f: 60 rts
; -----------------------------------------------------------------------------
BlockObjectsCore
be70: b5 26 lda Block_State,x ;get state of block object
be72: f0 5d beq UpdSte ;if not set, branch to leave
be74: 29 0f and #$0f ;mask out high nybble
be76: 48 pha ;push to stack
be77: a8 tay ;put in Y for now
be78: 8a txa
be79: 18 clc
be7a: 69 09 adc #$09 ;add 9 bytes to offset (note two block objects are created
be7c: aa tax ;when using brick chunks, but only one offset for both)
be7d: 88 dey ;decrement Y to check for solid block state
be7e: f0 33 beq BouncingBlockHandler ;branch if found, otherwise continue for brick chunks
be80: 20 a4 bf jsr ImposeGravityBlock ;do sub to impose gravity on one block object object
be83: 20 0f bf jsr MoveObjectHorizontally ;do another sub to move horizontally
be86: 8a txa
be87: 18 clc ;move onto next block object
be88: 69 02 adc #$02
be8a: aa tax
be8b: 20 a4 bf jsr ImposeGravityBlock ;do sub to impose gravity on other block object
be8e: 20 0f bf jsr MoveObjectHorizontally ;do another sub to move horizontally
be91: a6 08 ldx ObjectOffset ;get block object offset used for both
be93: 20 59 f1 jsr RelativeBlockPosition ;get relative coordinates
be96: 20 b6 f1 jsr GetBlockOffscreenBits ;get offscreen information
be99: 20 53 ec jsr DrawBrickChunks ;draw the brick chunks
be9c: 68 pla ;get lower nybble of saved state
be9d: b4 be ldy Block_Y_HighPos,x ;check vertical high byte of block object
be9f: f0 30 beq UpdSte ;if above the screen, branch to kill it
bea1: 48 pha ;otherwise save state back into stack
bea2: a9 f0 lda #$f0
bea4: d5 d9 cmp Block_Y_Position+2,x ;check to see if bottom block object went
bea6: b0 02 bcs ChkTop ; to the bottom of the screen, and branch if not
bea8: 95 d9 sta Block_Y_Position+2,x ;otherwise set offscreen coordinate
beaa: b5 d7 ChkTop lda Block_Y_Position,x ;get top block object's vertical coordinate
beac: c9 f0 cmp #$f0 ;see if it went to the bottom of the screen
beae: 68 pla ;pull block object state from stack
beaf: 90 20 bcc UpdSte ;if not, branch to save state
beb1: b0 1c bcs KillBlock ;otherwise do unconditional branch to kill it
BouncingBlockHandler
beb3: 20 a4 bf jsr ImposeGravityBlock ;do sub to impose gravity on block object
beb6: a6 08 ldx ObjectOffset ;get block object offset
beb8: 20 59 f1 jsr RelativeBlockPosition ;get relative coordinates
bebb: 20 b6 f1 jsr GetBlockOffscreenBits ;get offscreen information
bebe: 20 d1 eb jsr DrawBlock ;draw the block
bec1: b5 d7 lda Block_Y_Position,x ;get vertical coordinate
bec3: 29 0f and #$0f ;mask out high nybble
bec5: c9 05 cmp #$05 ;check to see if low nybble wrapped around
bec7: 68 pla ;pull state from stack
bec8: b0 07 bcs UpdSte ;if still above amount, not time to kill block yet, thus branch
beca: a9 01 lda #$01
becc: 9d ec 03 sta Block_RepFlag,x ;otherwise set flag to replace metatile
becf: a9 00 KillBlock lda #$00 ;if branched here, nullify object state
bed1: 95 26 UpdSte sta Block_State,x ;store contents of A in block object state
bed3: 60 rts
; -----------------------------------------------------------------------------
; $02 - used to store offset to block buffer
; $06-$07 - used to store block buffer address
BlockObjMT_Updater
bed4: a2 01 ldx #$01 ;set offset to start with second block object
bed6: 86 08 UpdateLoop stx ObjectOffset ;set offset here
bed8: ad 01 03 lda VRAM_Buffer1 ;if vram buffer already being used here,
bedb: d0 21 bne NextBUpd ;branch to move onto next block object
bedd: bd ec 03 lda Block_RepFlag,x ;if flag for block object already clear,
bee0: f0 1c beq NextBUpd ;branch to move onto next block object
bee2: bd e6 03 lda Block_BBuf_Low,x ;get low byte of block buffer
bee5: 85 06 sta $06 ;store into block buffer address
bee7: a9 05 lda #$05
bee9: 85 07 sta $07 ;set high byte of block buffer address
beeb: bd e4 03 lda Block_Orig_YPos,x ;get original vertical coordinate of block object
beee: 85 02 sta $02 ;store here and use as offset to block buffer
bef0: a8 tay
bef1: bd e8 03 lda Block_Metatile,x ;get metatile to be written
bef4: 91 06 sta ($06),y ;write it to the block buffer
bef6: 20 61 8a jsr ReplaceBlockMetatile ;do sub to replace metatile where block object is
bef9: a9 00 lda #$00
befb: 9d ec 03 sta Block_RepFlag,x ;clear block object flag
befe: ca NextBUpd dex ;decrement block object offset
beff: 10 d5 bpl UpdateLoop ;do this until both block objects are dealt with
bf01: 60 rts ;then leave
; -----------------------------------------------------------------------------
; $00 - used to store high nybble of horizontal speed as adder
; $01 - used to store low nybble of horizontal speed
; $02 - used to store adder to page location
MoveEnemyHorizontally
bf02: e8 inx ;increment offset for enemy offset
bf03: 20 0f bf jsr MoveObjectHorizontally ;position object horizontally according to
bf06: a6 08 ldx ObjectOffset ; counters, return with saved value in A,
bf08: 60 rts ; put enemy offset back in X and leave
MovePlayerHorizontally
bf09: ad 0e 07 lda JumpspringAnimCtrl ;if jumpspring currently animating,
bf0c: d0 3e bne ExXMove ;branch to leave
bf0e: aa tax ;otherwise set zero for offset to use player's stuff
MoveObjectHorizontally
bf0f: b5 57 lda SprObject_X_Speed,x ;get currently saved value (horizontal
bf11: 0a asl A ; speed, secondary counter, whatever)
bf12: 0a asl A ; and move low nybble to high
bf13: 0a asl A
bf14: 0a asl A
bf15: 85 01 sta $01 ;store result here
bf17: b5 57 lda SprObject_X_Speed,x ;get saved value again
bf19: 4a lsr A ;move high nybble to low
bf1a: 4a lsr A
bf1b: 4a lsr A
bf1c: 4a lsr A
bf1d: c9 08 cmp #$08 ;if < 8, branch, do not change
bf1f: 90 02 bcc SaveXSpd
bf21: 09 f0 ora #%11110000 ;otherwise alter high nybble
bf23: 85 00 SaveXSpd sta $00 ;save result here
bf25: a0 00 ldy #$00 ;load default Y value here
bf27: c9 00 cmp #$00 ;if result positive, leave Y alone
bf29: 10 01 bpl UseAdder
bf2b: 88 dey ;otherwise decrement Y
bf2c: 84 02 UseAdder sty $02 ;save Y here
bf2e: bd 00 04 lda SprObject_X_MoveForce,x ;get whatever number's here
bf31: 18 clc
bf32: 65 01 adc $01 ;add low nybble moved to high
bf34: 9d 00 04 sta SprObject_X_MoveForce,x ;store result here
bf37: a9 00 lda #$00 ;init A
bf39: 2a rol A ;rotate carry into d0
bf3a: 48 pha ;push onto stack
bf3b: 6a ror A ;rotate d0 back onto carry
bf3c: b5 86 lda Player_X_Position,x
bf3e: 65 00 adc $00 ;add carry plus saved value (high nybble moved to low
bf40: 95 86 sta Player_X_Position,x ; plus $f0 if necessary) to object's horizontal position
bf42: b5 6d lda Player_PageLoc,x
bf44: 65 02 adc $02 ;add carry plus other saved value to the
bf46: 95 6d sta Player_PageLoc,x ; object's page location and save
bf48: 68 pla
bf49: 18 clc ;pull old carry from stack and add
bf4a: 65 00 adc $00 ; to high nybble moved to low
bf4c: 60 ExXMove rts ;and leave
; -----------------------------------------------------------------------------
; $00 - used for downward force
; $01 - used for upward force
; $02 - used for maximum vertical speed
MovePlayerVertically
bf4d: a2 00 ldx #$00 ;set X for player offset
bf4f: ad 47 07 lda TimerControl
bf52: d0 05 bne NoJSChk ;if master timer control set, branch ahead
bf54: ad 0e 07 lda JumpspringAnimCtrl ;otherwise check to see if jumpspring is animating
bf57: d0 f3 bne ExXMove ;branch to leave if so
bf59: ad 09 07 NoJSChk lda VerticalForce ;dump vertical force
bf5c: 85 00 sta $00
bf5e: a9 04 lda #$04 ;set maximum vertical speed here
bf60: 4c ad bf jmp ImposeGravitySprObj ;then jump to move player vertically
; -----------------------------------------------------------------------------
MoveD_EnemyVertically
bf63: a0 3d ldy #$3d ;set quick movement amount downwards
bf65: b5 1e lda Enemy_State,x ;then check enemy state
bf67: c9 05 cmp #$05 ;if not set to unique state for spiny's egg, go ahead
bf69: d0 02 bne ContVMove ;and use, otherwise set different movement amount, continue on
MoveFallingPlatform
bf6b: a0 20 ldy #$20 ;set movement amount
bf6d: 4c 94 bf ContVMove jmp SetHiMax ;jump to skip the rest of this
; -----------------------------------------------------------------------------
MoveRedPTroopaDown
bf70: a0 00 ldy #$00 ;set Y to move downwards
bf72: 4c 77 bf jmp MoveRedPTroopa ;skip to movement routine
MoveRedPTroopaUp
bf75: a0 01 ldy #$01 ;set Y to move upwards
bf77: e8 MoveRedPTroopa inx ;increment X for enemy offset
bf78: a9 03 lda #$03
bf7a: 85 00 sta $00 ;set downward movement amount here
bf7c: a9 06 lda #$06
bf7e: 85 01 sta $01 ;set upward movement amount here
bf80: a9 02 lda #$02
bf82: 85 02 sta $02 ;set maximum speed here
bf84: 98 tya ;set movement direction in A, and
bf85: 4c d1 bf jmp RedPTroopaGrav ; jump to move this thing
; -----------------------------------------------------------------------------
MoveDropPlatform
bf88: a0 7f ldy #$7f ;set movement amount for drop platform
bf8a: d0 02 bne SetMdMax ;skip ahead of other value set here
MoveEnemySlowVert
bf8c: a0 0f ldy #$0f ;set movement amount for bowser/other objects
bf8e: a9 02 SetMdMax lda #$02 ;set maximum speed in A
bf90: d0 04 bne SetXMoveAmt ;unconditional branch
; -----------------------------------------------------------------------------
MoveJ_EnemyVertically
bf92: a0 1c ldy #$1c ;set movement amount for podoboo/other objects
bf94: a9 03 SetHiMax lda #$03 ;set maximum speed in A
bf96: 84 00 SetXMoveAmt sty $00 ;set movement amount here
bf98: e8 inx ;increment X for enemy offset
bf99: 20 ad bf jsr ImposeGravitySprObj ;do a sub to move enemy object downwards
bf9c: a6 08 ldx ObjectOffset ;get enemy object buffer offset and leave
bf9e: 60 rts
; -----------------------------------------------------------------------------
bf9f: 06 08 MaxSpdBlockData .bulk $06,$08
bfa1: a0 00 unref_bfa1 ldy #$00 ;this part appears to be residual,
bfa3: 2c bit βΌ $01a0 ;no code branches or jumps to it...
ImposeGravityBlock
bfa4: a0 01 ldy #$01 ;set offset for maximum speed
bfa6: a9 50 lda #$50 ;set movement amount here
bfa8: 85 00 sta $00
bfaa: b9 9f bf lda MaxSpdBlockData,y ;get maximum speed
ImposeGravitySprObj
bfad: 85 02 sta $02 ;set maximum speed here
bfaf: a9 00 lda #$00 ;set value to move downwards
bfb1: 4c d7 bf jmp ImposeGravity ;jump to the code that actually moves it
; -----------------------------------------------------------------------------
MovePlatformDown
bfb4: a9 00 lda #$00 ;save value to stack (if branching here, execute next
bfb6: 2c bit βΌ $01a9 ; part as BIT instruction)
bfb7: a9 01 MovePlatformUp lda #$01 ;save value to stack
bfb9: 48 pha
bfba: b4 16 ldy Enemy_ID,x ;get enemy object identifier
bfbc: e8 inx ;increment offset for enemy object
bfbd: a9 05 lda #$05 ;load default value here
bfbf: c0 29 cpy #$29 ;residual comparison, object #29 never executes
bfc1: d0 02 bne SetDblSpd ; this code, thus unconditional branch here
bfc3: a9 09 lda #$09 ;residual code
bfc5: 85 00 SetDblSpd sta $00 ;save downward movement amount here
bfc7: a9 0a lda #$0a ;save upward movement amount here
bfc9: 85 01 sta $01
bfcb: a9 03 lda #$03 ;save maximum vertical speed here
bfcd: 85 02 sta $02
bfcf: 68 pla ;get value from stack
bfd0: a8 tay ;use as Y, then move onto code shared by red koopa
bfd1: 20 d7 bf RedPTroopaGrav jsr ImposeGravity ;do a sub to move object gradually
bfd4: a6 08 ldx ObjectOffset ;get enemy object offset and leave
bfd6: 60 rts
; -----------------------------------------------------------------------------
; $00 - used for downward force
; $01 - used for upward force
; $07 - used as adder for vertical position
bfd7: 48 ImposeGravity pha ;push value to stack
bfd8: bd 16 04 lda SprObject_YMF_Dummy,x
bfdb: 18 clc ;add value in movement force to contents of dummy variable
bfdc: 7d 33 04 adc SprObject_Y_MoveForce,x
bfdf: 9d 16 04 sta SprObject_YMF_Dummy,x
bfe2: a0 00 ldy #$00 ;set Y to zero by default
bfe4: b5 9f lda SprObject_Y_Speed,x ;get current vertical speed
bfe6: 10 01 bpl AlterYP ;if currently moving downwards, do not decrement Y
bfe8: 88 dey ;otherwise decrement Y
bfe9: 84 07 AlterYP sty $07 ;store Y here
bfeb: 75 ce adc SprObject_Y_Position,x ;add vertical position to vertical speed plus carry
bfed: 95 ce sta SprObject_Y_Position,x ;store as new vertical position
bfef: b5 b5 lda SprObject_Y_HighPos,x
bff1: 65 07 adc $07 ;add carry plus contents of $07 to vertical high byte
bff3: 95 b5 sta SprObject_Y_HighPos,x ;store as new vertical high byte
bff5: bd 33 04 lda SprObject_Y_MoveForce,x
bff8: 18 clc
bff9: 65 00 adc $00 ;add downward movement amount to contents of $0433
bffb: 9d 33 04 sta SprObject_Y_MoveForce,x
bffe: b5 9f lda SprObject_Y_Speed,x ;add carry to vertical speed and store
c000: 69 00 adc #$00
c002: 95 9f sta SprObject_Y_Speed,x
c004: c5 02 cmp $02 ;compare to maximum speed
c006: 30 10 bmi ChkUpM ;if less than preset value, skip this part
c008: bd 33 04 lda SprObject_Y_MoveForce,x
c00b: c9 80 cmp #$80 ;if less positively than preset maximum, skip this part
c00d: 90 09 bcc ChkUpM
c00f: a5 02 lda $02
c011: 95 9f sta SprObject_Y_Speed,x ;keep vertical speed within maximum value
c013: a9 00 lda #$00
c015: 9d 33 04 sta SprObject_Y_MoveForce,x ;clear fractional
c018: 68 ChkUpM pla ;get value from stack
c019: f0 2b beq ExVMove ;if set to zero, branch to leave
c01b: a5 02 lda $02
c01d: 49 ff eor #%11111111 ;otherwise get two's compliment of maximum speed
c01f: a8 tay
c020: c8 iny
c021: 84 07 sty $07 ;store two's compliment here
c023: bd 33 04 lda SprObject_Y_MoveForce,x
c026: 38 sec ;subtract upward movement amount from contents
c027: e5 01 sbc $01 ; of movement force, note that $01 is twice as large as $00,
c029: 9d 33 04 sta SprObject_Y_MoveForce,x ; thus it effectively undoes add we did earlier
c02c: b5 9f lda SprObject_Y_Speed,x
c02e: e9 00 sbc #$00 ;subtract borrow from vertical speed and store
c030: 95 9f sta SprObject_Y_Speed,x
c032: c5 07 cmp $07 ;compare vertical speed to two's compliment
c034: 10 10 bpl ExVMove ;if less negatively than preset maximum, skip this part
c036: bd 33 04 lda SprObject_Y_MoveForce,x
c039: c9 80 cmp #$80 ;check if fractional part is above certain amount,
c03b: b0 09 bcs ExVMove ;and if so, branch to leave
c03d: a5 07 lda $07
c03f: 95 9f sta SprObject_Y_Speed,x ;keep vertical speed within maximum value
c041: a9 ff lda #$ff
c043: 9d 33 04 sta SprObject_Y_MoveForce,x ;clear fractional
c046: 60 ExVMove rts ;leave!
; -----------------------------------------------------------------------------
EnemiesAndLoopsCore
c047: b5 0f lda Enemy_Flag,x ;check data here for MSB set
c049: 48 pha ;save in stack
c04a: 0a asl A
c04b: b0 12 bcs ChkBowserF ;if MSB set in enemy flag, branch ahead of jumps
c04d: 68 pla ;get from stack
c04e: f0 03 beq ChkAreaTsk ;if data zero, branch
c050: 4c 82 c8 jmp RunEnemyObjectsCore ;otherwise, jump to run enemy subroutines
c053: ad 1f 07 ChkAreaTsk lda AreaParserTaskNum ;check number of tasks to perform
c056: 29 07 and #$07
c058: c9 07 cmp #$07 ;if at a specific task, jump and leave
c05a: f0 0e beq ExitELCore
c05c: 4c cc c0 jmp ProcLoopCommand ;otherwise, jump to process loop command/load enemies
c05f: 68 ChkBowserF pla ;get data from stack
c060: 29 0f and #%00001111 ;mask out high nybble
c062: a8 tay
c063: b9 0f 00 lda Enemy_Flag,y ;use as pointer and load same place with different offset
c066: d0 02 bne ExitELCore
c068: 95 0f sta Enemy_Flag,x ;if second enemy flag not set, also clear first one
c06a: 60 ExitELCore rts
; -----------------------------------------------------------------------------
LoopCmdWorldNumber
c06b: 03 03 06 06+ .bulk $03,$03,$06,$06,$06,$06,$06,$06,$07,$07,$07
LoopCmdPageNumber
c076: 05 09 04 05+ .bulk $05,$09,$04,$05,$06,$08,$09,$0a,$06,$0b,$10
LoopCmdYPosition
c081: 40 b0 b0 80+ .bulk $40,$b0,$b0,$80,$40,$40,$80,$40,$f0,$f0,$f0
ExecGameLoopback
c08c: a5 6d lda Player_PageLoc ;send player back four pages
c08e: 38 sec
c08f: e9 04 sbc #$04
c091: 85 6d sta Player_PageLoc
c093: ad 25 07 lda CurrentPageLoc ;send current page back four pages
c096: 38 sec
c097: e9 04 sbc #$04
c099: 8d 25 07 sta CurrentPageLoc
c09c: ad 1a 07 lda ScreenLeft_PageLoc ;subtract four from page location
c09f: 38 sec ; of screen's left border
c0a0: e9 04 sbc #$04
c0a2: 8d 1a 07 sta ScreenLeft_PageLoc
c0a5: ad 1b 07 lda ScreenRight_PageLoc ;do the same for the page location
c0a8: 38 sec ; of screen's right border
c0a9: e9 04 sbc #$04
c0ab: 8d 1b 07 sta ScreenRight_PageLoc
c0ae: ad 2a 07 lda AreaObjectPageLoc ;subtract four from page control
c0b1: 38 sec ; for area objects
c0b2: e9 04 sbc #$04
c0b4: 8d 2a 07 sta AreaObjectPageLoc
c0b7: a9 00 lda #$00 ;initialize page select for both
c0b9: 8d 3b 07 sta EnemyObjectPageSel ; area and enemy objects
c0bc: 8d 2b 07 sta AreaObjectPageSel
c0bf: 8d 39 07 sta EnemyDataOffset ;initialize enemy object data offset
c0c2: 8d 3a 07 sta EnemyObjectPageLoc ;and enemy object page control
c0c5: b9 f8 9b lda AreaDataOfsLoopback,y ;adjust area object offset based on
c0c8: 8d 2c 07 sta AreaDataOffset ; which loop command we encountered
c0cb: 60 rts
c0cc: ad 45 07 ProcLoopCommand lda LoopCommand ;check if loop command was found
c0cf: f0 5e beq ChkEnemyFrenzy
c0d1: ad 26 07 lda CurrentColumnPos ;check to see if we're still on the first page
c0d4: d0 59 bne ChkEnemyFrenzy ;if not, do not loop yet
c0d6: a0 0b ldy #$0b ;start at the end of each set of loop data
c0d8: 88 FindLoop dey
c0d9: 30 54 bmi ChkEnemyFrenzy ;if all data is checked and not match, do not loop
c0db: ad 5f 07 lda WorldNumber ;check to see if one of the world numbers
c0de: d9 6b c0 cmp LoopCmdWorldNumber,y ; matches our current world number
c0e1: d0 f5 bne FindLoop
c0e3: ad 25 07 lda CurrentPageLoc ;check to see if one of the page numbers
c0e6: d9 76 c0 cmp LoopCmdPageNumber,y ; matches the page we're currently on
c0e9: d0 ed bne FindLoop
c0eb: a5 ce lda Player_Y_Position ;check to see if the player is at the correct position
c0ed: d9 81 c0 cmp LoopCmdYPosition,y ;if not, branch to check for world 7
c0f0: d0 23 bne WrongChk
c0f2: a5 1d lda Player_State ;check to see if the player is
c0f4: c9 00 cmp #$00 ;on solid ground (i.e. not jumping or falling)
c0f6: d0 1d bne WrongChk ;if not, player fails to pass loop, and loopback
c0f8: ad 5f 07 lda WorldNumber ;are we in world 7? (check performed on correct
c0fb: c9 06 cmp #World7 ; vertical position and on solid ground)
c0fd: d0 23 bne InitMLp ;if not, initialize flags used there, otherwise
c0ff: ee d9 06 inc MultiLoopCorrectCntr ;increment counter for correct progression
c102: ee da 06 IncMLoop inc MultiLoopPassCntr ;increment master multi-part counter
c105: ad da 06 lda MultiLoopPassCntr ;have we done all three parts?
c108: c9 03 cmp #$03
c10a: d0 1e bne InitLCmd ;if not, skip this part
c10c: ad d9 06 lda MultiLoopCorrectCntr ;if so, have we done them all correctly?
c10f: c9 03 cmp #$03
c111: f0 0f beq InitMLp ;if so, branch past unnecessary check here
c113: d0 07 bne DoLpBack ;unconditional branch if previous branch fails
c115: ad 5f 07 WrongChk lda WorldNumber ;are we in world 7? (check performed on
c118: c9 06 cmp #World7 ; incorrect vertical position or not on solid ground)
c11a: f0 e6 beq IncMLoop
c11c: 20 8c c0 DoLpBack jsr ExecGameLoopback ;if player is not in right place, loop back
c11f: 20 71 d0 jsr KillAllEnemies
c122: a9 00 InitMLp lda #$00 ;initialize counters used for multi-part loop commands
c124: 8d da 06 sta MultiLoopPassCntr
c127: 8d d9 06 sta MultiLoopCorrectCntr
c12a: a9 00 InitLCmd lda #$00 ;initialize loop command flag
c12c: 8d 45 07 sta LoopCommand
;
c12f: ad cd 06 ChkEnemyFrenzy lda EnemyFrenzyQueue ;check for enemy object in frenzy queue
c132: f0 10 beq ProcessEnemyData ;if not, skip this part
c134: 95 16 sta Enemy_ID,x ;store as enemy object identifier here
c136: a9 01 lda #$01
c138: 95 0f sta Enemy_Flag,x ;activate enemy object flag
c13a: a9 00 lda #$00
c13c: 95 1e sta Enemy_State,x ;initialize state and frenzy queue
c13e: 8d cd 06 sta EnemyFrenzyQueue
c141: 4c 26 c2 jmp InitEnemyObject ;and then jump to deal with this enemy
; -----------------------------------------------------------------------------
; $06 - used to hold page location of extended right boundary
; $07 - used to hold high nybble of position of extended right boundary
ProcessEnemyData
c144: ac 39 07 ldy EnemyDataOffset ;get offset of enemy object data
c147: b1 e9 lda (EnemyData),y ;load first byte
c149: c9 ff cmp #$ff ;check for EOD terminator
c14b: d0 03 bne ChkEndofBuffer
c14d: 4c 16 c2 jmp CheckFrenzyBuffer ;if found, jump to check frenzy buffer, otherwise
c150: 29 0f ChkEndofBuffer and #%00001111 ;check for special row $0e
c152: c9 0e cmp #$0e
c154: f0 0e beq CheckRightBounds ;if found, branch, otherwise
c156: e0 05 cpx #$05 ;check for end of buffer
c158: 90 0a bcc CheckRightBounds ;if not at end of buffer, branch
c15a: c8 iny
c15b: b1 e9 lda (EnemyData),y ;check for specific value here
c15d: 29 3f and #%00111111 ;not sure what this was intended for, exactly
c15f: c9 2e cmp #$2e ;this part is quite possibly residual code
c161: f0 01 beq CheckRightBounds ; but it has the effect of keeping enemies out of
c163: 60 rts ; the sixth slot
CheckRightBounds
c164: ad 1d 07 lda ScreenRight_X_Pos ;add 48 to pixel coordinate of right boundary
c167: 18 clc
c168: 69 30 adc #$30
c16a: 29 f0 and #%11110000 ;store high nybble
c16c: 85 07 sta $07
c16e: ad 1b 07 lda ScreenRight_PageLoc ;add carry to page location of right boundary
c171: 69 00 adc #$00
c173: 85 06 sta $06 ;store page location + carry
c175: ac 39 07 ldy EnemyDataOffset
c178: c8 iny
c179: b1 e9 lda (EnemyData),y ;if MSB of enemy object is clear, branch to check for row $0f
c17b: 0a asl A
c17c: 90 0b bcc CheckPageCtrlRow
c17e: ad 3b 07 lda EnemyObjectPageSel ;if page select already set, do not set again
c181: d0 06 bne CheckPageCtrlRow
c183: ee 3b 07 inc EnemyObjectPageSel ;otherwise, if MSB is set, set page select
c186: ee 3a 07 inc EnemyObjectPageLoc ; and increment page control
CheckPageCtrlRow
c189: 88 dey
c18a: b1 e9 lda (EnemyData),y ;reread first byte
c18c: 29 0f and #$0f
c18e: c9 0f cmp #$0f ;check for special row $0f
c190: d0 19 bne PositionEnemyObj ;if not found, branch to position enemy object
c192: ad 3b 07 lda EnemyObjectPageSel ;if page select set,
c195: d0 14 bne PositionEnemyObj ;branch without reading second byte
c197: c8 iny
c198: b1 e9 lda (EnemyData),y ;otherwise, get second byte, mask out 2 MSB
c19a: 29 3f and #%00111111
c19c: 8d 3a 07 sta EnemyObjectPageLoc ;store as page control for enemy object data
c19f: ee 39 07 inc EnemyDataOffset ;increment enemy object data offset 2 bytes
c1a2: ee 39 07 inc EnemyDataOffset
c1a5: ee 3b 07 inc EnemyObjectPageSel ;set page select for enemy object data and
c1a8: 4c cc c0 jmp ProcLoopCommand ;jump back to process loop commands again
PositionEnemyObj
c1ab: ad 3a 07 lda EnemyObjectPageLoc ;store page control as page location
c1ae: 95 6e sta Enemy_PageLoc,x ; for enemy object
c1b0: b1 e9 lda (EnemyData),y ;get first byte of enemy object
c1b2: 29 f0 and #%11110000
c1b4: 95 87 sta Enemy_X_Position,x ;store column position
c1b6: cd 1d 07 cmp ScreenRight_X_Pos ;check column position against right boundary
c1b9: b5 6e lda Enemy_PageLoc,x ;without subtracting, then subtract borrow
c1bb: ed 1b 07 sbc ScreenRight_PageLoc ; from page location
c1be: b0 0b bcs CheckRightExtBounds ;if enemy object beyond or at boundary, branch
c1c0: b1 e9 lda (EnemyData),y
c1c2: 29 0f and #%00001111 ;check for special row $0e
c1c4: c9 0e cmp #$0e ;if found, jump elsewhere
c1c6: f0 69 beq ParseRow0e
c1c8: 4c 50 c2 jmp CheckThreeBytes ;if not found, unconditional jump
CheckRightExtBounds
c1cb: a5 07 lda $07 ;check right boundary + 48 against
c1cd: d5 87 cmp Enemy_X_Position,x ; column position without subtracting,
c1cf: a5 06 lda $06 ; then subtract borrow from page control temp
c1d1: f5 6e sbc Enemy_PageLoc,x ; plus carry
c1d3: 90 41 bcc CheckFrenzyBuffer ;if enemy object beyond extended boundary, branch
c1d5: a9 01 lda #$01 ;store value in vertical high byte
c1d7: 95 b6 sta Enemy_Y_HighPos,x
c1d9: b1 e9 lda (EnemyData),y ;get first byte again
c1db: 0a asl A ;multiply by four to get the vertical
c1dc: 0a asl A ; coordinate
c1dd: 0a asl A
c1de: 0a asl A
c1df: 95 cf sta Enemy_Y_Position,x
c1e1: c9 e0 cmp #$e0 ;do one last check for special row $0e
c1e3: f0 4c beq ParseRow0e ;(necessary if branched to $c1cb)
c1e5: c8 iny
c1e6: b1 e9 lda (EnemyData),y ;get second byte of object
c1e8: 29 40 and #%01000000 ;check to see if hard mode bit is set
c1ea: f0 05 beq CheckForEnemyGroup ;if not, branch to check for group enemy objects
c1ec: ad cc 06 lda SecondaryHardMode ;if set, check to see if secondary hard mode flag
c1ef: f0 6d beq Inc2B ;is on, and if not, branch to skip this object completely
CheckForEnemyGroup
c1f1: b1 e9 lda (EnemyData),y ;get second byte and mask out 2 MSB
c1f3: 29 3f and #%00111111
c1f5: c9 37 cmp #$37 ;check for value below $37
c1f7: 90 04 bcc BuzzyBeetleMutate
c1f9: c9 3f cmp #$3f ;if $37 or greater, check for value
c1fb: 90 31 bcc DoGroup ;below $3f, branch if below $3f
BuzzyBeetleMutate
c1fd: c9 06 cmp #Goomba ;if below $37, check for goomba
c1ff: d0 07 bne StrID ; value ($3f or more always fails)
c201: ac 6a 07 ldy PrimaryHardMode ;check if primary hard mode flag is set
c204: f0 02 beq StrID ; and if so, change goomba to buzzy beetle
c206: a9 02 lda #BuzzyBeetle
c208: 95 16 StrID sta Enemy_ID,x ;store enemy object number into buffer
c20a: a9 01 lda #$01
c20c: 95 0f sta Enemy_Flag,x ;set flag for enemy in buffer
c20e: 20 26 c2 jsr InitEnemyObject
c211: b5 0f lda Enemy_Flag,x ;check to see if flag is set
c213: d0 49 bne Inc2B ;if not, leave, otherwise branch
c215: 60 rts
CheckFrenzyBuffer
c216: ad cb 06 lda EnemyFrenzyBuffer ;if enemy object stored in frenzy buffer
c219: d0 09 bne StrFre ; then branch ahead to store in enemy object buffer
c21b: ad 98 03 lda VineFlagOffset ;otherwise check vine flag offset
c21e: c9 01 cmp #$01
c220: d0 0b bne ExEPar ;if other value <> 1, leave
c222: a9 2f lda #VineObject ;otherwise put vine in enemy identifier
c224: 95 16 StrFre sta Enemy_ID,x ;store contents of frenzy buffer into enemy identifier value
c226: a9 00 InitEnemyObject lda #$00 ;initialize enemy state
c228: 95 1e sta Enemy_State,x
c22a: 20 6c c2 jsr CheckpointEnemyID ;jump ahead to run jump engine and subroutines
c22d: 60 ExEPar rts ;then leave
c22e: 4c 1b c7 DoGroup jmp HandleGroupEnemies ;handle enemy group objects
c231: c8 ParseRow0e iny ;increment Y to load third byte of object
c232: c8 iny
c233: b1 e9 lda (EnemyData),y
c235: 4a lsr A ;move 3 MSB to the bottom, effectively
c236: 4a lsr A ; making %xxx00000 into %00000xxx
c237: 4a lsr A
c238: 4a lsr A
c239: 4a lsr A
c23a: cd 5f 07 cmp WorldNumber ;is it the same world number as we're on?
c23d: d0 0e bne NotUse ;if not, do not use (this allows multiple uses
c23f: 88 dey ; of the same area, like the underground bonus areas)
c240: b1 e9 lda (EnemyData),y ;otherwise, get second byte and use as offset
c242: 8d 50 07 sta AreaPointer ; to addresses for level and enemy object data
c245: c8 iny
c246: b1 e9 lda (EnemyData),y ;get third byte again, and this time mask out
c248: 29 1f and #%00011111 ; the 3 MSB from before, save as page number to be
c24a: 8d 51 07 sta EntrancePage ; used upon entry to area, if area is entered
c24d: 4c 5b c2 NotUse jmp Inc3B
c250: ac 39 07 CheckThreeBytes ldy EnemyDataOffset
c253: b1 e9 lda (EnemyData),y
c255: 29 0f and #$0f
c257: c9 0e cmp #$0e
c259: d0 03 bne Inc2B
c25b: ee 39 07 Inc3B inc EnemyDataOffset
c25e: ee 39 07 Inc2B inc EnemyDataOffset
c261: ee 39 07 inc EnemyDataOffset
c264: a9 00 lda #$00
c266: 8d 3b 07 sta EnemyObjectPageSel
c269: a6 08 ldx ObjectOffset
c26b: 60 rts
CheckpointEnemyID
c26c: b5 16 lda Enemy_ID,x
c26e: c9 15 cmp #$15
c270: b0 0d bcs InitEnemyRoutines
c272: a8 tay
c273: b5 cf lda Enemy_Y_Position,x
c275: 69 08 adc #$08
c277: 95 cf sta Enemy_Y_Position,x
c279: a9 01 lda #$01
c27b: 9d d8 03 sta EnemyOffscrBitsMasked,x
c27e: 98 tya
InitEnemyRoutines
c27f: 20 04 8e jsr JumpEngine
; jump engine table for newly loaded enemy objects
c282: 0e c3 .dd2 InitNormalEnemy ;for objects $00-$0f
c284: 0e c3 .dd2 InitNormalEnemy
c286: 0e c3 .dd2 InitNormalEnemy
c288: 1e c3 .dd2 InitRedKoopa
c28a: f0 c2 .dd2 NoInitCode
c28c: 28 c3 .dd2 InitHammerBro
c28e: f1 c2 .dd2 InitGoomba
c290: 42 c3 .dd2 InitBloober
c292: 6b c3 .dd2 InitBulletBill
c294: f0 c2 .dd2 NoInitCode
c296: 75 c3 .dd2 InitCheepCheep
c298: 75 c3 .dd2 InitCheepCheep
c29a: f7 c2 .dd2 InitPodoboo
c29c: 87 c7 .dd2 InitPiranhaPlant
c29e: d1 c7 .dd2 InitJumpGPTroopa
c2a0: 4a c3 .dd2 InitRedPTroopa
c2a2: 3d c3 .dd2 InitHorizFlySwimEnemy ;for objects $10-$1f
c2a4: 85 c3 .dd2 InitLakitu
c2a6: a0 c7 .dd2 InitEnemyFrenzy
c2a8: f0 c2 .dd2 NoInitCode
c2aa: a0 c7 .dd2 InitEnemyFrenzy
c2ac: a0 c7 .dd2 InitEnemyFrenzy
c2ae: a0 c7 .dd2 InitEnemyFrenzy
c2b0: a0 c7 .dd2 InitEnemyFrenzy
c2b2: b8 c7 .dd2 EndFrenzy
c2b4: f0 c2 .dd2 NoInitCode
c2b6: f0 c2 .dd2 NoInitCode
c2b8: 5c c4 .dd2 InitShortFirebar
c2ba: 5c c4 .dd2 InitShortFirebar
c2bc: 5c c4 .dd2 InitShortFirebar
c2be: 5c c4 .dd2 InitShortFirebar
c2c0: 59 c4 .dd2 InitLongFirebar
c2c2: f0 c2 .dd2 NoInitCode ;for objects $20-$2f
c2c4: f0 c2 .dd2 NoInitCode
c2c6: f0 c2 .dd2 NoInitCode
c2c8: f0 c2 .dd2 NoInitCode
c2ca: df c7 .dd2 InitBalPlatform
c2cc: 12 c8 .dd2 InitVertPlatform
c2ce: 3f c8 .dd2 LargeLiftUp
c2d0: 45 c8 .dd2 LargeLiftDown
c2d2: 0b c8 .dd2 InitHoriPlatform
c2d4: 03 c8 .dd2 InitDropPlatform
c2d6: 0b c8 .dd2 InitHoriPlatform
c2d8: 4b c8 .dd2 PlatLiftUp
c2da: 57 c8 .dd2 PlatLiftDown
c2dc: 49 c5 .dd2 InitBowser
c2de: 60 bc .dd2 PwrUpJmp ;possibly dummy value
c2e0: 1e b9 .dd2 Setup_Vine
c2e2: f0 c2 .dd2 NoInitCode ;for objects $30-$36
c2e4: f0 c2 .dd2 NoInitCode
c2e6: f0 c2 .dd2 NoInitCode
c2e8: f0 c2 .dd2 NoInitCode
c2ea: f0 c2 .dd2 NoInitCode
c2ec: 07 c3 .dd2 InitRetainerObj
c2ee: 81 c8 .dd2 EndOFEnemyInitCode
; -----------------------------------------------------------------------------
c2f0: 60 NoInitCode rts ;this executed when enemy object has no init code
; -----------------------------------------------------------------------------
c2f1: 20 0e c3 InitGoomba jsr InitNormalEnemy ;set appropriate horizontal speed
c2f4: 4c 46 c3 jmp SmallBBox ;set $09 as bounding box control, set other values
; -----------------------------------------------------------------------------
c2f7: a9 02 InitPodoboo lda #$02 ;set enemy position to below
c2f9: 95 b6 sta Enemy_Y_HighPos,x ; the bottom of the screen
c2fb: 95 cf sta Enemy_Y_Position,x
c2fd: 4a lsr A
c2fe: 9d 96 07 sta EnemyIntervalTimer,x ;set timer for enemy
c301: 4a lsr A
c302: 95 1e sta Enemy_State,x ;initialize enemy state, then jump to use
c304: 4c 46 c3 jmp SmallBBox ; $09 as bounding box size and set other things
; -----------------------------------------------------------------------------
c307: a9 b8 InitRetainerObj lda #$b8 ;set fixed vertical position for
c309: 95 cf sta Enemy_Y_Position,x ; princess/mushroom retainer object
c30b: 60 rts
; -----------------------------------------------------------------------------
c30c: f8 f4 NormalXSpdData .bulk $f8,$f4
c30e: a0 01 InitNormalEnemy ldy #$01 ;load offset of 1 by default
c310: ad 6a 07 lda PrimaryHardMode ;check for primary hard mode flag set
c313: d0 01 bne GetESpd
c315: 88 dey ;if not set, decrement offset
c316: b9 0c c3 GetESpd lda NormalXSpdData,y ;get appropriate horizontal speed
c319: 95 58 SetESpd sta BlooperMoveSpeed,x ;store as speed for enemy object
c31b: 4c 5a c3 jmp TallBBox ;branch to set bounding box control and other data
; -----------------------------------------------------------------------------
c31e: 20 0e c3 InitRedKoopa jsr InitNormalEnemy ;load appropriate horizontal speed
c321: a9 01 lda #$01 ;set enemy state for red koopa troopa $03
c323: 95 1e sta Enemy_State,x
c325: 60 rts
; -----------------------------------------------------------------------------
HBroWalkingTimerData
c326: 80 50 .bulk $80,$50
c328: a9 00 InitHammerBro lda #$00 ;init horizontal speed and timer used by hammer bro
c32a: 9d a2 03 sta HammerThrowingTimer,x ;apparently to time hammer throwing
c32d: 95 58 sta Enemy_X_Speed,x
c32f: ac cc 06 ldy SecondaryHardMode ;get secondary hard mode flag
c332: b9 26 c3 lda HBroWalkingTimerData,y
c335: 9d 96 07 sta EnemyIntervalTimer,x ;set value as delay for hammer bro to walk left
c338: a9 0b lda #$0b ;set specific value for bounding box size control
c33a: 4c 5c c3 jmp SetBBox
; -----------------------------------------------------------------------------
InitHorizFlySwimEnemy
c33d: a9 00 lda #$00 ;initialize horizontal speed
c33f: 4c 19 c3 jmp SetESpd
; -----------------------------------------------------------------------------
c342: a9 00 InitBloober lda #$00 ;initialize horizontal speed
c344: 95 58 sta BlooperMoveSpeed,x
c346: a9 09 SmallBBox lda #$09 ;set specific bounding box size control
c348: d0 12 bne SetBBox ;unconditional branch
; -----------------------------------------------------------------------------
c34a: a0 30 InitRedPTroopa ldy #$30 ;load central position adder for 48 pixels down
c34c: b5 cf lda Enemy_Y_Position,x ;set vertical coordinate into location to
c34e: 9d 01 04 sta RedPTroopaOrigXPos,x ; be used as original vertical coordinate
c351: 10 02 bpl GetCent ;if vertical coordinate < $80
c353: a0 e0 ldy #$e0 ;if => $80, load position adder for 32 pixels up
c355: 98 GetCent tya ;send central position adder to A
c356: 75 cf adc Enemy_Y_Position,x ;add to current vertical coordinate
c358: 95 58 sta RedPTroopaCenterYPos,x ;store as central vertical coordinate
c35a: a9 03 TallBBox lda #$03 ;set specific bounding box size control
c35c: 9d 9a 04 SetBBox sta Enemy_BoundBoxCtrl,x ;set bounding box control here
c35f: a9 02 lda #$02 ;set moving direction for left
c361: 95 46 sta Enemy_MovingDir,x
c363: a9 00 InitVStf lda #$00 ;initialize vertical speed
c365: 95 a0 sta Enemy_Y_Speed,x ; and movement force
c367: 9d 34 04 sta Enemy_Y_MoveForce,x
c36a: 60 rts
; -----------------------------------------------------------------------------
c36b: a9 02 InitBulletBill lda #$02 ;set moving direction for left
c36d: 95 46 sta Enemy_MovingDir,x
c36f: a9 09 lda #$09 ;set bounding box control for $09
c371: 9d 9a 04 sta Enemy_BoundBoxCtrl,x
c374: 60 rts
; -----------------------------------------------------------------------------
c375: 20 46 c3 InitCheepCheep jsr SmallBBox ;set vertical bounding box, speed, init others
c378: bd a7 07 lda PseudoRandomBitReg,x ;check one portion of LSFR
c37b: 29 10 and #%00010000 ;get d4 from it
c37d: 95 58 sta CheepCheepMoveMFlag,x ;save as movement flag of some sort
c37f: b5 cf lda Enemy_Y_Position,x
c381: 9d 34 04 sta CheepCheepOrigYPos,x ;save original vertical coordinate here
c384: 60 rts
; -----------------------------------------------------------------------------
c385: ad cb 06 InitLakitu lda EnemyFrenzyBuffer ;check to see if an enemy is already in
c388: d0 0b bne KillLakitu ; the frenzy buffer, and branch to kill lakitu if so
c38a: a9 00 SetupLakitu lda #$00 ;erase counter for lakitu's reappearance
c38c: 8d d1 06 sta LakituReappearTimer
c38f: 20 3d c3 jsr InitHorizFlySwimEnemy ;set $03 as bounding box, set other attributes
c392: 4c d9 c7 jmp TallBBox2 ;set $03 as bounding box again (not necessary) and leave
c395: 4c 98 c9 KillLakitu jmp EraseEnemyObject
; -----------------------------------------------------------------------------
; $01-$03 - used to hold pseudorandom difference adjusters
PRDiffAdjustData
c398: 26 2c 32 38 .bulk $26,$2c,$32,$38
c39c: 20 22 24 26 .bulk $20,$22,$24,$26
c3a0: 13 14 15 16 .bulk $13,$14,$15,$16
LakituAndSpinyHandler
c3a4: ad 8f 07 lda FrenzyEnemyTimer ;if timer here not expired, leave
c3a7: d0 3c bne ExLSHand
c3a9: e0 05 cpx #$05 ;if we are on the special use slot, leave
c3ab: b0 38 bcs ExLSHand
c3ad: a9 80 lda #$80 ;set timer
c3af: 8d 8f 07 sta FrenzyEnemyTimer
c3b2: a0 04 ldy #$04 ;start with the last enemy slot
c3b4: b9 16 00 ChkLak lda Enemy_ID,y ;check all enemy slots to see
c3b7: c9 11 cmp #Lakitu ;if lakitu is on one of them
c3b9: f0 2b beq CreateSpiny ;if so, branch out of this loop
c3bb: 88 dey ;otherwise check another slot
c3bc: 10 f6 bpl ChkLak ;loop until all slots are checked
c3be: ee d1 06 inc LakituReappearTimer ;increment reappearance timer
c3c1: ad d1 06 lda LakituReappearTimer
c3c4: c9 07 cmp #$07 ;check to see if we're up to a certain value yet
c3c6: 90 1d bcc ExLSHand ;if not, leave
c3c8: a2 04 ldx #$04 ;start with the last enemy slot again
c3ca: b5 0f ChkNoEn lda Enemy_Flag,x ;check enemy buffer flag for non-active enemy slot
c3cc: f0 05 beq CreateL ;branch out of loop if found
c3ce: ca dex ;otherwise check next slot
c3cf: 10 f9 bpl ChkNoEn ;branch until all slots are checked
c3d1: 30 10 bmi RetEOfs ;if no empty slots were found, branch to leave
c3d3: a9 00 CreateL lda #$00 ;initialize enemy state
c3d5: 95 1e sta Enemy_State,x
c3d7: a9 11 lda #Lakitu ;create lakitu enemy object
c3d9: 95 16 sta Enemy_ID,x
c3db: 20 8a c3 jsr SetupLakitu ;do a sub to set up lakitu
c3de: a9 20 lda #$20
c3e0: 20 d8 c5 jsr PutAtRightExtent ;finish setting up lakitu
c3e3: a6 08 RetEOfs ldx ObjectOffset ;get enemy object buffer offset again and leave
c3e5: 60 ExLSHand rts
; -----------------------------------------------------------------------------
c3e6: a5 ce CreateSpiny lda Player_Y_Position ;if player above a certain point, branch to leave
c3e8: c9 2c cmp #$2c
c3ea: 90 f9 bcc ExLSHand
c3ec: b9 1e 00 lda Enemy_State,y ;if lakitu is not in normal state, branch to leave
c3ef: d0 f4 bne ExLSHand
c3f1: b9 6e 00 lda Enemy_PageLoc,y ;store horizontal coordinates (high and low) of lakitu
c3f4: 95 6e sta Enemy_PageLoc,x ;into the coordinates of the spiny we're going to create
c3f6: b9 87 00 lda Enemy_X_Position,y
c3f9: 95 87 sta Enemy_X_Position,x
c3fb: a9 01 lda #$01 ;put spiny within vertical screen unit
c3fd: 95 b6 sta Enemy_Y_HighPos,x
c3ff: b9 cf 00 lda Enemy_Y_Position,y ;put spiny eight pixels above where lakitu is
c402: 38 sec
c403: e9 08 sbc #$08
c405: 95 cf sta Enemy_Y_Position,x
c407: bd a7 07 lda PseudoRandomBitReg,x ;get 2 LSB of LSFR and save to Y
c40a: 29 03 and #%00000011
c40c: a8 tay
c40d: a2 02 ldx #$02
c40f: b9 98 c3 DifLoop lda PRDiffAdjustData,y ;get three values and save them
c412: 95 01 sta $01,x ;to $01-$03
c414: c8 iny
c415: c8 iny ;increment Y four bytes for each value
c416: c8 iny
c417: c8 iny
c418: ca dex ;decrement X for each one
c419: 10 f4 bpl DifLoop ;loop until all three are written
c41b: a6 08 ldx ObjectOffset ;get enemy object buffer offset
c41d: 20 6c cf jsr PlayerLakituDiff ;move enemy, change direction, get value - difference
c420: a4 57 ldy Player_X_Speed ;check player's horizontal speed
c422: c0 08 cpy #$08
c424: b0 0e bcs SetSpSpd ;if moving faster than a certain amount, branch elsewhere
c426: a8 tay ;otherwise save value in A to Y for now
c427: bd a8 07 lda PseudoRandomBitReg+1,x
c42a: 29 03 and #%00000011 ;get one of the LSFR parts and save the 2 LSB
c42c: f0 05 beq UsePosv ;branch if neither bits are set
c42e: 98 tya
c42f: 49 ff eor #%11111111 ;otherwise get two's compliment of Y
c431: a8 tay
c432: c8 iny
c433: 98 UsePosv tya ;put value from A in Y back to A (they will be lost anyway)
c434: 20 46 c3 SetSpSpd jsr SmallBBox ;set bounding box control, init attributes, lose contents of A
c437: a0 02 ldy #$02
c439: 95 58 sta Enemy_X_Speed,x ;set horizontal speed to zero because previous contents
c43b: c9 00 cmp #$00 ; of A were lost...branch here will never be taken for
c43d: 30 01 bmi SpinyRte ; the same reason
c43f: 88 dey
c440: 94 46 SpinyRte sty Enemy_MovingDir,x ;set moving direction to the right
c442: a9 fd lda #$fd
c444: 95 a0 sta BlooperMoveCounter,x ;set vertical speed to move upwards
c446: a9 01 lda #$01
c448: 95 0f sta Enemy_Flag,x ;enable enemy object by setting flag
c44a: a9 05 lda #$05
c44c: 95 1e sta Enemy_State,x ;put spiny in egg state and leave
c44e: 60 ChpChpEx rts
; -----------------------------------------------------------------------------
FirebarSpinSpdData
c44f: 28 38 28 38+ .bulk $28,$38,$28,$38,$28
FirebarSpinDirData
c454: 00 00 10 10+ .bulk $00,$00,$10,$10,$00
c459: 20 75 c5 InitLongFirebar jsr DuplicateEnemyObj ;create enemy object for long firebar
InitShortFirebar
c45c: a9 00 lda #$00 ;initialize low byte of spin state
c45e: 95 58 sta FirebarSpinState_Low,x
c460: b5 16 lda Enemy_ID,x ;subtract $1b from enemy identifier
c462: 38 sec ; to get proper offset for firebar data
c463: e9 1b sbc #$1b
c465: a8 tay
c466: b9 4f c4 lda FirebarSpinSpdData,y ;get spinning speed of firebar
c469: 9d 88 03 sta FirebarSpinSpeed,x
c46c: b9 54 c4 lda FirebarSpinDirData,y ;get spinning direction of firebar
c46f: 95 34 sta DestinationPageLoc,x
c471: b5 cf lda Enemy_Y_Position,x
c473: 18 clc ;add four pixels to vertical coordinate
c474: 69 04 adc #$04
c476: 95 cf sta Enemy_Y_Position,x
c478: b5 87 lda Enemy_X_Position,x
c47a: 18 clc ;add four pixels to horizontal coordinate
c47b: 69 04 adc #$04
c47d: 95 87 sta Enemy_X_Position,x
c47f: b5 6e lda Enemy_PageLoc,x
c481: 69 00 adc #$00 ;add carry to page location
c483: 95 6e sta Enemy_PageLoc,x
c485: 4c d9 c7 jmp TallBBox2 ;set bounding box control (not used) and leave
; -----------------------------------------------------------------------------
; $00-$01 - used to hold pseudorandom bits
FlyCCXPositionData
c488: 80 30 40 80 .bulk $80,$30,$40,$80
c48c: 30 50 50 70 .bulk $30,$50,$50,$70
c490: 20 40 80 a0 .bulk $20,$40,$80,$a0
c494: 70 40 90 68 .bulk $70,$40,$90,$68
c498: 0e 05 06 0e FlyCCXSpeedData .bulk $0e,$05,$06,$0e
c49c: 1c 20 10 0c .bulk $1c,$20,$10,$0c
c4a0: 1e 22 18 14 .bulk $1e,$22,$18,$14
c4a4: 10 60 20 48 FlyCCTimerData .bulk $10,$60,$20,$48
InitFlyingCheepCheep
c4a8: ad 8f 07 lda FrenzyEnemyTimer ;if timer here not expired yet, branch to leave
c4ab: d0 a1 bne ChpChpEx
c4ad: 20 46 c3 jsr SmallBBox ;jump to set bounding box size $09 and init other values
c4b0: bd a8 07 lda PseudoRandomBitReg+1,x
c4b3: 29 03 and #%00000011 ;set pseudorandom offset here
c4b5: a8 tay
c4b6: b9 a4 c4 lda FlyCCTimerData,y ;load timer with pseudorandom offset
c4b9: 8d 8f 07 sta FrenzyEnemyTimer
c4bc: a0 03 ldy #$03 ;load Y with default value
c4be: ad cc 06 lda SecondaryHardMode
c4c1: f0 01 beq MaxCC ;if secondary hard mode flag not set, do not increment Y
c4c3: c8 iny ;otherwise, increment Y to allow as many as four onscreen
c4c4: 84 00 MaxCC sty $00 ;store whatever pseudorandom bits are in Y
c4c6: e4 00 cpx $00 ;compare enemy object buffer offset with Y
c4c8: b0 84 bcs ChpChpEx ;if X => Y, branch to leave
c4ca: bd a7 07 lda PseudoRandomBitReg,x
c4cd: 29 03 and #%00000011 ;get last two bits of LSFR, first part
c4cf: 85 00 sta $00 ; and store in two places
c4d1: 85 01 sta $01
c4d3: a9 fb lda #$fb ;set vertical speed for cheep-cheep
c4d5: 95 a0 sta Enemy_Y_Speed,x
c4d7: a9 00 lda #$00 ;load default value
c4d9: a4 57 ldy Player_X_Speed ;check player's horizontal speed
c4db: f0 07 beq GSeed ;if player not moving left or right, skip this part
c4dd: a9 04 lda #$04
c4df: c0 19 cpy #$19 ;if moving to the right but not very quickly,
c4e1: 90 01 bcc GSeed ; do not change A
c4e3: 0a asl A ;otherwise, multiply A by 2
c4e4: 48 GSeed pha ;save to stack
c4e5: 18 clc
c4e6: 65 00 adc $00 ;add to last two bits of LSFR we saved earlier
c4e8: 85 00 sta $00 ;save it there
c4ea: bd a8 07 lda PseudoRandomBitReg+1,x
c4ed: 29 03 and #%00000011 ;if neither of the last two bits of second LSFR set,
c4ef: f0 07 beq RSeed ; skip this part and save contents of $00
c4f1: bd a9 07 lda PseudoRandomBitReg+2,x
c4f4: 29 0f and #%00001111 ;otherwise overwrite with lower nybble of
c4f6: 85 00 sta $00 ; third LSFR part
c4f8: 68 RSeed pla ;get value from stack we saved earlier
c4f9: 18 clc
c4fa: 65 01 adc $01 ;add to last two bits of LSFR we saved in other place
c4fc: a8 tay ;use as pseudorandom offset here
c4fd: b9 98 c4 lda FlyCCXSpeedData,y ;get horizontal speed using pseudorandom offset
c500: 95 58 sta Enemy_X_Speed,x
c502: a9 01 lda #$01 ;set to move towards the right
c504: 95 46 sta Enemy_MovingDir,x
c506: a5 57 lda Player_X_Speed ;if player moving left or right, branch ahead of this part
c508: d0 12 bne D2XPos1
c50a: a4 00 ldy $00 ;get first LSFR or third LSFR lower nybble
c50c: 98 tya ;and check for d1 set
c50d: 29 02 and #%00000010
c50f: f0 0b beq D2XPos1 ;if d1 not set, branch
c511: b5 58 lda Enemy_X_Speed,x
c513: 49 ff eor #$ff ;if d1 set, change horizontal speed
c515: 18 clc ; into two's compliment, thus moving in the opposite
c516: 69 01 adc #$01 ; direction
c518: 95 58 sta Enemy_X_Speed,x
c51a: f6 46 inc Enemy_MovingDir,x ;increment to move towards the left
c51c: 98 D2XPos1 tya ;get first LSFR or third LSFR lower nybble again
c51d: 29 02 and #%00000010
c51f: f0 0f beq D2XPos2 ;check for d1 set again, branch again if not set
c521: a5 86 lda Player_X_Position ;get player's horizontal position
c523: 18 clc
c524: 79 88 c4 adc FlyCCXPositionData,y ;if d1 set, add value obtained from pseudorandom offset
c527: 95 87 sta Enemy_X_Position,x ; and save as enemy's horizontal position
c529: a5 6d lda Player_PageLoc ;get player's page location
c52b: 69 00 adc #$00 ;add carry and jump past this part
c52d: 4c 3c c5 jmp FinCCst
c530: a5 86 D2XPos2 lda Player_X_Position ;get player's horizontal position
c532: 38 sec
c533: f9 88 c4 sbc FlyCCXPositionData,y ;if d1 not set, subtract value obtained from pseudorandom
c536: 95 87 sta Enemy_X_Position,x ; offset and save as enemy's horizontal position
c538: a5 6d lda Player_PageLoc ;get player's page location
c53a: e9 00 sbc #$00 ;subtract borrow
c53c: 95 6e FinCCst sta Enemy_PageLoc,x ;save as enemy's page location
c53e: a9 01 lda #$01
c540: 95 0f sta Enemy_Flag,x ;set enemy's buffer flag
c542: 95 b6 sta Enemy_Y_HighPos,x ;set enemy's high vertical byte
c544: a9 f8 lda #$f8
c546: 95 cf sta Enemy_Y_Position,x ;put enemy below the screen, and we are done
c548: 60 rts
; -----------------------------------------------------------------------------
c549: 20 75 c5 InitBowser jsr DuplicateEnemyObj ;jump to create another bowser object
c54c: 8e 68 03 stx BowserFront_Offset ;save offset of first here
c54f: a9 00 lda #$00
c551: 8d 63 03 sta BowserBodyControls ;initialize bowser's body controls
c554: 8d 69 03 sta BridgeCollapseOffset ;and bridge collapse offset
c557: b5 87 lda Enemy_X_Position,x
c559: 8d 66 03 sta BowserOrigXPos ;store original horizontal position here
c55c: a9 df lda #$df
c55e: 8d 90 07 sta BowserFireBreathTimer ;store something here
c561: 95 46 sta Enemy_MovingDir,x ;and in moving direction
c563: a9 20 lda #$20
c565: 8d 64 03 sta BowserFeetCounter ;set bowser's feet timer and in enemy timer
c568: 9d 8a 07 sta EnemyFrameTimer,x
c56b: a9 05 lda #$05
c56d: 8d 83 04 sta BowserHitPoints ;give bowser 5 hit points
c570: 4a lsr A
c571: 8d 65 03 sta BowserMovementSpeed ;set default movement speed here
c574: 60 rts
; -----------------------------------------------------------------------------
DuplicateEnemyObj
c575: a0 ff ldy #$ff ;start at beginning of enemy slots
c577: c8 FSLoop iny ;increment one slot
c578: b9 0f 00 lda Enemy_Flag,y ;check enemy buffer flag for empty slot
c57b: d0 fa bne FSLoop ;if set, branch and keep checking
c57d: 8c cf 06 sty DuplicateObj_Offset ;otherwise set offset here
c580: 8a txa ;transfer original enemy buffer offset
c581: 09 80 ora #%10000000 ;store with d7 set as flag in new enemy
c583: 99 0f 00 sta Enemy_Flag,y ; slot as well as enemy offset
c586: b5 6e lda Enemy_PageLoc,x
c588: 99 6e 00 sta Enemy_PageLoc,y ;copy page location and horizontal coordinates
c58b: b5 87 lda Enemy_X_Position,x ; from original enemy to new enemy
c58d: 99 87 00 sta Enemy_X_Position,y
c590: a9 01 lda #$01
c592: 95 0f sta Enemy_Flag,x ;set flag as normal for original enemy
c594: 99 b6 00 sta Enemy_Y_HighPos,y ;set high vertical byte for new enemy
c597: b5 cf lda Enemy_Y_Position,x
c599: 99 cf 00 sta Enemy_Y_Position,y ;copy vertical coordinate from original to new
c59c: 60 FlmEx rts ;and then leave
; -----------------------------------------------------------------------------
c59d: 90 80 70 90 FlameYPosData .bulk $90,$80,$70,$90
FlameYMFAdderData
c5a1: ff 01 .bulk $ff,$01
c5a3: ad 8f 07 InitBowserFlame lda FrenzyEnemyTimer ;if timer not expired yet, branch to leave
c5a6: d0 f4 bne FlmEx
c5a8: 9d 34 04 sta Enemy_Y_MoveForce,x ;reset something here
c5ab: a5 fd lda NoiseSoundQueue
c5ad: 09 02 ora #Sfx_BowserFlame ;load bowser's flame sound into queue
c5af: 85 fd sta NoiseSoundQueue
c5b1: ac 68 03 ldy BowserFront_Offset ;get bowser's buffer offset
c5b4: b9 16 00 lda Enemy_ID,y ;check for bowser
c5b7: c9 2d cmp #Bowser
c5b9: f0 31 beq SpawnFromMouth ;branch if found
c5bb: 20 d9 d1 jsr SetFlameTimer ;get timer data based on flame counter
c5be: 18 clc
c5bf: 69 20 adc #$20 ;add 32 frames by default
c5c1: ac cc 06 ldy SecondaryHardMode
c5c4: f0 03 beq SetFrT ;if secondary mode flag not set, use as timer setting
c5c6: 38 sec
c5c7: e9 10 sbc #$10 ;otherwise subtract 16 frames for secondary hard mode
c5c9: 8d 8f 07 SetFrT sta FrenzyEnemyTimer ;set timer accordingly
c5cc: bd a7 07 lda PseudoRandomBitReg,x
c5cf: 29 03 and #%00000011 ;get 2 LSB from first part of LSFR
c5d1: 9d 17 04 sta BowserFlamePRandomOfs,x ;set here
c5d4: a8 tay ;use as offset
c5d5: b9 9d c5 lda FlameYPosData,y ;load vertical position based on pseudorandom offset
PutAtRightExtent
c5d8: 95 cf sta Enemy_Y_Position,x ;set vertical position
c5da: ad 1d 07 lda ScreenRight_X_Pos
c5dd: 18 clc
c5de: 69 20 adc #$20 ;place enemy 32 pixels beyond right side of screen
c5e0: 95 87 sta Enemy_X_Position,x
c5e2: ad 1b 07 lda ScreenRight_PageLoc
c5e5: 69 00 adc #$00 ;add carry
c5e7: 95 6e sta Enemy_PageLoc,x
c5e9: 4c 1f c6 jmp FinishFlame ;skip this part to finish setting values
c5ec: b9 87 00 SpawnFromMouth lda Enemy_X_Position,y ;get bowser's horizontal position
c5ef: 38 sec
c5f0: e9 0e sbc #$0e ;subtract 14 pixels
c5f2: 95 87 sta Enemy_X_Position,x ;save as flame's horizontal position
c5f4: b9 6e 00 lda Enemy_PageLoc,y
c5f7: 95 6e sta Enemy_PageLoc,x ;copy page location from bowser to flame
c5f9: b9 cf 00 lda Enemy_Y_Position,y
c5fc: 18 clc ;add 8 pixels to bowser's vertical position
c5fd: 69 08 adc #$08
c5ff: 95 cf sta Enemy_Y_Position,x ;save as flame's vertical position
c601: bd a7 07 lda PseudoRandomBitReg,x
c604: 29 03 and #%00000011 ;get 2 LSB from first part of LSFR
c606: 9d 17 04 sta Enemy_YMF_Dummy,x ;save here
c609: a8 tay ;use as offset
c60a: b9 9d c5 lda FlameYPosData,y ;get value here using bits as offset
c60d: a0 00 ldy #$00 ;load default offset
c60f: d5 cf cmp Enemy_Y_Position,x ;compare value to flame's current vertical position
c611: 90 01 bcc SetMF ;if less, do not increment offset
c613: c8 iny ;otherwise increment now
c614: b9 a1 c5 SetMF lda FlameYMFAdderData,y ;get value here and save
c617: 9d 34 04 sta Enemy_Y_MoveForce,x ; to vertical movement force
c61a: a9 00 lda #$00
c61c: 8d cb 06 sta EnemyFrenzyBuffer ;clear enemy frenzy buffer
c61f: a9 08 FinishFlame lda #$08 ;set $08 for bounding box control
c621: 9d 9a 04 sta Enemy_BoundBoxCtrl,x
c624: a9 01 lda #$01 ;set high byte of vertical and
c626: 95 b6 sta Enemy_Y_HighPos,x ; enemy buffer flag
c628: 95 0f sta Enemy_Flag,x
c62a: 4a lsr A
c62b: 9d 01 04 sta Enemy_X_MoveForce,x ;initialize horizontal movement force, and
c62e: 95 1e sta Enemy_State,x ;enemy state
c630: 60 rts
; -----------------------------------------------------------------------------
FireworksXPosData
c631: 00 30 60 60+ .bulk $00,$30,$60,$60,$00,$20
FireworksYPosData
c637: 60 40 70 40+ .bulk $60,$40,$70,$40,$60,$30
c63d: ad 8f 07 InitFireworks lda FrenzyEnemyTimer ;if timer not expired yet, branch to leave
c640: d0 47 bne ExitFWk
c642: a9 20 lda #$20 ;otherwise reset timer
c644: 8d 8f 07 sta FrenzyEnemyTimer
c647: ce d7 06 dec FireworksCounter ;decrement for each explosion
c64a: a0 06 ldy #$06 ;start at last slot
c64c: 88 StarFChk dey
c64d: b9 16 00 lda Enemy_ID,y ;check for presence of star flag object
c650: c9 31 cmp #StarFlagObject ;if there isn't a star flag object,
c652: d0 f8 bne StarFChk ; routine goes into infinite loop = crash
c654: b9 87 00 lda Enemy_X_Position,y
c657: 38 sec ;get horizontal coordinate of star flag object, then
c658: e9 30 sbc #$30 ;subtract 48 pixels from it and save to
c65a: 48 pha ; the stack
c65b: b9 6e 00 lda Enemy_PageLoc,y
c65e: e9 00 sbc #$00 ;subtract the carry from the page location
c660: 85 00 sta $00 ; of the star flag object
c662: ad d7 06 lda FireworksCounter ;get fireworks counter
c665: 18 clc
c666: 79 1e 00 adc Enemy_State,y ;add state of star flag object (possibly not necessary)
c669: a8 tay ;use as offset
c66a: 68 pla ;get saved horizontal coordinate of star flag - 48 pixels
c66b: 18 clc
c66c: 79 31 c6 adc FireworksXPosData,y ;add number based on offset of fireworks counter
c66f: 95 87 sta Enemy_X_Position,x ;store as the fireworks object horizontal coordinate
c671: a5 00 lda $00
c673: 69 00 adc #$00 ;add carry and store as page location for
c675: 95 6e sta Enemy_PageLoc,x ; the fireworks object
c677: b9 37 c6 lda FireworksYPosData,y ;get vertical position using same offset
c67a: 95 cf sta Enemy_Y_Position,x ;and store as vertical coordinate for fireworks object
c67c: a9 01 lda #$01
c67e: 95 b6 sta Enemy_Y_HighPos,x ;store in vertical high byte
c680: 95 0f sta Enemy_Flag,x ;and activate enemy buffer flag
c682: 4a lsr A
c683: 95 58 sta ExplosionGfxCounter,x ;initialize explosion counter
c685: a9 08 lda #$08
c687: 95 a0 sta ExplosionTimerCounter,x ;set explosion timing counter
c689: 60 ExitFWk rts
; -----------------------------------------------------------------------------
c68a: 01 Bitmasks .dd1 %00000001
c68b: 02 .dd1 %00000010
c68c: 04 .dd1 %00000100
c68d: 08 .dd1 %00001000
c68e: 10 .dd1 %00010000
c68f: 20 .dd1 %00100000
c690: 40 .dd1 %01000000
c691: 80 .dd1 %10000000
c692: 40 30 90 50+ Enemy17YPosData .bulk $40,$30,$90,$50,$20,$60,$a0,$70
c69a: 0a 0b SwimCC_IDData .bulk $0a,$0b
BulletBillCheepCheep
c69c: ad 8f 07 lda FrenzyEnemyTimer ;if timer not expired yet, branch to leave
c69f: d0 6f bne ExF17
c6a1: ad 4e 07 lda AreaType ;are we in a water-type level?
c6a4: d0 57 bne DoBulletBills ;if not, branch elsewhere
c6a6: e0 03 cpx #$03 ;are we past third enemy slot?
c6a8: b0 66 bcs ExF17 ;if so, branch to leave
c6aa: a0 00 ldy #$00 ;load default offset
c6ac: bd a7 07 lda PseudoRandomBitReg,x
c6af: c9 aa cmp #$aa ;check first part of LSFR against preset value
c6b1: 90 01 bcc ChkW2 ;if less than preset, do not increment offset
c6b3: c8 iny ;otherwise increment
c6b4: ad 5f 07 ChkW2 lda WorldNumber ;check world number
c6b7: c9 01 cmp #World2
c6b9: f0 01 beq Get17ID ;if we're on world 2, do not increment offset
c6bb: c8 iny ;otherwise increment
c6bc: 98 Get17ID tya
c6bd: 29 01 and #%00000001 ;mask out all but last bit of offset
c6bf: a8 tay
c6c0: b9 9a c6 lda SwimCC_IDData,y ;load identifier for cheep-cheeps
c6c3: 95 16 Set17ID sta Enemy_ID,x ;store whatever's in A as enemy identifier
c6c5: ad dd 06 lda BitMFilter
c6c8: c9 ff cmp #$ff ;if not all bits set, skip init part and compare bits
c6ca: d0 05 bne GetRBit
c6cc: a9 00 lda #$00 ;initialize vertical position filter
c6ce: 8d dd 06 sta BitMFilter
c6d1: bd a7 07 GetRBit lda PseudoRandomBitReg,x ;get first part of LSFR
c6d4: 29 07 and #%00000111 ;mask out all but 3 LSB
c6d6: a8 ChkRBit tay ;use as offset
c6d7: b9 8a c6 lda Bitmasks,y ;load bitmask
c6da: 2c dd 06 bit BitMFilter ;perform AND on filter without changing it
c6dd: f0 07 beq AddFBit
c6df: c8 iny ;increment offset
c6e0: 98 tya
c6e1: 29 07 and #%00000111 ;mask out all but 3 LSB thus keeping it 0-7
c6e3: 4c d6 c6 jmp ChkRBit ;do another check
c6e6: 0d dd 06 AddFBit ora BitMFilter ;add bit to already set bits in filter
c6e9: 8d dd 06 sta BitMFilter ;and store
c6ec: b9 92 c6 lda Enemy17YPosData,y ;load vertical position using offset
c6ef: 20 d8 c5 jsr PutAtRightExtent ;set vertical position and other values
c6f2: 9d 17 04 sta Enemy_YMF_Dummy,x ;initialize dummy variable
c6f5: a9 20 lda #$20 ;set timer
c6f7: 8d 8f 07 sta FrenzyEnemyTimer
c6fa: 4c 6c c2 jmp CheckpointEnemyID ;process our new enemy object
c6fd: a0 ff DoBulletBills ldy #$ff ;start at beginning of enemy slots
c6ff: c8 BB_SLoop iny ;move onto the next slot
c700: c0 05 cpy #$05 ;branch to play sound if we've done all slots
c702: b0 0d bcs FireBulletBill
c704: b9 0f 00 lda Enemy_Flag,y ;if enemy buffer flag not set,
c707: f0 f6 beq BB_SLoop ; loop back and check another slot
c709: b9 16 00 lda Enemy_ID,y
c70c: c9 08 cmp #BulletBill_FrenzyVar ;check enemy identifier for
c70e: d0 ef bne BB_SLoop ; bullet bill object (frenzy variant)
c710: 60 ExF17 rts ;if found, leave
c711: a5 fe FireBulletBill lda Square2SoundQueue
c713: 09 08 ora #Sfx_Blast ;play fireworks/gunfire sound
c715: 85 fe sta Square2SoundQueue
c717: a9 08 lda #BulletBill_FrenzyVar ;load identifier for bullet bill object
c719: d0 a8 bne Set17ID ;unconditional branch
; -----------------------------------------------------------------------------
; $00 - used to store Y position of group enemies
; $01 - used to store enemy ID
; $02 - used to store page location of right side of screen
; $03 - used to store X position of right side of screen
HandleGroupEnemies
c71b: a0 00 ldy #$00 ;load value for green koopa troopa
c71d: 38 sec
c71e: e9 37 sbc #$37 ;subtract $37 from second byte read
c720: 48 pha ;save result in stack for now
c721: c9 04 cmp #$04 ;was byte in $3b-$3e range?
c723: b0 0b bcs SnglID ;if so, branch
c725: 48 pha ;save another copy to stack
c726: a0 06 ldy #Goomba ;load value for goomba enemy
c728: ad 6a 07 lda PrimaryHardMode ;if primary hard mode flag not set,
c72b: f0 02 beq PullID ; branch, otherwise change to value
c72d: a0 02 ldy #BuzzyBeetle ; for buzzy beetle
c72f: 68 PullID pla ;get second copy from stack
c730: 84 01 SnglID sty $01 ;save enemy id here
c732: a0 b0 ldy #$b0 ;load default y coordinate
c734: 29 02 and #$02 ;check to see if d1 was set
c736: f0 02 beq SetYGp ;if so, move y coordinate up,
c738: a0 70 ldy #$70 ; otherwise branch and use default
c73a: 84 00 SetYGp sty $00 ;save y coordinate here
c73c: ad 1b 07 lda ScreenRight_PageLoc ;get page number of right edge of screen
c73f: 85 02 sta $02 ;save here
c741: ad 1d 07 lda ScreenRight_X_Pos ;get pixel coordinate of right edge
c744: 85 03 sta $03 ;save here
c746: a0 02 ldy #$02 ;load two enemies by default
c748: 68 pla ;get first copy from stack
c749: 4a lsr A ;check to see if d0 was set
c74a: 90 01 bcc CntGrp ;if not, use default value
c74c: c8 iny ;otherwise increment to three enemies
c74d: 8c d3 06 CntGrp sty NumberofGroupEnemies ;save number of enemies here
c750: a2 ff GrLoop ldx #$ff ;start at beginning of enemy buffers
c752: e8 GSltLp inx ;increment and branch if past
c753: e0 05 cpx #$05 ;end of buffers
c755: b0 2d bcs NextED
c757: b5 0f lda Enemy_Flag,x ;check to see if enemy is already
c759: d0 f7 bne GSltLp ; stored in buffer, and branch if so
c75b: a5 01 lda $01
c75d: 95 16 sta Enemy_ID,x ;store enemy object identifier
c75f: a5 02 lda $02
c761: 95 6e sta Enemy_PageLoc,x ;store page location for enemy object
c763: a5 03 lda $03
c765: 95 87 sta Enemy_X_Position,x ;store x coordinate for enemy object
c767: 18 clc
c768: 69 18 adc #$18 ;add 24 pixels for next enemy
c76a: 85 03 sta $03
c76c: a5 02 lda $02 ;add carry to page location for
c76e: 69 00 adc #$00 ; next enemy
c770: 85 02 sta $02
c772: a5 00 lda $00 ;store y coordinate for enemy object
c774: 95 cf sta Enemy_Y_Position,x
c776: a9 01 lda #$01 ;activate flag for buffer, and
c778: 95 b6 sta Enemy_Y_HighPos,x ; put enemy within the screen vertically
c77a: 95 0f sta Enemy_Flag,x
c77c: 20 6c c2 jsr CheckpointEnemyID ;process each enemy object separately
c77f: ce d3 06 dec NumberofGroupEnemies ;do this until we run out of enemy objects
c782: d0 cc bne GrLoop
c784: 4c 5e c2 NextED jmp Inc2B ;jump to increment data offset and leave
; -----------------------------------------------------------------------------
InitPiranhaPlant
c787: a9 01 lda #$01 ;set initial speed
c789: 95 58 sta PiranhaPlant_Y_Speed,x
c78b: 4a lsr A
c78c: 95 1e sta Enemy_State,x ;initialize enemy state and what would normally
c78e: 95 a0 sta PiranhaPlant_MoveFlag,x ; be used as vertical speed, but not in this case
c790: b5 cf lda Enemy_Y_Position,x
c792: 9d 34 04 sta PiranhaPlantDownYPos,x ;save original vertical coordinate here
c795: 38 sec
c796: e9 18 sbc #$18
c798: 9d 17 04 sta PiranhaPlantUpYPos,x ;save original vertical coordinate - 24 pixels here
c79b: a9 09 lda #$09
c79d: 4c db c7 jmp SetBBox2 ;set specific value for bounding box control
; -----------------------------------------------------------------------------
c7a0: b5 16 InitEnemyFrenzy lda Enemy_ID,x ;load enemy identifier
c7a2: 8d cb 06 sta EnemyFrenzyBuffer ;save in enemy frenzy buffer
c7a5: 38 sec
c7a6: e9 12 sbc #$12 ;subtract 12 and use as offset for jump engine
c7a8: 20 04 8e jsr JumpEngine
c7ab: a4 c3 .dd2 LakituAndSpinyHandler
c7ad: b7 c7 .dd2 NoFrenzyCode
c7af: a8 c4 .dd2 InitFlyingCheepCheep
c7b1: a3 c5 .dd2 InitBowserFlame
c7b3: 3d c6 .dd2 InitFireworks
c7b5: 9c c6 .dd2 BulletBillCheepCheep
; -----------------------------------------------------------------------------
c7b7: 60 NoFrenzyCode rts
; -----------------------------------------------------------------------------
c7b8: a0 05 EndFrenzy ldy #$05 ;start at last slot
c7ba: b9 16 00 LakituChk lda Enemy_ID,y ;check enemy identifiers
c7bd: c9 11 cmp #Lakitu ; for lakitu
c7bf: d0 05 bne NextFSlot
c7c1: a9 01 lda #$01 ;if found, set state
c7c3: 99 1e 00 sta Enemy_State,y
c7c6: 88 NextFSlot dey ;move onto the next slot
c7c7: 10 f1 bpl LakituChk ;do this until all slots are checked
c7c9: a9 00 lda #$00
c7cb: 8d cb 06 sta EnemyFrenzyBuffer ;empty enemy frenzy buffer
c7ce: 95 0f sta Enemy_Flag,x ;disable enemy buffer flag for this object
c7d0: 60 rts
; -----------------------------------------------------------------------------
InitJumpGPTroopa
c7d1: a9 02 lda #$02 ;set for movement to the left
c7d3: 95 46 sta Enemy_MovingDir,x
c7d5: a9 f8 lda #$f8 ;set horizontal speed
c7d7: 95 58 sta Enemy_X_Speed,x
c7d9: a9 03 TallBBox2 lda #$03 ;set specific value for bounding box control
c7db: 9d 9a 04 SetBBox2 sta Enemy_BoundBoxCtrl,x ;set bounding box control then leave
c7de: 60 rts
; -----------------------------------------------------------------------------
c7df: d6 cf InitBalPlatform dec Enemy_Y_Position,x ;raise vertical position by two pixels
c7e1: d6 cf dec Enemy_Y_Position,x
c7e3: ac cc 06 ldy SecondaryHardMode ;if secondary hard mode flag not set,
c7e6: d0 05 bne AlignP ;branch ahead
c7e8: a0 02 ldy #$02 ;otherwise set value here
c7ea: 20 71 c8 jsr PosPlatform ;do a sub to add or subtract pixels
c7ed: a0 ff AlignP ldy #$ff ;set default value here for now
c7ef: ad a0 03 lda BalPlatformAlignment ;get current balance platform alignment
c7f2: 95 1e sta Enemy_State,x ;set platform alignment to object state here
c7f4: 10 02 bpl SetBPA ;if old alignment $ff, put $ff as alignment for negative
c7f6: 8a txa ;if old contents already $ff, put
c7f7: a8 tay ;object offset as alignment to make next positive
c7f8: 8c a0 03 SetBPA sty BalPlatformAlignment ;store whatever value's in Y here
c7fb: a9 00 lda #$00
c7fd: 95 46 sta Enemy_MovingDir,x ;init moving direction
c7ff: a8 tay ;init Y
c800: 20 71 c8 jsr PosPlatform ;do a sub to add 8 pixels, then run shared code here
;
InitDropPlatform
c803: a9 ff lda #$ff
c805: 9d a2 03 sta PlatformCollisionFlag,x ;set some value here
c808: 4c 28 c8 jmp CommonPlatCode ;then jump ahead to execute more code
; -----------------------------------------------------------------------------
InitHoriPlatform
c80b: a9 00 lda #$00
c80d: 95 58 sta XMoveSecondaryCounter,x ;init one of the moving counters
c80f: 4c 28 c8 jmp CommonPlatCode ;jump ahead to execute more code
; -----------------------------------------------------------------------------
InitVertPlatform
c812: a0 40 ldy #$40 ;set default value here
c814: b5 cf lda Enemy_Y_Position,x ;check vertical position
c816: 10 07 bpl SetYO ;if above a certain point, skip this part
c818: 49 ff eor #$ff
c81a: 18 clc ;otherwise get two's compliment
c81b: 69 01 adc #$01
c81d: a0 c0 ldy #$c0 ;get alternate value to add to vertical position
c81f: 9d 01 04 SetYO sta YPlatformTopYPos,x ;save as top vertical position
c822: 98 tya
c823: 18 clc ;load value from earlier, add number of pixels
c824: 75 cf adc Enemy_Y_Position,x ; to vertical position
c826: 95 58 sta YPlatformCenterYPos,x ;save result as central vertical position
;
c828: 20 63 c3 CommonPlatCode jsr InitVStf ;do a sub to init certain other values
c82b: a9 05 SPBBox lda #$05 ;set default bounding box size control
c82d: ac 4e 07 ldy AreaType
c830: c0 03 cpy #$03 ;check for castle-type level
c832: f0 07 beq CasPBB ;use default value if found
c834: ac cc 06 ldy SecondaryHardMode ;otherwise check for secondary hard mode flag
c837: d0 02 bne CasPBB ;if set, use default value
c839: a9 06 lda #$06 ;use alternate value if not castle or secondary not set
c83b: 9d 9a 04 CasPBB sta Enemy_BoundBoxCtrl,x ;set bounding box size control here and leave
c83e: 60 rts
; -----------------------------------------------------------------------------
c83f: 20 4b c8 LargeLiftUp jsr PlatLiftUp ;execute code for platforms going up
c842: 4c 48 c8 jmp LargeLiftBBox ;overwrite bounding box for large platforms
c845: 20 57 c8 LargeLiftDown jsr PlatLiftDown ;execute code for platforms going down
c848: 4c 2b c8 LargeLiftBBox jmp SPBBox ;jump to overwrite bounding box size control
; -----------------------------------------------------------------------------
c84b: a9 10 PlatLiftUp lda #$10 ;set movement amount here
c84d: 9d 34 04 sta Enemy_Y_MoveForce,x
c850: a9 ff lda #$ff ;set moving speed for platforms going up
c852: 95 a0 sta BlooperMoveCounter,x
c854: 4c 60 c8 jmp CommonSmallLift ;skip ahead to part we should be executing
; -----------------------------------------------------------------------------
c857: a9 f0 PlatLiftDown lda #$f0 ;set movement amount here
c859: 9d 34 04 sta Enemy_Y_MoveForce,x
c85c: a9 00 lda #$00 ;set moving speed for platforms going down
c85e: 95 a0 sta Enemy_Y_Speed,x
;
c860: a0 01 CommonSmallLift ldy #$01
c862: 20 71 c8 jsr PosPlatform ;do a sub to add 12 pixels due to preset value
c865: a9 04 lda #$04
c867: 9d 9a 04 sta Enemy_BoundBoxCtrl,x ;set bounding box control for small platforms
c86a: 60 rts
; -----------------------------------------------------------------------------
c86b: 08 0c f8 PlatPosDataLow .bulk $08,$0c,$f8
c86e: 00 00 ff PlatPosDataHigh .bulk $00,$00,$ff
c871: b5 87 PosPlatform lda Enemy_X_Position,x ;get horizontal coordinate
c873: 18 clc
c874: 79 6b c8 adc PlatPosDataLow,y ;add or subtract pixels depending on offset
c877: 95 87 sta Enemy_X_Position,x ;store as new horizontal coordinate
c879: b5 6e lda Enemy_PageLoc,x
c87b: 79 6e c8 adc PlatPosDataHigh,y ;add or subtract page location depending on offset
c87e: 95 6e sta Enemy_PageLoc,x ;store as new page location
c880: 60 rts ;and go back
; -----------------------------------------------------------------------------
EndOFEnemyInitCode
c881: 60 rts
; -----------------------------------------------------------------------------
RunEnemyObjectsCore
c882: a6 08 ldx ObjectOffset ;get offset for enemy object buffer
c884: a9 00 lda #$00 ;load value 0 for jump engine by default
c886: b4 16 ldy Enemy_ID,x
c888: c0 15 cpy #$15 ;if enemy object < $15, use default value
c88a: 90 03 bcc JmpEO
c88c: 98 tya ;otherwise subtract $14 from the value and use
c88d: e9 14 sbc #$14 ; as value for jump engine
c88f: 20 04 8e JmpEO jsr JumpEngine
c892: e0 c8 .dd2 RunNormalEnemies ;for objects $00-$14
c894: 35 c9 .dd2 RunBowserFlame ;for objects $15-$1f
c896: 95 d2 .dd2 RunFireworks
c898: d6 c8 .dd2 NoRunCode
c89a: d6 c8 .dd2 NoRunCode
c89c: d6 c8 .dd2 NoRunCode
c89e: d6 c8 .dd2 NoRunCode
c8a0: 47 c9 .dd2 RunFirebarObj
c8a2: 47 c9 .dd2 RunFirebarObj
c8a4: 47 c9 .dd2 RunFirebarObj
c8a6: 47 c9 .dd2 RunFirebarObj
c8a8: 47 c9 .dd2 RunFirebarObj
c8aa: 47 c9 .dd2 RunFirebarObj ;for objects $20-$2f
c8ac: 47 c9 .dd2 RunFirebarObj
c8ae: 47 c9 .dd2 RunFirebarObj
c8b0: d6 c8 .dd2 NoRunCode
c8b2: 65 c9 .dd2 RunLargePlatform
c8b4: 65 c9 .dd2 RunLargePlatform
c8b6: 65 c9 .dd2 RunLargePlatform
c8b8: 65 c9 .dd2 RunLargePlatform
c8ba: 65 c9 .dd2 RunLargePlatform
c8bc: 65 c9 .dd2 RunLargePlatform
c8be: 65 c9 .dd2 RunLargePlatform
c8c0: 4d c9 .dd2 RunSmallPlatform
c8c2: 4d c9 .dd2 RunSmallPlatform
c8c4: 65 d0 .dd2 RunBowser
c8c6: 85 bc .dd2 PowerUpObjHandler
c8c8: 4b b9 .dd2 VineObjectHandler
c8ca: d6 c8 .dd2 NoRunCode ;for objects $30-$35
c8cc: d9 d2 .dd2 RunStarFlagObj
c8ce: ba b8 .dd2 JumpspringHandler
c8d0: d6 c8 .dd2 NoRunCode
c8d2: a4 b7 .dd2 WarpZoneObject
c8d4: d7 c8 .dd2 RunRetainerObj
; -----------------------------------------------------------------------------
c8d6: 60 NoRunCode rts
; -----------------------------------------------------------------------------
c8d7: 20 af f1 RunRetainerObj jsr GetEnemyOffscreenBits
c8da: 20 52 f1 jsr RelativeEnemyPosition
c8dd: 4c 7d e8 jmp EnemyGfxHandler
; -----------------------------------------------------------------------------
RunNormalEnemies
c8e0: a9 00 lda #$00 ;init sprite attributes
c8e2: 9d c5 03 sta Enemy_SprAttrib,x
c8e5: 20 af f1 jsr GetEnemyOffscreenBits
c8e8: 20 52 f1 jsr RelativeEnemyPosition
c8eb: 20 7d e8 jsr EnemyGfxHandler
c8ee: 20 43 e2 jsr GetEnemyBoundBox
c8f1: 20 c1 df jsr EnemyToBGCollisionDet
c8f4: 20 33 da jsr EnemiesCollision
c8f7: 20 53 d8 jsr PlayerEnemyCollision
c8fa: ac 47 07 ldy TimerControl ;if master timer control set, skip to last routine
c8fd: d0 03 bne SkipMove
c8ff: 20 05 c9 jsr EnemyMovementSubs
c902: 4c 7a d6 SkipMove jmp OffscreenBoundsCheck
; -----------------------------------------------------------------------------
EnemyMovementSubs
c905: b5 16 lda Enemy_ID,x
c907: 20 04 8e jsr JumpEngine
c90a: 77 ca .dd2 MoveNormalEnemy ;only objects $00-$14 use this table
c90c: 77 ca .dd2 MoveNormalEnemy
c90e: 77 ca .dd2 MoveNormalEnemy
c910: 77 ca .dd2 MoveNormalEnemy
c912: 77 ca .dd2 MoveNormalEnemy
c914: d8 c9 .dd2 ProcHammerBro
c916: 77 ca .dd2 MoveNormalEnemy
c918: 89 cb .dd2 MoveBloober
c91a: 36 cc .dd2 MoveBulletBill
c91c: 34 c9 .dd2 NoMoveCode
c91e: 4a cc .dd2 MoveSwimmingCheepCheep
c920: 4a cc .dd2 MoveSwimmingCheepCheep
c922: b0 c9 .dd2 MovePodoboo
c924: b0 d3 .dd2 MovePiranhaPlant
c926: f9 ca .dd2 MoveJumpingEnemy
c928: ff ca .dd2 ProcMoveRedPTroopa
c92a: 25 cb .dd2 MoveFlyGreenPTroopa
c92c: 28 cf .dd2 MoveLakitu
c92e: 77 ca .dd2 MoveNormalEnemy
c930: 34 c9 .dd2 NoMoveCode ;dummy
c932: df ce .dd2 MoveFlyingCheepCheep
; -----------------------------------------------------------------------------
c934: 60 NoMoveCode rts
; -----------------------------------------------------------------------------
c935: 20 eb d1 RunBowserFlame jsr ProcBowserFlame
c938: 20 af f1 jsr GetEnemyOffscreenBits
c93b: 20 52 f1 jsr RelativeEnemyPosition
c93e: 20 43 e2 jsr GetEnemyBoundBox
c941: 20 53 d8 jsr PlayerEnemyCollision
c944: 4c 7a d6 jmp OffscreenBoundsCheck
; -----------------------------------------------------------------------------
c947: 20 3c cd RunFirebarObj jsr ProcFirebar
c94a: 4c 7a d6 jmp OffscreenBoundsCheck
; -----------------------------------------------------------------------------
RunSmallPlatform
c94d: 20 af f1 jsr GetEnemyOffscreenBits
c950: 20 52 f1 jsr RelativeEnemyPosition
c953: 20 4c e2 jsr SmallPlatformBoundBox
c956: 20 7b db jsr SmallPlatformCollision
c959: 20 52 f1 jsr RelativeEnemyPosition
c95c: 20 66 ed jsr DrawSmallPlatform
c95f: 20 55 d6 jsr MoveSmallPlatform
c962: 4c 7a d6 jmp OffscreenBoundsCheck
; -----------------------------------------------------------------------------
RunLargePlatform
c965: 20 af f1 jsr GetEnemyOffscreenBits
c968: 20 52 f1 jsr RelativeEnemyPosition
c96b: 20 73 e2 jsr LargePlatformBoundBox
c96e: 20 45 db jsr LargePlatformCollision
c971: ad 47 07 lda TimerControl ;if master timer control set,
c974: d0 03 bne SkipPT ; skip subroutine tree
c976: 20 82 c9 jsr LargePlatformSubroutines
c979: 20 52 f1 SkipPT jsr RelativeEnemyPosition
c97c: 20 c8 e5 jsr DrawLargePlatform
c97f: 4c 7a d6 jmp OffscreenBoundsCheck
; -----------------------------------------------------------------------------
LargePlatformSubroutines
c982: b5 16 lda Enemy_ID,x ;subtract $24 to get proper offset for jump table
c984: 38 sec
c985: e9 24 sbc #$24
c987: 20 04 8e jsr JumpEngine
c98a: 32 d4 .dd2 BalancePlatform ;table used by objects $24-$2a
c98c: d3 d5 .dd2 YMovingPlatform
c98e: 4f d6 .dd2 MoveLargeLiftPlat
c990: 4f d6 .dd2 MoveLargeLiftPlat
c992: 07 d6 .dd2 XMovingPlatform
c994: 31 d6 .dd2 DropPlatform
c996: 3d d6 .dd2 RightPlatform
; -----------------------------------------------------------------------------
EraseEnemyObject
c998: a9 00 lda #$00 ;clear all enemy object variables
c99a: 95 0f sta Enemy_Flag,x
c99c: 95 16 sta Enemy_ID,x
c99e: 95 1e sta Enemy_State,x
c9a0: 9d 10 01 sta FloateyNum_Control,x
c9a3: 9d 96 07 sta EnemyIntervalTimer,x
c9a6: 9d 25 01 sta ShellChainCounter,x
c9a9: 9d c5 03 sta Enemy_SprAttrib,x
c9ac: 9d 8a 07 sta EnemyFrameTimer,x
c9af: 60 rts
; -----------------------------------------------------------------------------
c9b0: bd 96 07 MovePodoboo lda EnemyIntervalTimer,x ;check enemy timer
c9b3: d0 16 bne PdbM ;branch to move enemy if not expired
c9b5: 20 f7 c2 jsr InitPodoboo ;otherwise set up podoboo again
c9b8: bd a8 07 lda PseudoRandomBitReg+1,x ;get part of LSFR
c9bb: 09 80 ora #%10000000 ;set d7
c9bd: 9d 34 04 sta Enemy_Y_MoveForce,x ;store as movement force
c9c0: 29 0f and #%00001111 ;mask out high nybble
c9c2: 09 06 ora #$06 ;set for at least six intervals
c9c4: 9d 96 07 sta EnemyIntervalTimer,x ;store as new enemy timer
c9c7: a9 f9 lda #$f9
c9c9: 95 a0 sta BlooperMoveCounter,x ;set vertical speed to move podoboo upwards
c9cb: 4c 92 bf PdbM jmp MoveJ_EnemyVertically ;branch to impose gravity on podoboo
; -----------------------------------------------------------------------------
; $00 - used in HammerBroJumpCode as bitmask
HammerThrowTmrData
c9ce: 30 1c .bulk $30,$1c
c9d0: 00 e8 00 18 XSpeedAdderData .bulk $00,$e8,$00,$18
c9d4: 08 f8 0c f4 RevivedXSpeed .bulk $08,$f8,$0c,$f4
c9d8: b5 1e ProcHammerBro lda Enemy_State,x ;check hammer bro's enemy state for d5 set
c9da: 29 20 and #%00100000
c9dc: f0 03 beq ChkJH ;if not set, go ahead with code
c9de: 4c e5 ca jmp MoveDefeatedEnemy ;otherwise jump to something else
c9e1: b5 3c ChkJH lda HammerBroJumpTimer,x ;check jump timer
c9e3: f0 2d beq HammerBroJumpCode ;if expired, branch to jump
c9e5: d6 3c dec HammerBroJumpTimer,x ;otherwise decrement jump timer
c9e7: ad d1 03 lda Enemy_OffscreenBits
c9ea: 29 0c and #%00001100 ;check offscreen bits
c9ec: d0 6a bne MoveHammerBroXDir ;if hammer bro a little offscreen, skip to movement code
c9ee: bd a2 03 lda HammerThrowingTimer,x ;check hammer throwing timer
c9f1: d0 17 bne DecHT ;if not expired, skip ahead, do not throw hammer
c9f3: ac cc 06 ldy SecondaryHardMode ;otherwise get secondary hard mode flag
c9f6: b9 ce c9 lda HammerThrowTmrData,y ;get timer data using flag as offset
c9f9: 9d a2 03 sta HammerThrowingTimer,x ;set as new timer
c9fc: 20 94 ba jsr SpawnHammerObj ;do a sub here to spawn hammer object
c9ff: 90 09 bcc DecHT ;if carry clear, hammer not spawned, skip to decrement timer
ca01: b5 1e lda Enemy_State,x
ca03: 09 08 ora #%00001000 ;set d3 in enemy state for hammer throw
ca05: 95 1e sta Enemy_State,x
ca07: 4c 58 ca jmp MoveHammerBroXDir ;jump to move hammer bro
ca0a: de a2 03 DecHT dec HammerThrowingTimer,x ;decrement timer
ca0d: 4c 58 ca jmp MoveHammerBroXDir ;jump to move hammer bro
HammerBroJumpLData
ca10: 20 37 .bulk $20,$37
HammerBroJumpCode
ca12: b5 1e lda Enemy_State,x ;get hammer bro's enemy state
ca14: 29 07 and #%00000111 ;mask out all but 3 LSB
ca16: c9 01 cmp #$01 ;check for d0 set (for jumping)
ca18: f0 3e beq MoveHammerBroXDir ;if set, branch ahead to moving code
ca1a: a9 00 lda #$00 ;load default value here
ca1c: 85 00 sta $00 ;save into temp variable for now
ca1e: a0 fa ldy #$fa ;set default vertical speed
ca20: b5 cf lda Enemy_Y_Position,x ;check hammer bro's vertical coordinate
ca22: 30 13 bmi SetHJ ;if on the bottom half of the screen, use current speed
ca24: a0 fd ldy #$fd ;otherwise set alternate vertical speed
ca26: c9 70 cmp #$70 ;check to see if hammer bro is above the middle of screen
ca28: e6 00 inc $00 ;increment preset value to $01
ca2a: 90 0b bcc SetHJ ;if above the middle of the screen, use current speed and $01
ca2c: c6 00 dec $00 ;otherwise return value to $00
ca2e: bd a8 07 lda PseudoRandomBitReg+1,x ;get part of LSFR, mask out all but LSB
ca31: 29 01 and #$01
ca33: d0 02 bne SetHJ ;if d0 of LSFR set, branch and use current speed and $00
ca35: a0 fa ldy #$fa ;otherwise reset to default vertical speed
ca37: 94 a0 SetHJ sty Enemy_Y_Speed,x ;set vertical speed for jumping
ca39: b5 1e lda Enemy_State,x ;set d0 in enemy state for jumping
ca3b: 09 01 ora #$01
ca3d: 95 1e sta Enemy_State,x
ca3f: a5 00 lda $00 ;load preset value here to use as bitmask
ca41: 3d a9 07 and PseudoRandomBitReg+2,x ;and do bit-wise comparison with part of LSFR
ca44: a8 tay ;then use as offset
ca45: ad cc 06 lda SecondaryHardMode ;check secondary hard mode flag
ca48: d0 01 bne HJump
ca4a: a8 tay ;if secondary hard mode flag clear, set offset to 0
ca4b: b9 10 ca HJump lda HammerBroJumpLData,y ;get jump length timer data using offset from before
ca4e: 9d 8a 07 sta EnemyFrameTimer,x ;save in enemy timer
ca51: bd a8 07 lda PseudoRandomBitReg+1,x
ca54: 09 c0 ora #%11000000 ;get contents of part of LSFR, set d7 and d6, then
ca56: 95 3c sta HammerBroJumpTimer,x ;store in jump timer
MoveHammerBroXDir
ca58: a0 fc ldy #$fc ;move hammer bro a little to the left
ca5a: a5 09 lda FrameCounter
ca5c: 29 40 and #%01000000 ;change hammer bro's direction every 64 frames
ca5e: d0 02 bne Shimmy
ca60: a0 04 ldy #$04 ;if d6 set in counter, move him a little to the right
ca62: 94 58 Shimmy sty Enemy_X_Speed,x ;store horizontal speed
ca64: a0 01 ldy #$01 ;set to face right by default
ca66: 20 43 e1 jsr PlayerEnemyDiff ;get horizontal difference between player and hammer bro
ca69: 30 0a bmi SetShim ;if enemy to the left of player, skip this part
ca6b: c8 iny ;set to face left
ca6c: bd 96 07 lda EnemyIntervalTimer,x ;check walking timer
ca6f: d0 04 bne SetShim ;if not yet expired, skip to set moving direction
ca71: a9 f8 lda #$f8
ca73: 95 58 sta Enemy_X_Speed,x ;otherwise, make the hammer bro walk left towards player
ca75: 94 46 SetShim sty Enemy_MovingDir,x ;set moving direction
;
ca77: a0 00 MoveNormalEnemy ldy #$00 ;init Y to leave horizontal movement as-is
ca79: b5 1e lda Enemy_State,x
ca7b: 29 40 and #%01000000 ;check enemy state for d6 set, if set skip
ca7d: d0 19 bne FallE ; to move enemy vertically, then horizontally if necessary
ca7f: b5 1e lda Enemy_State,x
ca81: 0a asl A ;check enemy state for d7 set
ca82: b0 30 bcs SteadM ;if set, branch to move enemy horizontally
ca84: b5 1e lda Enemy_State,x
ca86: 29 20 and #%00100000 ;check enemy state for d5 set
ca88: d0 5b bne MoveDefeatedEnemy ;if set, branch to move defeated enemy object
ca8a: b5 1e lda Enemy_State,x
ca8c: 29 07 and #%00000111 ;check d2-d0 of enemy state for any set bits
ca8e: f0 24 beq SteadM ;if enemy in normal state, branch to move enemy horizontally
ca90: c9 05 cmp #$05
ca92: f0 04 beq FallE ;if enemy in state used by spiny's egg, go ahead here
ca94: c9 03 cmp #$03
ca96: b0 30 bcs ReviveStunned ;if enemy in states $03 or $04, skip ahead to yet another part
ca98: 20 63 bf FallE jsr MoveD_EnemyVertically ;do a sub here to move enemy downwards
ca9b: a0 00 ldy #$00
ca9d: b5 1e lda Enemy_State,x ;check for enemy state $02
ca9f: c9 02 cmp #$02
caa1: f0 0c beq MEHor ;if found, branch to move enemy horizontally
caa3: 29 40 and #%01000000 ;check for d6 set
caa5: f0 0d beq SteadM ;if not set, branch to something else
caa7: b5 16 lda Enemy_ID,x
caa9: c9 2e cmp #PowerUpObject ;check for power-up object
caab: f0 07 beq SteadM
caad: d0 03 bne SlowM ;if any other object where d6 set, jump to set Y
caaf: 4c 02 bf MEHor jmp MoveEnemyHorizontally ;jump here to move enemy horizontally for <> $2e and d6 set
cab2: a0 01 SlowM ldy #$01 ;if branched here, increment Y to slow horizontal movement
cab4: b5 58 SteadM lda Enemy_X_Speed,x ;get current horizontal speed
cab6: 48 pha ;save to stack
cab7: 10 02 bpl AddHS ;if not moving or moving right, skip, leave Y alone
cab9: c8 iny
caba: c8 iny ;otherwise increment Y to next data
cabb: 18 AddHS clc
cabc: 79 d0 c9 adc XSpeedAdderData,y ;add value here to slow enemy down if necessary
cabf: 95 58 sta Enemy_X_Speed,x ;save as horizontal speed temporarily
cac1: 20 02 bf jsr MoveEnemyHorizontally ;then do a sub to move horizontally
cac4: 68 pla
cac5: 95 58 sta Enemy_X_Speed,x ;get old horizontal speed from stack and return to
cac7: 60 rts ; original memory location, then leave
cac8: bd 96 07 ReviveStunned lda EnemyIntervalTimer,x ;if enemy timer not expired yet,
cacb: d0 1e bne ChkKillGoomba ; skip ahead to something else
cacd: 95 1e sta Enemy_State,x ;otherwise initialize enemy state to normal
cacf: a5 09 lda FrameCounter
cad1: 29 01 and #$01 ;get d0 of frame counter
cad3: a8 tay ;use as Y and increment for movement direction
cad4: c8 iny
cad5: 94 46 sty Enemy_MovingDir,x ;store as pseudorandom movement direction
cad7: 88 dey ;decrement for use as pointer
cad8: ad 6a 07 lda PrimaryHardMode ;check primary hard mode flag
cadb: f0 02 beq SetRSpd ;if not set, use pointer as-is
cadd: c8 iny
cade: c8 iny ;otherwise increment 2 bytes to next data
cadf: b9 d4 c9 SetRSpd lda RevivedXSpeed,y ;load and store new horizontal speed
cae2: 95 58 sta Enemy_X_Speed,x ;and leave
cae4: 60 rts
MoveDefeatedEnemy
cae5: 20 63 bf jsr MoveD_EnemyVertically ;execute sub to move defeated enemy downwards
cae8: 4c 02 bf jmp MoveEnemyHorizontally ;now move defeated enemy horizontally
caeb: c9 0e ChkKillGoomba cmp #$0e ;check to see if enemy timer has reached
caed: d0 09 bne HKGmba ; a certain point, and branch to leave if not
caef: b5 16 lda Enemy_ID,x
caf1: c9 06 cmp #Goomba ;check for goomba object
caf3: d0 03 bne HKGmba ;branch if not found
caf5: 20 98 c9 jsr EraseEnemyObject ;otherwise, kill this goomba object
caf8: 60 HKGmba rts ;leave!
; -----------------------------------------------------------------------------
MoveJumpingEnemy
caf9: 20 92 bf jsr MoveJ_EnemyVertically ;do a sub to impose gravity on green paratroopa
cafc: 4c 02 bf jmp MoveEnemyHorizontally ;jump to move enemy horizontally
; -----------------------------------------------------------------------------
ProcMoveRedPTroopa
caff: b5 a0 lda Enemy_Y_Speed,x
cb01: 1d 34 04 ora Enemy_Y_MoveForce,x ;check for any vertical force or speed
cb04: d0 13 bne MoveRedPTUpOrDown ;branch if any found
cb06: 9d 17 04 sta Enemy_YMF_Dummy,x ;initialize something here
cb09: b5 cf lda Enemy_Y_Position,x ;check current vs. original vertical coordinate
cb0b: dd 01 04 cmp RedPTroopaOrigXPos,x
cb0e: b0 09 bcs MoveRedPTUpOrDown ;if current => original, skip ahead to more code
cb10: a5 09 lda FrameCounter ;get frame counter
cb12: 29 07 and #%00000111 ;mask out all but 3 LSB
cb14: d0 02 bne NoIncPT ;if any bits set, branch to leave
cb16: f6 cf inc Enemy_Y_Position,x ;otherwise increment red paratroopa's vertical position
cb18: 60 NoIncPT rts ;leave
MoveRedPTUpOrDown
cb19: b5 cf lda Enemy_Y_Position,x ;check current vs. central vertical coordinate
cb1b: d5 58 cmp RedPTroopaCenterYPos,x
cb1d: 90 03 bcc MovPTDwn ;if current < central, jump to move downwards
cb1f: 4c 75 bf jmp MoveRedPTroopaUp ;otherwise jump to move upwards
cb22: 4c 70 bf MovPTDwn jmp MoveRedPTroopaDown ;move downwards
; -----------------------------------------------------------------------------
; $00 - used to store adder for movement, also used as adder for platform
; $01 - used to store maximum value for secondary counter
MoveFlyGreenPTroopa
cb25: 20 45 cb jsr XMoveCntr_GreenPTroopa ;do sub to increment primary and secondary counters
cb28: 20 66 cb jsr MoveWithXMCntrs ;do sub to move green paratroopa accordingly, and horizontally
cb2b: a0 01 ldy #$01 ;set Y to move green paratroopa down
cb2d: a5 09 lda FrameCounter
cb2f: 29 03 and #%00000011 ;check frame counter 2 LSB for any bits set
cb31: d0 11 bne NoMGPT ;branch to leave if set to move up/down every fourth frame
cb33: a5 09 lda FrameCounter
cb35: 29 40 and #%01000000 ;check frame counter for d6 set
cb37: d0 02 bne YSway ;branch to move green paratroopa down if set
cb39: a0 ff ldy #$ff ;otherwise set Y to move green paratroopa up
cb3b: 84 00 YSway sty $00 ;store adder here
cb3d: b5 cf lda Enemy_Y_Position,x
cb3f: 18 clc ;add or subtract from vertical position
cb40: 65 00 adc $00 ; to give green paratroopa a wavy flight
cb42: 95 cf sta Enemy_Y_Position,x
cb44: 60 NoMGPT rts ;leave!
XMoveCntr_GreenPTroopa
cb45: a9 13 lda #$13 ;load preset maximum value for secondary counter
;
XMoveCntr_Platform
cb47: 85 01 sta $01 ;store value here
cb49: a5 09 lda FrameCounter
cb4b: 29 03 and #%00000011 ;branch to leave if not on
cb4d: d0 0d bne NoIncXM ;every fourth frame
cb4f: b4 58 ldy XMoveSecondaryCounter,x ;get secondary counter
cb51: b5 a0 lda XMovePrimaryCounter,x ;get primary counter
cb53: 4a lsr A
cb54: b0 0a bcs DecSeXM ;if d0 of primary counter set, branch elsewhere
cb56: c4 01 cpy $01 ;compare secondary counter to preset maximum value
cb58: f0 03 beq IncPXM ;if equal, branch ahead of this part
cb5a: f6 58 inc XMoveSecondaryCounter,x ;increment secondary counter and leave
cb5c: 60 NoIncXM rts
cb5d: f6 a0 IncPXM inc XMovePrimaryCounter,x ;increment primary counter and leave
cb5f: 60 rts
cb60: 98 DecSeXM tya ;put secondary counter in A
cb61: f0 fa beq IncPXM ;if secondary counter at zero, branch back
cb63: d6 58 dec XMoveSecondaryCounter,x ;otherwise decrement secondary counter and leave
cb65: 60 rts
cb66: b5 58 MoveWithXMCntrs lda XMoveSecondaryCounter,x ;save secondary counter to stack
cb68: 48 pha
cb69: a0 01 ldy #$01 ;set value here by default
cb6b: b5 a0 lda XMovePrimaryCounter,x
cb6d: 29 02 and #%00000010 ;if d1 of primary counter is
cb6f: d0 0b bne XMRight ; set, branch ahead of this part here
cb71: b5 58 lda XMoveSecondaryCounter,x
cb73: 49 ff eor #$ff ;otherwise change secondary
cb75: 18 clc ;counter to two's compliment
cb76: 69 01 adc #$01
cb78: 95 58 sta XMoveSecondaryCounter,x
cb7a: a0 02 ldy #$02 ;load alternate value here
cb7c: 94 46 XMRight sty Enemy_MovingDir,x ;store as moving direction
cb7e: 20 02 bf jsr MoveEnemyHorizontally
cb81: 85 00 sta $00 ;save value obtained from sub here
cb83: 68 pla ;get secondary counter from stack
cb84: 95 58 sta XMoveSecondaryCounter,x ; and return to original place
cb86: 60 rts
; -----------------------------------------------------------------------------
cb87: 3f BlooberBitmasks .dd1 %00111111
cb88: 03 .dd1 %00000011
cb89: b5 1e MoveBloober lda Enemy_State,x
cb8b: 29 20 and #%00100000 ;check enemy state for d5 set
cb8d: d0 4d bne MoveDefeatedBloober ;branch if set to move defeated bloober
cb8f: ac cc 06 ldy SecondaryHardMode ;use secondary hard mode flag as offset
cb92: bd a8 07 lda PseudoRandomBitReg+1,x ;get LSFR
cb95: 39 87 cb and BlooberBitmasks,y ;mask out bits in LSFR using bitmask loaded with offset
cb98: d0 12 bne BlooberSwim ;if any bits set, skip ahead to make swim
cb9a: 8a txa
cb9b: 4a lsr A ;check to see if on second or fourth slot (1 or 3)
cb9c: 90 04 bcc FBLeft ;if not, branch to figure out moving direction
cb9e: a4 45 ldy Player_MovingDir ;otherwise, load player's moving direction and
cba0: b0 08 bcs SBMDir ; do an unconditional branch to set
cba2: a0 02 FBLeft ldy #$02 ;set left moving direction by default
cba4: 20 43 e1 jsr PlayerEnemyDiff ;get horizontal difference between player and bloober
cba7: 10 01 bpl SBMDir ;if enemy to the right of player, keep left
cba9: 88 dey ;otherwise decrement to set right moving direction
cbaa: 94 46 SBMDir sty Enemy_MovingDir,x ;set moving direction of bloober, then continue on here
cbac: 20 df cb BlooberSwim jsr ProcSwimmingB ;execute sub to make bloober swim characteristically
cbaf: b5 cf lda Enemy_Y_Position,x ;get vertical coordinate
cbb1: 38 sec
cbb2: fd 34 04 sbc Enemy_Y_MoveForce,x ;subtract movement force
cbb5: c9 20 cmp #$20 ;check to see if position is above edge of status bar
cbb7: 90 02 bcc SwimX ;if so, don't do it
cbb9: 95 cf sta Enemy_Y_Position,x ;otherwise, set new vertical position, make bloober swim
cbbb: b4 46 SwimX ldy Enemy_MovingDir,x ;check moving direction
cbbd: 88 dey
cbbe: d0 0e bne LeftSwim ;if moving to the left, branch to second part
cbc0: b5 87 lda Enemy_X_Position,x
cbc2: 18 clc ;add movement speed to horizontal coordinate
cbc3: 75 58 adc BlooperMoveSpeed,x
cbc5: 95 87 sta Enemy_X_Position,x ;store result as new horizontal coordinate
cbc7: b5 6e lda Enemy_PageLoc,x
cbc9: 69 00 adc #$00 ;add carry to page location
cbcb: 95 6e sta Enemy_PageLoc,x ;store as new page location and leave
cbcd: 60 rts
cbce: b5 87 LeftSwim lda Enemy_X_Position,x
cbd0: 38 sec ;subtract movement speed from horizontal coordinate
cbd1: f5 58 sbc BlooperMoveSpeed,x
cbd3: 95 87 sta Enemy_X_Position,x ;store result as new horizontal coordinate
cbd5: b5 6e lda Enemy_PageLoc,x
cbd7: e9 00 sbc #$00 ;subtract borrow from page location
cbd9: 95 6e sta Enemy_PageLoc,x ;store as new page location and leave
cbdb: 60 rts
MoveDefeatedBloober
cbdc: 4c 8c bf jmp MoveEnemySlowVert ;jump to move defeated bloober downwards
cbdf: b5 a0 ProcSwimmingB lda BlooperMoveCounter,x ;get enemy's movement counter
cbe1: 29 02 and #%00000010 ;check for d1 set
cbe3: d0 37 bne ChkForFloatdown ;branch if set
cbe5: a5 09 lda FrameCounter
cbe7: 29 07 and #%00000111 ;get 3 LSB of frame counter
cbe9: 48 pha ;get 3 LSB of frame counter
cbea: b5 a0 lda BlooperMoveCounter,x ;get enemy's movement counter
cbec: 4a lsr A ;check for d0 set
cbed: b0 15 bcs SlowSwim ;branch if set
cbef: 68 pla ;pull 3 LSB of frame counter from the stack
cbf0: d0 11 bne BSwimE ;branch to leave, execute code only every eighth frame
cbf2: bd 34 04 lda Enemy_Y_MoveForce,x
cbf5: 18 clc ;add to movement force to speed up swim
cbf6: 69 01 adc #$01
cbf8: 9d 34 04 sta Enemy_Y_MoveForce,x ;set movement force
cbfb: 95 58 sta BlooperMoveSpeed,x ;set as movement speed
cbfd: c9 02 cmp #$02
cbff: d0 02 bne BSwimE ;if certain horizontal speed, branch to leave
cc01: f6 a0 inc BlooperMoveCounter,x ;otherwise increment movement counter
cc03: 60 BSwimE rts
cc04: 68 SlowSwim pla ;pull 3 LSB of frame counter from the stack
cc05: d0 14 bne NoSSw ;branch to leave, execute code only every eighth frame
cc07: bd 34 04 lda Enemy_Y_MoveForce,x
cc0a: 38 sec ;subtract from movement force to slow swim
cc0b: e9 01 sbc #$01
cc0d: 9d 34 04 sta Enemy_Y_MoveForce,x ;set movement force
cc10: 95 58 sta BlooperMoveSpeed,x ;set as movement speed
cc12: d0 07 bne NoSSw ;if any speed, branch to leave
cc14: f6 a0 inc BlooperMoveCounter,x ;otherwise increment movement counter
cc16: a9 02 lda #$02
cc18: 9d 96 07 sta EnemyIntervalTimer,x ;set enemy's timer
cc1b: 60 NoSSw rts ;leave
cc1c: bd 96 07 ChkForFloatdown lda EnemyIntervalTimer,x ;get enemy timer
cc1f: f0 08 beq ChkNeearPlayer ;branch if expired
cc21: a5 09 Floatdown lda FrameCounter ;get frame counter
cc23: 4a lsr A ;check for d0 set
cc24: b0 02 bcs NoFD ;branch to leave on every other frame
cc26: f6 cf inc Enemy_Y_Position,x ;otherwise increment vertical coordinate
cc28: 60 NoFD rts ;leave
cc29: b5 cf ChkNeearPlayer lda Enemy_Y_Position,x ;get vertical coordinate
cc2b: 69 10 adc #$10 ;add sixteen pixels
cc2d: c5 ce cmp Player_Y_Position ;compare result with player's vertical coordinate
cc2f: 90 f0 bcc Floatdown ;if modified vertical less than player's, branch
cc31: a9 00 lda #$00
cc33: 95 a0 sta BlooperMoveCounter,x ;otherwise nullify movement counter
cc35: 60 rts
; -----------------------------------------------------------------------------
cc36: b5 1e MoveBulletBill lda Enemy_State,x ;check bullet bill's enemy object state for d5 set
cc38: 29 20 and #%00100000
cc3a: f0 03 beq NotDefB ;if not set, continue with movement code
cc3c: 4c 92 bf jmp MoveJ_EnemyVertically ;otherwise jump to move defeated bullet bill downwards
cc3f: a9 e8 NotDefB lda #$e8 ;set bullet bill's horizontal speed
cc41: 95 58 sta Enemy_X_Speed,x ;and move it accordingly (note: this bullet bill
cc43: 4c 02 bf jmp MoveEnemyHorizontally ; object occurs in frenzy object $17, not from cannons)
; -----------------------------------------------------------------------------
; $02 - used to hold preset values
; $03 - used to hold enemy state
cc46: 40 80 SwimCCXMoveData .bulk $40,$80
cc48: 04 04 .bulk $04,$04 ;residual data, not used
MoveSwimmingCheepCheep
cc4a: b5 1e lda Enemy_State,x ;check cheep-cheep's enemy object state
cc4c: 29 20 and #%00100000 ;for d5 set
cc4e: f0 03 beq CCSwim ;if not set, continue with movement code
cc50: 4c 8c bf jmp MoveEnemySlowVert ;otherwise jump to move defeated cheep-cheep downwards
cc53: 85 03 CCSwim sta $03 ;save enemy state in $03
cc55: b5 16 lda Enemy_ID,x ;get enemy identifier
cc57: 38 sec
cc58: e9 0a sbc #$0a ;subtract ten for cheep-cheep identifiers
cc5a: a8 tay ;use as offset
cc5b: b9 46 cc lda SwimCCXMoveData,y ;load value here
cc5e: 85 02 sta $02
cc60: bd 01 04 lda Enemy_X_MoveForce,x ;load horizontal force
cc63: 38 sec
cc64: e5 02 sbc $02 ;subtract preset value from horizontal force
cc66: 9d 01 04 sta Enemy_X_MoveForce,x ;store as new horizontal force
cc69: b5 87 lda Enemy_X_Position,x ;get horizontal coordinate
cc6b: e9 00 sbc #$00 ;subtract borrow (thus moving it slowly)
cc6d: 95 87 sta Enemy_X_Position,x ;and save as new horizontal coordinate
cc6f: b5 6e lda Enemy_PageLoc,x
cc71: e9 00 sbc #$00 ;subtract borrow again, this time from the
cc73: 95 6e sta Enemy_PageLoc,x ; page location, then save
cc75: a9 20 lda #$20
cc77: 85 02 sta $02 ;save new value here
cc79: e0 02 cpx #$02 ;check enemy object offset
cc7b: 90 49 bcc ExSwCC ;if in first or second slot, branch to leave
cc7d: b5 58 lda CheepCheepMoveMFlag,x ;check movement flag
cc7f: c9 10 cmp #$10 ;if movement speed set to $00,
cc81: 90 16 bcc CCSwimUpwards ; branch to move upwards
cc83: bd 17 04 lda Enemy_YMF_Dummy,x
cc86: 18 clc
cc87: 65 02 adc $02 ;add preset value to dummy variable to get carry
cc89: 9d 17 04 sta Enemy_YMF_Dummy,x ;and save dummy
cc8c: b5 cf lda Enemy_Y_Position,x ;get vertical coordinate
cc8e: 65 03 adc $03 ;add carry to it plus enemy state to slowly move it downwards
cc90: 95 cf sta Enemy_Y_Position,x ;save as new vertical coordinate
cc92: b5 b6 lda Enemy_Y_HighPos,x
cc94: 69 00 adc #$00 ;add carry to page location and
cc96: 4c ac cc jmp ChkSwimYPos ;jump to end of movement code
cc99: bd 17 04 CCSwimUpwards lda Enemy_YMF_Dummy,x
cc9c: 38 sec
cc9d: e5 02 sbc $02 ;subtract preset value to dummy variable to get borrow
cc9f: 9d 17 04 sta Enemy_YMF_Dummy,x ;and save dummy
cca2: b5 cf lda Enemy_Y_Position,x ;get vertical coordinate
cca4: e5 03 sbc $03 ;subtract borrow to it plus enemy state to slowly move it upwards
cca6: 95 cf sta Enemy_Y_Position,x ;save as new vertical coordinate
cca8: b5 b6 lda Enemy_Y_HighPos,x
ccaa: e9 00 sbc #$00 ;subtract borrow from page location
ccac: 95 b6 ChkSwimYPos sta Enemy_Y_HighPos,x ;save new page location here
ccae: a0 00 ldy #$00 ;load movement speed to upwards by default
ccb0: b5 cf lda Enemy_Y_Position,x ;get vertical coordinate
ccb2: 38 sec
ccb3: fd 34 04 sbc CheepCheepOrigYPos,x ;subtract original coordinate from current
ccb6: 10 07 bpl YPDiff ;if result positive, skip to next part
ccb8: a0 10 ldy #$10 ;otherwise load movement speed to downwards
ccba: 49 ff eor #$ff
ccbc: 18 clc ;get two's compliment of result
ccbd: 69 01 adc #$01 ; to obtain total difference of original vs. current
ccbf: c9 0f YPDiff cmp #$0f ;if difference between original vs. current vertical
ccc1: 90 03 bcc ExSwCC ; coordinates < 15 pixels, leave movement speed alone
ccc3: 98 tya
ccc4: 95 58 sta CheepCheepMoveMFlag,x ;otherwise change movement speed
ccc6: 60 ExSwCC rts ;leave
; -----------------------------------------------------------------------------
; $00 - used as counter for firebar parts
; $01 - used for oscillated high byte of spin state or to hold horizontal adder
; $02 - used for oscillated high byte of spin state or to hold vertical adder
; $03 - used for mirror data
; $04 - used to store player's sprite 1 X coordinate
; $05 - used to evaluate mirror data
; $06 - used to store either screen X coordinate or sprite data offset
; $07 - used to store screen Y coordinate
; $ed - used to hold maximum length of firebar
; $ef - used to hold high byte of spinstate
;
; horizontal adder is at first byte + high byte of spinstate, vertical adder is
; same + 8 bytes, two's compliment if greater than $08 for proper oscillation
FirebarPosLookupTbl
ccc7: 00 01 03 04+ .bulk $00,$01,$03,$04,$05,$06,$07,$07,$08,$00,$03,$06,$09,$0b,$0d,$0e
+ $0f,$10,$00,$04,$09,$0d,$10,$13,$16,$17,$18,$00,$06,$0c,$12,$16
+ $1a,$1d,$1f,$20,$00,$07,$0f,$16,$1c,$21,$25,$27,$28,$00,$09,$12
+ $1b,$21,$27,$2c,$2f,$30,$00,$0b,$15,$1f,$27,$2e,$33,$37,$38,$00
+ $0c,$18,$24,$2d,$35,$3b,$3e,$40,$00,$0e,$1b,$28,$32,$3b,$42,$46
+ $48,$00,$0f,$1f,$2d,$38,$42,$4a,$4e,$50,$00,$11,$22,$31,$3e,$49
+ $51,$56,$58
FirebarMirrorData
cd2a: 01 03 02 00 .bulk $01,$03,$02,$00
FirebarTblOffsets
cd2e: 00 09 12 1b+ .bulk $00,$09,$12,$1b,$24,$2d
cd34: 36 3f 48 51+ .bulk $36,$3f,$48,$51,$5a,$63
cd3a: 0c 18 FirebarYPos .bulk $0c,$18
cd3c: 20 af f1 ProcFirebar jsr GetEnemyOffscreenBits ;get offscreen information
cd3f: ad d1 03 lda Enemy_OffscreenBits ;check for d3 set
cd42: 29 08 and #%00001000 ;if so, branch to leave
cd44: d0 74 bne SkipFBar
cd46: ad 47 07 lda TimerControl ;if master timer control set, branch
cd49: d0 0a bne SusFbar ; ahead of this part
cd4b: bd 88 03 lda FirebarSpinSpeed,x ;load spinning speed of firebar
cd4e: 20 10 d4 jsr FirebarSpin ;modify current spinstate
cd51: 29 1f and #%00011111 ;mask out all but 5 LSB
cd53: 95 a0 sta FirebarSpinState_High,x ;and store as new high byte of spinstate
cd55: b5 a0 SusFbar lda FirebarSpinState_High,x ;get high byte of spinstate
cd57: b4 16 ldy Enemy_ID,x ;check enemy identifier
cd59: c0 1f cpy #$1f
cd5b: 90 0d bcc SetupGFB ;if < $1f (long firebar), branch
cd5d: c9 08 cmp #$08 ;check high byte of spinstate
cd5f: f0 04 beq SkpFSte ;if eight, branch to change
cd61: c9 18 cmp #$18
cd63: d0 05 bne SetupGFB ;if not at twenty-four branch to not change
cd65: 18 SkpFSte clc
cd66: 69 01 adc #$01 ;add one to spinning thing to avoid horizontal state
cd68: 95 a0 sta FirebarSpinState_High,x
cd6a: 85 ef SetupGFB sta $ef ;save high byte of spinning thing, modified or otherwise
cd6c: 20 52 f1 jsr RelativeEnemyPosition ;get relative coordinates to screen
cd6f: 20 8e ce jsr GetFirebarPosition ;do a sub here (residual, too early to be used now)
cd72: bc e5 06 ldy Enemy_SprDataOffset,x ;get OAM data offset
cd75: ad b9 03 lda Enemy_Rel_YPos ;get relative vertical coordinate
cd78: 99 00 02 sta Sprite_Y_Position,y ;store as Y in OAM data
cd7b: 85 07 sta $07 ;also save here
cd7d: ad ae 03 lda Enemy_Rel_XPos ;get relative horizontal coordinate
cd80: 99 03 02 sta Sprite_X_Position,y ;store as X in OAM data
cd83: 85 06 sta $06 ;also save here
cd85: a9 01 lda #$01
cd87: 85 00 sta $00 ;set $01 value here (not necessary)
cd89: 20 08 ce jsr FirebarCollision ;draw fireball part and do collision detection
cd8c: a0 05 ldy #$05 ;load value for short firebars by default
cd8e: b5 16 lda Enemy_ID,x
cd90: c9 1f cmp #$1f ;are we doing a long firebar?
cd92: 90 02 bcc SetMFbar ;no, branch then
cd94: a0 0b ldy #$0b ;otherwise load value for long firebars
cd96: 84 ed SetMFbar sty $ed ;store maximum value for length of firebars
cd98: a9 00 lda #$00
cd9a: 85 00 sta $00 ;initialize counter here
cd9c: a5 ef DrawFbar lda $ef ;load high byte of spinstate
cd9e: 20 8e ce jsr GetFirebarPosition ;get fireball position data depending on firebar part
cda1: 20 bb cd jsr DrawFirebar_Collision ;position it properly, draw it and do collision detection
cda4: a5 00 lda $00 ;check which firebar part
cda6: c9 04 cmp #$04
cda8: d0 08 bne NextFbar
cdaa: ac cf 06 ldy DuplicateObj_Offset ;if we arrive at fifth firebar part,
cdad: b9 e5 06 lda Enemy_SprDataOffset,y ; get offset from long firebar and load OAM data offset
cdb0: 85 06 sta $06 ; using long firebar offset, then store as new one here
cdb2: e6 00 NextFbar inc $00 ;move onto the next firebar part
cdb4: a5 00 lda $00
cdb6: c5 ed cmp $ed ;if we end up at the maximum part, go on and leave
cdb8: 90 e2 bcc DrawFbar ;otherwise go back and do another
cdba: 60 SkipFBar rts
DrawFirebar_Collision
cdbb: a5 03 lda $03 ;store mirror data elsewhere
cdbd: 85 05 sta $05
cdbf: a4 06 ldy $06 ;load OAM data offset for firebar
cdc1: a5 01 lda $01 ;load horizontal adder we got from position loader
cdc3: 46 05 lsr $05 ;shift LSB of mirror data
cdc5: b0 04 bcs AddHA ;if carry was set, skip this part
cdc7: 49 ff eor #$ff
cdc9: 69 01 adc #$01 ;otherwise get two's compliment of horizontal adder
cdcb: 18 AddHA clc ;add horizontal coordinate relative to screen to
cdcc: 6d ae 03 adc Enemy_Rel_XPos ;horizontal adder, modified or otherwise
cdcf: 99 03 02 sta Sprite_X_Position,y ;store as X coordinate here
cdd2: 85 06 sta $06 ;store here for now, note offset is saved in Y still
cdd4: cd ae 03 cmp Enemy_Rel_XPos ;compare X coordinate of sprite to original X of firebar
cdd7: b0 09 bcs SubtR1 ;if sprite coordinate => original coordinate, branch
cdd9: ad ae 03 lda Enemy_Rel_XPos
cddc: 38 sec ;otherwise subtract sprite X from the
cddd: e5 06 sbc $06 ; original one and skip this part
cddf: 4c e6 cd jmp ChkFOfs
cde2: 38 SubtR1 sec ;subtract original X from the
cde3: ed ae 03 sbc Enemy_Rel_XPos ;current sprite X
cde6: c9 59 ChkFOfs cmp #$59 ;if difference of coordinates within a certain range,
cde8: 90 04 bcc VAHandl ; continue by handling vertical adder
cdea: a9 f8 lda #$f8 ;otherwise, load offscreen Y coordinate
cdec: d0 15 bne SetVFbr ; and unconditionally branch to move sprite offscreen
cdee: ad b9 03 VAHandl lda Enemy_Rel_YPos ;if vertical relative coordinate offscreen,
cdf1: c9 f8 cmp #$f8 ;skip ahead of this part and write into sprite Y coordinate
cdf3: f0 0e beq SetVFbr
cdf5: a5 02 lda $02 ;load vertical adder we got from position loader
cdf7: 46 05 lsr $05 ;shift LSB of mirror data one more time
cdf9: b0 04 bcs AddVA ;if carry was set, skip this part
cdfb: 49 ff eor #$ff
cdfd: 69 01 adc #$01 ;otherwise get two's compliment of second part
cdff: 18 AddVA clc ;add vertical coordinate relative to screen to
ce00: 6d b9 03 adc Enemy_Rel_YPos ; the second data, modified or otherwise
ce03: 99 00 02 SetVFbr sta Sprite_Y_Position,y ;store as Y coordinate here
ce06: 85 07 sta $07 ;also store here for now
FirebarCollision
ce08: 20 ed ec jsr DrawFirebar ;run sub here to draw current tile of firebar
ce0b: 98 tya ;return OAM data offset and save
ce0c: 48 pha ;to the stack for now
ce0d: ad 9f 07 lda StarInvincibleTimer ;if star mario invincibility timer
ce10: 0d 47 07 ora TimerControl ; or master timer controls set
ce13: d0 70 bne NoColFB ; then skip all of this
ce15: 85 05 sta $05 ;otherwise initialize counter
ce17: a4 b5 ldy Player_Y_HighPos
ce19: 88 dey ;if player's vertical high byte offscreen,
ce1a: d0 69 bne NoColFB ;skip all of this
ce1c: a4 ce ldy Player_Y_Position ;get player's vertical position
ce1e: ad 54 07 lda PlayerSize ;get player's size
ce21: d0 05 bne AdjSm ;if player small, branch to alter variables
ce23: ad 14 07 lda CrouchingFlag
ce26: f0 09 beq BigJp ;if player big and not crouching, jump ahead
ce28: e6 05 AdjSm inc $05 ;if small or big but crouching, execute this part
ce2a: e6 05 inc $05 ;first increment our counter twice (setting $02 as flag)
ce2c: 98 tya
ce2d: 18 clc ;then add 24 pixels to the player's
ce2e: 69 18 adc #$18 ; vertical coordinate
ce30: a8 tay
ce31: 98 BigJp tya ;get vertical coordinate, altered or otherwise, from Y
ce32: 38 FBCLoop sec ;subtract vertical position of firebar
ce33: e5 07 sbc $07 ; from the vertical coordinate of the player
ce35: 10 05 bpl ChkVFBD ;if player lower on the screen than firebar,
ce37: 49 ff eor #$ff ;skip two's compliment part
ce39: 18 clc ;otherwise get two's compliment
ce3a: 69 01 adc #$01
ce3c: c9 08 ChkVFBD cmp #$08 ;if difference => 8 pixels, skip ahead of this part
ce3e: b0 1c bcs Chk20fs
ce40: a5 06 lda $06 ;if firebar on far right on the screen, skip this,
ce42: c9 f0 cmp #$f0 ; because, really, what's the point?
ce44: b0 16 bcs Chk20fs
ce46: ad 07 02 lda Sprite_X_Position+4 ;get OAM X coordinate for sprite #1
ce49: 18 clc
ce4a: 69 04 adc #$04 ;add four pixels
ce4c: 85 04 sta $04 ;store here
ce4e: 38 sec ;subtract horizontal coordinate of firebar
ce4f: e5 06 sbc $06 ;from the X coordinate of player's sprite 1
ce51: 10 05 bpl ChkFBCl ;if modded X coordinate to the right of firebar
ce53: 49 ff eor #$ff ;skip two's compliment part
ce55: 18 clc ;otherwise get two's compliment
ce56: 69 01 adc #$01
ce58: c9 08 ChkFBCl cmp #$08 ;if difference < 8 pixels, collision, thus branch
ce5a: 90 13 bcc ChgSDir ; to process
ce5c: a5 05 Chk20fs lda $05 ;if value of $02 was set earlier for whatever reason,
ce5e: c9 02 cmp #$02 ; branch to increment OAM offset and leave, no collision
ce60: f0 23 beq NoColFB
ce62: a4 05 ldy $05 ;otherwise get temp here and use as offset
ce64: a5 ce lda Player_Y_Position
ce66: 18 clc
ce67: 79 3a cd adc FirebarYPos,y ;add value loaded with offset to player's vertical coordinate
ce6a: e6 05 inc $05 ; then increment temp and jump back
ce6c: 4c 32 ce jmp FBCLoop
ce6f: a2 01 ChgSDir ldx #$01 ;set movement direction by default
ce71: a5 04 lda $04 ;if OAM X coordinate of player's sprite 1
ce73: c5 06 cmp $06 ; is greater than horizontal coordinate of firebar
ce75: b0 01 bcs SetSDir ; then do not alter movement direction
ce77: e8 inx ;otherwise increment it
ce78: 86 46 SetSDir stx Enemy_MovingDir ;store movement direction here
ce7a: a2 00 ldx #$00
ce7c: a5 00 lda $00 ;save value written to $00 to stack
ce7e: 48 pha
ce7f: 20 2c d9 jsr InjurePlayer ;perform sub to hurt or kill player
ce82: 68 pla
ce83: 85 00 sta $00 ;get value of $00 from stack
ce85: 68 NoColFB pla ;get OAM data offset
ce86: 18 clc ;add four to it and save
ce87: 69 04 adc #$04
ce89: 85 06 sta $06
ce8b: a6 08 ldx ObjectOffset ;get enemy object buffer offset and leave
ce8d: 60 rts
GetFirebarPosition
ce8e: 48 pha ;save high byte of spinstate to the stack
ce8f: 29 0f and #%00001111 ;mask out low nybble
ce91: c9 09 cmp #$09
ce93: 90 05 bcc GetHAdder ;if lower than $09, branch ahead
ce95: 49 0f eor #%00001111 ;otherwise get two's compliment to oscillate
ce97: 18 clc
ce98: 69 01 adc #$01
ce9a: 85 01 GetHAdder sta $01 ;store result, modified or not, here
ce9c: a4 00 ldy $00 ;load number of firebar ball where we're at
ce9e: b9 2e cd lda FirebarTblOffsets,y ;load offset to firebar position data
cea1: 18 clc
cea2: 65 01 adc $01 ;add oscillated high byte of spinstate
cea4: a8 tay ; to offset here and use as new offset
cea5: b9 c7 cc lda FirebarPosLookupTbl,y ;get data here and store as horizontal adder
cea8: 85 01 sta $01
ceaa: 68 pla ;pull whatever was in A from the stack
ceab: 48 pha ;save it again because we still need it
ceac: 18 clc
cead: 69 08 adc #$08 ;add eight this time, to get vertical adder
ceaf: 29 0f and #%00001111 ;mask out high nybble
ceb1: c9 09 cmp #$09 ;if lower than $09, branch ahead
ceb3: 90 05 bcc GetVAdder
ceb5: 49 0f eor #%00001111 ;otherwise get two's compliment
ceb7: 18 clc
ceb8: 69 01 adc #$01
ceba: 85 02 GetVAdder sta $02 ;store result here
cebc: a4 00 ldy $00
cebe: b9 2e cd lda FirebarTblOffsets,y ;load offset to firebar position data again
cec1: 18 clc
cec2: 65 02 adc $02 ;this time add value in $02 to offset here and use as offset
cec4: a8 tay
cec5: b9 c7 cc lda FirebarPosLookupTbl,y ;get data here and store as vertica adder
cec8: 85 02 sta $02
ceca: 68 pla ;pull out whatever was in A one last time
cecb: 4a lsr A ;divide by eight or shift three to the right
cecc: 4a lsr A
cecd: 4a lsr A
cece: a8 tay ;use as offset
cecf: b9 2a cd lda FirebarMirrorData,y ;load mirroring data here
ced2: 85 03 sta $03 ;store
ced4: 60 rts
; -----------------------------------------------------------------------------
PRandomSubtracter
ced5: f8 a0 70 bd+ .bulk $f8,$a0,$70,$bd,$00
ceda: 20 20 20 00+ FlyCCBPriority .bulk $20,$20,$20,$00,$00
MoveFlyingCheepCheep
cedf: b5 1e lda Enemy_State,x ;check cheep-cheep's enemy state
cee1: 29 20 and #%00100000 ;for d5 set
cee3: f0 08 beq FlyCC ;branch to continue code if not set
cee5: a9 00 lda #$00
cee7: 9d c5 03 sta Enemy_SprAttrib,x ;otherwise clear sprite attributes
ceea: 4c 92 bf jmp MoveJ_EnemyVertically ;and jump to move defeated cheep-cheep downwards
ceed: 20 02 bf FlyCC jsr MoveEnemyHorizontally ;move cheep-cheep horizontally based on speed and force
cef0: a0 0d ldy #$0d ;set vertical movement amount
cef2: a9 05 lda #$05 ;set maximum speed
cef4: 20 96 bf jsr SetXMoveAmt ;branch to impose gravity on flying cheep-cheep
cef7: bd 34 04 lda Enemy_Y_MoveForce,x
cefa: 4a lsr A ;get vertical movement force and
cefb: 4a lsr A ;move high nybble to low
cefc: 4a lsr A
cefd: 4a lsr A
cefe: a8 tay ;save as offset (note this tends to go into reach of code)
ceff: b5 cf lda Enemy_Y_Position,x ;get vertical position
cf01: 38 sec ;subtract pseudorandom value based on offset from position
cf02: f9 d5 ce sbc PRandomSubtracter,y
cf05: 10 05 bpl AddCCF ;if result within top half of screen, skip this part
cf07: 49 ff eor #$ff
cf09: 18 clc ;otherwise get two's compliment
cf0a: 69 01 adc #$01
cf0c: c9 08 AddCCF cmp #$08 ;if result or two's compliment greater than eight,
cf0e: b0 0e bcs BPGet ;skip to the end without changing movement force
cf10: bd 34 04 lda Enemy_Y_MoveForce,x
cf13: 18 clc
cf14: 69 10 adc #$10 ;otherwise add to it
cf16: 9d 34 04 sta Enemy_Y_MoveForce,x
cf19: 4a lsr A ;move high nybble to low again
cf1a: 4a lsr A
cf1b: 4a lsr A
cf1c: 4a lsr A
cf1d: a8 tay
cf1e: b9 da ce BPGet lda FlyCCBPriority,y ;load bg priority data and store (this is very likely
cf21: 9d c5 03 sta Enemy_SprAttrib,x ; broken or residual code, value is overwritten before
cf24: 60 rts ; drawing it next frame), then leave
; -----------------------------------------------------------------------------
; $00 - used to hold horizontal difference
; $01-$03 - used to hold difference adjusters
cf25: 15 30 40 LakituDiffAdj .bulk $15,$30,$40
cf28: b5 1e MoveLakitu lda Enemy_State,x ;check lakitu's enemy state
cf2a: 29 20 and #%00100000 ;for d5 set
cf2c: f0 03 beq ChkLS ;if not set, continue with code
cf2e: 4c 63 bf jmp MoveD_EnemyVertically ;otherwise jump to move defeated lakitu downwards
cf31: b5 1e ChkLS lda Enemy_State,x ;if lakitu's enemy state not set at all,
cf33: f0 0b beq Fr12S ; go ahead and continue with code
cf35: a9 00 lda #$00
cf37: 95 a0 sta LakituMoveDirection,x ;otherwise initialize moving direction to move to left
cf39: 8d cb 06 sta EnemyFrenzyBuffer ;initialize frenzy buffer
cf3c: a9 10 lda #$10
cf3e: d0 13 bne SetLSpd ;load horizontal speed and do unconditional branch
cf40: a9 12 Fr12S lda #Spiny
cf42: 8d cb 06 sta EnemyFrenzyBuffer ;set spiny identifier in frenzy buffer
cf45: a0 02 ldy #$02
cf47: b9 25 cf LdLDa lda LakituDiffAdj,y ;load values
cf4a: 99 01 00 sta $0001,y ;store in zero page
cf4d: 88 dey
cf4e: 10 f7 bpl LdLDa ;do this until all values are stired
cf50: 20 6c cf jsr PlayerLakituDiff ;execute sub to set speed and create spinys
cf53: 95 58 SetLSpd sta LakituMoveSpeed,x ;set movement speed returned from sub
cf55: a0 01 ldy #$01 ;set moving direction to right by default
cf57: b5 a0 lda LakituMoveDirection,x
cf59: 29 01 and #$01 ;get LSB of moving direction
cf5b: d0 0a bne SetLMov ;if set, branch to the end to use moving direction
cf5d: b5 58 lda LakituMoveSpeed,x
cf5f: 49 ff eor #$ff ;get two's compliment of moving speed
cf61: 18 clc
cf62: 69 01 adc #$01
cf64: 95 58 sta LakituMoveSpeed,x ;store as new moving speed
cf66: c8 iny ;increment moving direction to left
cf67: 94 46 SetLMov sty Enemy_MovingDir,x ;store moving direction
cf69: 4c 02 bf jmp MoveEnemyHorizontally ;move lakitu horizontally
PlayerLakituDiff
cf6c: a0 00 ldy #$00 ;set Y for default value
cf6e: 20 43 e1 jsr PlayerEnemyDiff ;get horizontal difference between enemy and player
cf71: 10 0a bpl ChkLakDif ;branch if enemy is to the right of the player
cf73: c8 iny ;increment Y for left of player
cf74: a5 00 lda $00
cf76: 49 ff eor #$ff ;get two's compliment of low byte of horizontal difference
cf78: 18 clc
cf79: 69 01 adc #$01 ;store two's compliment as horizontal difference
cf7b: 85 00 sta $00
cf7d: a5 00 ChkLakDif lda $00 ;get low byte of horizontal difference
cf7f: c9 3c cmp #$3c ;if within a certain distance of player, branch
cf81: 90 1c bcc ChkPSpeed
cf83: a9 3c lda #$3c ;otherwise set maximum distance
cf85: 85 00 sta $00
cf87: b5 16 lda Enemy_ID,x ;check if lakitu is in our current enemy slot
cf89: c9 11 cmp #Lakitu
cf8b: d0 12 bne ChkPSpeed ;if not, branch elsewhere
cf8d: 98 tya ;compare contents of Y, now in A
cf8e: d5 a0 cmp LakituMoveDirection,x ;to what is being used as horizontal movement direction
cf90: f0 0d beq ChkPSpeed ;if moving toward the player, branch, do not alter
cf92: b5 a0 lda LakituMoveDirection,x ;if moving to the left beyond maximum distance,
cf94: f0 06 beq SetLMovD ; branch and alter without delay
cf96: d6 58 dec LakituMoveSpeed,x ;decrement horizontal speed
cf98: b5 58 lda LakituMoveSpeed,x ;if horizontal speed not yet at zero, branch to leave
cf9a: d0 40 bne ExMoveLak
cf9c: 98 SetLMovD tya ;set horizontal direction depending on horizontal
cf9d: 95 a0 sta LakituMoveDirection,x ;difference between enemy and player if necessary
cf9f: a5 00 ChkPSpeed lda $00
cfa1: 29 3c and #%00111100 ;mask out all but four bits in the middle
cfa3: 4a lsr A ;divide masked difference by four
cfa4: 4a lsr A
cfa5: 85 00 sta $00 ;store as new value
cfa7: a0 00 ldy #$00 ;init offset
cfa9: a5 57 lda Player_X_Speed
cfab: f0 24 beq SubDifAdj ;if player not moving horizontally, branch
cfad: ad 75 07 lda ScrollAmount
cfb0: f0 1f beq SubDifAdj ;if scroll speed not set, branch to same place
cfb2: c8 iny ;otherwise increment offset
cfb3: a5 57 lda Player_X_Speed
cfb5: c9 19 LCFB5 cmp #$19 ;if player not running, branch
cfb7: 90 08 bcc ChkSpinyO
cfb9: ad 75 07 lda ScrollAmount
cfbc: c9 02 cmp #$02 ;if scroll speed below a certain amount, branch
cfbe: 90 01 bcc ChkSpinyO ; to same place
cfc0: c8 iny ;otherwise increment once more
cfc1: b5 16 ChkSpinyO lda Enemy_ID,x ;check for spiny object
cfc3: c9 12 cmp #Spiny
cfc5: d0 04 bne ChkEmySpd ;branch if not found
cfc7: a5 57 lda Player_X_Speed ;if player not moving, skip this part
cfc9: d0 06 bne SubDifAdj
cfcb: b5 a0 ChkEmySpd lda LakituMoveDirection,x ;check vertical speed
cfcd: d0 02 bne SubDifAdj ;branch if nonzero
cfcf: a0 00 ldy #$00 ;otherwise reinit offset
cfd1: b9 01 00 SubDifAdj lda $0001,y ;get one of three saved values from earlier
cfd4: a4 00 ldy $00 ;get saved horizontal difference
cfd6: 38 SPixelLak sec ;subtract one for each pixel of horizontal difference
cfd7: e9 01 sbc #$01 ; from one of three saved values
cfd9: 88 dey
cfda: 10 fa bpl SPixelLak ;branch until all pixels are subtracted, to adjust difference
cfdc: 60 ExMoveLak rts ;leave!!!
; -----------------------------------------------------------------------------
; $04-$05 - used to store name table address in little endian order
BridgeCollapseData
cfdd: 1a .dd1 $1a ;axe
cfde: 58 .dd1 $58 ;chain
cfdf: 98 96 94 92+ .bulk $98,$96,$94,$92,$90,$8e,$8c ;bridge
cfe6: 8a 88 86 84+ .bulk $8a,$88,$86,$84,$82,$80
cfec: ae 68 03 BridgeCollapse ldx BowserFront_Offset ;get enemy offset for bowser
cfef: b5 16 lda Enemy_ID,x ;check enemy object identifier for bowser
cff1: c9 2d cmp #Bowser ;if not found, branch ahead,
cff3: d0 10 bne SetM2 ; metatile removal not necessary
cff5: 86 08 stx ObjectOffset ;store as enemy offset here
cff7: b5 1e lda Enemy_State,x ;if bowser in normal state, skip all of this
cff9: f0 1a beq RemoveBridge
cffb: 29 40 and #%01000000 ;if bowser's state has d6 clear, skip to silence music
cffd: f0 06 beq SetM2
cfff: b5 cf lda Enemy_Y_Position,x ;check bowser's vertical coordinate
d001: c9 e0 cmp #$e0 ;if bowser not yet low enough, skip this part ahead
d003: 90 0a bcc MoveD_Bowser
d005: a9 80 SetM2 lda #Silence ;silence music
d007: 85 fc sta EventMusicQueue
d009: ee 72 07 inc OperMode_Task ;move onto next secondary mode in autoctrl mode
d00c: 4c 71 d0 jmp KillAllEnemies ;jump to empty all enemy slots and then leave
d00f: 20 8c bf MoveD_Bowser jsr MoveEnemySlowVert ;do a sub to move bowser downwards
d012: 4c 7b d1 jmp BowserGfxHandler ;jump to draw bowser's front and rear, then leave
d015: ce 64 03 RemoveBridge dec BowserFeetCounter ;decrement timer to control bowser's feet
d018: d0 44 bne NoBFall ;if not expired, skip all of this
d01a: a9 04 lda #$04
d01c: 8d 64 03 sta BowserFeetCounter ;otherwise, set timer now
d01f: ad 63 03 lda BowserBodyControls
d022: 49 01 eor #$01 ;invert bit to control bowser's feet
d024: 8d 63 03 sta BowserBodyControls
d027: a9 22 lda #$22 ;put high byte of name table address here for now
d029: 85 05 sta $05
d02b: ac 69 03 ldy BridgeCollapseOffset ;get bridge collapse offset here
d02e: b9 dd cf lda BridgeCollapseData,y ;load low byte of name table address and store here
d031: 85 04 sta $04
d033: ac 00 03 ldy VRAM_Buffer1_Offset ;increment vram buffer offset
d036: c8 iny
d037: a2 0c ldx #$0c ;set offset for tile data for sub to draw blank metatile
d039: 20 cd 8a jsr RemBridge ;do sub here to remove bowser's bridge metatiles
d03c: a6 08 ldx ObjectOffset ;get enemy offset
d03e: 20 8f 8a jsr MoveVOffset ;set new vram buffer offset
d041: a9 08 lda #Sfx_Blast ;load the fireworks/gunfire sound into the square 2 sfx
d043: 85 fe sta Square2SoundQueue ; queue while at the same time loading the brick
d045: a9 01 lda #Sfx_BrickShatter ; shatter sound into the noise sfx queue thus
d047: 85 fd sta NoiseSoundQueue ; producing the unique sound of the bridge collapsing
d049: ee 69 03 inc BridgeCollapseOffset ;increment bridge collapse offset
d04c: ad 69 03 lda BridgeCollapseOffset
d04f: c9 0f cmp #$0f ;if bridge collapse offset has not yet reached
d051: d0 0b bne NoBFall ; the end, go ahead and skip this part
d053: 20 63 c3 jsr InitVStf ;initialize whatever vertical speed bowser has
d056: a9 40 lda #%01000000
d058: 95 1e sta Enemy_State,x ;set bowser's state to one of defeated states (d6 set)
d05a: a9 80 lda #Sfx_BowserFall
d05c: 85 fe sta Square2SoundQueue ;play bowser defeat sound
d05e: 4c 7b d1 NoBFall jmp BowserGfxHandler ;jump to code that draws bowser
; -----------------------------------------------------------------------------
d061: 21 41 11 31 PRandomRange .bulk $21,$41,$11,$31
d065: b5 1e RunBowser lda Enemy_State,x ;if d5 in enemy state is not set
d067: 29 20 and #%00100000 ; then branch elsewhere to run bowser
d069: f0 14 beq BowserControl
d06b: b5 cf lda Enemy_Y_Position,x ;otherwise check vertical position
d06d: c9 e0 cmp #$e0 ;if above a certain point, branch to move defeated bowser
d06f: 90 9e bcc MoveD_Bowser ;otherwise proceed to KillAllEnemies
d071: a2 04 KillAllEnemies ldx #$04 ;start with last enemy slot
d073: 20 98 c9 KillLoop jsr EraseEnemyObject ;branch to kill enemy objects
d076: ca dex ;move onto next enemy slot
d077: 10 fa bpl KillLoop ;do this until all slots are emptied
d079: 8d cb 06 sta EnemyFrenzyBuffer ;empty frenzy buffer
d07c: a6 08 ldx ObjectOffset ;get enemy object offset and leave
d07e: 60 rts
d07f: a9 00 BowserControl lda #$00
d081: 8d cb 06 sta EnemyFrenzyBuffer ;empty frenzy buffer
d084: ad 47 07 lda TimerControl ;if master timer control not set,
d087: f0 03 beq ChkMouth ;skip jump and execute code here
d089: 4c 39 d1 jmp SkipToFB ;otherwise, jump over a bunch of code
d08c: ad 63 03 ChkMouth lda BowserBodyControls ;check bowser's mouth
d08f: 10 03 bpl FeetTmr ;if bit clear, go ahead with code here
d091: 4c 0f d1 jmp HammerChk ;otherwise skip a whole section starting here
d094: ce 64 03 FeetTmr dec BowserFeetCounter ;decrement timer to control bowser's feet
d097: d0 0d bne ResetMDr ;if not expired, skip this part
d099: a9 20 lda #$20 ;otherwise, reset timer
d09b: 8d 64 03 sta BowserFeetCounter
d09e: ad 63 03 lda BowserBodyControls ;and invert bit used
d0a1: 49 01 eor #%00000001 ; to control bowser's feet
d0a3: 8d 63 03 sta BowserBodyControls
d0a6: a5 09 ResetMDr lda FrameCounter ;check frame counter
d0a8: 29 0f and #%00001111 ;if not on every sixteenth frame, skip
d0aa: d0 04 bne B_FaceP ; ahead to continue code
d0ac: a9 02 lda #$02 ;otherwise reset moving/facing direction every
d0ae: 95 46 sta Enemy_MovingDir,x ; sixteen frames
d0b0: bd 8a 07 B_FaceP lda EnemyFrameTimer,x ;if timer set here expired,
d0b3: f0 1c beq GetPRCmp ;branch to next section
d0b5: 20 43 e1 jsr PlayerEnemyDiff ;get horizontal difference between player and bowser,
d0b8: 10 17 bpl GetPRCmp ; and branch if bowser to the right of the player
d0ba: a9 01 lda #$01
d0bc: 95 46 sta Enemy_MovingDir,x ;set bowser to move and face to the right
d0be: a9 02 lda #$02
d0c0: 8d 65 03 sta BowserMovementSpeed ;set movement speed
d0c3: a9 20 lda #$20
d0c5: 9d 8a 07 sta EnemyFrameTimer,x ;set timer here
d0c8: 8d 90 07 sta BowserFireBreathTimer ;set timer used for bowser's flame
d0cb: b5 87 lda Enemy_X_Position,x
d0cd: c9 c8 cmp #$c8 ;if bowser to the right past a certain point,
d0cf: b0 3e bcs HammerChk ; skip ahead to some other section
d0d1: a5 09 GetPRCmp lda FrameCounter ;get frame counter
d0d3: 29 03 and #%00000011
d0d5: d0 38 bne HammerChk ;execute this code every fourth frame, otherwise branch
d0d7: b5 87 lda Enemy_X_Position,x
d0d9: cd 66 03 cmp BowserOrigXPos ;if bowser not at original horizontal position,
d0dc: d0 0c bne GetDToO ; branch to skip this part
d0de: bd a7 07 lda PseudoRandomBitReg,x
d0e1: 29 03 and #%00000011 ;get pseudorandom offset
d0e3: a8 tay
d0e4: b9 61 d0 lda PRandomRange,y ;load value using pseudorandom offset
d0e7: 8d dc 06 sta MaxRangeFromOrigin ; and store here
d0ea: b5 87 GetDToO lda Enemy_X_Position,x
d0ec: 18 clc ;add movement speed to bowser's horizontal
d0ed: 6d 65 03 adc BowserMovementSpeed ; coordinate and save as new horizontal position
d0f0: 95 87 sta Enemy_X_Position,x
d0f2: b4 46 ldy Enemy_MovingDir,x
d0f4: c0 01 cpy #$01 ;if bowser moving and facing to the right, skip ahead
d0f6: f0 17 beq HammerChk
d0f8: a0 ff ldy #$ff ;set default movement speed here (move left)
d0fa: 38 sec ;get difference of current vs. original
d0fb: ed 66 03 sbc BowserOrigXPos ; horizontal position
d0fe: 10 07 bpl CompDtoO ;if current position to the right of original, skip ahead
d100: 49 ff eor #$ff
d102: 18 clc ;get two's compliment
d103: 69 01 adc #$01
d105: a0 01 ldy #$01 ;set alternate movement speed here (move right)
d107: cd dc 06 CompDtoO cmp MaxRangeFromOrigin ;compare difference with pseudorandom value
d10a: 90 03 bcc HammerChk ;if difference < pseudorandom value, leave speed alone
d10c: 8c 65 03 sty BowserMovementSpeed ;otherwise change bowser's movement speed
d10f: bd 8a 07 HammerChk lda EnemyFrameTimer,x ;if timer set here not expired yet, skip ahead to
d112: d0 28 bne MakeBJump ; some other section of code
d114: 20 8c bf jsr MoveEnemySlowVert ;otherwise start by moving bowser downwards
d117: ad 5f 07 lda WorldNumber ;check world number
d11a: c9 05 cmp #World6
d11c: 90 09 bcc SetHmrTmr ;if world 1-5, skip this part (not time to throw hammers yet)
d11e: a5 09 lda FrameCounter
d120: 29 03 and #%00000011 ;check to see if it's time to execute sub
d122: d0 03 bne SetHmrTmr ;if not, skip sub, otherwise
d124: 20 94 ba jsr SpawnHammerObj ;execute sub on every fourth frame to spawn misc object (hammer)
d127: b5 cf SetHmrTmr lda Enemy_Y_Position,x ;get current vertical position
d129: c9 80 cmp #$80 ;if still above a certain point
d12b: 90 1c bcc ChkFireB ; then skip to world number check for flames
d12d: bd a7 07 lda PseudoRandomBitReg,x
d130: 29 03 and #%00000011 ;get pseudorandom offset
d132: a8 tay
d133: b9 61 d0 lda PRandomRange,y ;get value using pseudorandom offset
d136: 9d 8a 07 sta EnemyFrameTimer,x ;set for timer here
d139: 4c 49 d1 SkipToFB jmp ChkFireB ;jump to execute flames code
d13c: c9 01 MakeBJump cmp #$01 ;if timer not yet about to expire,
d13e: d0 09 bne ChkFireB ; skip ahead to next part
d140: d6 cf dec Enemy_Y_Position,x ;otherwise decrement vertical coordinate
d142: 20 63 c3 jsr InitVStf ;initialize movement amount
d145: a9 fe lda #$fe
d147: 95 a0 sta Enemy_Y_Speed,x ;set vertical speed to move bowser upwards
d149: ad 5f 07 ChkFireB lda WorldNumber ;check world number here
d14c: c9 07 cmp #World8 ;world 8?
d14e: f0 04 beq SpawnFBr ;if so, execute this part here
d150: c9 05 cmp #World6 ;world 6-7?
d152: b0 27 bcs BowserGfxHandler ;if so, skip this part here
d154: ad 90 07 SpawnFBr lda BowserFireBreathTimer ;check timer here
d157: d0 22 bne BowserGfxHandler ;if not expired yet, skip all of this
d159: a9 20 lda #$20
d15b: 8d 90 07 sta BowserFireBreathTimer ;set timer here
d15e: ad 63 03 lda BowserBodyControls
d161: 49 80 eor #%10000000 ;invert bowser's mouth bit to open
d163: 8d 63 03 sta BowserBodyControls ; and close bowser's mouth
d166: 30 e1 bmi ChkFireB ;if bowser's mouth open, loop back
d168: 20 d9 d1 jsr SetFlameTimer ;get timing for bowser's flame
d16b: ac cc 06 ldy SecondaryHardMode
d16e: f0 03 beq SetFBTmr ;if secondary hard mode flag not set, skip this
d170: 38 sec
d171: e9 10 sbc #$10 ;otherwise subtract from value in A
d173: 8d 90 07 SetFBTmr sta BowserFireBreathTimer ;set value as timer here
d176: a9 15 lda #$15 ;put bowser's flame identifier
d178: 8d cb 06 sta EnemyFrenzyBuffer ; in enemy frenzy buffer
;
BowserGfxHandler
d17b: 20 bc d1 jsr ProcessBowserHalf ;do a sub here to process bowser's front
d17e: a0 10 ldy #$10 ;load default value here to position bowser's rear
d180: b5 46 lda Enemy_MovingDir,x ;check moving direction
d182: 4a lsr A
d183: 90 02 bcc CopyFToR ;if moving left, use default
d185: a0 f0 ldy #$f0 ;otherwise load alternate positioning value here
d187: 98 CopyFToR tya ;move bowser's rear object position value to A
d188: 18 clc
d189: 75 87 adc Enemy_X_Position,x ;add to bowser's front object horizontal coordinate
d18b: ac cf 06 ldy DuplicateObj_Offset ;get bowser's rear object offset
d18e: 99 87 00 sta Enemy_X_Position,y ;store A as bowser's rear horizontal coordinate
d191: b5 cf lda Enemy_Y_Position,x
d193: 18 clc ;add eight pixels to bowser's front object
d194: 69 08 adc #$08 ;vertical coordinate and store as vertical coordinate
d196: 99 cf 00 sta Enemy_Y_Position,y ; for bowser's rear
d199: b5 1e lda Enemy_State,x
d19b: 99 1e 00 sta Enemy_State,y ;copy enemy state directly from front to rear
d19e: b5 46 lda Enemy_MovingDir,x
d1a0: 99 46 00 sta Enemy_MovingDir,y ;copy moving direction also
d1a3: a5 08 lda ObjectOffset ;save enemy object offset of front to stack
d1a5: 48 pha
d1a6: ae cf 06 ldx DuplicateObj_Offset ;put enemy object offset of rear as current
d1a9: 86 08 stx ObjectOffset
d1ab: a9 2d lda #Bowser ;set bowser's enemy identifier
d1ad: 95 16 sta Enemy_ID,x ;store in bowser's rear object
d1af: 20 bc d1 jsr ProcessBowserHalf ;do a sub here to process bowser's rear
d1b2: 68 pla
d1b3: 85 08 sta ObjectOffset ;get original enemy object offset
d1b5: aa tax
d1b6: a9 00 lda #$00 ;nullify bowser's front/rear graphics flag
d1b8: 8d 6a 03 sta BowserGfxFlag
d1bb: 60 ExBgfxH rts ;leave!
ProcessBowserHalf
d1bc: ee 6a 03 inc BowserGfxFlag ;increment bowser's graphics flag, then run subroutines
d1bf: 20 d7 c8 jsr RunRetainerObj ;to get offscreen bits, relative position and draw bowser (finally!)
d1c2: b5 1e lda Enemy_State,x
d1c4: d0 f5 bne ExBgfxH ;if either enemy object not in normal state, branch to leave
d1c6: a9 0a lda #$0a
d1c8: 9d 9a 04 sta Enemy_BoundBoxCtrl,x ;set bounding box size control
d1cb: 20 43 e2 jsr GetEnemyBoundBox ;get bounding box coordinates
d1ce: 4c 53 d8 jmp PlayerEnemyCollision ;do player-to-enemy collision detection
; -----------------------------------------------------------------------------
; $00 - used to hold movement force and tile number
; $01 - used to hold sprite attribute data
d1d1: bf 40 bf bf+ FlameTimerData .bulk $bf,$40,$bf,$bf,$bf,$40,$40,$bf
d1d9: ac 67 03 SetFlameTimer ldy BowserFlameTimerCtrl ;load counter as offset
d1dc: ee 67 03 inc BowserFlameTimerCtrl ;increment
d1df: ad 67 03 lda BowserFlameTimerCtrl ;mask out all but 3 LSB
d1e2: 29 07 and #%00000111 ; to keep in range of 0-7
d1e4: 8d 67 03 sta BowserFlameTimerCtrl
d1e7: b9 d1 d1 lda FlameTimerData,y ;load value to be used then leave
d1ea: 60 ExFl rts
d1eb: ad 47 07 ProcBowserFlame lda TimerControl ;if master timer control flag set,
d1ee: d0 30 bne SetGfxF ; skip all of this
d1f0: a9 40 lda #$40 ;load default movement force
d1f2: ac cc 06 ldy SecondaryHardMode
d1f5: f0 02 beq SFlmX ;if secondary hard mode flag not set, use default
d1f7: a9 60 lda #$60 ;otherwise load alternate movement force to go faster
d1f9: 85 00 SFlmX sta $00 ;store value here
d1fb: bd 01 04 lda Enemy_X_MoveForce,x
d1fe: 38 sec ;subtract value from movement force
d1ff: e5 00 sbc $00
d201: 9d 01 04 sta Enemy_X_MoveForce,x ;save new value
d204: b5 87 lda Enemy_X_Position,x
d206: e9 01 sbc #$01 ;subtract one from horizontal position to move
d208: 95 87 sta Enemy_X_Position,x ; to the left
d20a: b5 6e lda Enemy_PageLoc,x
d20c: e9 00 sbc #$00 ;subtract borrow from page location
d20e: 95 6e sta Enemy_PageLoc,x
d210: bc 17 04 ldy BowserFlamePRandomOfs,x ;get some value here and use as offset
d213: b5 cf lda Enemy_Y_Position,x ;load vertical coordinate
d215: d9 9d c5 cmp FlameYPosData,y ;compare against coordinate data using $0417,x as offset
d218: f0 06 beq SetGfxF ;if equal, branch and do not modify coordinate
d21a: 18 clc
d21b: 7d 34 04 adc Enemy_Y_MoveForce,x ;otherwise add value here to coordinate and store
d21e: 95 cf sta Enemy_Y_Position,x ;as new vertical coordinate
d220: 20 52 f1 SetGfxF jsr RelativeEnemyPosition ;get new relative coordinates
d223: b5 1e lda Enemy_State,x ;if bowser's flame not in normal state,
d225: d0 c3 bne ExFl ; branch to leave
d227: a9 51 lda #$51 ;otherwise, continue
d229: 85 00 sta $00 ;write first tile number
d22b: a0 02 ldy #$02 ;load attributes without vertical flip by default
d22d: a5 09 lda FrameCounter
d22f: 29 02 and #%00000010 ;invert vertical flip bit every 2 frames
d231: f0 02 beq FlmeAt ;if d1 not set, write default value
d233: a0 82 ldy #$82 ;otherwise write value with vertical flip bit set
d235: 84 01 FlmeAt sty $01 ;set bowser's flame sprite attributes here
d237: bc e5 06 ldy Enemy_SprDataOffset,x ;get OAM data offset
d23a: a2 00 ldx #$00
d23c: ad b9 03 DrawFlameLoop lda Enemy_Rel_YPos ;get Y relative coordinate of current enemy object
d23f: 99 00 02 sta Sprite_Y_Position,y ;write into Y coordinate of OAM data
d242: a5 00 lda $00
d244: 99 01 02 sta Sprite_Tilenumber,y ;write current tile number into OAM data
d247: e6 00 inc $00 ;increment tile number to draw more bowser's flame
d249: a5 01 lda $01
d24b: 99 02 02 sta Sprite_Attributes,y ;write saved attributes into OAM data
d24e: ad ae 03 lda Enemy_Rel_XPos
d251: 99 03 02 sta Sprite_X_Position,y ;write X relative coordinate of current enemy object
d254: 18 clc
d255: 69 08 adc #$08
d257: 8d ae 03 sta Enemy_Rel_XPos ;then add eight to it and store
d25a: c8 iny
d25b: c8 iny
d25c: c8 iny
d25d: c8 iny ;increment Y four times to move onto the next OAM
d25e: e8 inx ;move onto the next OAM, and branch if three
d25f: e0 03 cpx #$03 ; have not yet been done
d261: 90 d9 bcc DrawFlameLoop
d263: a6 08 ldx ObjectOffset ;reload original enemy offset
d265: 20 af f1 jsr GetEnemyOffscreenBits ;get offscreen information
d268: bc e5 06 ldy Enemy_SprDataOffset,x ;get OAM data offset
d26b: ad d1 03 lda Enemy_OffscreenBits ;get enemy object offscreen bits
d26e: 4a lsr A ;move d0 to carry and result to stack
d26f: 48 pha
d270: 90 05 bcc M3FOfs ;branch if carry not set
d272: a9 f8 lda #$f8 ;otherwise move sprite offscreen, this part likely
d274: 99 0c 02 sta Sprite_Y_Position+12,y ; residual since flame is only made of three sprites
d277: 68 M3FOfs pla ;get bits from stack
d278: 4a lsr A ;move d1 to carry and move bits back to stack
d279: 48 pha
d27a: 90 05 bcc M2FOfs ;branch if carry not set again
d27c: a9 f8 lda #$f8 ;otherwise move third sprite offscreen
d27e: 99 08 02 sta Sprite_Y_Position+8,y
d281: 68 M2FOfs pla ;get bits from stack again
d282: 4a lsr A ;move d2 to carry and move bits back to stack again
d283: 48 pha
d284: 90 05 bcc M1FOfs ;branch if carry not set yet again
d286: a9 f8 lda #$f8 ;otherwise move second sprite offscreen
d288: 99 04 02 sta Sprite_Y_Position+4,y
d28b: 68 M1FOfs pla ;get bits from stack one last time
d28c: 4a lsr A ;move d3 to carry
d28d: 90 05 bcc ExFlmeD ;branch if carry not set one last time
d28f: a9 f8 lda #$f8
d291: 99 00 02 sta Sprite_Y_Position,y ;otherwise move first sprite offscreen
d294: 60 ExFlmeD rts ;leave
; -----------------------------------------------------------------------------
d295: d6 a0 RunFireworks dec ExplosionTimerCounter,x ;decrement explosion timing counter here
d297: d0 0c bne SetupExpl ;if not expired, skip this part
d299: a9 08 lda #$08
d29b: 95 a0 sta ExplosionTimerCounter,x ;reset counter
d29d: f6 58 inc ExplosionGfxCounter,x ;increment explosion graphics counter
d29f: b5 58 lda ExplosionGfxCounter,x
d2a1: c9 03 cmp #$03 ;check explosion graphics counter
d2a3: b0 18 bcs FireworksSoundScore ;if at a certain point, branch to kill this object
d2a5: 20 52 f1 SetupExpl jsr RelativeEnemyPosition ;get relative coordinates of explosion
d2a8: ad b9 03 lda Enemy_Rel_YPos ;copy relative coordinates
d2ab: 8d ba 03 sta Fireball_Rel_YPos ;from the enemy object to the fireball object
d2ae: ad ae 03 lda Enemy_Rel_XPos ;first vertical, then horizontal
d2b1: 8d af 03 sta Fireball_Rel_XPos
d2b4: bc e5 06 ldy Enemy_SprDataOffset,x ;get OAM data offset
d2b7: b5 58 lda ExplosionGfxCounter,x ;get explosion graphics counter
d2b9: 20 17 ed jsr DrawExplosion_Fireworks ;do a sub to draw the explosion then leave
d2bc: 60 rts
FireworksSoundScore
d2bd: a9 00 lda #$00 ;disable enemy buffer flag
d2bf: 95 0f sta Enemy_Flag,x
d2c1: a9 08 lda #Sfx_Blast ;play fireworks/gunfire sound
d2c3: 85 fe sta Square2SoundQueue
d2c5: a9 05 lda #$05 ;set part of score modifier for 500 points
d2c7: 8d 38 01 sta DigitModifier+4
d2ca: 4c 36 d3 jmp EndAreaPoints ;jump to award points accordingly then leave
; -----------------------------------------------------------------------------
StarFlagYPosAdder
d2cd: 00 00 08 08 .bulk $00,$00,$08,$08
StarFlagXPosAdder
d2d1: 00 08 00 08 .bulk $00,$08,$00,$08
StarFlagTileData
d2d5: 54 55 56 57 .bulk $54,$55,$56,$57
d2d9: a9 00 RunStarFlagObj lda #$00 ;initialize enemy frenzy buffer
d2db: 8d cb 06 sta EnemyFrenzyBuffer
d2de: ad 46 07 lda StarFlagTaskControl ;check star flag object task number here
d2e1: c9 05 cmp #$05 ;if greater than 5, branch to exit
d2e3: b0 2c bcs StarFlagExit
d2e5: 20 04 8e jsr JumpEngine ;otherwise jump to appropriate sub
d2e8: 11 d3 .dd2 StarFlagExit
d2ea: f2 d2 .dd2 GameTimerFireworks
d2ec: 12 d3 .dd2 AwardGameTimerPoints
d2ee: 4e d3 .dd2 RaiseFlagSetoffFworks
d2f0: a2 d3 .dd2 DelayToAreaEnd
GameTimerFireworks
d2f2: a0 05 ldy #$05 ;set default state for star flag object
d2f4: ad fa 07 lda GameTimerDisplay+2 ;get game timer's last digit
d2f7: c9 01 cmp #$01
d2f9: f0 0e beq SetFWC ;if last digit of game timer set to 1, skip ahead
d2fb: a0 03 ldy #$03 ;otherwise load new value for state
d2fd: c9 03 cmp #$03
d2ff: f0 08 beq SetFWC ;if last digit of game timer set to 3, skip ahead
d301: a0 00 ldy #$00 ;otherwise load one more potential value for state
d303: c9 06 cmp #$06
d305: f0 02 beq SetFWC ;if last digit of game timer set to 6, skip ahead
d307: a9 ff lda #$ff ;otherwise set value for no fireworks
d309: 8d d7 06 SetFWC sta FireworksCounter ;set fireworks counter here
d30c: 94 1e sty Enemy_State,x ;set whatever state we have in star flag object
IncrementSFTask1
d30e: ee 46 07 inc StarFlagTaskControl ;increment star flag object task number
d311: 60 StarFlagExit rts ;leave
AwardGameTimerPoints
d312: ad f8 07 lda GameTimerDisplay ;check all game timer digits for any intervals left
d315: 0d f9 07 ora GameTimerDisplay+1
d318: 0d fa 07 ora GameTimerDisplay+2
d31b: f0 f1 beq IncrementSFTask1 ;if no time left on game timer at all, branch to next task
d31d: a5 09 lda FrameCounter
d31f: 29 04 and #%00000100 ;check frame counter for d2 set (skip ahead
d321: f0 04 beq NoTTick ; for four frames every four frames) branch if not set
d323: a9 10 lda #Sfx_TimerTick
d325: 85 fe sta Square2SoundQueue ;load timer tick sound
d327: a0 23 NoTTick ldy #$23 ;set offset here to subtract from game timer's last digit
d329: a9 ff lda #$ff ;set adder here to $ff, or -1, to subtract one
d32b: 8d 39 01 sta DigitModifier+5 ; from the last digit of the game timer
d32e: 20 5f 8f jsr DigitsMathRoutine ;subtract digit
d331: a9 05 lda #$05 ;set now to add 50 points
d333: 8d 39 01 sta DigitModifier+5 ;per game timer interval subtracted
d336: a0 0b EndAreaPoints ldy #$0b ;load offset for mario's score by default
d338: ad 53 07 lda CurrentPlayer ;check player on the screen
d33b: f0 02 beq ELPGive ;if mario, do not change
d33d: a0 11 ldy #$11 ;otherwise load offset for luigi's score
d33f: 20 5f 8f ELPGive jsr DigitsMathRoutine ;award 50 points per game timer interval
d342: ad 53 07 lda CurrentPlayer ;get player on the screen (or 500 points per
d345: 0a asl A ; fireworks explosion if branched here from there)
d346: 0a asl A ;shift to high nybble
d347: 0a asl A
d348: 0a asl A
d349: 09 04 ora #%00000100 ;add four to set nybble for game timer
d34b: 4c 36 bc jmp UpdateNumber ;jump to print the new score and game timer
RaiseFlagSetoffFworks
d34e: b5 cf lda Enemy_Y_Position,x ;check star flag's vertical position
d350: c9 72 cmp #$72 ;against preset value
d352: 90 05 bcc SetoffF ;if star flag higher vertically, branch to other code
d354: d6 cf dec Enemy_Y_Position,x ;otherwise, raise star flag by one pixel
d356: 4c 65 d3 jmp DrawStarFlag ; and skip this part here
d359: ad d7 06 SetoffF lda FireworksCounter ;check fireworks counter
d35c: f0 38 beq DrawFlagSetTimer ;if no fireworks left to go off, skip this part
d35e: 30 36 bmi DrawFlagSetTimer ;if no fireworks set to go off, skip this part
d360: a9 16 lda #Fireworks
d362: 8d cb 06 sta EnemyFrenzyBuffer ;otherwise set fireworks object in frenzy queue
;
d365: 20 52 f1 DrawStarFlag jsr RelativeEnemyPosition ;get relative coordinates of star flag
d368: bc e5 06 ldy Enemy_SprDataOffset,x ;get OAM data offset
d36b: a2 03 ldx #$03 ;do four sprites
d36d: ad b9 03 DSFloop lda Enemy_Rel_YPos ;get relative vertical coordinate
d370: 18 clc
d371: 7d cd d2 adc StarFlagYPosAdder,x ;add Y coordinate adder data
d374: 99 00 02 sta Sprite_Y_Position,y ;store as Y coordinate
d377: bd d5 d2 lda StarFlagTileData,x ;get tile number
d37a: 99 01 02 sta Sprite_Tilenumber,y ;store as tile number
d37d: a9 22 lda #$22 ;set palette and background priority bits
d37f: 99 02 02 sta Sprite_Attributes,y ;store as attributes
d382: ad ae 03 lda Enemy_Rel_XPos ;get relative horizontal coordinate
d385: 18 clc
d386: 7d d1 d2 adc StarFlagXPosAdder,x ;add X coordinate adder data
d389: 99 03 02 sta Sprite_X_Position,y ;store as X coordinate
d38c: c8 iny
d38d: c8 iny ;increment OAM data offset four bytes
d38e: c8 iny ; for next sprite
d38f: c8 iny
d390: ca dex ;move onto next sprite
d391: 10 da bpl DSFloop ;do this until all sprites are done
d393: a6 08 ldx ObjectOffset ;get enemy object offset and leave
d395: 60 rts
DrawFlagSetTimer
d396: 20 65 d3 jsr DrawStarFlag ;do sub to draw star flag
d399: a9 06 lda #$06
d39b: 9d 96 07 sta EnemyIntervalTimer,x ;set interval timer here
IncrementSFTask2
d39e: ee 46 07 inc StarFlagTaskControl ;move onto next task
d3a1: 60 rts
d3a2: 20 65 d3 DelayToAreaEnd jsr DrawStarFlag ;do sub to draw star flag
d3a5: bd 96 07 lda EnemyIntervalTimer,x ;if interval timer set in previous task
d3a8: d0 05 bne StarFlagExit2 ;not yet expired, branch to leave
d3aa: ad b1 07 lda EventMusicBuffer ;if event music buffer empty,
d3ad: f0 ef beq IncrementSFTask2 ;branch to increment task
d3af: 60 StarFlagExit2 rts ;otherwise leave
; -----------------------------------------------------------------------------
; $00 - used to store horizontal difference between player and piranha plant
MovePiranhaPlant
d3b0: b5 1e lda Enemy_State,x ;check enemy state
d3b2: d0 56 bne PutinPipe ;if set at all, branch to leave
d3b4: bd 8a 07 lda EnemyFrameTimer,x ;check enemy's timer here
d3b7: d0 51 bne PutinPipe ;branch to end if not yet expired
d3b9: b5 a0 lda PiranhaPlant_MoveFlag,x ;check movement flag
d3bb: d0 23 bne SetupToMovePPlant ;if moving, skip to part ahead
d3bd: b5 58 lda PiranhaPlant_Y_Speed,x ;if currently rising, branch
d3bf: 30 14 bmi ReversePlantSpeed ;to move enemy upwards out of pipe
d3c1: 20 43 e1 jsr PlayerEnemyDiff ;get horizontal difference between player and
d3c4: 10 09 bpl ChkPlayerNearPipe ; piranha plant, and branch if enemy to right of player
d3c6: a5 00 lda $00 ;otherwise get saved horizontal difference
d3c8: 49 ff eor #$ff
d3ca: 18 clc ;and change to two's compliment
d3cb: 69 01 adc #$01
d3cd: 85 00 sta $00 ;save as new horizontal difference
ChkPlayerNearPipe
d3cf: a5 00 lda $00 ;get saved horizontal difference
d3d1: c9 21 cmp #$21
d3d3: 90 35 bcc PutinPipe ;if player within a certain distance, branch to leave
ReversePlantSpeed
d3d5: b5 58 lda PiranhaPlant_Y_Speed,x ;get vertical speed
d3d7: 49 ff eor #$ff
d3d9: 18 clc ;change to two's compliment
d3da: 69 01 adc #$01
d3dc: 95 58 sta PiranhaPlant_Y_Speed,x ;save as new vertical speed
d3de: f6 a0 inc PiranhaPlant_MoveFlag,x ;increment to set movement flag
SetupToMovePPlant
d3e0: bd 34 04 lda PiranhaPlantDownYPos,x ;get original vertical coordinate (lowest point)
d3e3: b4 58 ldy PiranhaPlant_Y_Speed,x ;get vertical speed
d3e5: 10 03 bpl RiseFallPiranhaPlant ;branch if moving downwards
d3e7: bd 17 04 lda PiranhaPlantUpYPos,x ;otherwise get other vertical coordinate (highest point)
RiseFallPiranhaPlant
d3ea: 85 00 sta $00 ;save vertical coordinate here
d3ec: a5 09 lda FrameCounter ;get frame counter
d3ee: 4a lsr A
d3ef: 90 19 bcc PutinPipe ;branch to leave if d0 set (execute code every other frame)
d3f1: ad 47 07 lda TimerControl ;get master timer control
d3f4: d0 14 bne PutinPipe ;branch to leave if set (likely not necessary)
d3f6: b5 cf lda Enemy_Y_Position,x ;get current vertical coordinate
d3f8: 18 clc
d3f9: 75 58 adc PiranhaPlant_Y_Speed,x ;add vertical speed to move up or down
d3fb: 95 cf sta Enemy_Y_Position,x ;save as new vertical coordinate
d3fd: c5 00 cmp $00 ;compare against low or high coordinate
d3ff: d0 09 bne PutinPipe ;branch to leave if not yet reached
d401: a9 00 lda #$00
d403: 95 a0 sta PiranhaPlant_MoveFlag,x ;otherwise clear movement flag
d405: a9 40 lda #$40
d407: 9d 8a 07 sta EnemyFrameTimer,x ;set timer to delay piranha plant movement
d40a: a9 20 PutinPipe lda #%00100000 ;set background priority bit in sprite
d40c: 9d c5 03 sta Enemy_SprAttrib,x ; attributes to give illusion of being inside pipe
d40f: 60 rts ;then leave
; -----------------------------------------------------------------------------
; $07 - spinning speed
d410: 85 07 FirebarSpin sta $07 ;save spinning speed here
d412: b5 34 lda FirebarSpinDirection,x ;check spinning direction
d414: d0 0e bne SpinCounterClockwise ;if moving counter-clockwise, branch to other part
d416: a0 18 ldy #$18 ;possibly residual ldy
d418: b5 58 lda FirebarSpinState_Low,x
d41a: 18 clc ;add spinning speed to what would normally be
d41b: 65 07 adc $07 ; the horizontal speed
d41d: 95 58 sta FirebarSpinState_Low,x
d41f: b5 a0 lda FirebarSpinState_High,x ;add carry to what would normally be the vertical speed
d421: 69 00 adc #$00
d423: 60 rts
SpinCounterClockwise
d424: a0 08 ldy #$08 ;possibly residual ldy
d426: b5 58 lda FirebarSpinState_Low,x
d428: 38 sec ;subtract spinning speed to what would normally be
d429: e5 07 sbc $07 ; the horizontal speed
d42b: 95 58 sta FirebarSpinState_Low,x
d42d: b5 a0 lda FirebarSpinState_High,x ;add carry to what would normally be the vertical speed
d42f: e9 00 sbc #$00
d431: 60 rts
; -----------------------------------------------------------------------------
; $00 - used to hold collision flag, Y movement force + 5 or low byte of name
; table for rope
; $01 - used to hold high byte of name table for rope
; $02 - used to hold page location of rope
d432: b5 b6 BalancePlatform lda Enemy_Y_HighPos,x ;check high byte of vertical position
d434: c9 03 cmp #$03
d436: d0 03 bne DoBPl
d438: 4c 98 c9 jmp EraseEnemyObject ;if far below screen, kill the object
d43b: b5 1e DoBPl lda Enemy_State,x ;get object's state (set to $ff or other platform offset)
d43d: 10 01 bpl CheckBalPlatform ;if doing other balance platform, branch to leave
d43f: 60 rts
CheckBalPlatform
d440: a8 tay ;save offset from state as Y
d441: bd a2 03 lda PlatformCollisionFlag,x ;get collision flag of platform
d444: 85 00 sta $00 ;store here
d446: b5 46 lda Enemy_MovingDir,x ;get moving direction
d448: f0 03 beq ChkForFall
d44a: 4c bb d5 jmp PlatformFall ;if set, jump here
d44d: a9 2d ChkForFall lda #$2d ;check if platform is above a certain point
d44f: d5 cf cmp Enemy_Y_Position,x
d451: 90 0f bcc ChkOtherForFall ;if not, branch elsewhere
d453: c4 00 cpy $00 ;if collision flag is set to same value as
d455: f0 08 beq MakePlatformFall ; enemy state, branch to make platforms fall
d457: 18 clc
d458: 69 02 adc #$02 ;otherwise add 2 pixels to vertical position
d45a: 95 cf sta Enemy_Y_Position,x ; of current platform and branch elsewhere
d45c: 4c b1 d5 jmp StopPlatforms ; to make platforms stop
MakePlatformFall
d45f: 4c 98 d5 jmp InitPlatformFall ;make platforms fall
d462: d9 cf 00 ChkOtherForFall cmp Enemy_Y_Position,y ;check if other platform is above a certain point
d465: 90 0d bcc ChkToMoveBalPlat ;if not, branch elsewhere
d467: e4 00 cpx $00 ;if collision flag is set to same value as
d469: f0 f4 beq MakePlatformFall ; enemy state, branch to make platforms fall
d46b: 18 clc
d46c: 69 02 adc #$02 ;otherwise add 2 pixels to vertical position
d46e: 99 cf 00 sta Enemy_Y_Position,y ; of other platform and branch elsewhere
d471: 4c b1 d5 jmp StopPlatforms ;jump to stop movement and do not return
ChkToMoveBalPlat
d474: b5 cf lda Enemy_Y_Position,x ;save vertical position to stack
d476: 48 pha
d477: bd a2 03 lda PlatformCollisionFlag,x ;get collision flag
d47a: 10 18 bpl ColFlg ;branch if collision
d47c: bd 34 04 lda Enemy_Y_MoveForce,x
d47f: 18 clc ;add $05 to contents of moveforce, whatever they be
d480: 69 05 adc #$05
d482: 85 00 sta $00 ;store here
d484: b5 a0 lda Enemy_Y_Speed,x
d486: 69 00 adc #$00 ;add carry to vertical speed
d488: 30 1a bmi PlatDn ;branch if moving downwards
d48a: d0 0c bne PlatUp ;branch elsewhere if moving upwards
d48c: a5 00 lda $00
d48e: c9 0b cmp #$0b ;check if there's still a little force left
d490: 90 0c bcc PlatSt ;if not enough, branch to stop movement
d492: b0 04 bcs PlatUp ;otherwise keep branch to move upwards
d494: c5 08 ColFlg cmp ObjectOffset ;if collision flag matches
d496: f0 0c beq PlatDn ; current enemy object offset, branch
d498: 20 b7 bf PlatUp jsr MovePlatformUp ;do a sub to move upwards
d49b: 4c a7 d4 jmp DoOtherPlatform ;jump ahead to remaining code
d49e: 20 b1 d5 PlatSt jsr StopPlatforms ;do a sub to stop movement
d4a1: 4c a7 d4 jmp DoOtherPlatform ;jump ahead to remaining code
d4a4: 20 b4 bf PlatDn jsr MovePlatformDown ;do a sub to move downwards
d4a7: b4 1e DoOtherPlatform ldy Enemy_State,x ;get offset of other platform
d4a9: 68 pla ;get old vertical coordinate from stack
d4aa: 38 sec
d4ab: f5 cf sbc Enemy_Y_Position,x ;get difference of old vs. new coordinate
d4ad: 18 clc
d4ae: 79 cf 00 adc Enemy_Y_Position,y ;add difference to vertical coordinate of other
d4b1: 99 cf 00 sta Enemy_Y_Position,y ; platform to move it in the opposite direction
d4b4: bd a2 03 lda PlatformCollisionFlag,x ;if no collision, skip this part here
d4b7: 30 04 bmi DrawEraseRope
d4b9: aa tax ;put offset which collision occurred here
d4ba: 20 21 dc jsr PositionPlayerOnVPlat ; and use it to position player accordingly
d4bd: a4 08 DrawEraseRope ldy ObjectOffset ;get enemy object offset
d4bf: b9 a0 00 lda Enemy_Y_Speed,y ;check to see if current platform is
d4c2: 19 34 04 ora Enemy_Y_MoveForce,y ; moving at all
d4c5: f0 77 beq ExitRp ;if not, skip all of this and branch to leave
d4c7: ae 00 03 ldx VRAM_Buffer1_Offset ;get vram buffer offset
d4ca: e0 20 cpx #$20 ;if offset beyond a certain point, go ahead
d4cc: b0 70 bcs ExitRp ; and skip this, branch to leave
d4ce: b9 a0 00 lda Enemy_Y_Speed,y
d4d1: 48 pha ;save two copies of vertical speed to stack
d4d2: 48 pha
d4d3: 20 41 d5 jsr SetupPlatformRope ;do a sub to figure out where to put new bg tiles
d4d6: a5 01 lda $01 ;write name table address to vram buffer
d4d8: 9d 01 03 sta VRAM_Buffer1,x ;first the high byte, then the low
d4db: a5 00 lda $00
d4dd: 9d 02 03 sta VRAM_Buffer1+1,x
d4e0: a9 02 lda #$02 ;set length for 2 bytes
d4e2: 9d 03 03 sta VRAM_Buffer1+2,x
d4e5: b9 a0 00 lda Enemy_Y_Speed,y ;if platform moving upwards, branch
d4e8: 30 0d bmi EraseR1 ; to do something else
d4ea: a9 a2 lda #$a2
d4ec: 9d 04 03 sta VRAM_Buffer1+3,x ;otherwise put tile numbers for left
d4ef: a9 a3 lda #$a3 ; and right sides of rope in vram buffer
d4f1: 9d 05 03 sta VRAM_Buffer1+4,x
d4f4: 4c ff d4 jmp OtherRope ;jump to skip this part
d4f7: a9 24 EraseR1 lda #$24 ;put blank tiles in vram buffer
d4f9: 9d 04 03 sta VRAM_Buffer1+3,x ; to erase rope
d4fc: 9d 05 03 sta VRAM_Buffer1+4,x
d4ff: b9 1e 00 OtherRope lda Enemy_State,y ;get offset of other platform from state
d502: a8 tay ;use as Y here
d503: 68 pla ;pull second copy of vertical speed from stack
d504: 49 ff eor #$ff ;invert bits to reverse speed
d506: 20 41 d5 jsr SetupPlatformRope ;do sub again to figure out where to put bg tiles
d509: a5 01 lda $01 ;write name table address to vram buffer
d50b: 9d 06 03 sta VRAM_Buffer1+5,x ;this time we're doing putting tiles for
d50e: a5 00 lda $00 ; the other platform
d510: 9d 07 03 sta VRAM_Buffer1+6,x
d513: a9 02 lda #$02
d515: 9d 08 03 sta VRAM_Buffer1+7,x ;set length again for 2 bytes
d518: 68 pla ;pull first copy of vertical speed from stack
d519: 10 0d bpl EraseR2 ;if moving upwards (note inversion earlier), skip this
d51b: a9 a2 lda #$a2
d51d: 9d 09 03 sta VRAM_Buffer1+8,x ;otherwise put tile numbers for left
d520: a9 a3 lda #$a3 ; and right sides of rope in vram
d522: 9d 0a 03 sta VRAM_Buffer1+9,x ;transfer buffer
d525: 4c 30 d5 jmp EndRp ;jump to skip this part
d528: a9 24 EraseR2 lda #$24 ;put blank tiles in vram buffer
d52a: 9d 09 03 sta VRAM_Buffer1+8,x ; to erase rope
d52d: 9d 0a 03 sta VRAM_Buffer1+9,x
d530: a9 00 EndRp lda #$00 ;put null terminator at the end
d532: 9d 0b 03 sta VRAM_Buffer1+10,x
d535: ad 00 03 lda VRAM_Buffer1_Offset ;add ten bytes to the vram buffer offset
d538: 18 clc ; and store
d539: 69 0a adc #$0a
d53b: 8d 00 03 sta VRAM_Buffer1_Offset
d53e: a6 08 ExitRp ldx ObjectOffset ;get enemy object buffer offset and leave
d540: 60 rts
SetupPlatformRope
d541: 48 pha ;save second/third copy to stack
d542: b9 87 00 lda Enemy_X_Position,y ;get horizontal coordinate
d545: 18 clc
d546: 69 08 adc #$08 ;add eight pixels
d548: ae cc 06 ldx SecondaryHardMode ;if secondary hard mode flag set,
d54b: d0 03 bne GetLRp ; use coordinate as-is
d54d: 18 clc
d54e: 69 10 adc #$10 ;otherwise add sixteen more pixels
d550: 48 GetLRp pha ;save modified horizontal coordinate to stack
d551: b9 6e 00 lda Enemy_PageLoc,y
d554: 69 00 adc #$00 ;add carry to page location
d556: 85 02 sta $02 ; and save here
d558: 68 pla ;pull modified horizontal coordinate
d559: 29 f0 and #%11110000 ; from the stack, mask out low nybble
d55b: 4a lsr A ; and shift three bits to the right
d55c: 4a lsr A
d55d: 4a lsr A
d55e: 85 00 sta $00 ;store result here as part of name table low byte
d560: b6 cf ldx Enemy_Y_Position,y ;get vertical coordinate
d562: 68 pla ;get second/third copy of vertical speed from stack
d563: 10 05 bpl GetHRp ;skip this part if moving downwards or not at all
d565: 8a txa
d566: 18 clc
d567: 69 08 adc #$08 ;add eight to vertical coordinate and
d569: aa tax ; save as X
d56a: 8a GetHRp txa ;move vertical coordinate to A
d56b: ae 00 03 ldx VRAM_Buffer1_Offset ;get vram buffer offset
d56e: 0a asl A
d56f: 2a rol A ;rotate d7 to d0 and d6 into carry
d570: 48 pha ;save modified vertical coordinate to stack
d571: 2a rol A ;rotate carry to d0, thus d7 and d6 are at 2 LSB
d572: 29 03 and #%00000011 ;mask out all bits but d7 and d6, then set
d574: 09 20 ora #%00100000 ; d5 to get appropriate high byte of name table
d576: 85 01 sta $01 ; address, then store
d578: a5 02 lda $02 ;get saved page location from earlier
d57a: 29 01 and #$01 ;mask out all but LSB
d57c: 0a asl A
d57d: 0a asl A ;shift twice to the left and save with the
d57e: 05 01 ora $01 ; rest of the bits of the high byte, to get
d580: 85 01 sta $01 ; the proper name table and the right place on it
d582: 68 pla ;get modified vertical coordinate from stack
d583: 29 e0 and #%11100000 ;mask out low nybble and LSB of high nybble
d585: 18 clc
d586: 65 00 adc $00 ;add to horizontal part saved here
d588: 85 00 sta $00 ;save as name table low byte
d58a: b9 cf 00 lda Enemy_Y_Position,y
d58d: c9 e8 cmp #$e8 ;if vertical position not below the
d58f: 90 06 bcc ExPRp ; bottom of the screen, we're done, branch to leave
d591: a5 00 lda $00
d593: 29 bf and #%10111111 ;mask out d6 of low byte of name table address
d595: 85 00 sta $00
d597: 60 ExPRp rts ;leave!
InitPlatformFall
d598: 98 tya ;move offset of other platform from Y to X
d599: aa tax
d59a: 20 af f1 jsr GetEnemyOffscreenBits ;get offscreen bits
d59d: a9 06 lda #$06
d59f: 20 11 da jsr SetupFloateyNumber ;award 1000 points to player
d5a2: ad ad 03 lda Player_Rel_XPos
d5a5: 9d 17 01 sta FloateyNum_X_Pos,x ;put floatey number coordinates where player is
d5a8: a5 ce lda Player_Y_Position
d5aa: 9d 1e 01 sta FloateyNum_Y_Pos,x
d5ad: a9 01 lda #$01 ;set moving direction as flag for
d5af: 95 46 sta Enemy_MovingDir,x ; falling platforms
d5b1: 20 63 c3 StopPlatforms jsr InitVStf ;initialize vertical speed and low byte
d5b4: 99 a0 00 sta Enemy_Y_Speed,y ; for both platforms and leave
d5b7: 99 34 04 sta Enemy_Y_MoveForce,y
d5ba: 60 rts
d5bb: 98 PlatformFall tya ;save offset for other platform to stack
d5bc: 48 pha
d5bd: 20 6b bf jsr MoveFallingPlatform ;make current platform fall
d5c0: 68 pla
d5c1: aa tax ;pull offset from stack and save to X
d5c2: 20 6b bf jsr MoveFallingPlatform ;make other platform fall
d5c5: a6 08 ldx ObjectOffset
d5c7: bd a2 03 lda PlatformCollisionFlag,x ;if player not standing on either platform,
d5ca: 30 04 bmi ExPF ; skip this part
d5cc: aa tax ;transfer collision flag offset as offset to X
d5cd: 20 21 dc jsr PositionPlayerOnVPlat ; and position player appropriately
d5d0: a6 08 ExPF ldx ObjectOffset ;get enemy object buffer offset and leave
d5d2: 60 rts
; -----------------------------------------------------------------------------
d5d3: b5 a0 YMovingPlatform lda Enemy_Y_Speed,x ;if platform moving up or down, skip ahead to
d5d5: 1d 34 04 ora Enemy_Y_MoveForce,x ; check on other position
d5d8: d0 15 bne ChkYCenterPos
d5da: 9d 17 04 sta Enemy_YMF_Dummy,x ;initialize dummy variable
d5dd: b5 cf lda Enemy_Y_Position,x
d5df: dd 01 04 cmp YPlatformTopYPos,x ;if current vertical position => top position, branch
d5e2: b0 0b bcs ChkYCenterPos ; ahead of all this
d5e4: a5 09 lda FrameCounter
d5e6: 29 07 and #%00000111 ;check for every eighth frame
d5e8: d0 02 bne SkipIY
d5ea: f6 cf inc Enemy_Y_Position,x ;increase vertical position every eighth frame
d5ec: 4c fe d5 SkipIY jmp ChkYPCollision ;skip ahead to last part
d5ef: b5 cf ChkYCenterPos lda Enemy_Y_Position,x ;if current vertical position < central position, branch
d5f1: d5 58 cmp YPlatformCenterYPos,x ; to slow ascent/move downwards
d5f3: 90 06 bcc YMDown
d5f5: 20 b7 bf jsr MovePlatformUp ;otherwise start slowing descent/moving upwards
d5f8: 4c fe d5 jmp ChkYPCollision
d5fb: 20 b4 bf YMDown jsr MovePlatformDown ;start slowing ascent/moving downwards
d5fe: bd a2 03 ChkYPCollision lda HammerThrowingTimer,x ;if collision flag not set here, branch
d601: 30 03 bmi ExYPl ; to leave
d603: 20 21 dc jsr PositionPlayerOnVPlat ;otherwise position player appropriately
d606: 60 ExYPl rts ;leave
; -----------------------------------------------------------------------------
; $00 - used as adder to position player hotizontally
d607: a9 0e XMovingPlatform lda #$0e ;load preset maximum value for secondary counter
d609: 20 47 cb jsr XMoveCntr_Platform ;do a sub to increment counters for movement
d60c: 20 66 cb jsr MoveWithXMCntrs ;do a sub to move platform accordingly, and return value
d60f: bd a2 03 lda PlatformCollisionFlag,x ;if no collision with player,
d612: 30 1c bmi ExXMP ; branch ahead to leave
PositionPlayerOnHPlat
d614: a5 86 lda Player_X_Position
d616: 18 clc ;add saved value from second subroutine to
d617: 65 00 adc $00 ; current player's position to position
d619: 85 86 sta Player_X_Position ; player accordingly in horizontal position
d61b: a5 6d lda Player_PageLoc ;get player's page location
d61d: a4 00 ldy $00 ;check to see if saved value here is positive or negative
d61f: 30 05 bmi PPHSubt ;if negative, branch to subtract
d621: 69 00 adc #$00 ;otherwise add carry to page location
d623: 4c 28 d6 jmp SetPVar ;jump to skip subtraction
d626: e9 00 PPHSubt sbc #$00 ;subtract borrow from page location
d628: 85 6d SetPVar sta Player_PageLoc ;save result to player's page location
d62a: 8c a1 03 sty Platform_X_Scroll ;put saved value from second sub here to be used later
d62d: 20 21 dc jsr PositionPlayerOnVPlat ;position player vertically and appropriately
d630: 60 ExXMP rts ;and we are done here
; -----------------------------------------------------------------------------
d631: bd a2 03 DropPlatform lda PlatformCollisionFlag,x ;if no collision between platform and player
d634: 30 06 bmi ExDPl ; occurred, just leave without moving anything
d636: 20 88 bf jsr MoveDropPlatform ;otherwise do a sub to move platform down very quickly
d639: 20 21 dc jsr PositionPlayerOnVPlat ;do a sub to position player appropriately
d63c: 60 ExDPl rts ;leave
; -----------------------------------------------------------------------------
; $00 - residual value from sub
d63d: 20 02 bf RightPlatform jsr MoveEnemyHorizontally ;move platform with current horizontal speed, if any
d640: 85 00 sta $00 ;store saved value here (residual code)
d642: bd a2 03 lda PlatformCollisionFlag,x ;check collision flag, if no collision between player
d645: 30 07 bmi ExRPl ; and platform, branch ahead, leave speed unaltered
d647: a9 10 lda #$10
d649: 95 58 sta Enemy_X_Speed,x ;otherwise set new speed (gets moving if motionless)
d64b: 20 14 d6 jsr PositionPlayerOnHPlat ;use saved value from earlier sub to position player
d64e: 60 ExRPl rts ;then leave
; -----------------------------------------------------------------------------
MoveLargeLiftPlat
d64f: 20 5b d6 jsr MoveLiftPlatforms ;execute common to all large and small lift platforms
d652: 4c fe d5 jmp ChkYPCollision ;branch to position player correctly
MoveSmallPlatform
d655: 20 5b d6 jsr MoveLiftPlatforms ;execute common to all large and small lift platforms
d658: 4c 71 d6 jmp ChkSmallPlatCollision ;branch to position player correctly
MoveLiftPlatforms
d65b: ad 47 07 lda TimerControl ;if master timer control set, skip all of this
d65e: d0 19 bne ExLiftP ; and branch to leave
d660: bd 17 04 lda Enemy_YMF_Dummy,x
d663: 18 clc ;add contents of movement amount to whatever's here
d664: 7d 34 04 adc Enemy_Y_MoveForce,x
d667: 9d 17 04 sta Enemy_YMF_Dummy,x
d66a: b5 cf lda Enemy_Y_Position,x ;add whatever vertical speed is set to current
d66c: 75 a0 adc Enemy_Y_Speed,x ; vertical position plus carry to move up or down
d66e: 95 cf sta Enemy_Y_Position,x ; and then leave
d670: 60 rts
ChkSmallPlatCollision
d671: bd a2 03 lda PlatformCollisionFlag,x ;get bounding box counter saved in collision flag
d674: f0 03 beq ExLiftP ;if none found, leave player position alone
d676: 20 19 dc jsr PositionPlayerOnS_Plat ;use to position player correctly
d679: 60 ExLiftP rts ;then leave
; -----------------------------------------------------------------------------
; $00 - page location of extended left boundary
; $01 - extended left boundary position
; $02 - page location of extended right boundary
; $03 - extended right boundary position
OffscreenBoundsCheck
d67a: b5 16 lda Enemy_ID,x ;check for cheep-cheep object
d67c: c9 14 cmp #FlyingCheepCheep ;branch to leave if found
d67e: f0 55 beq ExScrnBd
d680: ad 1c 07 lda ScreenLeft_X_Pos ;get horizontal coordinate for left side of screen
d683: b4 16 ldy Enemy_ID,x
d685: c0 05 cpy #HammerBro ;check for hammer bro object
d687: f0 04 beq LimitB
d689: c0 0d cpy #PiranhaPlant ;check for piranha plant object
d68b: d0 02 bne ExtendLB ;these two will be erased sooner than others if too far left
d68d: 69 38 LimitB adc #56 ;add 56 pixels to coordinate if hammer bro or piranha plant
d68f: e9 48 ExtendLB sbc #72 ;subtract 72 pixels regardless of enemy object
d691: 85 01 sta $01 ;store result here
d693: ad 1a 07 lda ScreenLeft_PageLoc
d696: e9 00 sbc #$00 ;subtract borrow from page location of left side
d698: 85 00 sta $00 ;store result here
d69a: ad 1d 07 lda ScreenRight_X_Pos ;add 72 pixels to the right side horizontal coordinate
d69d: 69 48 adc #72
d69f: 85 03 sta $03 ;store result here
d6a1: ad 1b 07 lda ScreenRight_PageLoc
d6a4: 69 00 adc #$00 ;then add the carry to the page location
d6a6: 85 02 sta $02 ;and store result here
d6a8: b5 87 lda Enemy_X_Position,x ;compare horizontal coordinate of the enemy object
d6aa: c5 01 cmp $01 ; to modified horizontal left edge coordinate to get carry
d6ac: b5 6e lda Enemy_PageLoc,x
d6ae: e5 00 sbc $00 ;then subtract it from the page coordinate of the enemy object
d6b0: 30 20 bmi TooFar ;if enemy object is too far left, branch to erase it
d6b2: b5 87 lda Enemy_X_Position,x ;compare horizontal coordinate of the enemy object
d6b4: c5 03 cmp $03 ;to modified horizontal right edge coordinate to get carry
d6b6: b5 6e lda Enemy_PageLoc,x
d6b8: e5 02 sbc $02 ;then subtract it from the page coordinate of the enemy object
d6ba: 30 19 bmi ExScrnBd ;if enemy object is on the screen, leave, do not erase enemy
d6bc: b5 1e lda Enemy_State,x ;if at this point, enemy is offscreen to the right, so check
d6be: c9 05 cmp #HammerBro ;if in state used by spiny's egg, do not erase
d6c0: f0 13 beq ExScrnBd
d6c2: c0 0d cpy #PiranhaPlant ;if piranha plant, do not erase
d6c4: f0 0f beq ExScrnBd
d6c6: c0 30 cpy #FlagpoleFlagObject ;if flagpole flag, do not erase
d6c8: f0 0b beq ExScrnBd
d6ca: c0 31 cpy #StarFlagObject ;if star flag, do not erase
d6cc: f0 07 beq ExScrnBd
d6ce: c0 32 cpy #JumpspringObject ;if jumpspring, do not erase
d6d0: f0 03 beq ExScrnBd ;erase all others too far to the right
d6d2: 20 98 c9 TooFar jsr EraseEnemyObject ;erase object if necessary
d6d5: 60 ExScrnBd rts ;leave
; -----------------------------------------------------------------------------
; some unused space
d6d6: ff ff ff .bulk $ff,$ff,$ff
; -----------------------------------------------------------------------------
; $01 - enemy buffer offset
FireballEnemyCollision
d6d9: b5 24 lda Fireball_State,x ;check to see if fireball state is set at all
d6db: f0 56 beq ExitFBallEnemy ;branch to leave if not
d6dd: 0a asl A
d6de: b0 53 bcs ExitFBallEnemy ;branch to leave also if d7 in state is set
d6e0: a5 09 lda FrameCounter
d6e2: 4a lsr A ;get LSB of frame counter
d6e3: b0 4e bcs ExitFBallEnemy ;branch to leave if set (do routine every other frame)
d6e5: 8a txa
d6e6: 0a asl A ;multiply fireball offset by four
d6e7: 0a asl A
d6e8: 18 clc
d6e9: 69 1c adc #$1c ;then add $1c or 28 bytes to it
d6eb: a8 tay ; to use fireball's bounding box coordinates
d6ec: a2 04 ldx #$04
FireballEnemyCDLoop
d6ee: 86 01 stx $01 ;store enemy object offset here
d6f0: 98 tya
d6f1: 48 pha ;push fireball offset to the stack
d6f2: b5 1e lda Enemy_State,x
d6f4: 29 20 and #%00100000 ;check to see if d5 is set in enemy state
d6f6: d0 34 bne NoFToECol ;if so, skip to next enemy slot
d6f8: b5 0f lda Enemy_Flag,x ;check to see if buffer flag is set
d6fa: f0 30 beq NoFToECol ;if not, skip to next enemy slot
d6fc: b5 16 lda Enemy_ID,x ;check enemy identifier
d6fe: c9 24 cmp #$24
d700: 90 04 bcc GoombaDie ;if < $24, branch to check further
d702: c9 2b cmp #$2b
d704: 90 26 bcc NoFToECol ;if in range $24-$2a, skip to next enemy slot
d706: c9 06 GoombaDie cmp #Goomba ;check for goomba identifier
d708: d0 06 bne NoGoomba ;if not found, continue with code
d70a: b5 1e lda Enemy_State,x ;otherwise check for defeated state
d70c: c9 02 cmp #$02 ;if stomped or otherwise defeated,
d70e: b0 1c bcs NoFToECol ; skip to next enemy slot
d710: bd d8 03 NoGoomba lda EnemyOffscrBitsMasked,x ;if any masked offscreen bits set,
d713: d0 17 bne NoFToECol ; skip to next enemy slot
d715: 8a txa
d716: 0a asl A ;otherwise multiply enemy offset by four
d717: 0a asl A
d718: 18 clc
d719: 69 04 adc #$04 ;add 4 bytes to it
d71b: aa tax ;to use enemy's bounding box coordinates
d71c: 20 27 e3 jsr SprObjectCollisionCore ;do fireball-to-enemy collision detection
d71f: a6 08 ldx ObjectOffset ;return fireball's original offset
d721: 90 09 bcc NoFToECol ;if carry clear, no collision, thus do next enemy slot
d723: a9 80 lda #%10000000
d725: 95 24 sta Fireball_State,x ;set d7 in enemy state
d727: a6 01 ldx $01 ;get enemy offset
d729: 20 3e d7 jsr HandleEnemyFBallCol ;jump to handle fireball to enemy collision
d72c: 68 NoFToECol pla ;pull fireball offset from stack
d72d: a8 tay ;put it in Y
d72e: a6 01 ldx $01 ;get enemy object offset
d730: ca dex ;decrement it
d731: 10 bb bpl FireballEnemyCDLoop ;loop back until collision detection done on all enemies
d733: a6 08 ExitFBallEnemy ldx ObjectOffset ;get original fireball offset and leave
d735: 60 rts
BowserIdentities
d736: 06 .dd1 Goomba
d737: 00 .dd1 GreenKoopa
d738: 02 .dd1 BuzzyBeetle
d739: 12 .dd1 Spiny
d73a: 11 .dd1 Lakitu
d73b: 07 .dd1 Bloober
d73c: 05 .dd1 HammerBro
d73d: 2d .dd1 Bowser
HandleEnemyFBallCol
d73e: 20 52 f1 jsr RelativeEnemyPosition ;get relative coordinate of enemy
d741: a6 01 ldx $01 ;get current enemy object offset
d743: b5 0f lda Enemy_Flag,x ;check buffer flag for d7 set
d745: 10 0b bpl ChkBuzzyBeetle ;branch if not set to continue
d747: 29 0f and #%00001111 ;otherwise mask out high nybble and
d749: aa tax ; use low nybble as enemy offset
d74a: b5 16 lda Enemy_ID,x
d74c: c9 2d cmp #Bowser ;check enemy identifier for bowser
d74e: f0 0c beq HurtBowser ;branch if found
d750: a6 01 ldx $01 ;otherwise retrieve current enemy offset
d752: b5 16 ChkBuzzyBeetle lda Enemy_ID,x
d754: c9 02 cmp #BuzzyBeetle ;check for buzzy beetle
d756: f0 6b beq ExHCF ;branch if found to leave (buzzy beetles fireproof)
d758: c9 2d cmp #Bowser ;check for bowser one more time (necessary if d7 of flag was clear)
d75a: d0 2d bne ChkOtherEnemies ;if not found, branch to check other enemies
d75c: ce 83 04 HurtBowser dec BowserHitPoints ;decrement bowser's hit points
d75f: d0 62 bne ExHCF ;if bowser still has hit points, branch to leave
d761: 20 63 c3 jsr InitVStf ;otherwise do sub to init vertical speed and movement force
d764: 95 58 sta Enemy_X_Speed,x ;initialize horizontal speed
d766: 8d cb 06 sta EnemyFrenzyBuffer ;init enemy frenzy buffer
d769: a9 fe lda #$fe
d76b: 95 a0 sta Enemy_Y_Speed,x ;set vertical speed to make defeated bowser jump a little
d76d: ac 5f 07 ldy WorldNumber ;use world number as offset
d770: b9 36 d7 lda BowserIdentities,y ;get enemy identifier to replace bowser with
d773: 95 16 sta Enemy_ID,x ;set as new enemy identifier
d775: a9 20 lda #$20 ;set A to use starting value for state
d777: c0 03 cpy #$03 ;check to see if using offset of 3 or more
d779: b0 02 bcs SetDBSte ;branch if so
d77b: 09 03 ora #$03 ;otherwise add 3 to enemy state
d77d: 95 1e SetDBSte sta Enemy_State,x ;set defeated enemy state
d77f: a9 80 lda #Sfx_BowserFall
d781: 85 fe sta Square2SoundQueue ;load bowser defeat sound
d783: a6 01 ldx $01 ;get enemy offset
d785: a9 09 lda #$09 ;award 5000 points to player for defeating bowser
d787: d0 33 bne EnemySmackCore ;unconditional branch to award points
d789: c9 08 ChkOtherEnemies cmp #BulletBill_FrenzyVar
d78b: f0 36 beq ExHCF ;branch to leave if bullet bill (frenzy variant)
d78d: c9 0c cmp #Podoboo
d78f: f0 32 beq ExHCF ;branch to leave if podoboo
d791: c9 15 cmp #$15
d793: b0 2e bcs ExHCF ;branch to leave if identifier => $15
ShellOrBlockDefeat
d795: b5 16 lda Enemy_ID,x ;check for piranha plant
d797: c9 0d cmp #PiranhaPlant
d799: d0 06 bne StnE ;branch if not found
d79b: b5 cf lda Enemy_Y_Position,x
d79d: 69 18 adc #$18 ;add 24 pixels to enemy object's vertical position
d79f: 95 cf sta Enemy_Y_Position,x
d7a1: 20 1b e0 StnE jsr ChkToStunEnemies ;do yet another sub
d7a4: b5 1e lda Enemy_State,x
d7a6: 29 1f and #%00011111 ;mask out 2 MSB of enemy object's state
d7a8: 09 20 ora #%00100000 ;set d5 to defeat enemy and save as new state
d7aa: 95 1e sta Enemy_State,x
d7ac: a9 02 lda #$02 ;award 200 points by default
d7ae: b4 16 ldy Enemy_ID,x ;check for hammer bro
d7b0: c0 05 cpy #HammerBro
d7b2: d0 02 bne GoombaPoints ;branch if not found
d7b4: a9 06 lda #$06 ;award 1000 points for hammer bro
d7b6: c0 06 GoombaPoints cpy #Goomba ;check for goomba
d7b8: d0 02 bne EnemySmackCore ;branch if not found
d7ba: a9 01 lda #$01 ;award 100 points for goomba
d7bc: 20 11 da EnemySmackCore jsr SetupFloateyNumber ;update necessary score variables
d7bf: a9 08 lda #Sfx_EnemySmack ;play smack enemy sound
d7c1: 85 ff sta Square1SoundQueue
d7c3: 60 ExHCF rts ;and now let's leave
; -----------------------------------------------------------------------------
PlayerHammerCollision
d7c4: a5 09 lda FrameCounter ;get frame counter
d7c6: 4a lsr A ;shift d0 into carry
d7c7: 90 36 bcc ExPHC ;branch to leave if d0 not set to execute every other frame
d7c9: ad 47 07 lda TimerControl ;if either master timer control
d7cc: 0d d6 03 ora Misc_OffscreenBits ; or any offscreen bits for hammer are set,
d7cf: d0 2e bne ExPHC ; branch to leave
d7d1: 8a txa
d7d2: 0a asl A ;multiply misc object offset by four
d7d3: 0a asl A
d7d4: 18 clc
d7d5: 69 24 adc #$24 ;add 36 or $24 bytes to get proper offset
d7d7: a8 tay ;for misc object bounding box coordinates
d7d8: 20 25 e3 jsr PlayerCollisionCore ;do player-to-hammer collision detection
d7db: a6 08 ldx ObjectOffset ;get misc object offset
d7dd: 90 1b bcc ClHCol ;if no collision, then branch
d7df: bd be 06 lda Misc_Collision_Flag,x ;otherwise read collision flag
d7e2: d0 1b bne ExPHC ;if collision flag already set, branch to leave
d7e4: a9 01 lda #$01
d7e6: 9d be 06 sta Misc_Collision_Flag,x ;otherwise set collision flag now
d7e9: b5 64 lda Misc_X_Speed,x
d7eb: 49 ff eor #$ff ;get two's compliment of
d7ed: 18 clc ; hammer's horizontal speed
d7ee: 69 01 adc #$01
d7f0: 95 64 sta Misc_X_Speed,x ;set to send hammer flying the opposite direction
d7f2: ad 9f 07 lda StarInvincibleTimer ;if star mario invincibility timer set,
d7f5: d0 08 bne ExPHC ; branch to leave
d7f7: 4c 2c d9 jmp InjurePlayer ;otherwise jump to hurt player, do not return
d7fa: a9 00 ClHCol lda #$00 ;clear collision flag
d7fc: 9d be 06 sta Misc_Collision_Flag,x
d7ff: 60 ExPHC rts
; -----------------------------------------------------------------------------
HandlePowerUpCollision
d800: 20 98 c9 jsr EraseEnemyObject ;erase the power-up object
d803: a9 06 lda #$06
d805: 20 11 da jsr SetupFloateyNumber ;award 1000 points to player by default
d808: a9 20 lda #Sfx_PowerUpGrab
d80a: 85 fe sta Square2SoundQueue ;play the power-up sound
d80c: a5 39 lda PowerUpType ;check power-up type
d80e: c9 02 cmp #$02
d810: 90 0e bcc Shroom_Flower_PUp ;if mushroom or fire flower, branch
d812: c9 03 cmp #$03
d814: f0 24 beq SetFor1Up ;if 1-up mushroom, branch
d816: a9 23 lda #$23 ;otherwise set star mario invincibility
d818: 8d 9f 07 sta StarInvincibleTimer ; timer, and load the star mario music
d81b: a9 40 lda #StarPowerMusic ; into the area music queue, then leave
d81d: 85 fb sta AreaMusicQueue
d81f: 60 rts
Shroom_Flower_PUp
d820: ad 56 07 lda PlayerStatus ;if player status = small, branch
d823: f0 1b beq UpToSuper
d825: c9 01 cmp #$01 ;if player status not super, leave
d827: d0 23 bne NoPUp
d829: a6 08 ldx ObjectOffset ;get enemy offset, not necessary
d82b: a9 02 lda #$02 ;set player status to fiery
d82d: 8d 56 07 sta PlayerStatus
d830: 20 f1 85 jsr GetPlayerColors ;run sub to change colors of player
d833: a6 08 ldx ObjectOffset ;get enemy offset again, and again not necessary
d835: a9 0c lda #$0c ;set value to be used by subroutine tree (fiery)
d837: 4c 47 d8 jmp UpToFiery ;jump to set values accordingly
d83a: a9 0b SetFor1Up lda #$0b ;change 1000 points into 1-up instead
d83c: 9d 10 01 sta FloateyNum_Control,x ; and then leave
d83f: 60 rts
d840: a9 01 UpToSuper lda #$01 ;set player status to super
d842: 8d 56 07 sta PlayerStatus
d845: a9 09 lda #$09 ;set value to be used by subroutine tree (super)
d847: a0 00 UpToFiery ldy #$00 ;set value to be used as new player state
d849: 20 48 d9 jsr SetPRout ;set values to stop certain things in motion
d84c: 60 NoPUp rts
; -----------------------------------------------------------------------------
ResidualXSpdData
d84d: 18 e8 .bulk $18,$e8
KickedShellXSpdData
d84f: 30 d0 .bulk $30,$d0
DemotedKoopaXSpdData
d851: 08 f8 .bulk $08,$f8
PlayerEnemyCollision
d853: a5 09 lda FrameCounter ;check counter for d0 set
d855: 4a lsr A
d856: b0 f4 bcs NoPUp ;if set, branch to leave
d858: 20 41 dc jsr CheckPlayerVertical ;if player object is completely offscreen or
d85b: b0 23 bcs NoPECol ; if down past 224th pixel row, branch to leave
d85d: bd d8 03 lda EnemyOffscrBitsMasked,x ;if current enemy is offscreen by any amount,
d860: d0 1e bne NoPECol ; go ahead and branch to leave
d862: a5 0e lda GameEngineSubroutine
d864: c9 08 cmp #$08 ;if not set to run player control routine
d866: d0 18 bne NoPECol ; on next frame, branch to leave
d868: b5 1e lda Enemy_State,x
d86a: 29 20 and #%00100000 ;if enemy state has d5 set, branch to leave
d86c: d0 12 bne NoPECol
d86e: 20 52 dc jsr GetEnemyBoundBoxOfs ;get bounding box offset for current enemy object
d871: 20 25 e3 jsr PlayerCollisionCore ;do collision detection on player vs. enemy
d874: a6 08 ldx ObjectOffset ;get enemy object buffer offset
d876: b0 09 bcs ChkForPUpCollision ;if collision, branch past this part here
d878: bd 91 04 lda Enemy_CollisionBits,x
d87b: 29 fe and #%11111110 ;otherwise, clear d0 of current enemy object's
d87d: 9d 91 04 sta Enemy_CollisionBits,x ; collision bit
d880: 60 NoPECol rts
ChkForPUpCollision
d881: b4 16 ldy Enemy_ID,x
d883: c0 2e cpy #PowerUpObject ;check for power-up object
d885: d0 03 bne EColl ;if not found, branch to next part
d887: 4c 00 d8 jmp HandlePowerUpCollision ;otherwise, unconditional jump backwards
d88a: ad 9f 07 EColl lda StarInvincibleTimer ;if star mario invincibility timer expired,
d88d: f0 06 beq HandlePECollisions ; perform task here, otherwise kill enemy like
d88f: 4c 95 d7 jmp ShellOrBlockDefeat ; hit with a shell, or from beneath
KickedShellPtsData
d892: 0a 06 04 .bulk $0a,$06,$04
HandlePECollisions
d895: bd 91 04 lda Enemy_CollisionBits,x ;check enemy collision bits for d0 set
d898: 29 01 and #%00000001 ;or for being offscreen at all
d89a: 1d d8 03 ora EnemyOffscrBitsMasked,x
d89d: d0 59 bne ExPEC ;branch to leave if either is true
d89f: a9 01 lda #$01
d8a1: 1d 91 04 ora Enemy_CollisionBits,x ;otherwise set d0 now
d8a4: 9d 91 04 sta Enemy_CollisionBits,x
d8a7: c0 12 cpy #Spiny ;branch if spiny
d8a9: f0 4e beq ChkForPlayerInjury
d8ab: c0 0d cpy #PiranhaPlant ;branch if piranha plant
d8ad: f0 7d beq InjurePlayer
d8af: c0 0c cpy #Podoboo ;branch if podoboo
d8b1: f0 79 beq InjurePlayer
d8b3: c0 33 cpy #BulletBill_CannonVar ;branch if bullet bill
d8b5: f0 42 beq ChkForPlayerInjury
d8b7: c0 15 cpy #$15 ;branch if object => $15
d8b9: b0 71 bcs InjurePlayer
d8bb: ad 4e 07 lda AreaType ;branch if water type level
d8be: f0 6c beq InjurePlayer
d8c0: b5 1e lda Enemy_State,x ;branch if d7 of enemy state was set
d8c2: 0a asl A
d8c3: b0 34 bcs ChkForPlayerInjury
d8c5: b5 1e lda Enemy_State,x ;mask out all but 3 LSB of enemy state
d8c7: 29 07 and #%00000111
d8c9: c9 02 cmp #$02 ;branch if enemy is in normal or falling state
d8cb: 90 2c bcc ChkForPlayerInjury
d8cd: b5 16 lda Enemy_ID,x ;branch to leave if goomba in defeated state
d8cf: c9 06 cmp #$06
d8d1: f0 25 beq ExPEC
d8d3: a9 08 lda #Sfx_EnemySmack ;play smack enemy sound
d8d5: 85 ff sta Square1SoundQueue
d8d7: b5 1e lda Enemy_State,x ;set d7 in enemy state, thus become moving shell
d8d9: 09 80 ora #%10000000
d8db: 95 1e sta Enemy_State,x
d8dd: 20 05 da jsr EnemyFacePlayer ;set moving direction and get offset
d8e0: b9 4f d8 lda KickedShellXSpdData,y ;load and set horizontal speed data with offset
d8e3: 95 58 sta Enemy_X_Speed,x
d8e5: a9 03 lda #$03 ;add three to whatever the stomp counter contains
d8e7: 18 clc ; to give points for kicking the shell
d8e8: 6d 84 04 adc StompChainCounter
d8eb: bc 96 07 ldy EnemyIntervalTimer,x ;check shell enemy's timer
d8ee: c0 03 cpy #$03 ;if above a certain point, branch using the points
d8f0: b0 03 bcs KSPts ; data obtained from the stomp counter + 3
d8f2: b9 92 d8 lda KickedShellPtsData,y ;otherwise, set points based on proximity to timer expiration
d8f5: 20 11 da KSPts jsr SetupFloateyNumber ;set values for floatey number now
d8f8: 60 ExPEC rts ;leave!!!
ChkForPlayerInjury
d8f9: a5 9f lda Player_Y_Speed ;check player's vertical speed
d8fb: 30 02 bmi ChkInj ;perform procedure below if player moving upwards
d8fd: d0 6a bne EnemyStomped ;or not at all, and branch elsewhere if moving downwards
d8ff: b5 16 ChkInj lda Enemy_ID,x ;branch if enemy object < $07
d901: c9 07 cmp #Bloober
d903: 90 09 bcc ChkETmrs
d905: a5 ce lda Player_Y_Position ;add 12 pixels to player's vertical position
d907: 18 clc
d908: 69 0c adc #$0c
d90a: d5 cf cmp Enemy_Y_Position,x ;compare modified player's position to enemy's position
d90c: 90 5b bcc EnemyStomped ;branch if this player's position above (less than) enemy's
d90e: ad 91 07 ChkETmrs lda StompTimer ;check stomp timer
d911: d0 56 bne EnemyStomped ;branch if set
d913: ad 9e 07 lda InjuryTimer ;check to see if injured invincibility timer still
d916: d0 3d bne ExInjColRoutines ;counting down, and branch elsewhere to leave if so
d918: ad ad 03 lda Player_Rel_XPos
d91b: cd ae 03 cmp Enemy_Rel_XPos ;if player's relative position to the left of enemy's
d91e: 90 03 bcc TInjE ;relative position, branch here
d920: 4c f6 d9 jmp ChkEnemyFaceRight ;otherwise do a jump here
d923: b5 46 TInjE lda Enemy_MovingDir,x ;if enemy moving towards the left,
d925: c9 01 cmp #$01 ; branch, otherwise do a jump here
d927: d0 03 bne InjurePlayer ; to turn the enemy around
d929: 4c ff d9 jmp LInj
d92c: ad 9e 07 InjurePlayer lda InjuryTimer ;check again to see if injured invincibility timer is
d92f: d0 24 bne ExInjColRoutines ; at zero, and branch to leave if so
;
d931: ae 56 07 ForceInjury ldx PlayerStatus ;check player's status
d934: f0 22 beq KillPlayer ;branch if small
d936: 8d 56 07 sta PlayerStatus ;otherwise set player's status to small
d939: a9 08 lda #$08
d93b: 8d 9e 07 sta InjuryTimer ;set injured invincibility timer
d93e: 0a asl A
d93f: 85 ff sta Square1SoundQueue ;play pipedown/injury sound
d941: 20 f1 85 jsr GetPlayerColors ;change player's palette if necessary
d944: a9 0a lda #$0a ;set subroutine to run on next frame
d946: a0 01 SetKRout ldy #$01 ;set new player state
d948: 85 0e SetPRout sta GameEngineSubroutine ;load new value to run subroutine on next frame
d94a: 84 1d sty Player_State ;store new player state
d94c: a0 ff ldy #$ff
d94e: 8c 47 07 sty TimerControl ;set master timer control flag to halt timers
d951: c8 iny
d952: 8c 75 07 sty ScrollAmount ;initialize scroll speed
ExInjColRoutines
d955: a6 08 ldx ObjectOffset ;get enemy offset and leave
d957: 60 rts
d958: 86 57 KillPlayer stx Player_X_Speed ;halt player's horizontal movement by initializing speed
d95a: e8 inx
d95b: 86 fc stx EventMusicQueue ;set event music queue to death music
d95d: a9 fc lda #$fc
d95f: 85 9f sta Player_Y_Speed ;set new vertical speed
d961: a9 0b lda #$0b ;set subroutine to run on next frame
d963: d0 e1 bne SetKRout ;branch to set player's state and other things
StompedEnemyPtsData
d965: 02 06 05 06 .bulk $02,$06,$05,$06
d969: b5 16 EnemyStomped lda Enemy_ID,x ;check for spiny, branch to hurt player
d96b: c9 12 cmp #Spiny ; if found
d96d: f0 bd beq InjurePlayer
d96f: a9 04 lda #Sfx_EnemyStomp ;otherwise play stomp/swim sound
d971: 85 ff sta Square1SoundQueue
d973: b5 16 lda Enemy_ID,x
d975: a0 00 ldy #$00 ;initialize points data offset for stomped enemies
d977: c9 14 cmp #FlyingCheepCheep ;branch for cheep-cheep
d979: f0 1b beq EnemyStompedPts
d97b: c9 08 cmp #BulletBill_FrenzyVar ;branch for either bullet bill object
d97d: f0 17 beq EnemyStompedPts
d97f: c9 33 cmp #BulletBill_CannonVar
d981: f0 13 beq EnemyStompedPts
d983: c9 0c cmp #Podoboo ;branch for podoboo (this branch is logically impossible
d985: f0 0f beq EnemyStompedPts ; for cpu to take due to earlier checking of podoboo)
d987: c8 iny ;increment points data offset
d988: c9 05 cmp #HammerBro ;branch for hammer bro
d98a: f0 0a beq EnemyStompedPts
d98c: c8 iny ;increment points data offset
d98d: c9 11 cmp #Lakitu ;branch for lakitu
d98f: f0 05 beq EnemyStompedPts
d991: c8 iny ;increment points data offset
d992: c9 07 cmp #Bloober ;branch if NOT bloober
d994: d0 1d bne ChkForDemoteKoopa
d996: b9 65 d9 EnemyStompedPts lda StompedEnemyPtsData,y ;load points data using offset in Y
d999: 20 11 da jsr SetupFloateyNumber ;run sub to set floatey number controls
d99c: b5 46 lda Enemy_MovingDir,x
d99e: 48 pha ;save enemy movement direction to stack
d99f: 20 2f e0 jsr SetStun ;run sub to kill enemy
d9a2: 68 pla
d9a3: 95 46 sta Enemy_MovingDir,x ;return enemy movement direction from stack
d9a5: a9 20 lda #%00100000
d9a7: 95 1e sta Enemy_State,x ;set d5 in enemy state
d9a9: 20 63 c3 jsr InitVStf ;nullify vertical speed, physics-related thing,
d9ac: 95 58 sta Enemy_X_Speed,x ; and horizontal speed
d9ae: a9 fd lda #$fd ;set player's vertical speed, to give bounce
d9b0: 85 9f sta Player_Y_Speed
d9b2: 60 rts
ChkForDemoteKoopa
d9b3: c9 09 cmp #$09 ;branch elsewhere if enemy object < $09
d9b5: 90 1d bcc HandleStompedShellE
d9b7: 29 01 and #%00000001 ;demote koopa paratroopas to ordinary troopas
d9b9: 95 16 sta Enemy_ID,x
d9bb: a0 00 ldy #$00 ;return enemy to normal state
d9bd: 94 1e sty Enemy_State,x
d9bf: a9 03 lda #$03 ;award 400 points to the player
d9c1: 20 11 da jsr SetupFloateyNumber
d9c4: 20 63 c3 jsr InitVStf ;nullify physics-related thing and vertical speed
d9c7: 20 05 da jsr EnemyFacePlayer ;turn enemy around if necessary
d9ca: b9 51 d8 lda DemotedKoopaXSpdData,y
d9cd: 95 58 sta Enemy_X_Speed,x ;set appropriate moving speed based on direction
d9cf: 4c f1 d9 jmp SBnce ;then move onto something else
d9d2: 10 0b RevivalRateData .bulk $10,$0b
HandleStompedShellE
d9d4: a9 04 lda #$04 ;set defeated state for enemy
d9d6: 95 1e sta Enemy_State,x
d9d8: ee 84 04 inc StompChainCounter ;increment the stomp counter
d9db: ad 84 04 lda StompChainCounter ;add whatever is in the stomp counter
d9de: 18 clc ; to whatever is in the stomp timer
d9df: 6d 91 07 adc StompTimer
d9e2: 20 11 da jsr SetupFloateyNumber ;award points accordingly
d9e5: ee 91 07 inc StompTimer ;increment stomp timer of some sort
d9e8: ac 6a 07 ldy PrimaryHardMode ;check primary hard mode flag
d9eb: b9 d2 d9 lda RevivalRateData,y ;load timer setting according to flag
d9ee: 9d 96 07 sta EnemyIntervalTimer,x ;set as enemy timer to revive stomped enemy
d9f1: a9 fc SBnce lda #$fc ;set player's vertical speed for bounce
d9f3: 85 9f sta Player_Y_Speed ;and then leave!!!
d9f5: 60 rts
ChkEnemyFaceRight
d9f6: b5 46 lda Enemy_MovingDir,x ;check to see if enemy is moving to the right
d9f8: c9 01 cmp #$01
d9fa: d0 03 bne LInj ;if not, branch
d9fc: 4c 2c d9 jmp InjurePlayer ;otherwise go back to hurt player
d9ff: 20 1c db LInj jsr EnemyTurnAround ;turn the enemy around, if necessary
da02: 4c 2c d9 jmp InjurePlayer ;go back to hurt player
da05: a0 01 EnemyFacePlayer ldy #$01 ;set to move right by default
da07: 20 43 e1 jsr PlayerEnemyDiff ;get horizontal difference between player and enemy
da0a: 10 01 bpl SFcRt ;if enemy is to the right of player, do not increment
da0c: c8 iny ;otherwise, increment to set to move to the left
da0d: 94 46 SFcRt sty Enemy_MovingDir,x ;set moving direction here
da0f: 88 dey ;then decrement to use as a proper offset
da10: 60 rts
SetupFloateyNumber
da11: 9d 10 01 sta FloateyNum_Control,x ;set number of points control for floatey numbers
da14: a9 30 lda #$30
da16: 9d 2c 01 sta FloateyNum_Timer,x ;set timer for floatey numbers
da19: b5 cf lda Enemy_Y_Position,x
da1b: 9d 1e 01 sta FloateyNum_Y_Pos,x ;set vertical coordinate
da1e: ad ae 03 lda Enemy_Rel_XPos
da21: 9d 17 01 sta FloateyNum_X_Pos,x ;set horizontal coordinate and leave
da24: 60 ExSFN rts
; -----------------------------------------------------------------------------
; $01 - used to hold enemy offset for second enemy
da25: 80 SetBitsMask .dd1 %10000000
da26: 40 .dd1 %01000000
da27: 20 .dd1 %00100000
da28: 10 .dd1 %00010000
da29: 08 .dd1 %00001000
da2a: 04 .dd1 %00000100
da2b: 02 .dd1 %00000010
da2c: 7f ClearBitsMask .dd1 %01111111
da2d: bf .dd1 %10111111
da2e: df .dd1 %11011111
da2f: ef .dd1 %11101111
da30: f7 .dd1 %11110111
da31: fb .dd1 %11111011
da32: fd .dd1 %11111101
EnemiesCollision
da33: a5 09 lda FrameCounter ;check counter for d0 set
da35: 4a lsr A
da36: 90 ec bcc ExSFN ;if d0 not set, leave
da38: ad 4e 07 lda AreaType
da3b: f0 e7 beq ExSFN ;if water area type, leave
da3d: b5 16 lda Enemy_ID,x
da3f: c9 15 cmp #$15 ;if enemy object => $15, branch to leave
da41: b0 6e bcs ExitECRoutine
da43: c9 11 cmp #Lakitu ;if lakitu, branch to leave
da45: f0 6a beq ExitECRoutine
da47: c9 0d cmp #PiranhaPlant ;if piranha plant, branch to leave
da49: f0 66 beq ExitECRoutine
da4b: bd d8 03 lda EnemyOffscrBitsMasked,x ;if masked offscreen bits nonzero, branch to leave
da4e: d0 61 bne ExitECRoutine
da50: 20 52 dc jsr GetEnemyBoundBoxOfs ;otherwise, do sub, get appropriate bounding box offset for
da53: ca dex ; first enemy we're going to compare, then decrement for second
da54: 30 5b bmi ExitECRoutine ;branch to leave if there are no other enemies
da56: 86 01 ECLoop stx $01 ;save enemy object buffer offset for second enemy here
da58: 98 tya ;save first enemy's bounding box offset to stack
da59: 48 pha
da5a: b5 0f lda Enemy_Flag,x ;check enemy object enable flag
da5c: f0 4c beq ReadyNextEnemy ;branch if flag not set
da5e: b5 16 lda Enemy_ID,x
da60: c9 15 cmp #$15 ;check for enemy object => $15
da62: b0 46 bcs ReadyNextEnemy ;branch if true
da64: c9 11 cmp #Lakitu
da66: f0 42 beq ReadyNextEnemy ;branch if enemy object is lakitu
da68: c9 0d cmp #PiranhaPlant
da6a: f0 3e beq ReadyNextEnemy ;branch if enemy object is piranha plant
da6c: bd d8 03 lda EnemyOffscrBitsMasked,x
da6f: d0 39 bne ReadyNextEnemy ;branch if masked offscreen bits set
da71: 8a txa ;get second enemy object's bounding box offset
da72: 0a asl A ;multiply by four, then add four
da73: 0a asl A
da74: 18 clc
da75: 69 04 adc #$04
da77: aa tax ;use as new contents of X
da78: 20 27 e3 jsr SprObjectCollisionCore ;do collision detection using the two enemies here
da7b: a6 08 ldx ObjectOffset ;use first enemy offset for X
da7d: a4 01 ldy $01 ;use second enemy offset for Y
da7f: 90 20 bcc NoEnemyCollision ;if carry clear, no collision, branch ahead of this
da81: b5 1e lda Enemy_State,x
da83: 19 1e 00 ora Enemy_State,y ;check both enemy states for d7 set
da86: 29 80 and #%10000000
da88: d0 11 bne YesEC ;branch if at least one of them is set
da8a: b9 91 04 lda Enemy_CollisionBits,y ;load first enemy's collision-related bits
da8d: 3d 25 da and SetBitsMask,x ;check to see if bit connected to second enemy is
da90: d0 18 bne ReadyNextEnemy ; already set, and move onto next enemy slot if set
da92: b9 91 04 lda Enemy_CollisionBits,y
da95: 1d 25 da ora SetBitsMask,x ;if the bit is not set, set it now
da98: 99 91 04 sta Enemy_CollisionBits,y
da9b: 20 b4 da YesEC jsr ProcEnemyCollisions ;react according to the nature of collision
da9e: 4c aa da jmp ReadyNextEnemy ;move onto next enemy slot
NoEnemyCollision
daa1: b9 91 04 lda Enemy_CollisionBits,y ;load first enemy's collision-related bits
daa4: 3d 2c da and ClearBitsMask,x ;clear bit connected to second enemy
daa7: 99 91 04 sta Enemy_CollisionBits,y ;then move onto next enemy slot
daaa: 68 ReadyNextEnemy pla ;get first enemy's bounding box offset from the stack
daab: a8 tay ;use as Y again
daac: a6 01 ldx $01 ;get and decrement second enemy's object buffer offset
daae: ca dex
daaf: 10 a5 bpl ECLoop ;loop until all enemy slots have been checked
dab1: a6 08 ExitECRoutine ldx ObjectOffset ;get enemy object buffer offset
dab3: 60 rts ;leave
ProcEnemyCollisions
dab4: b9 1e 00 lda Enemy_State,y ;check both enemy states for d5 set
dab7: 15 1e ora Enemy_State,x
dab9: 29 20 and #%00100000 ;if d5 is set in either state, or both, branch
dabb: d0 33 bne ExitProcessEColl ; to leave and do nothing else at this point
dabd: b5 1e lda Enemy_State,x
dabf: c9 06 cmp #$06 ;if second enemy state < $06, branch elsewhere
dac1: 90 2e bcc ProcSecondEnemyColl
dac3: b5 16 lda Enemy_ID,x ;check second enemy identifier for hammer bro
dac5: c9 05 cmp #HammerBro ;if hammer bro found in alt state, branch to leave
dac7: f0 27 beq ExitProcessEColl
dac9: b9 1e 00 lda Enemy_State,y ;check first enemy state for d7 set
dacc: 0a asl A
dacd: 90 0a bcc ShellCollisions ;branch if d7 is clear
dacf: a9 06 lda #$06
dad1: 20 11 da jsr SetupFloateyNumber ;award 1000 points for killing enemy
dad4: 20 95 d7 jsr ShellOrBlockDefeat ; then kill enemy, then load
dad7: a4 01 ldy $01 ; original offset of second enemy
dad9: 98 ShellCollisions tya ;move Y to X
dada: aa tax
dadb: 20 95 d7 jsr ShellOrBlockDefeat ;kill second enemy
dade: a6 08 ldx ObjectOffset
dae0: bd 25 01 lda ShellChainCounter,x ;get chain counter for shell
dae3: 18 clc
dae4: 69 04 adc #$04 ;add four to get appropriate point offset
dae6: a6 01 ldx $01
dae8: 20 11 da jsr SetupFloateyNumber ;award appropriate number of points for second enemy
daeb: a6 08 ldx ObjectOffset ;load original offset of first enemy
daed: fe 25 01 inc ShellChainCounter,x ;increment chain counter for additional enemies
ExitProcessEColl
daf0: 60 rts ;leave!!!
ProcSecondEnemyColl
daf1: b9 1e 00 lda Enemy_State,y ;if first enemy state < $06, branch elsewhere
daf4: c9 06 cmp #$06
daf6: 90 1d bcc MoveEOfs
daf8: b9 16 00 lda Enemy_ID,y ;check first enemy identifier for hammer bro
dafb: c9 05 cmp #HammerBro ;if hammer bro found in alt state, branch to leave
dafd: f0 f1 beq ExitProcessEColl
daff: 20 95 d7 jsr ShellOrBlockDefeat ;otherwise, kill first enemy
db02: a4 01 ldy $01
db04: b9 25 01 lda ShellChainCounter,y ;get chain counter for shell
db07: 18 clc
db08: 69 04 adc #$04 ;add four to get appropriate point offset
db0a: a6 08 ldx ObjectOffset
db0c: 20 11 da jsr SetupFloateyNumber ;award appropriate number of points for first enemy
db0f: a6 01 ldx $01 ;load original offset of second enemy
db11: fe 25 01 inc ShellChainCounter,x ;increment chain counter for additional enemies
db14: 60 rts ;leave!!!
db15: 98 MoveEOfs tya ;move Y ($01) to X
db16: aa tax
db17: 20 1c db jsr EnemyTurnAround ;do the sub here using value from $01
db1a: a6 08 ldx ObjectOffset ; then do it again using value from $08
;
db1c: b5 16 EnemyTurnAround lda Enemy_ID,x ;check for specific enemies
db1e: c9 0d cmp #PiranhaPlant
db20: f0 22 beq ExTA ;if piranha plant, leave
db22: c9 11 cmp #Lakitu
db24: f0 1e beq ExTA ;if lakitu, leave
db26: c9 05 cmp #HammerBro
db28: f0 1a beq ExTA ;if hammer bro, leave
db2a: c9 12 cmp #Spiny
db2c: f0 08 beq RXSpd ;if spiny, turn it around
db2e: c9 0e cmp #GreenParatroopaJump
db30: f0 04 beq RXSpd ;if green paratroopa, turn it around
db32: c9 07 cmp #$07
db34: b0 0e bcs ExTA ;if any OTHER enemy object => $07, leave
db36: b5 58 RXSpd lda Enemy_X_Speed,x ;load horizontal speed
db38: 49 ff eor #$ff ;get two's compliment for horizontal speed
db3a: a8 tay
db3b: c8 iny
db3c: 94 58 sty Enemy_X_Speed,x ;store as new horizontal speed
db3e: b5 46 lda Enemy_MovingDir,x
db40: 49 03 eor #%00000011 ;invert moving direction and store, then leave
db42: 95 46 sta Enemy_MovingDir,x ;thus effectively turning the enemy around
db44: 60 ExTA rts ;leave!!!
; -----------------------------------------------------------------------------
; $00 - vertical position of platform
LargePlatformCollision
db45: a9 ff lda #$ff ;save value here
db47: 9d a2 03 sta HammerThrowingTimer,x
db4a: ad 47 07 lda TimerControl ;check master timer control
db4d: d0 29 bne ExLPC ;if set, branch to leave
db4f: b5 1e lda Enemy_State,x ;if d7 set in object state,
db51: 30 25 bmi ExLPC ; branch to leave
db53: b5 16 lda Enemy_ID,x
db55: c9 24 cmp #$24 ;check enemy object identifier for
db57: d0 06 bne ChkForPlayerC_LargeP ;balance platform, branch if not found
db59: b5 1e lda Enemy_State,x
db5b: aa tax ;set state as enemy offset here
db5c: 20 5f db jsr ChkForPlayerC_LargeP ;perform code with state offset, then original offset, in X
;
ChkForPlayerC_LargeP
db5f: 20 41 dc jsr CheckPlayerVertical ;figure out if player is below a certain point
db62: b0 14 bcs ExLPC ; or offscreen, branch to leave if true
db64: 8a txa
db65: 20 54 dc jsr GetEnemyBoundBoxOfsArg ;get bounding box offset in Y
db68: b5 cf lda Enemy_Y_Position,x ;store vertical coordinate in
db6a: 85 00 sta $00 ; temp variable for now
db6c: 8a txa ;send offset we're on to the stack
db6d: 48 pha
db6e: 20 25 e3 jsr PlayerCollisionCore ;do player-to-platform collision detection
db71: 68 pla ;retrieve offset from the stack
db72: aa tax
db73: 90 03 bcc ExLPC ;if no collision, branch to leave
db75: 20 bc db jsr ProcLPlatCollisions ;otherwise collision, perform sub
db78: a6 08 ExLPC ldx ObjectOffset ;get enemy object buffer offset and leave
db7a: 60 rts
; -----------------------------------------------------------------------------
; $00 - counter for bounding boxes
SmallPlatformCollision
db7b: ad 47 07 lda TimerControl ;if master timer control set,
db7e: d0 37 bne ExSPC ; branch to leave
db80: 9d a2 03 sta PlatformCollisionFlag,x ;otherwise initialize collision flag
db83: 20 41 dc jsr CheckPlayerVertical ;do a sub to see if player is below a certain point
db86: b0 2f bcs ExSPC ; or entirely offscreen, and branch to leave if true
db88: a9 02 lda #$02
db8a: 85 00 sta $00 ;load counter here for 2 bounding boxes
ChkSmallPlatLoop
db8c: a6 08 ldx ObjectOffset ;get enemy object offset
db8e: 20 52 dc jsr GetEnemyBoundBoxOfs ;get bounding box offset in Y
db91: 29 02 and #%00000010 ;if d1 of offscreen lower nybble bits was set
db93: d0 22 bne ExSPC ; then branch to leave
db95: b9 ad 04 lda BoundingBox_UL_YPos,y ;check top of platform's bounding box for being
db98: c9 20 cmp #$20 ; above a specific point
db9a: 90 05 bcc MoveBoundBox ;if so, branch, don't do collision detection
db9c: 20 25 e3 jsr PlayerCollisionCore ;otherwise, perform player-to-platform collision detection
db9f: b0 19 bcs ProcSPlatCollisions ;skip ahead if collision
dba1: b9 ad 04 MoveBoundBox lda BoundingBox_UL_YPos,y ;move bounding box vertical coordinates
dba4: 18 clc ; 128 pixels downwards
dba5: 69 80 adc #$80
dba7: 99 ad 04 sta BoundingBox_UL_YPos,y
dbaa: b9 af 04 lda BoundingBox_DR_YPos,y
dbad: 18 clc
dbae: 69 80 adc #$80
dbb0: 99 af 04 sta BoundingBox_DR_YPos,y
dbb3: c6 00 dec $00 ;decrement counter we set earlier
dbb5: d0 d5 bne ChkSmallPlatLoop ;loop back until both bounding boxes are checked
dbb7: a6 08 ExSPC ldx ObjectOffset ;get enemy object buffer offset, then leave
dbb9: 60 rts
; -----------------------------------------------------------------------------
ProcSPlatCollisions
dbba: a6 08 ldx ObjectOffset ;return enemy object buffer offset to X, then continue
ProcLPlatCollisions
dbbc: b9 af 04 lda BoundingBox_DR_YPos,y ;get difference by subtracting the top
dbbf: 38 sec ; of the player's bounding box from the bottom
dbc0: ed ad 04 sbc BoundingBox_UL_YPos ; of the platform's bounding box
dbc3: c9 04 cmp #$04 ;if difference too large or negative,
dbc5: b0 08 bcs ChkForTopCollision ; branch, do not alter vertical speed of player
dbc7: a5 9f lda Player_Y_Speed ;check to see if player's vertical speed is moving down
dbc9: 10 04 bpl ChkForTopCollision ;if so, don't mess with it
dbcb: a9 01 lda #$01 ;otherwise, set vertical
dbcd: 85 9f sta Player_Y_Speed ;speed of player to kill jump
ChkForTopCollision
dbcf: ad af 04 lda BoundingBox_DR_YPos ;get difference by subtracting the top
dbd2: 38 sec ; of the platform's bounding box from the bottom
dbd3: f9 ad 04 sbc BoundingBox_UL_YPos,y ; of the player's bounding box
dbd6: c9 06 cmp #$06
dbd8: b0 1b bcs PlatformSideCollisions ;if difference not close enough, skip all of this
dbda: a5 9f lda Player_Y_Speed
dbdc: 30 17 bmi PlatformSideCollisions ;if player's vertical speed moving upwards, skip this
dbde: a5 00 lda $00 ;get saved bounding box counter from earlier
dbe0: b4 16 ldy Enemy_ID,x
dbe2: c0 2b cpy #$2b ;if either of the two small platform objects are found,
dbe4: f0 05 beq SetCollisionFlag ; regardless of which one, branch to use bounding box counter
dbe6: c0 2c cpy #$2c ; as contents of collision flag
dbe8: f0 01 beq SetCollisionFlag
dbea: 8a txa ;otherwise use enemy object buffer offset
SetCollisionFlag
dbeb: a6 08 ldx ObjectOffset ;get enemy object buffer offset
dbed: 9d a2 03 sta PlatformCollisionFlag,x ;save either bounding box counter or enemy offset here
dbf0: a9 00 lda #$00
dbf2: 85 1d sta Player_State ;set player state to normal then leave
dbf4: 60 rts
PlatformSideCollisions
dbf5: a9 01 lda #$01 ;set value here to indicate possible horizontal
dbf7: 85 00 sta $00 ; collision on left side of platform
dbf9: ad ae 04 lda BoundingBox_DR_XPos ;get difference by subtracting platform's left edge
dbfc: 38 sec ; from player's right edge
dbfd: f9 ac 04 sbc BoundingBox_UL_XPos,y
dc00: c9 08 cmp #$08 ;if difference close enough, skip all of this
dc02: 90 0d bcc SideC
dc04: e6 00 inc $00 ;otherwise increment value set here for right side collision
dc06: b9 ae 04 lda BoundingBox_DR_XPos,y ;get difference by subtracting player's left edge
dc09: 18 clc ; from platform's right edge
dc0a: ed ac 04 sbc BoundingBox_UL_XPos
dc0d: c9 09 cmp #$09 ;if difference not close enough, skip subroutine
dc0f: b0 03 bcs NoSideC ; and instead branch to leave (no collision)
dc11: 20 4b df SideC jsr ImpedePlayerMove ;deal with horizontal collision
dc14: a6 08 NoSideC ldx ObjectOffset ;return with enemy object buffer offset
dc16: 60 rts
; -----------------------------------------------------------------------------
PlayerPosSPlatData
dc17: 80 00 .bulk $80,$00
PositionPlayerOnS_Plat
dc19: a8 tay ;use bounding box counter saved in collision flag
dc1a: b5 cf lda Enemy_Y_Position,x ; for offset
dc1c: 18 clc ;add positioning data using offset to the vertical
dc1d: 79 16 dc adc PlayerPosSPlatData-1,y ; coordinate
dc20: 2c bit βΌ LCFB5 ;BIT instruction opcode
;
PositionPlayerOnVPlat
dc21: b5 cf lda Enemy_Y_Position,x ;get vertical coordinate
dc23: a4 0e ldy GameEngineSubroutine
dc25: c0 0b cpy #$0b ;if certain routine being executed on this frame,
dc27: f0 17 beq ExPlPos ; skip all of this
dc29: b4 b6 ldy Enemy_Y_HighPos,x
dc2b: c0 01 cpy #$01 ;if vertical high byte offscreen, skip this
dc2d: d0 11 bne ExPlPos
dc2f: 38 sec ;subtract 32 pixels from vertical coordinate
dc30: e9 20 sbc #$20 ; for the player object's height
dc32: 85 ce sta Player_Y_Position ;save as player's new vertical coordinate
dc34: 98 tya
dc35: e9 00 sbc #$00 ;subtract borrow and store as player's
dc37: 85 b5 sta Player_Y_HighPos ; new vertical high byte
dc39: a9 00 lda #$00
dc3b: 85 9f sta Player_Y_Speed ;initialize vertical speed and low byte of force
dc3d: 8d 33 04 sta Player_Y_MoveForce ; and then leave
dc40: 60 ExPlPos rts
; -----------------------------------------------------------------------------
CheckPlayerVertical
dc41: ad d0 03 lda Player_OffscreenBits ;if player object is completely offscreen
dc44: c9 f0 cmp #$f0 ; vertically, leave this routine
dc46: b0 09 bcs ExCPV
dc48: a4 b5 ldy Player_Y_HighPos ;if player high vertical byte is not
dc4a: 88 dey ; within the screen, leave this routine
dc4b: d0 04 bne ExCPV
dc4d: a5 ce lda Player_Y_Position ;if on the screen, check to see how far down
dc4f: c9 d0 cmp #$d0 ; the player is vertically
dc51: 60 ExCPV rts
; -----------------------------------------------------------------------------
GetEnemyBoundBoxOfs
dc52: a5 08 lda ObjectOffset ;get enemy object buffer offset
;
GetEnemyBoundBoxOfsArg
dc54: 0a asl A ;multiply A by four, then add four
dc55: 0a asl A ; to skip player's bounding box
dc56: 18 clc
dc57: 69 04 adc #$04
dc59: a8 tay ;send to Y
dc5a: ad d1 03 lda Enemy_OffscreenBits ;get offscreen bits for enemy object
dc5d: 29 0f and #%00001111 ;save low nybble
dc5f: c9 0f cmp #%00001111 ;check for all bits set
dc61: 60 rts
; -----------------------------------------------------------------------------
; $00-$01 - used to hold many values, essentially temp variables
; $04 - holds lower nybble of vertical coordinate from block buffer routine
; $eb - used to hold block buffer adder
PlayerBGUpperExtent
dc62: 20 10 .bulk $20,$10
PlayerBGCollision
dc64: ad 16 07 lda DisableCollisionDet ;if collision detection disabled flag set,
dc67: d0 2e bne ExPBGCol ; branch to leave
dc69: a5 0e lda GameEngineSubroutine
dc6b: c9 0b cmp #$0b ;if running routine #11 or $0b
dc6d: f0 28 beq ExPBGCol ;branch to leave
dc6f: c9 04 cmp #$04
dc71: 90 24 bcc ExPBGCol ;if running routines $00-$03 branch to leave
dc73: a9 01 lda #$01 ;load default player state for swimming
dc75: ac 04 07 ldy SwimmingFlag ;if swimming flag set,
dc78: d0 0a bne SetPSte ; branch ahead to set default state
dc7a: a5 1d lda Player_State ;if player in normal state,
dc7c: f0 04 beq SetFallS ; branch to set default state for falling
dc7e: c9 03 cmp #$03
dc80: d0 04 bne ChkOnScr ;if in any other state besides climbing, skip to next part
dc82: a9 02 SetFallS lda #$02 ;load default player state for falling
dc84: 85 1d SetPSte sta Player_State ;set whatever player state is appropriate
dc86: a5 b5 ChkOnScr lda Player_Y_HighPos
dc88: c9 01 cmp #$01 ;check player's vertical high byte for still on the screen
dc8a: d0 0b bne ExPBGCol ;branch to leave if not
dc8c: a9 ff lda #$ff
dc8e: 8d 90 04 sta Player_CollisionBits ;initialize player's collision flag
dc91: a5 ce lda Player_Y_Position
dc93: c9 cf cmp #$cf ;check player's vertical coordinate
dc95: 90 01 bcc ChkCollSize ;if not too close to the bottom of screen, continue
dc97: 60 ExPBGCol rts ;otherwise leave
dc98: a0 02 ChkCollSize ldy #$02 ;load default offset
dc9a: ad 14 07 lda CrouchingFlag
dc9d: d0 0c bne GBBAdr ;if player crouching, skip ahead
dc9f: ad 54 07 lda PlayerSize
dca2: d0 07 bne GBBAdr ;if player small, skip ahead
dca4: 88 dey ;otherwise decrement offset for big player not crouching
dca5: ad 04 07 lda SwimmingFlag
dca8: d0 01 bne GBBAdr ;if swimming flag set, skip ahead
dcaa: 88 dey ;otherwise decrement offset
dcab: b9 ad e3 GBBAdr lda BlockBufferAdderData,y ;get value using offset
dcae: 85 eb sta $eb ;store value here
dcb0: a8 tay ;put value into Y, as offset for block buffer routine
dcb1: ae 54 07 ldx PlayerSize ;get player's size as offset
dcb4: ad 14 07 lda CrouchingFlag
dcb7: f0 01 beq HeadChk ;if player not crouching, branch ahead
dcb9: e8 inx ;otherwise increment size as offset
dcba: a5 ce HeadChk lda Player_Y_Position ;get player's vertical coordinate
dcbc: dd 62 dc cmp PlayerBGUpperExtent,x ;compare with upper extent value based on offset
dcbf: 90 35 bcc DoFootCheck ;if player is too high, skip this part
dcc1: 20 e9 e3 jsr BlockBufferColli_Head ;do player-to-bg collision detection on top of
dcc4: f0 30 beq DoFootCheck ; player, and branch if nothing above player's head
dcc6: 20 a1 df jsr CheckForCoinMTiles ;check to see if player touched coin with their head
dcc9: b0 4f bcs AwardTouchedCoin ;if so, branch to some other part of code
dccb: a4 9f ldy Player_Y_Speed ;check player's vertical speed
dccd: 10 27 bpl DoFootCheck ;if player not moving upwards, branch elsewhere
dccf: a4 04 ldy $04 ;check lower nybble of vertical coordinate returned
dcd1: c0 04 cpy #$04 ;from collision detection routine
dcd3: 90 21 bcc DoFootCheck ;if low nybble < 4, branch
dcd5: 20 8f df jsr CheckForSolidMTiles ;check to see what player's head bumped on
dcd8: b0 10 bcs SolidOrClimb ;if player collided with solid metatile, branch
dcda: ac 4e 07 ldy AreaType ;otherwise check area type
dcdd: f0 13 beq MYSpd ;if water level, branch ahead
dcdf: ac 84 07 ldy BlockBounceTimer ;if block bounce timer not expired,
dce2: d0 0e bne MYSpd ; branch ahead, do not process collision
dce4: 20 ed bc jsr PlayerHeadCollision ;otherwise do a sub to process collision
dce7: 4c f6 dc jmp DoFootCheck ;jump ahead to skip these other parts here
dcea: c9 26 SolidOrClimb cmp #$26 ;if climbing metatile,
dcec: f0 04 beq MYSpd ; branch ahead and do not play sound
dcee: a9 02 lda #Sfx_Bump
dcf0: 85 ff sta Square1SoundQueue ;otherwise load bump sound
dcf2: a9 01 MYSpd lda #$01 ;set player's vertical speed to nullify
dcf4: 85 9f sta Player_Y_Speed ; jump or swim
dcf6: a4 eb ldy $eb ;get block buffer adder offset
dcf8: a5 ce lda Player_Y_Position
dcfa: c9 cf cmp #$cf ;check to see how low player is
dcfc: b0 60 bcs DoPlayerSideCheck ;if player is too far down on screen, skip all of this
dcfe: 20 e8 e3 jsr BlockBufferColli_Feet ;do player-to-bg collision detection on bottom left of player
dd01: 20 a1 df jsr CheckForCoinMTiles ;check to see if player touched coin with their left foot
dd04: b0 14 bcs AwardTouchedCoin ;if so, branch to some other part of code
dd06: 48 pha ;save bottom left metatile to stack
dd07: 20 e8 e3 jsr BlockBufferColli_Feet ;do player-to-bg collision detection on bottom right of player
dd0a: 85 00 sta $00 ;save bottom right metatile here
dd0c: 68 pla
dd0d: 85 01 sta $01 ;pull bottom left metatile and save here
dd0f: d0 0c bne ChkFootMTile ;if anything here, skip this part
dd11: a5 00 lda $00 ;otherwise check for anything in bottom right metatile
dd13: f0 49 beq DoPlayerSideCheck ; and skip ahead if not
dd15: 20 a1 df jsr CheckForCoinMTiles ;check to see if player touched coin with their right foot
dd18: 90 03 bcc ChkFootMTile ;if not, skip unconditional jump and continue code
AwardTouchedCoin
dd1a: 4c 05 de jmp HandleCoinMetatile ;follow the code to erase coin and award to player 1 coin
dd1d: 20 9a df jsr CheckForClimbMTiles ;check to see if player landed on climbable metatiles
dd20: b0 3c bcs DoPlayerSideCheck ;if so, branch
dd22: a4 9f ldy Player_Y_Speed ;check player's vertical speed
dd24: 30 38 bmi DoPlayerSideCheck ;if player moving upwards, branch
dd26: c9 c5 cmp #$c5
dd28: d0 03 bne ContChk ;if player did not touch axe, skip ahead
dd2a: 4c 0e de jmp HandleAxeMetatile ;otherwise jump to set modes of operation
dd2d: 20 bd de ContChk jsr ChkInvisibleMTiles ;do sub to check for hidden coin or 1-up blocks
dd30: f0 2c beq DoPlayerSideCheck ;if either found, branch
dd32: ac 0e 07 ldy JumpspringAnimCtrl ;if jumpspring animating right now,
dd35: d0 23 bne InitSteP ; branch ahead
dd37: a4 04 ldy $04 ;check lower nybble of vertical coordinate returned
dd39: c0 05 cpy #$05 ; from collision detection routine
dd3b: 90 07 bcc LandPlyr ;if lower nybble < 5, branch
dd3d: a5 45 lda Player_MovingDir
dd3f: 85 00 sta $00 ;use player's moving direction as temp variable
dd41: 4c 4b df jmp ImpedePlayerMove ;jump to impede player's movement in that direction
dd44: 20 c4 de LandPlyr jsr ChkForLandJumpSpring ;do sub to check for jumpspring metatiles and deal with it
dd47: a9 f0 lda #$f0
dd49: 25 ce and Player_Y_Position ;mask out lower nybble of player's vertical position
dd4b: 85 ce sta Player_Y_Position ; and store as new vertical position to land player properly
dd4d: 20 e8 de jsr HandlePipeEntry ;do sub to process potential pipe entry
dd50: a9 00 lda #$00
dd52: 85 9f sta Player_Y_Speed ;initialize vertical speed and fractional
dd54: 8d 33 04 sta Player_Y_MoveForce ;movement force to stop player's vertical movement
dd57: 8d 84 04 sta StompChainCounter ;initialize enemy stomp counter
dd5a: a9 00 InitSteP lda #$00
dd5c: 85 1d sta Player_State ;set player's state to normal
DoPlayerSideCheck
dd5e: a4 eb ldy $eb ;get block buffer adder offset
dd60: c8 iny
dd61: c8 iny ;increment offset 2 bytes to use adders for side collisions
dd62: a9 02 lda #$02 ;set value here to be used as counter
dd64: 85 00 sta $00
dd66: c8 SideCheckLoop iny ;move onto the next one
dd67: 84 eb sty $eb ;store it
dd69: a5 ce lda Player_Y_Position
dd6b: c9 20 cmp #$20 ;check player's vertical position
dd6d: 90 16 bcc BHalf ;if player is in status bar area, branch ahead to skip this part
dd6f: c9 e4 cmp #$e4
dd71: b0 28 bcs ExSCH ;branch to leave if player is too far down
dd73: 20 ec e3 jsr BlockBufferColli_Side ;do player-to-bg collision detection on one half of player
dd76: f0 0d beq BHalf ;branch ahead if nothing found
dd78: c9 1c cmp #$1c ;otherwise check for pipe metatiles
dd7a: f0 09 beq BHalf ;if collided with sideways pipe (top), branch ahead
dd7c: c9 6b cmp #$6b
dd7e: f0 05 beq BHalf ;if collided with water pipe (top), branch ahead
dd80: 20 9a df jsr CheckForClimbMTiles ;do sub to see if player bumped into anything climbable
dd83: 90 17 bcc ChkSideMTiles ;if not, branch to alternate section of code
dd85: a4 eb BHalf ldy $eb ;load block adder offset
dd87: c8 iny ;increment it
dd88: a5 ce lda Player_Y_Position ;get player's vertical position
dd8a: c9 08 cmp #$08
dd8c: 90 0d bcc ExSCH ;if too high, branch to leave
dd8e: c9 d0 cmp #$d0
dd90: b0 09 bcs ExSCH ;if too low, branch to leave
dd92: 20 ec e3 jsr BlockBufferColli_Side ;do player-to-bg collision detection on other half of player
dd95: d0 05 bne ChkSideMTiles ;if something found, branch
dd97: c6 00 dec $00 ;otherwise decrement counter
dd99: d0 cb bne SideCheckLoop ;run code until both sides of player are checked
dd9b: 60 ExSCH rts ;leave
dd9c: 20 bd de ChkSideMTiles jsr ChkInvisibleMTiles ;check for hidden or coin 1-up blocks
dd9f: f0 61 beq ExCSM ;branch to leave if either found
dda1: 20 9a df jsr CheckForClimbMTiles ;check for climbable metatiles
dda4: 90 03 bcc ContSChk ;if not found, skip and continue with code
dda6: 4c 2e de jmp HandleClimbing ;otherwise jump to handle climbing
dda9: 20 a1 df ContSChk jsr CheckForCoinMTiles ;check to see if player touched coin
ddac: b0 57 bcs HandleCoinMetatile ;if so, execute code to erase coin and award to player 1 coin
ddae: 20 dd de jsr ChkJumpspringMetatiles ;check for jumpspring metatiles
ddb1: 90 08 bcc ChkPBtm ;if not found, branch ahead to continue cude
ddb3: ad 0e 07 lda JumpspringAnimCtrl ;otherwise check jumpspring animation control
ddb6: d0 4a bne ExCSM ;branch to leave if set
ddb8: 4c ff dd jmp StopPlayerMove ;otherwise jump to impede player's movement
ddbb: a4 1d ChkPBtm ldy Player_State ;get player's state
ddbd: c0 00 cpy #$00 ;check for player's state set to normal
ddbf: d0 3e bne StopPlayerMove ;if not, branch to impede player's movement
ddc1: a4 33 ldy PlayerFacingDir ;get player's facing direction
ddc3: 88 dey
ddc4: d0 39 bne StopPlayerMove ;if facing left, branch to impede movement
ddc6: c9 6c cmp #$6c ;otherwise check for pipe metatiles
ddc8: f0 04 beq PipeDwnS ;if collided with sideways pipe (bottom), branch
ddca: c9 1f cmp #$1f ;if collided with water pipe (bottom), continue
ddcc: d0 31 bne StopPlayerMove ;otherwise branch to impede player's movement
ddce: ad c4 03 PipeDwnS lda Player_SprAttrib ;check player's attributes
ddd1: d0 04 bne PlyrPipe ;if already set, branch, do not play sound again
ddd3: a0 10 ldy #Sfx_PipeDown_Injury
ddd5: 84 ff sty Square1SoundQueue ;otherwise load pipedown/injury sound
ddd7: 09 20 PlyrPipe ora #%00100000
ddd9: 8d c4 03 sta Player_SprAttrib ;set background priority bit in player attributes
dddc: a5 86 lda Player_X_Position
ddde: 29 0f and #%00001111 ;get lower nybble of player's horizontal coordinate
dde0: f0 0e beq ChkGERtn ;if at zero, branch ahead to skip this part
dde2: a0 00 ldy #$00 ;set default offset for timer setting data
dde4: ad 1a 07 lda ScreenLeft_PageLoc ;load page location for left side of screen
dde7: f0 01 beq SetCATmr ;if at page zero, use default offset
dde9: c8 iny ;otherwise increment offset
ddea: b9 03 de SetCATmr lda AreaChangeTimerData,y ;set timer for change of area as appropriate
dded: 8d de 06 sta ChangeAreaTimer
ddf0: a5 0e ChkGERtn lda GameEngineSubroutine ;get number of game engine routine running
ddf2: c9 07 cmp #$07
ddf4: f0 0c beq ExCSM ;if running player entrance routine or
ddf6: c9 08 cmp #$08 ; player control routine, go ahead and branch to leave
ddf8: d0 08 bne ExCSM
ddfa: a9 02 lda #$02
ddfc: 85 0e sta GameEngineSubroutine ;otherwise set sideways pipe entry routine to run
ddfe: 60 rts ; and leave
; -----------------------------------------------------------------------------
; $02 - high nybble of vertical coordinate from block buffer
; $04 - low nybble of horizontal coordinate from block buffer
; $06-$07 - block buffer address
ddff: 20 4b df StopPlayerMove jsr ImpedePlayerMove ;stop player's movement
de02: 60 ExCSM rts ;leave
AreaChangeTimerData
de03: a0 34 .bulk $a0,$34
HandleCoinMetatile
de05: 20 1c de jsr ErACM ;do sub to erase coin metatile from block buffer
de08: ee 48 07 inc CoinTallyFor1Ups ;increment coin tally used for 1-up blocks
de0b: 4c fe bb jmp GiveOneCoin ;update coin amount and tally on the screen
HandleAxeMetatile
de0e: a9 00 lda #$00
de10: 8d 72 07 sta OperMode_Task ;reset secondary mode
de13: a9 02 lda #$02
de15: 8d 70 07 sta OperMode ;set primary mode to autoctrl mode
de18: a9 18 lda #$18
de1a: 85 57 sta Player_X_Speed ;set horizontal speed and continue to erase axe metatile
de1c: a4 02 ErACM ldy $02 ;load vertical high nybble offset for block buffer
de1e: a9 00 lda #$00 ;load blank metatile
de20: 91 06 sta ($06),y ;store to remove old contents from block buffer
de22: 4c 4d 8a jmp RemoveCoin_Axe ;update the screen accordingly
; -----------------------------------------------------------------------------
; $02 - high nybble of vertical coordinate from block buffer
; $04 - low nybble of horizontal coordinate from block buffer
; $06-$07 - block buffer address
de25: f9 07 ClimbXPosAdder .bulk $f9,$07
de27: ff 00 ClimbPLocAdder .bulk $ff,$00
FlagpoleYPosData
de29: 18 22 50 68+ .bulk $18,$22,$50,$68,$90
de2e: a4 04 HandleClimbing ldy $04 ;check low nybble of horizontal coordinate returned from
de30: c0 06 cpy #$06 ; collision detection routine against certain values, this
de32: 90 04 bcc ExHC ; makes actual physical part of vine or flagpole thinner
de34: c0 0a cpy #$0a ; than 16 pixels
de36: 90 01 bcc ChkForFlagpole
de38: 60 ExHC rts ;leave if too far left or too far right
de39: c9 24 ChkForFlagpole cmp #$24 ;check climbing metatiles
de3b: f0 04 beq FlagpoleCollision ;branch if flagpole ball found
de3d: c9 25 cmp #$25
de3f: d0 39 bne VineCollision ;branch to alternate code if flagpole shaft not found
FlagpoleCollision
de41: a5 0e lda GameEngineSubroutine
de43: c9 05 cmp #$05 ;check for end-of-level routine running
de45: f0 41 beq PutPlayerOnVine ;if running, branch to end of climbing code
de47: a9 01 lda #$01
de49: 85 33 sta PlayerFacingDir ;set player's facing direction to right
de4b: ee 23 07 inc ScrollLock ;set scroll lock flag
de4e: a5 0e lda GameEngineSubroutine
de50: c9 04 cmp #$04 ;check for flagpole slide routine running
de52: f0 1f beq RunFR ;if running, branch to end of flagpole code here
de54: a9 33 lda #BulletBill_CannonVar ;load identifier for bullet bills (cannon variant)
de56: 20 16 97 jsr KillEnemies ;get rid of them
de59: a9 80 lda #Silence
de5b: 85 fc sta EventMusicQueue ;silence music
de5d: 4a lsr A
de5e: 8d 13 07 sta FlagpoleSoundQueue ;load flagpole sound into flagpole sound queue
de61: a2 04 ldx #$04 ;start at end of vertical coordinate data
de63: a5 ce lda Player_Y_Position
de65: 8d 0f 07 sta FlagpoleCollisionYPos ;store player's vertical coordinate here to be used later
ChkFlagpoleYPosLoop
de68: dd 29 de cmp FlagpoleYPosData,x ;compare with current vertical coordinate data
de6b: b0 03 bcs MtchF ;if player's => current, branch to use current offset
de6d: ca dex ;otherwise decrement offset to use
de6e: d0 f8 bne ChkFlagpoleYPosLoop ;do this until all data is checked (use last one if all checked)
de70: 8e 0f 01 MtchF stx FlagpoleScore ;store offset here to be used later
de73: a9 04 RunFR lda #$04
de75: 85 0e sta GameEngineSubroutine ;set value to run flagpole slide routine
de77: 4c 88 de jmp PutPlayerOnVine ;jump to end of climbing code
de7a: c9 26 VineCollision cmp #$26 ;check for climbing metatile used on vines
de7c: d0 0a bne PutPlayerOnVine
de7e: a5 ce lda Player_Y_Position ;check player's vertical coordinate
de80: c9 20 cmp #$20 ;for being in status bar area
de82: b0 04 bcs PutPlayerOnVine ;branch if not that far up
de84: a9 01 lda #$01
de86: 85 0e sta GameEngineSubroutine ;otherwise set to run autoclimb routine next frame
de88: a9 03 PutPlayerOnVine lda #$03 ;set player state to climbing
de8a: 85 1d sta Player_State
de8c: a9 00 lda #$00 ;nullify player's horizontal speed
de8e: 85 57 sta Player_X_Speed ;and fractional horizontal movement force
de90: 8d 05 07 sta Player_X_MoveForce
de93: a5 86 lda Player_X_Position ;get player's horizontal coordinate
de95: 38 sec
de96: ed 1c 07 sbc ScreenLeft_X_Pos ;subtract from left side horizontal coordinate
de99: c9 10 cmp #$10
de9b: b0 04 bcs SetVXPl ;if 16 or more pixels difference, do not alter facing direction
de9d: a9 02 lda #$02
de9f: 85 33 sta PlayerFacingDir ;otherwise force player to face left
dea1: a4 33 SetVXPl ldy PlayerFacingDir ;get current facing direction, use as offset
dea3: a5 06 lda $06 ;get low byte of block buffer address
dea5: 0a asl A
dea6: 0a asl A ;move low nybble to high
dea7: 0a asl A
dea8: 0a asl A
dea9: 18 clc
deaa: 79 24 de adc ClimbXPosAdder-1,y ;add pixels depending on facing direction
dead: 85 86 sta Player_X_Position ;store as player's horizontal coordinate
deaf: a5 06 lda $06 ;get low byte of block buffer address again
deb1: d0 09 bne ExPVne ;if not zero, branch
deb3: ad 1b 07 lda ScreenRight_PageLoc ;load page location of right side of screen
deb6: 18 clc
deb7: 79 26 de adc ClimbPLocAdder-1,y ;add depending on facing location
deba: 85 6d sta Player_PageLoc ;store as player's page location
debc: 60 ExPVne rts ;finally, we're done!
; -----------------------------------------------------------------------------
ChkInvisibleMTiles
debd: c9 5f cmp #$5f ;check for hidden coin block
debf: f0 02 beq ExCInvT ;branch to leave if found
dec1: c9 60 cmp #$60 ;check for hidden 1-up block
dec3: 60 ExCInvT rts ;leave with zero flag set if either found
; -----------------------------------------------------------------------------
; $00-$01 - used to hold bottom right and bottom left metatiles (in that order)
; $00 - used as flag by ImpedePlayerMove to restrict specific movement
ChkForLandJumpSpring
dec4: 20 dd de jsr ChkJumpspringMetatiles ;do sub to check if player landed on jumpspring
dec7: 90 13 bcc ExCJSp ;if carry not set, jumpspring not found, therefore leave
dec9: a9 70 lda #$70
decb: 8d 09 07 sta VerticalForce ;otherwise set vertical movement force for player
dece: a9 f9 lda #$f9
ded0: 8d db 06 sta JumpspringForce ;set default jumpspring force
ded3: a9 03 lda #$03
ded5: 8d 86 07 sta JumpspringTimer ;set jumpspring timer to be used later
ded8: 4a lsr A
ded9: 8d 0e 07 sta JumpspringAnimCtrl ;set jumpspring animation control to start animating
dedc: 60 ExCJSp rts ; and leave
ChkJumpspringMetatiles
dedd: c9 67 cmp #$67 ;check for top jumpspring metatile
dedf: f0 05 beq JSFnd ;branch to set carry if found
dee1: c9 68 cmp #$68 ;check for bottom jumpspring metatile
dee3: 18 clc ;clear carry flag
dee4: d0 01 bne NoJSFnd ;branch to use cleared carry if not found
dee6: 38 JSFnd sec ;set carry if found
dee7: 60 NoJSFnd rts ;leave
dee8: a5 0b HandlePipeEntry lda Up_Down_Buttons ;check saved controller bits from earlier
deea: 29 04 and #%00000100 ; for pressing down
deec: f0 5c beq ExPipeE ;if not pressing down, branch to leave
deee: a5 00 lda $00
def0: c9 11 cmp #$11 ;check right foot metatile for warp pipe right metatile
def2: d0 56 bne ExPipeE ;branch to leave if not found
def4: a5 01 lda $01
def6: c9 10 cmp #$10 ;check left foot metatile for warp pipe left metatile
def8: d0 50 bne ExPipeE ;branch to leave if not found
defa: a9 30 lda #$30
defc: 8d de 06 sta ChangeAreaTimer ;set timer for change of area
deff: a9 03 lda #$03
df01: 85 0e sta GameEngineSubroutine ;set to run vertical pipe entry routine on next frame
df03: a9 10 lda #Sfx_PipeDown_Injury
df05: 85 ff sta Square1SoundQueue ;load pipedown/injury sound
df07: a9 20 lda #%00100000
df09: 8d c4 03 sta Player_SprAttrib ;set background priority bit in player's attributes
df0c: ad d6 06 lda WarpZoneControl ;check warp zone control
df0f: f0 39 beq ExPipeE ;branch to leave if none found
df11: 29 03 and #%00000011 ;mask out all but 2 LSB
df13: 0a asl A
df14: 0a asl A ;multiply by four
df15: aa tax ;save as offset to warp zone numbers (starts at left pipe)
df16: a5 86 lda Player_X_Position ;get player's horizontal position
df18: c9 60 cmp #$60
df1a: 90 06 bcc GetWNum ;if player at left, not near middle, use offset and skip ahead
df1c: e8 inx ;otherwise increment for middle pipe
df1d: c9 a0 cmp #$a0
df1f: 90 01 bcc GetWNum ;if player at middle, but not too far right, use offset and skip
df21: e8 inx ;otherwise increment for last pipe
df22: bc f2 87 GetWNum ldy WarpZoneNumbers,x ;get warp zone numbers
df25: 88 dey ;decrement for use as world number
df26: 8c 5f 07 sty WorldNumber ;store as world number and offset
df29: be b4 9c ldx WorldAddrOffsets,y ;get offset to where this world's area offsets are
df2c: bd bc 9c lda AreaAddrOffsets,x ;get area offset based on world offset
df2f: 8d 50 07 sta AreaPointer ;store area offset here to be used to change areas
df32: a9 80 lda #$80
df34: 85 fc sta EventMusicQueue ;silence music
df36: a9 00 lda #$00
df38: 8d 51 07 sta EntrancePage ;initialize starting page number
df3b: 8d 60 07 sta AreaNumber ;initialize area number used for area address offset
df3e: 8d 5c 07 sta LevelNumber ;initialize level number used for world display
df41: 8d 52 07 sta AltEntranceControl ;initialize mode of entry
df44: ee 5d 07 inc Hidden1UpFlag ;set flag for hidden 1-up blocks
df47: ee 57 07 inc FetchNewGameTimerFlag ;set flag to load new game timer
df4a: 60 ExPipeE rts ;leave!!!
ImpedePlayerMove
df4b: a9 00 lda #$00 ;initialize value here
df4d: a4 57 ldy Player_X_Speed ;get player's horizontal speed
df4f: a6 00 ldx $00 ;check value set earlier for
df51: ca dex ; left side collision
df52: d0 0a bne RImpd ;if right side collision, skip this part
df54: e8 inx ;return value to X
df55: c0 00 cpy #$00 ;if player moving to the left,
df57: 30 28 bmi ExIPM ; branch to invert bit and leave
df59: a9 ff lda #$ff ;otherwise load A with value to be used later
df5b: 4c 66 df jmp NXSpd ; and jump to affect movement
df5e: a2 02 RImpd ldx #$02 ;return $02 to X
df60: c0 01 cpy #$01 ;if player moving to the right,
df62: 10 1d bpl ExIPM ; branch to invert bit and leave
df64: a9 01 lda #$01 ;otherwise load A with value to be used here
df66: a0 10 NXSpd ldy #$10
df68: 8c 85 07 sty SideCollisionTimer ;set timer of some sort
df6b: a0 00 ldy #$00
df6d: 84 57 sty Player_X_Speed ;nullify player's horizontal speed
df6f: c9 00 cmp #$00 ;if value set in A not set to $ff,
df71: 10 01 bpl PlatF ; branch ahead, do not decrement Y
df73: 88 dey ;otherwise decrement Y now
df74: 84 00 PlatF sty $00 ;store Y as high bits of horizontal adder
df76: 18 clc
df77: 65 86 adc Player_X_Position ;add contents of A to player's horizontal
df79: 85 86 sta Player_X_Position ; position to move player left or right
df7b: a5 6d lda Player_PageLoc
df7d: 65 00 adc $00 ;add high bits and carry to
df7f: 85 6d sta Player_PageLoc ; page location if necessary
df81: 8a ExIPM txa ;invert contents of X
df82: 49 ff eor #$ff
df84: 2d 90 04 and Player_CollisionBits ;mask out bit that was set here
df87: 8d 90 04 sta Player_CollisionBits ;store to clear bit
df8a: 60 rts
; -----------------------------------------------------------------------------
SolidMTileUpperExt
df8b: 10 61 88 c4 .bulk $10,$61,$88,$c4
CheckForSolidMTiles
df8f: 20 b0 df jsr GetMTileAttrib ;find appropriate offset based on metatile's 2 MSB
df92: dd 8b df cmp SolidMTileUpperExt,x ;compare current metatile with solid metatiles
df95: 60 rts
ClimbMTileUpperExt
df96: 24 6d 8a c6 .bulk $24,$6d,$8a,$c6
CheckForClimbMTiles
df9a: 20 b0 df jsr GetMTileAttrib ;find appropriate offset based on metatile's 2 MSB
df9d: dd 96 df cmp ClimbMTileUpperExt,x ;compare current metatile with climbable metatiles
dfa0: 60 rts
CheckForCoinMTiles
dfa1: c9 c2 cmp #$c2 ;check for regular coin
dfa3: f0 06 beq CoinSd ;branch if found
dfa5: c9 c3 cmp #$c3 ;check for underwater coin
dfa7: f0 02 beq CoinSd ;branch if found
dfa9: 18 clc ;otherwise clear carry and leave
dfaa: 60 rts
dfab: a9 01 CoinSd lda #Sfx_CoinGrab
dfad: 85 fe sta Square2SoundQueue ;load coin grab sound and leave
dfaf: 60 rts
dfb0: a8 GetMTileAttrib tay ;save metatile value into Y
dfb1: 29 c0 and #%11000000 ;mask out all but 2 MSB
dfb3: 0a asl A
dfb4: 2a rol A ;shift and rotate d7-d6 to d1-d0
dfb5: 2a rol A
dfb6: aa tax ;use as offset for metatile data
dfb7: 98 tya ;get original metatile value back
dfb8: 60 ExEBG rts ;leave
; -----------------------------------------------------------------------------
; $06-$07 - address from block buffer routine
EnemyBGCStateData
dfb9: 01 01 02 02+ .bulk $01,$01,$02,$02,$02,$05
EnemyBGCXSpdData
dfbf: 10 f0 .bulk $10,$f0
EnemyToBGCollisionDet
dfc1: b5 1e lda Enemy_State,x ;check enemy state for d6 set
dfc3: 29 20 and #%00100000
dfc5: d0 f1 bne ExEBG ;if set, branch to leave
dfc7: 20 5b e1 jsr SubtEnemyYPos ;otherwise, do a subroutine here
dfca: 90 ec bcc ExEBG ;if enemy vertical coord + 62 < 68, branch to leave
dfcc: b4 16 ldy Enemy_ID,x
dfce: c0 12 cpy #Spiny ;if enemy object is not spiny, branch elsewhere
dfd0: d0 06 bne DoIDCheckBGColl
dfd2: b5 cf lda Enemy_Y_Position,x
dfd4: c9 25 cmp #$25 ;if enemy vertical coordinate < 36 branch to leave
dfd6: 90 e0 bcc ExEBG
dfd8: c0 0e DoIDCheckBGColl cpy #GreenParatroopaJump ;check for some other enemy object
dfda: d0 03 bne HBChk ;branch if not found
dfdc: 4c 63 e1 jmp EnemyJump ;otherwise jump elsewhere
dfdf: c0 05 HBChk cpy #HammerBro ;check for hammer bro
dfe1: d0 03 bne CInvu ;branch if not found
dfe3: 4c 85 e1 jmp HammerBroBGColl ;otherwise jump elsewhere
dfe6: c0 12 CInvu cpy #Spiny ;if enemy object is spiny, branch
dfe8: f0 08 beq YesIn
dfea: c0 2e cpy #PowerUpObject ;if special power-up object, branch
dfec: f0 04 beq YesIn
dfee: c0 07 cpy #$07 ;if enemy object =>$07, branch to leave
dff0: b0 74 bcs ExEBGChk
dff2: 20 ae e1 YesIn jsr ChkUnderEnemy ;if enemy object < $07, or = $12 or $2e, do this sub
dff5: d0 03 bne HandleEToBGCollision ;if block underneath enemy, branch
NoEToBGCollision
dff7: 4c e2 e0 jmp ChkForRedKoopa ;otherwise skip and do something else
; -----------------------------------------------------------------------------
; $02 - vertical coordinate from block buffer routine
HandleEToBGCollision
dffa: 20 b5 e1 jsr ChkForNonSolids ;if something is underneath enemy, find out what
dffd: f0 f8 beq NoEToBGCollision ;if blank $26, coins, or hidden blocks, jump, enemy falls through
dfff: c9 23 cmp #$23
e001: d0 64 bne LandEnemyProperly ;check for blank metatile $23 and branch if not found
e003: a4 02 ldy $02 ;get vertical coordinate used to find block
e005: a9 00 lda #$00 ;store default blank metatile in that spot so we won't
e007: 91 06 sta ($06),y ; trigger this routine accidentally again
e009: b5 16 lda Enemy_ID,x
e00b: c9 15 cmp #$15 ;if enemy object => $15, branch ahead
e00d: b0 0c bcs ChkToStunEnemies
e00f: c9 06 cmp #Goomba ;if enemy object not goomba, branch ahead of this routine
e011: d0 03 bne GiveOEPoints
e013: 20 8e e1 jsr KillEnemyAboveBlock ;if enemy object IS goomba, do this sub
e016: a9 01 GiveOEPoints lda #$01 ;award 100 points for hitting block beneath enemy
e018: 20 11 da jsr SetupFloateyNumber
ChkToStunEnemies
e01b: c9 09 cmp #$09 ;perform many comparisons on enemy object identifier
e01d: 90 10 bcc SetStun
e01f: c9 11 cmp #$11 ;if the enemy object identifier is equal to the values
e021: b0 0c bcs SetStun ; $09, $0e, $0f or $10, it will be modified, and not
e023: c9 0a cmp #$0a ; modified if not any of those values, note that piranha plant will
e025: 90 04 bcc Demote ; always fail this test because A will still have vertical
e027: c9 0d cmp #PiranhaPlant ; coordinate from previous addition, also these comparisons
e029: 90 04 bcc SetStun ; are only necessary if branching from $d7a1
e02b: 29 01 Demote and #%00000001 ;erase all but LSB, essentially turning enemy object
e02d: 95 16 sta Enemy_ID,x ; into green or red koopa troopa to demote them
;
e02f: b5 1e SetStun lda Enemy_State,x ;load enemy state
e031: 29 f0 and #%11110000 ;save high nybble
e033: 09 02 ora #%00000010
e035: 95 1e sta Enemy_State,x ;set d1 of enemy state
e037: d6 cf dec Enemy_Y_Position,x
e039: d6 cf dec Enemy_Y_Position,x ;subtract two pixels from enemy's vertical position
e03b: b5 16 lda Enemy_ID,x
e03d: c9 07 cmp #Bloober ;check for bloober object
e03f: f0 07 beq SetWySpd
e041: a9 fd lda #$fd ;set default vertical speed
e043: ac 4e 07 ldy AreaType
e046: d0 02 bne SetNotW ;if area type not water, set as speed, otherwise
e048: a9 ff SetWySpd lda #$ff ;change the vertical speed
e04a: 95 a0 SetNotW sta Enemy_Y_Speed,x ;set vertical speed now
e04c: a0 01 ldy #$01
e04e: 20 43 e1 jsr PlayerEnemyDiff ;get horizontal difference between player and enemy object
e051: 10 01 bpl ChkBBill ;branch if enemy is to the right of player
e053: c8 iny ;increment Y if not
e054: b5 16 ChkBBill lda Enemy_ID,x
e056: c9 33 cmp #BulletBill_CannonVar ;check for bullet bill (cannon variant)
e058: f0 06 beq NoCDirF
e05a: c9 08 cmp #BulletBill_FrenzyVar ;check for bullet bill (frenzy variant)
e05c: f0 02 beq NoCDirF ;branch if either found, direction does not change
e05e: 94 46 sty Enemy_MovingDir,x ;store as moving direction
e060: 88 NoCDirF dey ;decrement and use as offset
e061: b9 bf df lda EnemyBGCXSpdData,y ;get proper horizontal speed
e064: 95 58 sta Enemy_X_Speed,x ; and store, then leave
e066: 60 ExEBGChk rts
; -----------------------------------------------------------------------------
; $04 - low nybble of vertical coordinate from block buffer routine
LandEnemyProperly
e067: a5 04 lda $04 ;check lower nybble of vertical coordinate saved earlier
e069: 38 sec
e06a: e9 08 sbc #$08 ;subtract eight pixels
e06c: c9 05 cmp #$05 ;used to determine whether enemy landed from falling
e06e: b0 72 bcs ChkForRedKoopa ;branch if lower nybble in range of $0d-$0f before subtract
e070: b5 1e lda Enemy_State,x
e072: 29 40 and #%01000000 ;branch if d6 in enemy state is set
e074: d0 57 bne LandEnemyInitState
e076: b5 1e lda Enemy_State,x
e078: 0a asl A ;branch if d7 in enemy state is not set
e079: 90 03 bcc ChkLandedEnemyState
e07b: 4c fe e0 SChkA jmp DoEnemySideCheck ;if lower nybble < $0d, d7 set but d6 not set, jump here
ChkLandedEnemyState
e07e: b5 1e lda Enemy_State,x ;if enemy in normal state, branch back to jump here
e080: f0 f9 beq SChkA
e082: c9 05 cmp #$05 ;if in state used by spiny's egg
e084: f0 1f beq ProcEnemyDirection ;then branch elsewhere
e086: c9 03 cmp #$03 ;if already in state used by koopas and buzzy beetles
e088: b0 1a bcs ExSteChk ; or in higher numbered state, branch to leave
e08a: b5 1e lda Enemy_State,x ;load enemy state again (why?)
e08c: c9 02 cmp #$02 ;if not in $02 state (used by koopas and buzzy beetles)
e08e: d0 15 bne ProcEnemyDirection ;then branch elsewhere
e090: a9 10 lda #$10 ;load default timer here
e092: b4 16 ldy Enemy_ID,x ;check enemy identifier for spiny
e094: c0 12 cpy #Spiny
e096: d0 02 bne SetForStn ;branch if not found
e098: a9 00 lda #$00 ;set timer for $00 if spiny
e09a: 9d 96 07 SetForStn sta EnemyIntervalTimer,x ;set timer here
e09d: a9 03 lda #$03 ;set state here, apparently used to render
e09f: 95 1e sta Enemy_State,x ; upside-down koopas and buzzy beetles
e0a1: 20 4f e1 jsr EnemyLanding ;then land it properly
e0a4: 60 ExSteChk rts ;then leave
ProcEnemyDirection
e0a5: b5 16 lda Enemy_ID,x ;check enemy identifier for goomba
e0a7: c9 06 cmp #Goomba ;branch if found
e0a9: f0 22 beq LandEnemyInitState
e0ab: c9 12 cmp #Spiny ;check for spiny
e0ad: d0 0e bne InvtD ;branch if not found
e0af: a9 01 lda #$01
e0b1: 95 46 sta Enemy_MovingDir,x ;send enemy moving to the right by default
e0b3: a9 08 lda #$08
e0b5: 95 58 sta Enemy_X_Speed,x ;set horizontal speed accordingly
e0b7: a5 09 lda FrameCounter
e0b9: 29 07 and #%00000111 ;if timed appropriately, spiny will skip over
e0bb: f0 10 beq LandEnemyInitState ;trying to face the player
e0bd: a0 01 InvtD ldy #$01 ;load 1 for enemy to face the left (inverted here)
e0bf: 20 43 e1 jsr PlayerEnemyDiff ;get horizontal difference between player and enemy
e0c2: 10 01 bpl CNwCDir ;if enemy to the right of player, branch
e0c4: c8 iny ;if to the left, increment by one for enemy to face right (inverted)
e0c5: 98 CNwCDir tya
e0c6: d5 46 cmp Enemy_MovingDir,x ;compare direction in A with current direction in memory
e0c8: d0 03 bne LandEnemyInitState
e0ca: 20 24 e1 jsr ChkForBump_HammerBroJ ;if equal, not facing in correct dir, do sub to turn around
LandEnemyInitState
e0cd: 20 4f e1 jsr EnemyLanding ;land enemy properly
e0d0: b5 1e lda Enemy_State,x
e0d2: 29 80 and #%10000000 ;if d7 of enemy state is set, branch
e0d4: d0 05 bne NMovShellFallBit
e0d6: a9 00 lda #$00 ;otherwise initialize enemy state and leave
e0d8: 95 1e sta Enemy_State,x ;note this will also turn spiny's egg into spiny
e0da: 60 rts
NMovShellFallBit
e0db: b5 1e lda Enemy_State,x ;nullify d6 of enemy state, save other bits
e0dd: 29 bf and #%10111111 ;and store, then leave
e0df: 95 1e sta Enemy_State,x
e0e1: 60 rts
; -----------------------------------------------------------------------------
e0e2: b5 16 ChkForRedKoopa lda Enemy_ID,x ;check for red koopa troopa $03
e0e4: c9 03 cmp #RedKoopa
e0e6: d0 04 bne Chk2MSBSt ;branch if not found
e0e8: b5 1e lda Enemy_State,x
e0ea: f0 38 beq ChkForBump_HammerBroJ ;if enemy found and in normal state, branch
e0ec: b5 1e Chk2MSBSt lda Enemy_State,x ;save enemy state into Y
e0ee: a8 tay
e0ef: 0a asl A ;check for d7 set
e0f0: 90 07 bcc GetSteFromD ;branch if not set
e0f2: b5 1e lda Enemy_State,x
e0f4: 09 40 ora #%01000000 ;set d6
e0f6: 4c fc e0 jmp SetD6Ste ;jump ahead of this part
e0f9: b9 b9 df GetSteFromD lda EnemyBGCStateData,y ;load new enemy state with old as offset
e0fc: 95 1e SetD6Ste sta Enemy_State,x ;set as new state
; $00 - used to store bitmask (not used but initialized here)
; $eb - used in DoEnemySideCheck as counter and to compare moving directions
DoEnemySideCheck
e0fe: b5 cf lda Enemy_Y_Position,x ;if enemy within status bar, branch to leave
e100: c9 20 cmp #$20 ; because there's nothing there that impedes movement
e102: 90 1f bcc ExESdeC
e104: a0 16 ldy #$16 ;start by finding block to the left of enemy ($00,$14)
e106: a9 02 lda #$02 ;set value here in what is also used as
e108: 85 eb sta $eb ;OAM data offset
e10a: a5 eb SdeCLoop lda $eb ;check value
e10c: d5 46 cmp Enemy_MovingDir,x ;compare value against moving direction
e10e: d0 0c bne NextSdeC ;branch if different and do not seek block there
e110: a9 01 lda #$01 ;set flag in A for save horizontal coordinate
e112: 20 88 e3 jsr BlockBufferChk_Enemy ;find block to left or right of enemy object
e115: f0 05 beq NextSdeC ;if nothing found, branch
e117: 20 b5 e1 jsr ChkForNonSolids ;check for non-solid blocks
e11a: d0 08 bne ChkForBump_HammerBroJ ;branch if not found
e11c: c6 eb NextSdeC dec $eb ;move to the next direction
e11e: c8 iny
e11f: c0 18 cpy #$18 ;increment Y, loop only if Y < $18, thus we check
e121: 90 e7 bcc SdeCLoop ;enemy ($00, $14) and ($10, $14) pixel coordinates
e123: 60 ExESdeC rts
ChkForBump_HammerBroJ
e124: e0 05 cpx #$05 ;check if we're on the special use slot
e126: f0 09 beq NoBump ; and if so, branch ahead and do not play sound
e128: b5 1e lda Enemy_State,x ;if enemy state d7 not set, branch
e12a: 0a asl A ; ahead and do not play sound
e12b: 90 04 bcc NoBump
e12d: a9 02 lda #Sfx_Bump ;otherwise, play bump sound
e12f: 85 ff sta Square1SoundQueue ;sound will never be played if branching from ChkForRedKoopa
e131: b5 16 NoBump lda Enemy_ID,x ;check for hammer bro
e133: c9 05 cmp #HammerBro
e135: d0 09 bne InvEnemyDir ;branch if not found
e137: a9 00 lda #$00
e139: 85 00 sta $00 ;initialize value here for bitmask
e13b: a0 fa ldy #$fa ;load default vertical speed for jumping
e13d: 4c 37 ca jmp SetHJ ;jump to code that makes hammer bro jump
e140: 4c 36 db InvEnemyDir jmp RXSpd ;jump to turn the enemy around
; -----------------------------------------------------------------------------
; $00 - used to hold horizontal difference between player and enemy
e143: b5 87 PlayerEnemyDiff lda Enemy_X_Position,x ;get distance between enemy object's
e145: 38 sec ; horizontal coordinate and the player's
e146: e5 86 sbc Player_X_Position ; horizontal coordinate
e148: 85 00 sta $00 ;and store here
e14a: b5 6e lda Enemy_PageLoc,x
e14c: e5 6d sbc Player_PageLoc ;subtract borrow, then leave
e14e: 60 rts
; -----------------------------------------------------------------------------
e14f: 20 63 c3 EnemyLanding jsr InitVStf ;do something here to vertical speed and something else
e152: b5 cf lda Enemy_Y_Position,x
e154: 29 f0 and #%11110000 ;save high nybble of vertical coordinate, and
e156: 09 08 ora #%00001000 ; set d3, then store, probably used to set enemy object
e158: 95 cf sta Enemy_Y_Position,x ; neatly on whatever it's landing on
e15a: 60 rts
e15b: b5 cf SubtEnemyYPos lda Enemy_Y_Position,x ;add 62 pixels to enemy object's
e15d: 18 clc ; vertical coordinate
e15e: 69 3e adc #$3e
e160: c9 44 cmp #$44 ;compare against a certain range
e162: 60 rts ; and leave with flags set for conditional branch
e163: 20 5b e1 EnemyJump jsr SubtEnemyYPos ;do a sub here
e166: 90 1a bcc DoSide ;if enemy vertical coord + 62 < 68, branch to leave
e168: b5 a0 lda Enemy_Y_Speed,x
e16a: 18 clc ;add two to vertical speed
e16b: 69 02 adc #$02
e16d: c9 03 cmp #$03 ;if green paratroopa not falling, branch ahead
e16f: 90 11 bcc DoSide
e171: 20 ae e1 jsr ChkUnderEnemy ;otherwise, check to see if green paratroopa is
e174: f0 0c beq DoSide ; standing on anything, then branch to same place if not
e176: 20 b5 e1 jsr ChkForNonSolids ;check for non-solid blocks
e179: f0 07 beq DoSide ;branch if found
e17b: 20 4f e1 jsr EnemyLanding ;change vertical coordinate and speed
e17e: a9 fd lda #$fd
e180: 95 a0 sta Enemy_Y_Speed,x ;make the paratroopa jump again
e182: 4c fe e0 DoSide jmp DoEnemySideCheck ;check for horizontal blockage, then leave
; -----------------------------------------------------------------------------
e185: 20 ae e1 HammerBroBGColl jsr ChkUnderEnemy ;check to see if hammer bro is standing on anything
e188: f0 1d beq NoUnderHammerBro
e18a: c9 23 cmp #$23 ;check for blank metatile $23 and branch if not found
e18c: d0 08 bne UnderHammerBro
KillEnemyAboveBlock
e18e: 20 95 d7 jsr ShellOrBlockDefeat ;do this sub to kill enemy
e191: a9 fc lda #$fc ;alter vertical speed of enemy and leave
e193: 95 a0 sta Enemy_Y_Speed,x
e195: 60 rts
e196: bd 8a 07 UnderHammerBro lda EnemyFrameTimer,x ;check timer used by hammer bro
e199: d0 0c bne NoUnderHammerBro ;branch if not expired
e19b: b5 1e lda Enemy_State,x
e19d: 29 88 and #%10001000 ;save d7 and d3 from enemy state, nullify other bits
e19f: 95 1e sta Enemy_State,x ;and store
e1a1: 20 4f e1 jsr EnemyLanding ;modify vertical coordinate, speed and something else
e1a4: 4c fe e0 jmp DoEnemySideCheck ;then check for horizontal blockage and leave
NoUnderHammerBro
e1a7: b5 1e lda Enemy_State,x ;if hammer bro is not standing on anything, set d0
e1a9: 09 01 ora #$01 ; in the enemy state to indicate jumping or falling, then leave
e1ab: 95 1e sta Enemy_State,x
e1ad: 60 rts
e1ae: a9 00 ChkUnderEnemy lda #$00 ;set flag in A for save vertical coordinate
e1b0: a0 15 ldy #$15 ;set Y to check the bottom middle (8,18) of enemy object
e1b2: 4c 88 e3 jmp BlockBufferChk_Enemy ;hop to it!
e1b5: c9 26 ChkForNonSolids cmp #$26 ;blank metatile used for vines?
e1b7: f0 0e beq NSFnd
e1b9: c9 c2 cmp #$c2 ;regular coin?
e1bb: f0 0a beq NSFnd
e1bd: c9 c3 cmp #$c3 ;underwater coin?
e1bf: f0 06 beq NSFnd
e1c1: c9 5f cmp #$5f ;hidden coin block?
e1c3: f0 02 beq NSFnd
e1c5: c9 60 cmp #$60 ;hidden 1-up block?
e1c7: 60 NSFnd rts
FireballBGCollision
e1c8: b5 d5 lda Fireball_Y_Position,x ;check fireball's vertical coordinate
e1ca: c9 18 cmp #$18
e1cc: 90 21 bcc ClearBounceFlag ;if within the status bar area of the screen, branch ahead
e1ce: 20 9c e3 jsr BlockBufferChk_FBall ;do fireball to background collision detection on bottom of it
e1d1: f0 1c beq ClearBounceFlag ;if nothing underneath fireball, branch
e1d3: 20 b5 e1 jsr ChkForNonSolids ;check for non-solid metatiles
e1d6: f0 17 beq ClearBounceFlag ;branch if any found
e1d8: b5 a6 lda Fireball_Y_Speed,x ;if fireball's vertical speed set to move upwards,
e1da: 30 18 bmi InitFireballExplode ;branch to set exploding bit in fireball's state
e1dc: b5 3a lda FireballBouncingFlag,x ;if bouncing flag already set,
e1de: d0 14 bne InitFireballExplode ;branch to set exploding bit in fireball's state
e1e0: a9 fd lda #$fd
e1e2: 95 a6 sta Fireball_Y_Speed,x ;otherwise set vertical speed to move upwards (give it bounce)
e1e4: a9 01 lda #$01
e1e6: 95 3a sta FireballBouncingFlag,x ;set bouncing flag
e1e8: b5 d5 lda Fireball_Y_Position,x
e1ea: 29 f8 and #$f8 ;modify vertical coordinate to land it properly
e1ec: 95 d5 sta Fireball_Y_Position,x ;store as new vertical coordinate
e1ee: 60 rts ;leave
e1ef: a9 00 ClearBounceFlag lda #$00
e1f1: 95 3a sta FireballBouncingFlag,x ;clear bouncing flag by default
e1f3: 60 rts ;leave
InitFireballExplode
e1f4: a9 80 lda #$80
e1f6: 95 24 sta Fireball_State,x ;set exploding flag in fireball's state
e1f8: a9 02 lda #Sfx_Bump
e1fa: 85 ff sta Square1SoundQueue ;load bump sound
e1fc: 60 rts ;leave
; -----------------------------------------------------------------------------
; $00 - used to hold one of bitmasks, or offset
; $01 - used for relative X coordinate, also used to store middle screen page
; location
; $02 - used for relative Y coordinate, also used to store middle screen
; coordinate
;
; this data added to relative coordinates of sprite objects stored in order:
; left edge, top edge, right edge, bottom edge
BoundBoxCtrlData
e1fd: 02 08 0e 20 .bulk $02,$08,$0e,$20
e201: 03 14 0d 20 .bulk $03,$14,$0d,$20
e205: 02 14 0e 20 .bulk $02,$14,$0e,$20
e209: 02 09 0e 15 .bulk $02,$09,$0e,$15
e20d: 00 00 18 06 .bulk $00,$00,$18,$06
e211: 00 00 20 0d .bulk $00,$00,$20,$0d
e215: 00 00 30 0d .bulk $00,$00,$30,$0d
e219: 00 00 08 08 .bulk $00,$00,$08,$08
e21d: 06 04 0a 08 .bulk $06,$04,$0a,$08
e221: 03 0e 0d 14 .bulk $03,$0e,$0d,$14
e225: 00 02 10 15 .bulk $00,$02,$10,$15
e229: 04 04 0c 1c .bulk $04,$04,$0c,$1c
GetFireballBoundBox
e22d: 8a txa ;add seven bytes to offset
e22e: 18 clc ; to use in routines as offset for fireball
e22f: 69 07 adc #$07
e231: aa tax
e232: a0 02 ldy #$02 ;set offset for relative coordinates
e234: d0 07 bne FBallB ;unconditional branch
e236: 8a GetMiscBoundBox txa ;add nine bytes to offset
e237: 18 clc ; to use in routines as offset for misc object
e238: 69 09 adc #$09
e23a: aa tax
e23b: a0 06 ldy #$06 ;set offset for relative coordinates
e23d: 20 9c e2 FBallB jsr BoundingBoxCore ;get bounding box coordinates
e240: 4c de e2 jmp CheckRightScreenBBox ;jump to handle any offscreen coordinates
GetEnemyBoundBox
e243: a0 48 ldy #$48 ;store bitmask here for now
e245: 84 00 sty $00
e247: a0 44 ldy #$44 ;store another bitmask here for now and jump
e249: 4c 52 e2 jmp GetMaskedOffScrBits
SmallPlatformBoundBox
e24c: a0 08 ldy #$08 ;store bitmask here for now
e24e: 84 00 sty $00
e250: a0 04 ldy #$04 ;store another bitmask here for now
GetMaskedOffScrBits
e252: b5 87 lda Enemy_X_Position,x ;get enemy object position relative
e254: 38 sec ; to the left side of the screen
e255: ed 1c 07 sbc ScreenLeft_X_Pos
e258: 85 01 sta $01 ;store here
e25a: b5 6e lda Enemy_PageLoc,x ;subtract borrow from current page location
e25c: ed 1a 07 sbc ScreenLeft_PageLoc ; of left side
e25f: 30 06 bmi CMBits ;if enemy object is beyond left edge, branch
e261: 05 01 ora $01
e263: f0 02 beq CMBits ;if precisely at the left edge, branch
e265: a4 00 ldy $00 ;if to the right of left edge, use value in $00 for A
e267: 98 CMBits tya ;otherwise use contents of Y
e268: 2d d1 03 and Enemy_OffscreenBits ;preserve bitwise whatever's in here
e26b: 9d d8 03 sta EnemyOffscrBitsMasked,x ;save masked offscreen bits here
e26e: d0 19 bne MoveBoundBoxOffscreen ;if anything set here, branch
e270: 4c 7c e2 jmp SetupEOffsetFBBox ;otherwise, do something else
LargePlatformBoundBox
e273: e8 inx ;increment X to get the proper offset
e274: 20 f6 f1 jsr GetXOffscreenBits ;then jump directly to the sub for horizontal offscreen bits
e277: ca dex ;decrement to return to original offset
e278: c9 fe cmp #$fe ;if completely offscreen, branch to put entire bounding
e27a: b0 0d bcs MoveBoundBoxOffscreen ; box offscreen, otherwise start getting coordinates
SetupEOffsetFBBox
e27c: 8a txa ;add 1 to offset to properly address
e27d: 18 clc ; the enemy object memory locations
e27e: 69 01 adc #$01
e280: aa tax
e281: a0 01 ldy #$01 ;load 1 as offset here, same reason
e283: 20 9c e2 jsr BoundingBoxCore ;do a sub to get the coordinates of the bounding box
e286: 4c de e2 jmp CheckRightScreenBBox ;jump to handle offscreen coordinates of bounding box
MoveBoundBoxOffscreen
e289: 8a txa ;multiply offset by 4
e28a: 0a asl A
e28b: 0a asl A
e28c: a8 tay ;use as offset here
e28d: a9 ff lda #$ff
e28f: 99 b0 04 sta EnemyBoundingBoxCoord,y ;load value into four locations here and leave
e292: 99 b1 04 sta EnemyBoundingBoxCoord+1,y
e295: 99 b2 04 sta EnemyBoundingBoxCoord+2,y
e298: 99 b3 04 sta EnemyBoundingBoxCoord+3,y
e29b: 60 rts
e29c: 86 00 BoundingBoxCore stx $00 ;save offset here
e29e: b9 b8 03 lda SprObject_Rel_YPos,y ;store object coordinates relative to screen
e2a1: 85 02 sta $02 ;vertically and horizontally, respectively
e2a3: b9 ad 03 lda SprObject_Rel_XPos,y
e2a6: 85 01 sta $01
e2a8: 8a txa ;multiply offset by four and save to stack
e2a9: 0a asl A
e2aa: 0a asl A
e2ab: 48 pha
e2ac: a8 tay ;use as offset for Y, X is left alone
e2ad: bd 99 04 lda SprObj_BoundBoxCtrl,x ;load value here to be used as offset for X
e2b0: 0a asl A ;multiply that by four and use as X
e2b1: 0a asl A
e2b2: aa tax
e2b3: a5 01 lda $01 ;add the first number in the bounding box data to the
e2b5: 18 clc ; relative horizontal coordinate using enemy object offset
e2b6: 7d fd e1 adc BoundBoxCtrlData,x ; and store somewhere using same offset * 4
e2b9: 99 ac 04 sta BoundingBox_UL_XPos,y ;store here
e2bc: a5 01 lda $01
e2be: 18 clc
e2bf: 7d ff e1 adc BoundBoxCtrlData+2,x ;add the third number in the bounding box data to the
e2c2: 99 ae 04 sta BoundingBox_DR_XPos,y ; relative horizontal coordinate and store
e2c5: e8 inx ;increment both offsets
e2c6: c8 iny
e2c7: a5 02 lda $02 ;add the second number to the relative vertical coordinate
e2c9: 18 clc ; using incremented offset and store using the other
e2ca: 7d fd e1 adc BoundBoxCtrlData,x ; incremented offset
e2cd: 99 ac 04 sta BoundingBox_UL_XPos,y
e2d0: a5 02 lda $02
e2d2: 18 clc
e2d3: 7d ff e1 adc BoundBoxCtrlData+2,x ;add the fourth number to the relative vertical coordinate
e2d6: 99 ae 04 sta BoundingBox_DR_XPos,y ;and store
e2d9: 68 pla ;get original offset loaded into $00 * y from stack
e2da: a8 tay ;use as Y
e2db: a6 00 ldx $00 ;get original offset and use as X again
e2dd: 60 rts
CheckRightScreenBBox
e2de: ad 1c 07 lda ScreenLeft_X_Pos ;add 128 pixels to left side of screen
e2e1: 18 clc ; and store as horizontal coordinate of middle
e2e2: 69 80 adc #$80
e2e4: 85 02 sta $02
e2e6: ad 1a 07 lda ScreenLeft_PageLoc ;add carry to page location of left side of screen
e2e9: 69 00 adc #$00 ; and store as page location of middle
e2eb: 85 01 sta $01
e2ed: b5 86 lda SprObject_X_Position,x ;get horizontal coordinate
e2ef: c5 02 cmp $02 ;compare against middle horizontal coordinate
e2f1: b5 6d lda SprObject_PageLoc,x ;get page location
e2f3: e5 01 sbc $01 ;subtract from middle page location
e2f5: 90 15 bcc CheckLeftScreenBBox ;if object is on the left side of the screen, branch
e2f7: b9 ae 04 lda BoundingBox_DR_XPos,y ;check right-side edge of bounding box for offscreen
e2fa: 30 0d bmi NoOfs ; coordinates, branch if still on the screen
e2fc: a9 ff lda #$ff ;load offscreen value here to use on one or both horizontal sides
e2fe: be ac 04 ldx BoundingBox_UL_XPos,y ;check left-side edge of bounding box for offscreen
e301: 30 03 bmi SORte ; coordinates, and branch if still on the screen
e303: 99 ac 04 sta BoundingBox_UL_XPos,y ;store offscreen value for left side
e306: 99 ae 04 SORte sta BoundingBox_DR_XPos,y ;store offscreen value for right side
e309: a6 08 NoOfs ldx ObjectOffset ;get object offset and leave
e30b: 60 rts
CheckLeftScreenBBox
e30c: b9 ac 04 lda BoundingBox_UL_XPos,y ;check left-side edge of bounding box for offscreen
e30f: 10 11 bpl NoOfs2 ; coordinates, and branch if still on the screen
e311: c9 a0 cmp #$a0 ;check to see if left-side edge is in the middle of the
e313: 90 0d bcc NoOfs2 ; screen or really offscreen, and branch if still on
e315: a9 00 lda #$00
e317: be ae 04 ldx BoundingBox_DR_XPos,y ;check right-side edge of bounding box for offscreen
e31a: 10 03 bpl SOLft ; coordinates, branch if still onscreen
e31c: 99 ae 04 sta BoundingBox_DR_XPos,y ;store offscreen value for right side
e31f: 99 ac 04 SOLft sta BoundingBox_UL_XPos,y ;store offscreen value for left side
e322: a6 08 NoOfs2 ldx ObjectOffset ;get object offset and leave
e324: 60 rts
; -----------------------------------------------------------------------------
; $06 - second object's offset
; $07 - counter
PlayerCollisionCore
e325: a2 00 ldx #$00 ;initialize X to use player's bounding box for comparison
SprObjectCollisionCore
e327: 84 06 sty $06 ;save contents of Y here
e329: a9 01 lda #$01
e32b: 85 07 sta $07 ;save value 1 here as counter, compare horizontal coordinates first
CollisionCoreLoop
e32d: b9 ac 04 lda BoundingBox_UL_XPos,y ;compare left/top coordinates
e330: dd ac 04 cmp BoundingBox_UL_XPos,x ; of first and second objects' bounding boxes
e333: b0 2a bcs FirstBoxGreater ;if first left/top => second, branch
e335: dd ae 04 cmp BoundingBox_DR_XPos,x ;otherwise compare to right/bottom of second
e338: 90 12 bcc SecondBoxVerticalChk ;if first left/top < second right/bottom, branch elsewhere
e33a: f0 42 beq CollisionFound ;if somehow equal, collision, thus branch
e33c: b9 ae 04 lda BoundingBox_DR_XPos,y ;if somehow greater, check to see if bottom of
e33f: d9 ac 04 cmp BoundingBox_UL_XPos,y ; first object's bounding box is greater than its top
e342: 90 3a bcc CollisionFound ;if somehow less, vertical wrap collision, thus branch
e344: dd ac 04 cmp BoundingBox_UL_XPos,x ;otherwise compare bottom of first bounding box to the top
e347: b0 35 bcs CollisionFound ; of second box, and if equal or greater, collision, thus branch
e349: a4 06 ldy $06 ;otherwise return with carry clear and Y = $0006
e34b: 60 rts ;note horizontal wrapping never occurs
SecondBoxVerticalChk
e34c: bd ae 04 lda BoundingBox_DR_XPos,x ;check to see if the vertical bottom of the box
e34f: dd ac 04 cmp BoundingBox_UL_XPos,x ; is greater than the vertical top
e352: 90 2a bcc CollisionFound ;if somehow less, vertical wrap collision, thus branch
e354: b9 ae 04 lda BoundingBox_DR_XPos,y ;otherwise compare horizontal right or vertical bottom
e357: dd ac 04 cmp BoundingBox_UL_XPos,x ; of first box with horizontal left or vertical top of second box
e35a: b0 22 bcs CollisionFound ;if equal or greater, collision, thus branch
e35c: a4 06 ldy $06 ;otherwise return with carry clear and Y = $0006
e35e: 60 rts
e35f: dd ac 04 FirstBoxGreater cmp BoundingBox_UL_XPos,x ;compare first and second box horizontal left/vertical top again
e362: f0 1a beq CollisionFound ;if first coordinate = second, collision, thus branch
e364: dd ae 04 cmp BoundingBox_DR_XPos,x ;if not, compare with second object right or bottom edge
e367: 90 15 bcc CollisionFound ;if left/top of first less than or equal to right/bottom of second
e369: f0 13 beq CollisionFound ; then collision, thus branch
e36b: d9 ae 04 cmp BoundingBox_DR_XPos,y ;otherwise check to see if top of first box is greater than bottom
e36e: 90 0a bcc NoCollisionFound ;if less than or equal, no collision, branch to end
e370: f0 08 beq NoCollisionFound
e372: b9 ae 04 lda BoundingBox_DR_XPos,y ;otherwise compare bottom of first to top of second
e375: dd ac 04 cmp BoundingBox_UL_XPos,x ;if bottom of first is greater than top of second, vertical wrap
e378: b0 04 bcs CollisionFound ; collision, and branch, otherwise, proceed onwards here
NoCollisionFound
e37a: 18 clc ;clear carry, then load value set earlier, then leave
e37b: a4 06 ldy $06 ;like previous ones, if horizontal coordinates do not collide, we do
e37d: 60 rts ; not bother checking vertical ones, because what's the point?
e37e: e8 CollisionFound inx ;increment offsets on both objects to check
e37f: c8 iny ; the vertical coordinates
e380: c6 07 dec $07 ;decrement counter to reflect this
e382: 10 a9 bpl CollisionCoreLoop ;if counter not expired, branch to loop
e384: 38 sec ;otherwise we already did both sets, therefore collision, so set carry
e385: a4 06 ldy $06 ;load original value set here earlier, then leave
e387: 60 rts
; -----------------------------------------------------------------------------
; $02 - modified y coordinate
; $03 - stores metatile involved in block buffer collisions
; $04 - comes in with offset to block buffer adder data, goes out with low
; nybble x/y coordinate
; $05 - modified x coordinate
; $06-$07 - block buffer address
BlockBufferChk_Enemy
e388: 48 pha ;save contents of A to stack
e389: 8a txa
e38a: 18 clc ;add 1 to X to run sub with enemy offset in mind
e38b: 69 01 adc #$01
e38d: aa tax
e38e: 68 pla ;pull A from stack and jump elsewhere
e38f: 4c a5 e3 jmp BBChk_E
e392: 8a unref_e392 txa
e393: 18 clc ;supposedly used once to set offset for
e394: 69 0d adc #$0d ; miscellaneous objects
e396: aa tax
e397: a0 1b ldy #$1b ;supposedly used once to set offset for block buffer data
e399: 4c a3 e3 jmp ResJmpM ;probably used in early stages to do misc to bg collision detection
BlockBufferChk_FBall
e39c: a0 1a ldy #$1a ;set offset for block buffer adder data
e39e: 8a txa
e39f: 18 clc
e3a0: 69 07 adc #$07 ;add seven bytes to use
e3a2: aa tax
e3a3: a9 00 ResJmpM lda #$00 ;set A to return vertical coordinate
e3a5: 20 f0 e3 BBChk_E jsr BlockBufferCollision ;do collision detection subroutine for sprite object
e3a8: a6 08 ldx ObjectOffset ;get object offset
e3aa: c9 00 cmp #$00 ;check to see if object bumped into anything
e3ac: 60 rts
BlockBufferAdderData
e3ad: 00 07 0e .bulk $00,$07,$0e
BlockBuffer_X_Adder
e3b0: 08 03 0c 02+ .bulk $08,$03,$0c,$02,$02,$0d,$0d,$08,$03,$0c,$02,$02,$0d,$0d,$08,$03
+ $0c,$02,$02,$0d,$0d,$08,$00,$10,$04,$14,$04,$04
BlockBuffer_Y_Adder
e3cc: 04 20 20 08+ .bulk $04,$20,$20,$08,$18,$08,$18,$02,$20,$20,$08,$18,$08,$18,$12,$20
+ $20,$18,$18,$18,$18,$18,$14,$14,$06,$06,$08,$10
BlockBufferColli_Feet
e3e8: c8 iny ;if branched here, increment to next set of adders
BlockBufferColli_Head
e3e9: a9 00 lda #$00 ;set flag to return vertical coordinate
e3eb: 2c bit βΌ $01a9 ;BIT instruction opcode
BlockBufferColli_Side
e3ec: a9 01 lda #$01 ;set flag to return horizontal coordinate
e3ee: a2 00 ldx #$00 ;set offset for player object
BlockBufferCollision
e3f0: 48 pha ;save contents of A to stack
e3f1: 84 04 sty $04 ;save contents of Y here
e3f3: b9 b0 e3 lda BlockBuffer_X_Adder,y ;add horizontal coordinate
e3f6: 18 clc ; of object to value obtained using Y as offset
e3f7: 75 86 adc SprObject_X_Position,x
e3f9: 85 05 sta $05 ;store here
e3fb: b5 6d lda SprObject_PageLoc,x
e3fd: 69 00 adc #$00 ;add carry to page location
e3ff: 29 01 and #$01 ;get LSB, mask out all other bits
e401: 4a lsr A ;move to carry
e402: 05 05 ora $05 ;get stored value
e404: 6a ror A ;rotate carry to MSB of A
e405: 4a lsr A ; and effectively move high nybble to
e406: 4a lsr A ; lower, LSB which became MSB will be
e407: 4a lsr A ; d4 at this point
e408: 20 e1 9b jsr GetBlockBufferAddr ;get address of block buffer into $06, $07
e40b: a4 04 ldy $04 ;get old contents of Y
e40d: b5 ce lda SprObject_Y_Position,x ;get vertical coordinate of object
e40f: 18 clc
e410: 79 cc e3 adc BlockBuffer_Y_Adder,y ;add it to value obtained using Y as offset
e413: 29 f0 and #%11110000 ;mask out low nybble
e415: 38 sec
e416: e9 20 sbc #$20 ;subtract 32 pixels for the status ba
e418: 85 02 sta $02 ;store result here
e41a: a8 tay ;use as offset for block buffer
e41b: b1 06 lda ($06),y ;check current content of block buffer
e41d: 85 03 sta $03 ;and store here
e41f: a4 04 ldy $04 ;get old contents of Y again
e421: 68 pla ;pull A from stack
e422: d0 05 bne RetXC ;if A = 1, branch
e424: b5 ce lda SprObject_Y_Position,x ;if A = 0, load vertical coordinate
e426: 4c 2b e4 jmp RetYC ;and jump
e429: b5 86 RetXC lda SprObject_X_Position,x ;otherwise load horizontal coordinate
e42b: 29 0f RetYC and #%00001111 ;and mask out high nybble
e42d: 85 04 sta $04 ;store masked out result here
e42f: a5 03 lda $03 ;get saved content of block buffer
e431: 60 rts ;and leave
; -----------------------------------------------------------------------------
e432: ff .dd1 $ff ;unused byte
; -----------------------------------------------------------------------------
; $00 - offset to vine Y coordinate adder
; $02 - offset to sprite data
e433: 00 30 VineYPosAdder .bulk $00,$30
e435: 84 00 DrawVine sty $00 ;save offset here
e437: ad b9 03 lda Enemy_Rel_YPos ;get relative vertical coordinate
e43a: 18 clc
e43b: 79 33 e4 adc VineYPosAdder,y ;add value using offset in Y to get value
e43e: be 9a 03 ldx VineObjOffset,y ;get offset to vine
e441: bc e5 06 ldy Enemy_SprDataOffset,x ;get sprite data offset
e444: 84 02 sty $02 ;store sprite data offset here
e446: 20 ae e4 jsr SixSpriteStacker ;stack six sprites on top of each other vertically
e449: ad ae 03 lda Enemy_Rel_XPos ;get relative horizontal coordinate
e44c: 99 03 02 sta Sprite_X_Position,y ;store in first, third and fifth sprites
e44f: 99 0b 02 sta Sprite_X_Position+8,y
e452: 99 13 02 sta Sprite_X_Position+16,y
e455: 18 clc
e456: 69 06 adc #$06 ;add six pixels to second, fourth and sixth sprites
e458: 99 07 02 sta Sprite_X_Position+4,y ; to give characteristic staggered vine shape to
e45b: 99 0f 02 sta Sprite_X_Position+12,y ; our vertical stack of sprites
e45e: 99 17 02 sta Sprite_X_Position+20,y
e461: a9 21 lda #%00100001 ;set bg priority and palette attribute bits
e463: 99 02 02 sta Sprite_Attributes,y ;set in first, third and fifth sprites
e466: 99 0a 02 sta Sprite_Attributes+8,y
e469: 99 12 02 sta Sprite_Attributes+16,y
e46c: 09 40 ora #%01000000 ;additionally, set horizontal flip bit
e46e: 99 06 02 sta Sprite_Attributes+4,y ; for second, fourth and sixth sprites
e471: 99 0e 02 sta Sprite_Attributes+12,y
e474: 99 16 02 sta Sprite_Attributes+20,y
e477: a2 05 ldx #$05 ;set tiles for six sprites
e479: a9 e1 VineTL lda #$e1 ;set tile number for sprite
e47b: 99 01 02 sta Sprite_Tilenumber,y
e47e: c8 iny ;move offset to next sprite data
e47f: c8 iny
e480: c8 iny
e481: c8 iny
e482: ca dex ;move onto next sprite
e483: 10 f4 bpl VineTL ;loop until all sprites are done
e485: a4 02 ldy $02 ;get original offset
e487: a5 00 lda $00 ;get offset to vine adding data
e489: d0 05 bne SkpVTop ;if offset not zero, skip this part
e48b: a9 e0 lda #$e0
e48d: 99 01 02 sta Sprite_Tilenumber,y ;set other tile number for top of vine
e490: a2 00 SkpVTop ldx #$00 ;start with the first sprite again
e492: ad 9d 03 ChkFTop lda VineStart_Y_Position ;get original starting vertical coordinate
e495: 38 sec
e496: f9 00 02 sbc Sprite_Y_Position,y ;subtract top-most sprite's Y coordinate
e499: c9 64 cmp #$64 ;if two coordinates are less than 100/$64 pixels
e49b: 90 05 bcc NextVSp ; apart, skip this to leave sprite alone
e49d: a9 f8 lda #$f8
e49f: 99 00 02 sta Sprite_Y_Position,y ;otherwise move sprite offscreen
e4a2: c8 NextVSp iny ;move offset to next OAM data
e4a3: c8 iny
e4a4: c8 iny
e4a5: c8 iny
e4a6: e8 inx ;move onto next sprite
e4a7: e0 06 cpx #$06 ;do this until all sprites are checked
e4a9: d0 e7 bne ChkFTop
e4ab: a4 00 ldy $00 ;return offset set earlier
e4ad: 60 rts
SixSpriteStacker
e4ae: a2 06 ldx #$06 ;do six sprites
e4b0: 99 00 02 StkLp sta Sprite_Data,y ;store X or Y coordinate into OAM data
e4b3: 18 clc
e4b4: 69 08 adc #$08 ;add eight pixels
e4b6: c8 iny
e4b7: c8 iny ;move offset four bytes forward
e4b8: c8 iny
e4b9: c8 iny
e4ba: ca dex ;do another sprite
e4bb: d0 f3 bne StkLp ;do this until all sprites are done
e4bd: a4 02 ldy $02 ;get saved OAM data offset and leave
e4bf: 60 rts
; -----------------------------------------------------------------------------
e4c0: 04 00 04 00 FirstSprXPos .bulk $04,$00,$04,$00
e4c4: 00 04 00 04 FirstSprYPos .bulk $00,$04,$00,$04
e4c8: 00 08 00 08 SecondSprXPos .bulk $00,$08,$00,$08
e4cc: 08 00 08 00 SecondSprYPos .bulk $08,$00,$08,$00
e4d0: 80 82 81 83 FirstSprTilenum .bulk $80,$82,$81,$83
SecondSprTilenum
e4d4: 81 83 80 82 .bulk $81,$83,$80,$82
e4d8: 03 03 c3 c3 HammerSprAttrib .bulk $03,$03,$c3,$c3
e4dc: bc f3 06 DrawHammer ldy Misc_SprDataOffset,x ;get misc object OAM data offset
e4df: ad 47 07 lda TimerControl
e4e2: d0 08 bne ForceHPose ;if master timer control set, skip this part
e4e4: b5 2a lda Misc_State,x ;otherwise get hammer's state
e4e6: 29 7f and #%01111111 ;mask out d7
e4e8: c9 01 cmp #$01 ;check to see if set to 1 yet
e4ea: f0 04 beq GetHPose ;if so, branch
e4ec: a2 00 ForceHPose ldx #$00 ;reset offset here
e4ee: f0 07 beq RdnerH ;do unconditional branch to rendering part
e4f0: a5 09 GetHPose lda FrameCounter ;get frame counter
e4f2: 4a lsr A ;move d3-d2 to d1-d0
e4f3: 4a lsr A
e4f4: 29 03 and #%00000011 ;mask out all but d1-d0 (changes every four frames)
e4f6: aa tax ;use as timing offset
e4f7: ad be 03 RdnerH lda Misc_Rel_YPos ;get relative vertical coordinate
e4fa: 18 clc
e4fb: 7d c4 e4 adc FirstSprYPos,x ;add first sprite vertical adder based on offset
e4fe: 99 00 02 sta Sprite_Y_Position,y ;store as sprite Y coordinate for first sprite
e501: 18 clc
e502: 7d cc e4 adc SecondSprYPos,x ;add second sprite vertical adder based on offset
e505: 99 04 02 sta Sprite_Y_Position+4,y ;store as sprite Y coordinate for second sprite
e508: ad b3 03 lda Misc_Rel_XPos ;get relative horizontal coordinate
e50b: 18 clc
e50c: 7d c0 e4 adc FirstSprXPos,x ;add first sprite horizontal adder based on offset
e50f: 99 03 02 sta Sprite_X_Position,y ;store as sprite X coordinate for first sprite
e512: 18 clc
e513: 7d c8 e4 adc SecondSprXPos,x ;add second sprite horizontal adder based on offset
e516: 99 07 02 sta Sprite_X_Position+4,y ;store as sprite X coordinate for second sprite
e519: bd d0 e4 lda FirstSprTilenum,x
e51c: 99 01 02 sta Sprite_Tilenumber,y ;get and store tile number of first sprite
e51f: bd d4 e4 lda SecondSprTilenum,x
e522: 99 05 02 sta Sprite_Tilenumber+4,y ;get and store tile number of second sprite
e525: bd d8 e4 lda HammerSprAttrib,x
e528: 99 02 02 sta Sprite_Attributes,y ;get and store attribute bytes for both
e52b: 99 06 02 sta Sprite_Attributes+4,y ;note in this case they use the same data
e52e: a6 08 ldx ObjectOffset ;get misc object offset
e530: ad d6 03 lda Misc_OffscreenBits
e533: 29 fc and #%11111100 ;check offscreen bits
e535: f0 09 beq NoHOffscr ;if all bits clear, leave object alone
e537: a9 00 lda #$00
e539: 95 2a sta Misc_State,x ;otherwise nullify misc object state
e53b: a9 f8 lda #$f8
e53d: 20 c1 e5 jsr DumpTwoSpr ;do sub to move hammer sprites offscreen
e540: 60 NoHOffscr rts ;leave
; -----------------------------------------------------------------------------
; $00-$01 - used to hold tile numbers ($01 addressed in draw floatey number
; part)
; $02 - used to hold Y coordinate for floatey number
; $03 - residual byte used for flip (but value set here affects nothing)
; $04 - attribute byte for floatey number
; $05 - used as X coordinate for floatey number
FlagpoleScoreNumTiles
e541: f9 50 .bulk $f9,$50
e543: f7 50 .bulk $f7,$50
e545: fa fb .bulk $fa,$fb
e547: f8 fb .bulk $f8,$fb
e549: f6 fb .bulk $f6,$fb
FlagpoleGfxHandler
e54b: bc e5 06 ldy Enemy_SprDataOffset,x ;get sprite data offset for flagpole flag
e54e: ad ae 03 lda Enemy_Rel_XPos ;get relative horizontal coordinate
e551: 99 03 02 sta Sprite_X_Position,y ;store as X coordinate for first sprite
e554: 18 clc
e555: 69 08 adc #$08 ;add eight pixels and store
e557: 99 07 02 sta Sprite_X_Position+4,y ; as X coordinate for second and third sprites
e55a: 99 0b 02 sta Sprite_X_Position+8,y
e55d: 18 clc
e55e: 69 0c adc #$0c ;add twelve more pixels and
e560: 85 05 sta $05 ; store here to be used later by floatey number
e562: b5 cf lda Enemy_Y_Position,x ;get vertical coordinate
e564: 20 c1 e5 jsr DumpTwoSpr ; and do sub to dump into first and second sprites
e567: 69 08 adc #$08 ;add eight pixels
e569: 99 08 02 sta Sprite_Y_Position+8,y ;and store into third sprite
e56c: ad 0d 01 lda FlagpoleFNum_Y_Pos ;get vertical coordinate for floatey number
e56f: 85 02 sta $02 ;store it here
e571: a9 01 lda #$01
e573: 85 03 sta $03 ;set value for flip which will not be used, and
e575: 85 04 sta $04 ; attribute byte for floatey number
e577: 99 02 02 sta Sprite_Attributes,y ;set attribute bytes for all three sprites
e57a: 99 06 02 sta Sprite_Attributes+4,y
e57d: 99 0a 02 sta Sprite_Attributes+8,y
e580: a9 7e lda #$7e
e582: 99 01 02 sta Sprite_Tilenumber,y ;put triangle shaped tile
e585: 99 09 02 sta Sprite_Tilenumber+8,y ; into first and third sprites
e588: a9 7f lda #$7f
e58a: 99 05 02 sta Sprite_Tilenumber+4,y ;put skull tile into second sprite
e58d: ad 0f 07 lda FlagpoleCollisionYPos ;get vertical coordinate at time of collision
e590: f0 15 beq ChkFlagOffscreen ;if zero, branch ahead
e592: 98 tya
e593: 18 clc ;add 12 bytes to sprite data offset
e594: 69 0c adc #$0c
e596: a8 tay ;put back in Y
e597: ad 0f 01 lda FlagpoleScore ;get offset used to award points for touching flagpole
e59a: 0a asl A ;multiply by 2 to get proper offset here
e59b: aa tax
e59c: bd 41 e5 lda FlagpoleScoreNumTiles,x ;get appropriate tile data
e59f: 85 00 sta $00
e5a1: bd 42 e5 lda FlagpoleScoreNumTiles+1,x
e5a4: 20 b2 eb jsr DrawOneSpriteRow ;use it to render floatey number
ChkFlagOffscreen
e5a7: a6 08 ldx ObjectOffset ;get object offset for flag
e5a9: bc e5 06 ldy Enemy_SprDataOffset,x ;get OAM data offset
e5ac: ad d1 03 lda Enemy_OffscreenBits ;get offscreen bits
e5af: 29 0e and #%00001110 ;mask out all but d3-d1
e5b1: f0 14 beq ExitDumpSpr ;if none of these bits set, branch to leave
;
MoveSixSpritesOffscreen
e5b3: a9 f8 lda #$f8 ;set offscreen coordinate if jumping here
e5b5: 99 14 02 DumpSixSpr sta Sprite_Data+20,y ;dump A contents
e5b8: 99 10 02 sta Sprite_Data+16,y ;into third row sprites
e5bb: 99 0c 02 DumpFourSpr sta Sprite_Data+12,y ;into second row sprites
e5be: 99 08 02 DumpThreeSpr sta Sprite_Data+8,y
e5c1: 99 04 02 DumpTwoSpr sta Sprite_Data+4,y ;and into first row sprites
e5c4: 99 00 02 sta Sprite_Data,y
e5c7: 60 ExitDumpSpr rts
; -----------------------------------------------------------------------------
DrawLargePlatform
e5c8: bc e5 06 ldy Enemy_SprDataOffset,x ;get OAM data offset
e5cb: 84 02 sty $02 ;store here
e5cd: c8 iny ;add 3 to it for offset
e5ce: c8 iny ; to X coordinate
e5cf: c8 iny
e5d0: ad ae 03 lda Enemy_Rel_XPos ;get horizontal relative coordinate
e5d3: 20 ae e4 jsr SixSpriteStacker ;store X coordinates using A as base, stack horizontally
e5d6: a6 08 ldx ObjectOffset
e5d8: b5 cf lda Enemy_Y_Position,x ;get vertical coordinate
e5da: 20 bb e5 jsr DumpFourSpr ;dump into first four sprites as Y coordinate
e5dd: ac 4e 07 ldy AreaType
e5e0: c0 03 cpy #$03 ;check for castle-type level
e5e2: f0 05 beq ShrinkPlatform
e5e4: ac cc 06 ldy SecondaryHardMode ;check for secondary hard mode flag set
e5e7: f0 02 beq SetLast2Platform ;branch if not set elsewhere
e5e9: a9 f8 ShrinkPlatform lda #$f8 ;load offscreen coordinate if flag set or castle-type level
SetLast2Platform
e5eb: bc e5 06 ldy Enemy_SprDataOffset,x ;get OAM data offset
e5ee: 99 10 02 sta Sprite_Y_Position+16,y ;store vertical coordinate or offscreen
e5f1: 99 14 02 sta Sprite_Y_Position+20,y ; coordinate into last two sprites as Y coordinate
e5f4: a9 5b lda #$5b ;load default tile for platform (girder)
e5f6: ae 43 07 ldx CloudTypeOverride
e5f9: f0 02 beq SetPlatformTilenum ;if cloud level override flag not set, use
e5fb: a9 75 lda #$75 ;otherwise load other tile for platform (puff)
SetPlatformTilenum
e5fd: a6 08 ldx ObjectOffset ;get enemy object buffer offset
e5ff: c8 iny ;increment Y for tile offset
e600: 20 b5 e5 jsr DumpSixSpr ;dump tile number into all six sprites
e603: a9 02 lda #$02 ;set palette controls
e605: c8 iny ;increment Y for sprite attributes
e606: 20 b5 e5 jsr DumpSixSpr ;dump attributes into all six sprites
e609: e8 inx ;increment X for enemy objects
e60a: 20 f6 f1 jsr GetXOffscreenBits ;get offscreen bits again
e60d: ca dex
e60e: bc e5 06 ldy Enemy_SprDataOffset,x ;get OAM data offset
e611: 0a asl A ;rotate d7 into carry, save remaining
e612: 48 pha ;bits to the stack
e613: 90 05 bcc SChk2
e615: a9 f8 lda #$f8 ;if d7 was set, move first sprite offscreen
e617: 99 00 02 sta Sprite_Y_Position,y
e61a: 68 SChk2 pla ;get bits from stack
e61b: 0a asl A ;rotate d6 into carry
e61c: 48 pha ;save to stack
e61d: 90 05 bcc SChk3
e61f: a9 f8 lda #$f8 ;if d6 was set, move second sprite offscreen
e621: 99 04 02 sta Sprite_Y_Position+4,y
e624: 68 SChk3 pla ;get bits from stack
e625: 0a asl A ;rotate d5 into carry
e626: 48 pha ;save to stack
e627: 90 05 bcc SChk4
e629: a9 f8 lda #$f8 ;if d5 was set, move third sprite offscreen
e62b: 99 08 02 sta Sprite_Y_Position+8,y
e62e: 68 SChk4 pla ;get bits from stack
e62f: 0a asl A ;rotate d4 into carry
e630: 48 pha ;save to stack
e631: 90 05 bcc SChk5
e633: a9 f8 lda #$f8 ;if d4 was set, move fourth sprite offscreen
e635: 99 0c 02 sta Sprite_Y_Position+12,y
e638: 68 SChk5 pla ;get bits from stack
e639: 0a asl A ;rotate d3 into carry
e63a: 48 pha ;save to stack
e63b: 90 05 bcc SChk6
e63d: a9 f8 lda #$f8 ;if d3 was set, move fifth sprite offscreen
e63f: 99 10 02 sta Sprite_Y_Position+16,y
e642: 68 SChk6 pla ;get bits from stack
e643: 0a asl A ;rotate d2 into carry
e644: 90 05 bcc SLChk ;save to stack
e646: a9 f8 lda #$f8
e648: 99 14 02 sta Sprite_Y_Position+20,y ;if d2 was set, move sixth sprite offscreen
e64b: ad d1 03 SLChk lda Enemy_OffscreenBits ;check d7 of offscreen bits
e64e: 0a asl A ;and if d7 is not set, skip sub
e64f: 90 03 bcc ExDLPl
e651: 20 b3 e5 jsr MoveSixSpritesOffscreen ;otherwise branch to move all sprites offscreen
e654: 60 ExDLPl rts
; -----------------------------------------------------------------------------
DrawFloateyNumber_Coin
e655: a5 09 lda FrameCounter ;get frame counter
e657: 4a lsr A ;divide by 2
e658: b0 02 bcs NotRsNum ;branch if d0 not set to raise number every other frame
e65a: d6 db dec Misc_Y_Position,x ;otherwise, decrement vertical coordinate
e65c: b5 db NotRsNum lda Misc_Y_Position,x ;get vertical coordinate
e65e: 20 c1 e5 jsr DumpTwoSpr ;dump into both sprites
e661: ad b3 03 lda Misc_Rel_XPos ;get relative horizontal coordinate
e664: 99 03 02 sta Sprite_X_Position,y ;store as X coordinate for first sprite
e667: 18 clc
e668: 69 08 adc #$08 ;add eight pixels
e66a: 99 07 02 sta Sprite_X_Position+4,y ;store as X coordinate for second sprite
e66d: a9 02 lda #$02
e66f: 99 02 02 sta Sprite_Attributes,y ;store attribute byte in both sprites
e672: 99 06 02 sta Sprite_Attributes+4,y
e675: a9 f7 lda #$f7
e677: 99 01 02 sta Sprite_Tilenumber,y ;put tile numbers into both sprites
e67a: a9 fb lda #$fb ; that resemble "200"
e67c: 99 05 02 sta Sprite_Tilenumber+4,y
e67f: 4c bd e6 jmp ExJcGfx ;then jump to leave (why not an rts here instead?)
JumpingCoinTiles
e682: 60 61 62 63 .bulk $60,$61,$62,$63
e686: bc f3 06 JCoinGfxHandler ldy Misc_SprDataOffset,x ;get coin/floatey number's OAM data offset
e689: b5 2a lda Misc_State,x ;get state of misc object
e68b: c9 02 cmp #$02 ;if 2 or greater,
e68d: b0 c6 bcs DrawFloateyNumber_Coin ; branch to draw floatey number
e68f: b5 db lda Misc_Y_Position,x ;store vertical coordinate as
e691: 99 00 02 sta Sprite_Y_Position,y ; Y coordinate for first sprite
e694: 18 clc
e695: 69 08 adc #$08 ;add eight pixels
e697: 99 04 02 sta Sprite_Y_Position+4,y ;store as Y coordinate for second sprite
e69a: ad b3 03 lda Misc_Rel_XPos ;get relative horizontal coordinate
e69d: 99 03 02 sta Sprite_X_Position,y
e6a0: 99 07 02 sta Sprite_X_Position+4,y ;store as X coordinate for first and second sprites
e6a3: a5 09 lda FrameCounter ;get frame counter
e6a5: 4a lsr A ;divide by 2 to alter every other frame
e6a6: 29 03 and #%00000011 ;mask out d2-d1
e6a8: aa tax ;use as graphical offset
e6a9: bd 82 e6 lda JumpingCoinTiles,x ;load tile number
e6ac: c8 iny ;increment OAM data offset to write tile numbers
e6ad: 20 c1 e5 jsr DumpTwoSpr ;do sub to dump tile number into both sprites
e6b0: 88 dey ;decrement to get old offset
e6b1: a9 02 lda #$02
e6b3: 99 02 02 sta Sprite_Attributes,y ;set attribute byte in first sprite
e6b6: a9 82 lda #$82
e6b8: 99 06 02 sta Sprite_Attributes+4,y ;set attribute byte with vertical flip in second sprite
e6bb: a6 08 ldx ObjectOffset ;get misc object offset
e6bd: 60 ExJcGfx rts ;leave
; -----------------------------------------------------------------------------
; $00-$01 - used to hold tiles for drawing the power-up, $00 also used to hold
; power-up type
; $02 - used to hold bottom row Y position
; $03 - used to hold flip control (not used here)
; $04 - used to hold sprite attributes
; $05 - used to hold X position
; $07 - counter
;
; tiles arranged in top left, right, bottom left, right order
e6be: 76 77 78 79 PowerUpGfxTable .bulk $76,$77,$78,$79
e6c2: d6 d6 d9 d9 .bulk $d6,$d6,$d9,$d9
e6c6: 8d 8d e4 e4 .bulk $8d,$8d,$e4,$e4
e6ca: 76 77 78 79 .bulk $76,$77,$78,$79
PowerUpAttributes
e6ce: 02 01 02 01 .bulk $02,$01,$02,$01
e6d2: ac ea 06 DrawPowerUp ldy Enemy_SprDataOffset+5 ;get power-up's sprite data offset
e6d5: ad b9 03 lda Enemy_Rel_YPos ;get relative vertical coordinate
e6d8: 18 clc
e6d9: 69 08 adc #$08 ;add eight pixels
e6db: 85 02 sta $02 ;store result here
e6dd: ad ae 03 lda Enemy_Rel_XPos ;get relative horizontal coordinate
e6e0: 85 05 sta $05 ;store here
e6e2: a6 39 ldx PowerUpType ;get power-up type
e6e4: bd ce e6 lda PowerUpAttributes,x ;get attribute data for power-up type
e6e7: 0d ca 03 ora Enemy_SprAttrib+5 ;add background priority bit if set
e6ea: 85 04 sta $04 ;store attributes here
e6ec: 8a txa
e6ed: 48 pha ;save power-up type to the stack
e6ee: 0a asl A
e6ef: 0a asl A ;multiply by four to get proper offset
e6f0: aa tax ;use as X
e6f1: a9 01 lda #$01
e6f3: 85 07 sta $07 ;set counter here to draw two rows of sprite object
e6f5: 85 03 sta $03 ;init d1 of flip control
e6f7: bd be e6 PUpDrawLoop lda PowerUpGfxTable,x ;load left tile of power-up object
e6fa: 85 00 sta $00
e6fc: bd bf e6 lda PowerUpGfxTable+1,x ;load right tile
e6ff: 20 b2 eb jsr DrawOneSpriteRow ;branch to draw one row of our power-up object
e702: c6 07 dec $07 ;decrement counter
e704: 10 f1 bpl PUpDrawLoop ;branch until two rows are drawn
e706: ac ea 06 ldy Enemy_SprDataOffset+5 ;get sprite data offset again
e709: 68 pla ;pull saved power-up type from the stack
e70a: f0 2f beq PUpOfs ;if regular mushroom, branch, do not change colors or flip
e70c: c9 03 cmp #$03
e70e: f0 2b beq PUpOfs ;if 1-up mushroom, branch, do not change colors or flip
e710: 85 00 sta $00 ;store power-up type here now
e712: a5 09 lda FrameCounter ;get frame counter
e714: 4a lsr A ;divide by 2 to change colors every two frames
e715: 29 03 and #%00000011 ;mask out all but d1 and d0 (previously d2 and d1)
e717: 0d ca 03 ora Enemy_SprAttrib+5 ;add background priority bit if any set
e71a: 99 02 02 sta Sprite_Attributes,y ;set as new palette bits for top left and
e71d: 99 06 02 sta Sprite_Attributes+4,y ;top right sprites for fire flower and star
e720: a6 00 ldx $00
e722: ca dex ;check power-up type for fire flower
e723: f0 06 beq FlipPUpRightSide ;if found, skip this part
e725: 99 0a 02 sta Sprite_Attributes+8,y ;otherwise set new palette bits for bottom left
e728: 99 0e 02 sta Sprite_Attributes+12,y ; and bottom right sprites as well for star only
FlipPUpRightSide
e72b: b9 06 02 lda Sprite_Attributes+4,y
e72e: 09 40 ora #%01000000 ;set horizontal flip bit for top right sprite
e730: 99 06 02 sta Sprite_Attributes+4,y
e733: b9 0e 02 lda Sprite_Attributes+12,y
e736: 09 40 ora #%01000000 ;set horizontal flip bit for bottom right sprite
e738: 99 0e 02 sta Sprite_Attributes+12,y ;note these are only done for fire flower and star power-ups
e73b: 4c 64 eb PUpOfs jmp SprObjectOffscrChk ;jump to check to see if power-up is offscreen at all, then leave
; -----------------------------------------------------------------------------
; $00-$01 - used in DrawEnemyObjRow to hold sprite tile numbers
; $02 - used to store Y position
; $03 - used to store moving direction, used to flip enemies horizontally
; $04 - used to store enemy's sprite attributes
; $05 - used to store X position
; $eb - used to hold sprite data offset
; $ec - used to hold either altered enemy state or special value used in gfx
; handler as condition
; $ed - used to hold enemy state from buffer
; $ef - used to hold enemy code used in gfx handler (may or may not resemble
; Enemy_ID values)
;
; tiles arranged in top left, right, middle left, right, bottom left, right
; order
EnemyGraphicsTable
e73e: fc fc aa ab+ .bulk $fc,$fc,$aa,$ab,$ac,$ad ;buzzy beetle frame 1
e744: fc fc ae af+ .bulk $fc,$fc,$ae,$af,$b0,$b1 ; frame 2
e74a: fc a5 a6 a7+ .bulk $fc,$a5,$a6,$a7,$a8,$a9 ;koopa troopa frame 1
e750: fc a0 a1 a2+ .bulk $fc,$a0,$a1,$a2,$a3,$a4 ; frame 2
e756: 69 a5 6a a7+ .bulk $69,$a5,$6a,$a7,$a8,$a9 ;koopa paratroopa frame 1
e75c: 6b a0 6c a2+ .bulk $6b,$a0,$6c,$a2,$a3,$a4 ; frame 2
e762: fc fc 96 97+ .bulk $fc,$fc,$96,$97,$98,$99 ;spiny frame 1
e768: fc fc 9a 9b+ .bulk $fc,$fc,$9a,$9b,$9c,$9d ; frame 2
e76e: fc fc 8f 8e+ .bulk $fc,$fc,$8f,$8e,$8e,$8f ;spiny's egg frame 1
e774: fc fc 95 94+ .bulk $fc,$fc,$95,$94,$94,$95 ; frame 2
e77a: fc fc dc dc+ .bulk $fc,$fc,$dc,$dc,$df,$df ;bloober frame 1
e780: dc dc dd dd+ .bulk $dc,$dc,$dd,$dd,$de,$de ; frame 2
e786: fc fc b2 b3+ .bulk $fc,$fc,$b2,$b3,$b4,$b5 ;cheep-cheep frame 1
e78c: fc fc b6 b3+ .bulk $fc,$fc,$b6,$b3,$b7,$b5 ; frame 2
e792: fc fc 70 71+ .bulk $fc,$fc,$70,$71,$72,$73 ;goomba
e798: fc fc 6e 6e+ .bulk $fc,$fc,$6e,$6e,$6f,$6f ;koopa shell frame 1 (upside-down)
e79e: fc fc 6d 6d+ .bulk $fc,$fc,$6d,$6d,$6f,$6f ; frame 2
e7a4: fc fc 6f 6f+ .bulk $fc,$fc,$6f,$6f,$6e,$6e ;koopa shell frame 1 (rightsideup)
e7aa: fc fc 6f 6f+ .bulk $fc,$fc,$6f,$6f,$6d,$6d ; frame 2
e7b0: fc fc f4 f4+ .bulk $fc,$fc,$f4,$f4,$f5,$f5 ;buzzy beetle shell frame 1 (rightsideup)
e7b6: fc fc f4 f4+ .bulk $fc,$fc,$f4,$f4,$f5,$f5 ; frame 2
e7bc: fc fc f5 f5+ .bulk $fc,$fc,$f5,$f5,$f4,$f4 ;buzzy beetle shell frame 1 (upside-down)
e7c2: fc fc f5 f5+ .bulk $fc,$fc,$f5,$f5,$f4,$f4 ; frame 2
e7c8: fc fc fc fc+ .bulk $fc,$fc,$fc,$fc,$ef,$ef ;defeated goomba
e7ce: b9 b8 bb ba+ .bulk $b9,$b8,$bb,$ba,$bc,$bc ;lakitu frame 1
e7d4: fc fc bd bd+ .bulk $fc,$fc,$bd,$bd,$bc,$bc ; frame 2
e7da: 7a 7b da db+ .bulk $7a,$7b,$da,$db,$d8,$d8 ;princess
e7e0: cd cd ce ce+ .bulk $cd,$cd,$ce,$ce,$cf,$cf ;mushroom retainer
e7e6: 7d 7c d1 8c+ .bulk $7d,$7c,$d1,$8c,$d3,$d2 ;hammer bro frame 1
e7ec: 7d 7c 89 88+ .bulk $7d,$7c,$89,$88,$8b,$8a ; frame 2
e7f2: d5 d4 e3 e2+ .bulk $d5,$d4,$e3,$e2,$d3,$d2 ; frame 3
e7f8: d5 d4 e3 e2+ .bulk $d5,$d4,$e3,$e2,$8b,$8a ; frame 4
e7fe: e5 e5 e6 e6+ .bulk $e5,$e5,$e6,$e6,$eb,$eb ;piranha plant frame 1
e804: ec ec ed ed+ .bulk $ec,$ec,$ed,$ed,$ee,$ee ; frame 2
e80a: fc fc d0 d0+ .bulk $fc,$fc,$d0,$d0,$d7,$d7 ;podoboo
e810: bf be c1 c0+ .bulk $bf,$be,$c1,$c0,$c2,$fc ;bowser front frame 1
e816: c4 c3 c6 c5+ .bulk $c4,$c3,$c6,$c5,$c8,$c7 ;bowser rear frame 1
e81c: bf be ca c9+ .bulk $bf,$be,$ca,$c9,$c2,$fc ; front frame 2
e822: c4 c3 c6 c5+ .bulk $c4,$c3,$c6,$c5,$cc,$cb ; rear frame 2
e828: fc fc e8 e7+ .bulk $fc,$fc,$e8,$e7,$ea,$e9 ;bullet bill
e82e: f2 f2 f3 f3+ .bulk $f2,$f2,$f3,$f3,$f2,$f2 ;jumpspring frame 1
e834: f1 f1 f1 f1+ .bulk $f1,$f1,$f1,$f1,$fc,$fc ; frame 2
e83a: f0 f0 fc fc+ .bulk $f0,$f0,$fc,$fc,$fc,$fc ; frame 3
EnemyGfxTableOffsets
e840: 0c 0c 00 0c+ .bulk $0c,$0c,$00,$0c,$0c,$a8,$54,$3c,$ea,$18,$48,$48,$cc,$c0,$18,$18
+ $18,$90,$24,$ff,$48,$9c,$d2,$d8,$f0,$f6,$fc
EnemyAttributeData
e85b: 01 02 03 02+ .bulk $01,$02,$03,$02,$01,$01,$03,$03,$03,$01,$01,$02,$02,$21,$01,$02
+ $01,$01,$02,$ff,$02,$02,$01,$01,$02,$02,$02
EnemyAnimTimingBMask
e876: 08 18 .bulk $08,$18
JumpspringFrameOffsets
e878: 18 19 1a 19+ .bulk $18,$19,$1a,$19,$18
e87d: b5 cf EnemyGfxHandler lda Enemy_Y_Position,x ;get enemy object vertical position
e87f: 85 02 sta $02
e881: ad ae 03 lda Enemy_Rel_XPos ;get enemy object horizontal position
e884: 85 05 sta $05 ; relative to screen
e886: bc e5 06 ldy Enemy_SprDataOffset,x
e889: 84 eb sty $eb ;get sprite data offset
e88b: a9 00 lda #$00
e88d: 8d 09 01 sta VerticalFlipFlag ;initialize vertical flip flag by default
e890: b5 46 lda Enemy_MovingDir,x
e892: 85 03 sta $03 ;get enemy object moving direction
e894: bd c5 03 lda Enemy_SprAttrib,x
e897: 85 04 sta $04 ;get enemy object sprite attributes
e899: b5 16 lda Enemy_ID,x
e89b: c9 0d cmp #PiranhaPlant ;is enemy object piranha plant?
e89d: d0 0a bne CheckForRetainerObj ;if not, branch
e89f: b4 58 ldy PiranhaPlant_Y_Speed,x
e8a1: 30 06 bmi CheckForRetainerObj ;if piranha plant moving upwards, branch
e8a3: bc 8a 07 ldy EnemyFrameTimer,x
e8a6: f0 01 beq CheckForRetainerObj ;if timer for movement expired, branch
e8a8: 60 rts ;if all conditions fail, leave
CheckForRetainerObj
e8a9: b5 1e lda Enemy_State,x ;store enemy state
e8ab: 85 ed sta $ed
e8ad: 29 1f and #%00011111 ;nullify all but 5 LSB and use as Y
e8af: a8 tay
e8b0: b5 16 lda Enemy_ID,x ;check for mushroom retainer/princess object
e8b2: c9 35 cmp #$35
e8b4: d0 08 bne CheckForBulletBillCV ;if not found, branch
e8b6: a0 00 ldy #$00 ;if found, nullify saved state in Y
e8b8: a9 01 lda #$01 ;set value that will not be used
e8ba: 85 03 sta $03
e8bc: a9 15 lda #$15 ;set value $15 as code for mushroom retainer/princess object
CheckForBulletBillCV
e8be: c9 33 cmp #BulletBill_CannonVar ;otherwise check for bullet bill object
e8c0: d0 13 bne CheckForJumpspring ;if not found, branch again
e8c2: c6 02 dec $02 ;decrement saved vertical position
e8c4: a9 03 lda #$03
e8c6: bc 8a 07 ldy EnemyFrameTimer,x ;get timer for enemy object
e8c9: f0 02 beq SBBAt ;if expired, do not set priority bit
e8cb: 09 20 ora #%00100000 ;otherwise do so
e8cd: 85 04 SBBAt sta $04 ;set new sprite attributes
e8cf: a0 00 ldy #$00 ;nullify saved enemy state both in Y and in
e8d1: 84 ed sty $ed ; memory location here
e8d3: a9 08 lda #$08 ;set specific value to unconditionally branch once
CheckForJumpspring
e8d5: c9 32 cmp #JumpspringObject ;check for jumpspring object
e8d7: d0 08 bne CheckForPodoboo
e8d9: a0 03 ldy #$03 ;set enemy state -2 MSB here for jumpspring object
e8db: ae 0e 07 ldx JumpspringAnimCtrl ;get current frame number for jumpspring object
e8de: bd 78 e8 lda JumpspringFrameOffsets,x ;load data using frame number as offset
e8e1: 85 ef CheckForPodoboo sta $ef ;store saved enemy object value here
e8e3: 84 ec sty $ec ; and Y here (enemy state -2 MSB if not changed)
e8e5: a6 08 ldx ObjectOffset ;get enemy object offset
e8e7: c9 0c cmp #$0c ;check for podoboo object
e8e9: d0 07 bne CheckBowserGfxFlag ;branch if not found
e8eb: b5 a0 lda Enemy_Y_Speed,x ;if moving upwards, branch
e8ed: 30 03 bmi CheckBowserGfxFlag
e8ef: ee 09 01 inc VerticalFlipFlag ;otherwise, set flag for vertical flip
CheckBowserGfxFlag
e8f2: ad 6a 03 lda BowserGfxFlag ;if not drawing bowser at all, skip to something else
e8f5: f0 09 beq CheckForGoomba
e8f7: a0 16 ldy #$16 ;if set to 1, draw bowser's front
e8f9: c9 01 cmp #$01
e8fb: f0 01 beq SBwsrGfxOfs
e8fd: c8 iny ;otherwise draw bowser's rear
e8fe: 84 ef SBwsrGfxOfs sty $ef
e900: a4 ef CheckForGoomba ldy $ef ;check value for goomba object
e902: c0 06 cpy #$06
e904: d0 1d bne CheckBowserFront ;branch if not found
e906: b5 1e lda Enemy_State,x
e908: c9 02 cmp #$02 ;check for defeated state
e90a: 90 04 bcc GmbaAnim ;if not defeated, go ahead and animate
e90c: a2 04 ldx #$04 ;if defeated, write new value here
e90e: 86 ec stx $ec
e910: 29 20 GmbaAnim and #%00100000 ;check for d5 set in enemy object state
e912: 0d 47 07 ora TimerControl ;or timer disable flag set
e915: d0 0c bne CheckBowserFront ;if either condition true, do not animate goomba
e917: a5 09 lda FrameCounter
e919: 29 08 and #%00001000 ;check for every eighth frame
e91b: d0 06 bne CheckBowserFront
e91d: a5 03 lda $03
e91f: 49 03 eor #%00000011 ;invert bits to flip horizontally every eight frames
e921: 85 03 sta $03 ;leave alone otherwise
CheckBowserFront
e923: b9 5b e8 lda EnemyAttributeData,y ;load sprite attribute using enemy object
e926: 05 04 ora $04 ; as offset, and add to bits already loaded
e928: 85 04 sta $04
e92a: b9 40 e8 lda EnemyGfxTableOffsets,y ;load value based on enemy object as offset
e92d: aa tax ;save as X
e92e: a4 ec ldy $ec ;get previously saved value
e930: ad 6a 03 lda BowserGfxFlag
e933: f0 30 beq CheckForSpiny ;if not drawing bowser object at all, skip all of this
e935: c9 01 cmp #$01
e937: d0 13 bne CheckBowserRear ;if not drawing front part, branch to draw the rear part
e939: ad 63 03 lda BowserBodyControls ;check bowser's body control bits
e93c: 10 02 bpl CheckFrontSte ;branch if d7 not set (control's bowser's mouth)
e93e: a2 de ldx #$de ;otherwise load offset for second frame
e940: a5 ed CheckFrontSte lda $ed ;check saved enemy state
e942: 29 20 and #%00100000 ;if bowser not defeated, do not set flag
e944: f0 03 beq DrawBowser
e946: 8e 09 01 FlipBowserOver stx VerticalFlipFlag ;set vertical flip flag to nonzero
e949: 4c 4b ea DrawBowser jmp DrawEnemyObject ;draw bowser's graphics now
e94c: ad 63 03 CheckBowserRear lda BowserBodyControls ;check bowser's body control bits
e94f: 29 01 and #$01
e951: f0 02 beq ChkRearSte ;branch if d0 not set (control's bowser's feet)
e953: a2 e4 ldx #$e4 ;otherwise load offset for second frame
e955: a5 ed ChkRearSte lda $ed ;check saved enemy state
e957: 29 20 and #%00100000 ;if bowser not defeated, do not set flag
e959: f0 ee beq DrawBowser
e95b: a5 02 lda $02 ;subtract 16 pixels from
e95d: 38 sec ; saved vertical coordinate
e95e: e9 10 sbc #$10
e960: 85 02 sta $02
e962: 4c 46 e9 jmp FlipBowserOver ;jump to set vertical flip flag
e965: e0 24 CheckForSpiny cpx #$24 ;check if value loaded is for spiny
e967: d0 11 bne CheckForLakitu ;if not found, branch
e969: c0 05 cpy #$05 ;if enemy state set to $05, do this,
e96b: d0 0a bne NotEgg ; otherwise branch
e96d: a2 30 ldx #$30 ;set to spiny egg offset
e96f: a9 02 lda #$02
e971: 85 03 sta $03 ;set enemy direction to reverse sprites horizontally
e973: a9 05 lda #$05
e975: 85 ec sta $ec ;set enemy state
e977: 4c ca e9 NotEgg jmp CheckForHammerBro ;skip a big chunk of this if we found spiny but not in egg
e97a: e0 90 CheckForLakitu cpx #$90 ;check value for lakitu's offset loaded
e97c: d0 12 bne CheckUpsideDownShell ;branch if not loaded
e97e: a5 ed lda $ed
e980: 29 20 and #%00100000 ;check for d5 set in enemy state
e982: d0 09 bne NoLAFr ;branch if set
e984: ad 8f 07 lda FrenzyEnemyTimer
e987: c9 10 cmp #$10 ;check timer to see if we've reached a certain range
e989: b0 02 bcs NoLAFr ;branch if not
e98b: a2 96 ldx #$96 ;if d6 not set and timer in range, load alt frame for lakitu
e98d: 4c 37 ea NoLAFr jmp CheckDefeatedState ;skip this next part if we found lakitu but alt frame not needed
CheckUpsideDownShell
e990: a5 ef lda $ef ;check for enemy object => $04
e992: c9 04 cmp #$04
e994: b0 10 bcs CheckRightSideUpShell ;branch if true
e996: c0 02 cpy #$02
e998: 90 0c bcc CheckRightSideUpShell ;branch if enemy state < $02
e99a: a2 5a ldx #$5a ;set for upside-down koopa shell by default
e99c: a4 ef ldy $ef
e99e: c0 02 cpy #BuzzyBeetle ;check for buzzy beetle object
e9a0: d0 04 bne CheckRightSideUpShell
e9a2: a2 7e ldx #$7e ;set for upside-down buzzy beetle shell if found
e9a4: e6 02 inc $02 ;increment vertical position by one pixel
CheckRightSideUpShell
e9a6: a5 ec lda $ec ;check for value set here
e9a8: c9 04 cmp #$04 ;if enemy state < $02, do not change to shell, if
e9aa: d0 1e bne CheckForHammerBro ; enemy state => $02 but not = $04, leave shell upside-down
e9ac: a2 72 ldx #$72 ;set right-side up buzzy beetle shell by default
e9ae: e6 02 inc $02 ;increment saved vertical position by one pixel
e9b0: a4 ef ldy $ef
e9b2: c0 02 cpy #BuzzyBeetle ;check for buzzy beetle object
e9b4: f0 04 beq CheckForDefdGoomba ;branch if found
e9b6: a2 66 ldx #$66 ;change to right-side up koopa shell if not found
e9b8: e6 02 inc $02 ; and increment saved vertical position again
CheckForDefdGoomba
e9ba: c0 06 cpy #Goomba ;check for goomba object (necessary if previously
e9bc: d0 0c bne CheckForHammerBro ; failed buzzy beetle object test)
e9be: a2 54 ldx #$54 ;load for regular goomba
e9c0: a5 ed lda $ed ;note that this only gets performed if enemy state => $02
e9c2: 29 20 and #%00100000 ;check saved enemy state for d5 set
e9c4: d0 04 bne CheckForHammerBro ;branch if set
e9c6: a2 8a ldx #$8a ;load offset for defeated goomba
e9c8: c6 02 dec $02 ;set different value and decrement saved vertical position
CheckForHammerBro
e9ca: a4 08 ldy ObjectOffset
e9cc: a5 ef lda $ef ;check for hammer bro object
e9ce: c9 05 cmp #HammerBro
e9d0: d0 0c bne CheckForBloober ;branch if not found
e9d2: a5 ed lda $ed
e9d4: f0 24 beq CheckToAnimateEnemy ;branch if not in normal enemy state
e9d6: 29 08 and #%00001000
e9d8: f0 5d beq CheckDefeatedState ;if d3 not set, branch further away
e9da: a2 b4 ldx #$b4 ;otherwise load offset for different frame
e9dc: d0 1c bne CheckToAnimateEnemy ;unconditional branch
e9de: e0 48 CheckForBloober cpx #$48 ;check for cheep-cheep offset loaded
e9e0: f0 18 beq CheckToAnimateEnemy ;branch if found
e9e2: b9 96 07 lda EnemyIntervalTimer,y
e9e5: c9 05 cmp #$05
e9e7: b0 4e bcs CheckDefeatedState ;branch if some timer is above a certain point
e9e9: e0 3c cpx #$3c ;check for bloober offset loaded
e9eb: d0 0d bne CheckToAnimateEnemy ;branch if not found this time
e9ed: c9 01 cmp #$01
e9ef: f0 46 beq CheckDefeatedState ;branch if timer is set to certain point
e9f1: e6 02 inc $02 ;increment saved vertical coordinate three pixels
e9f3: e6 02 inc $02
e9f5: e6 02 inc $02
e9f7: 4c 29 ea jmp CheckAnimationStop ;and do something else
CheckToAnimateEnemy
e9fa: a5 ef lda $ef ;check for specific enemy objects
e9fc: c9 06 cmp #$06
e9fe: f0 37 beq CheckDefeatedState ;branch if goomba
ea00: c9 08 cmp #$08
ea02: f0 33 beq CheckDefeatedState ;branch if bullet bill (note both variants use $08 here)
ea04: c9 0c cmp #$0c
ea06: f0 2f beq CheckDefeatedState ;branch if podoboo
ea08: c9 18 cmp #$18 ;branch if => $18
ea0a: b0 2b bcs CheckDefeatedState
ea0c: a0 00 ldy #$00
ea0e: c9 15 cmp #$15 ;check for mushroom retainer/princess object
ea10: d0 10 bne CheckForSecondFrame ; which uses different code here, branch if not found
ea12: c8 iny ;residual instruction
ea13: ad 5f 07 lda WorldNumber ;are we on world 8?
ea16: c9 07 cmp #World8
ea18: b0 1d bcs CheckDefeatedState ;if so, leave the offset alone (use princess)
ea1a: a2 a2 ldx #$a2 ;otherwise, set for mushroom retainer object instead
ea1c: a9 03 lda #$03 ;set alternate state here
ea1e: 85 ec sta $ec
ea20: d0 15 bne CheckDefeatedState ;unconditional branch
CheckForSecondFrame
ea22: a5 09 lda FrameCounter ;load frame counter
ea24: 39 76 e8 and EnemyAnimTimingBMask,y ;mask it (partly residual, one byte not ever used)
ea27: d0 0e bne CheckDefeatedState ;branch if timing is off
CheckAnimationStop
ea29: a5 ed lda $ed ;check saved enemy state
ea2b: 29 a0 and #%10100000 ;for d7 or d5, or check for timers stopped
ea2d: 0d 47 07 ora TimerControl
ea30: d0 05 bne CheckDefeatedState ;if either condition true, branch
ea32: 8a txa
ea33: 18 clc
ea34: 69 06 adc #$06 ;add $06 to current enemy offset
ea36: aa tax ; to animate various enemy objects
CheckDefeatedState
ea37: a5 ed lda $ed ;check saved enemy state
ea39: 29 20 and #%00100000 ;for d5 set
ea3b: f0 0e beq DrawEnemyObject ;branch if not set
ea3d: a5 ef lda $ef
ea3f: c9 04 cmp #$04 ;check for saved enemy object => $04
ea41: 90 08 bcc DrawEnemyObject ;branch if less
ea43: a0 01 ldy #$01
ea45: 8c 09 01 sty VerticalFlipFlag ;set vertical flip flag
ea48: 88 dey
ea49: 84 ec sty $ec ;init saved value here
ea4b: a4 eb DrawEnemyObject ldy $eb ;load sprite data offset
ea4d: 20 aa eb jsr DrawEnemyObjRow ;draw six tiles of data
ea50: 20 aa eb jsr DrawEnemyObjRow ; into sprite data
ea53: 20 aa eb jsr DrawEnemyObjRow
ea56: a6 08 ldx ObjectOffset ;get enemy object offset
ea58: bc e5 06 ldy Enemy_SprDataOffset,x ;get sprite data offset
ea5b: a5 ef lda $ef
ea5d: c9 08 cmp #$08 ;get saved enemy object and check
ea5f: d0 03 bne CheckForVerticalFlip ; for bullet bill, branch if not found
ea61: 4c 64 eb SkipToOffScrChk jmp SprObjectOffscrChk ;jump if found
CheckForVerticalFlip
ea64: ad 09 01 lda VerticalFlipFlag ;check if vertical flip flag is set here
ea67: f0 3d beq CheckForESymmetry ;branch if not
ea69: b9 02 02 lda Sprite_Attributes,y ;get attributes of first sprite we dealt with
ea6c: 09 80 ora #%10000000 ;set bit for vertical flip
ea6e: c8 iny
ea6f: c8 iny ;increment two bytes so that we store the vertical flip
ea70: 20 b5 e5 jsr DumpSixSpr ; in attribute bytes of enemy obj sprite data
ea73: 88 dey
ea74: 88 dey ;now go back to the Y coordinate offset
ea75: 98 tya
ea76: aa tax ;give offset to X
ea77: a5 ef lda $ef
ea79: c9 05 cmp #HammerBro ;check saved enemy object for hammer bro
ea7b: f0 0d beq FlipEnemyVertically
ea7d: c9 11 cmp #Lakitu ;check saved enemy object for lakitu
ea7f: f0 09 beq FlipEnemyVertically ;branch for hammer bro or lakitu
ea81: c9 15 cmp #$15
ea83: b0 05 bcs FlipEnemyVertically ;also branch if enemy object => $15
ea85: 8a txa
ea86: 18 clc
ea87: 69 08 adc #$08 ;if not selected objects or => $15, set
ea89: aa tax ; offset in X for next row
FlipEnemyVertically
ea8a: bd 01 02 lda Sprite_Tilenumber,x ;load first or second row tiles
ea8d: 48 pha ; and save tiles to the stack
ea8e: bd 05 02 lda Sprite_Tilenumber+4,x
ea91: 48 pha
ea92: b9 11 02 lda Sprite_Tilenumber+16,y ;exchange third row tiles
ea95: 9d 01 02 sta Sprite_Tilenumber,x ; with first or second row tiles
ea98: b9 15 02 lda Sprite_Tilenumber+20,y
ea9b: 9d 05 02 sta Sprite_Tilenumber+4,x
ea9e: 68 pla ;pull first or second row tiles from stack
ea9f: 99 15 02 sta Sprite_Tilenumber+20,y ; and save in third row
eaa2: 68 pla
eaa3: 99 11 02 sta Sprite_Tilenumber+16,y
CheckForESymmetry
eaa6: ad 6a 03 lda BowserGfxFlag ;are we drawing bowser at all?
eaa9: d0 b6 bne SkipToOffScrChk ;branch if so
eaab: a5 ef lda $ef
eaad: a6 ec ldx $ec ;get alternate enemy state
eaaf: c9 05 cmp #$05 ;check for hammer bro object
eab1: d0 03 bne ContES
eab3: 4c 64 eb jmp SprObjectOffscrChk ;jump if found
eab6: c9 07 ContES cmp #Bloober ;check for bloober object
eab8: f0 1d beq MirrorEnemyGfx
eaba: c9 0d cmp #PiranhaPlant ;check for piranha plant object
eabc: f0 19 beq MirrorEnemyGfx
eabe: c9 0c cmp #Podoboo ;check for podoboo object
eac0: f0 15 beq MirrorEnemyGfx ;branch if either of three are found
eac2: c9 12 cmp #Spiny ;check for spiny object
eac4: d0 04 bne ESRtnr ;branch closer if not found
eac6: e0 05 cpx #$05 ;check spiny's state
eac8: d0 48 bne CheckToMirrorLakitu ;branch if not an egg, otherwise
eaca: c9 15 ESRtnr cmp #$15 ; check for princess/mushroom retainer object
eacc: d0 05 bne SpnySC
eace: a9 42 lda #$42 ;set horizontal flip on bottom right sprite
ead0: 99 16 02 sta Sprite_Attributes+20,y ;note that palette bits were already set earlier
ead3: e0 02 SpnySC cpx #$02 ;if alternate enemy state set to 1 or 0, branch
ead5: 90 3b bcc CheckToMirrorLakitu
ead7: ad 6a 03 MirrorEnemyGfx lda BowserGfxFlag ;if enemy object is bowser, skip all of this
eada: d0 36 bne CheckToMirrorLakitu
eadc: b9 02 02 lda Sprite_Attributes,y ;load attribute bits of first sprite
eadf: 29 a3 and #%10100011
eae1: 99 02 02 sta Sprite_Attributes,y ;save vertical flip, priority, and palette bits
eae4: 99 0a 02 sta Sprite_Attributes+8,y ; in left sprite column of enemy object OAM data
eae7: 99 12 02 sta Sprite_Attributes+16,y
eaea: 09 40 ora #%01000000 ;set horizontal flip
eaec: e0 05 cpx #$05 ;check for state used by spiny's egg
eaee: d0 02 bne EggExc ;if alternate state not set to $05, branch
eaf0: 09 80 ora #%10000000 ;otherwise set vertical flip
eaf2: 99 06 02 EggExc sta Sprite_Attributes+4,y ;set bits of right sprite column
eaf5: 99 0e 02 sta Sprite_Attributes+12,y ;of enemy object sprite data
eaf8: 99 16 02 sta Sprite_Attributes+20,y
eafb: e0 04 cpx #$04 ;check alternate enemy state
eafd: d0 13 bne CheckToMirrorLakitu ;branch if not $04
eaff: b9 0a 02 lda Sprite_Attributes+8,y ;get second row left sprite attributes
eb02: 09 80 ora #$80
eb04: 99 0a 02 sta Sprite_Attributes+8,y ;store bits with vertical flip in
eb07: 99 12 02 sta Sprite_Attributes+16,y ; second and third row left sprites
eb0a: 09 40 ora #$40
eb0c: 99 0e 02 sta Sprite_Attributes+12,y ;store with horizontal and vertical flip in
eb0f: 99 16 02 sta Sprite_Attributes+20,y ; second and third row right sprites
CheckToMirrorLakitu
eb12: a5 ef lda $ef ;check for lakitu enemy object
eb14: c9 11 cmp #$11
eb16: d0 36 bne CheckToMirrorJSpring ;branch if not found
eb18: ad 09 01 lda VerticalFlipFlag
eb1b: d0 21 bne NVFlak ;branch if vertical flip flag not set
eb1d: b9 12 02 lda Sprite_Attributes+16,y ;save vertical flip and palette bits
eb20: 29 81 and #%10000001 ; in third row left sprite
eb22: 99 12 02 sta Sprite_Attributes+16,y
eb25: b9 16 02 lda Sprite_Attributes+20,y ;set horizontal flip and palette bits
eb28: 09 41 ora #%01000001 ; in third row right sprite
eb2a: 99 16 02 sta Sprite_Attributes+20,y
eb2d: ae 8f 07 ldx FrenzyEnemyTimer ;check timer
eb30: e0 10 cpx #$10
eb32: b0 30 bcs SprObjectOffscrChk ;branch if timer has not reached a certain range
eb34: 99 0e 02 sta Sprite_Attributes+12,y ;otherwise set same for second row right sprite
eb37: 29 81 and #%10000001
eb39: 99 0a 02 sta Sprite_Attributes+8,y ;preserve vertical flip and palette bits for left sprite
eb3c: 90 26 bcc SprObjectOffscrChk ;unconditional branch
eb3e: b9 02 02 NVFlak lda Sprite_Attributes,y ;get first row left sprite attributes
eb41: 29 81 and #%10000001
eb43: 99 02 02 sta Sprite_Attributes,y ;save vertical flip and palette bits
eb46: b9 06 02 lda Sprite_Attributes+4,y ;get first row right sprite attributes
eb49: 09 41 ora #%01000001 ;set horizontal flip and palette bits
eb4b: 99 06 02 sta Sprite_Attributes+4,y ;note that vertical flip is left as-is
CheckToMirrorJSpring
eb4e: a5 ef lda $ef ;check for jumpspring object (any frame)
eb50: c9 18 cmp #$18
eb52: 90 10 bcc SprObjectOffscrChk ;branch if not jumpspring object at all
eb54: a9 82 lda #$82
eb56: 99 0a 02 sta Sprite_Attributes+8,y ;set vertical flip and palette bits of
eb59: 99 12 02 sta Sprite_Attributes+16,y ; second and third row left sprites
eb5c: 09 40 ora #$40
eb5e: 99 0e 02 sta Sprite_Attributes+12,y ;set, in addition to those, horizontal flip
eb61: 99 16 02 sta Sprite_Attributes+20,y ; for second and third row right sprites
SprObjectOffscrChk
eb64: a6 08 ldx ObjectOffset ;get enemy buffer offset
eb66: ad d1 03 lda Enemy_OffscreenBits ;check offscreen information
eb69: 4a lsr A
eb6a: 4a lsr A ;shift three times to the right
eb6b: 4a lsr A ; which puts d2 into carry
eb6c: 48 pha ;save to stack
eb6d: 90 05 bcc LcChk ;branch if not set
eb6f: a9 04 lda #$04 ;set for right column sprites
eb71: 20 c1 eb jsr MoveESprColOffscreen ; and move them offscreen
eb74: 68 LcChk pla ;get from stack
eb75: 4a lsr A ;move d3 to carry
eb76: 48 pha ;;save to stack
eb77: 90 05 bcc Row3C ;branch if not set
eb79: a9 00 lda #$00 ;set for left column sprites,
eb7b: 20 c1 eb jsr MoveESprColOffscreen ; move them offscreen
eb7e: 68 Row3C pla ;get from stack again
eb7f: 4a lsr A ;move d5 to carry this time
eb80: 4a lsr A
eb81: 48 pha ;save to stack again
eb82: 90 05 bcc Row23C ;branch if carry not set
eb84: a9 10 lda #$10 ;set for third row of sprites
eb86: 20 b7 eb jsr MoveESprRowOffscreen ;and move them offscreen
eb89: 68 Row23C pla ;get from stack
eb8a: 4a lsr A ;move d6 into carry
eb8b: 48 pha ;save to stack
eb8c: 90 05 bcc AllRowC
eb8e: a9 08 lda #$08 ;set for second and third rows
eb90: 20 b7 eb jsr MoveESprRowOffscreen ;move them offscreen
eb93: 68 AllRowC pla ;get from stack once more
eb94: 4a lsr A ;move d7 into carry
eb95: 90 12 bcc ExEGHandler
eb97: 20 b7 eb jsr MoveESprRowOffscreen ;move all sprites offscreen (A should be 0 by now)
eb9a: b5 16 lda Enemy_ID,x
eb9c: c9 0c cmp #Podoboo ;check enemy identifier for podoboo
eb9e: f0 09 beq ExEGHandler ;skip this part if found, we do not want to erase podoboo!
eba0: b5 b6 lda Enemy_Y_HighPos,x ;check high byte of vertical position
eba2: c9 02 cmp #$02 ;if not yet past the bottom of the screen, branch
eba4: d0 03 bne ExEGHandler
eba6: 20 98 c9 jsr EraseEnemyObject ;what it says
eba9: 60 ExEGHandler rts
ebaa: bd 3e e7 DrawEnemyObjRow lda EnemyGraphicsTable,x ;load two tiles of enemy graphics
ebad: 85 00 sta $00
ebaf: bd 3f e7 lda EnemyGraphicsTable+1,x
DrawOneSpriteRow
ebb2: 85 01 sta $01
ebb4: 4c 82 f2 jmp DrawSpriteObject ;draw them
MoveESprRowOffscreen
ebb7: 18 clc ;add A to enemy object OAM data offset
ebb8: 7d e5 06 adc Enemy_SprDataOffset,x
ebbb: a8 tay ;use as offset
ebbc: a9 f8 lda #$f8
ebbe: 4c c1 e5 jmp DumpTwoSpr ;move first row of sprites offscreen
MoveESprColOffscreen
ebc1: 18 clc ;add A to enemy object OAM data offset
ebc2: 7d e5 06 adc Enemy_SprDataOffset,x
ebc5: a8 tay ;use as offset
ebc6: 20 4a ec jsr MoveColOffscreen ;move first and second row sprites in column offscreen
ebc9: 99 10 02 sta Sprite_Data+16,y ;move third row sprite in column offscreen
ebcc: 60 rts
; -----------------------------------------------------------------------------
; $00-$01 - tile numbers
; $02 - relative Y position
; $03 - horizontal flip flag (not used here)
; $04 - attributes
; $05 - relative X position
DefaultBlockObjTiles
ebcd: 85 85 86 86 .bulk $85,$85,$86,$86
ebd1: ad bc 03 DrawBlock lda Block_Rel_YPos ;get relative vertical coordinate of block object
ebd4: 85 02 sta $02 ;store here
ebd6: ad b1 03 lda Block_Rel_XPos ;get relative horizontal coordinate of block object
ebd9: 85 05 sta $05 ;store here
ebdb: a9 03 lda #$03
ebdd: 85 04 sta $04 ;set attribute byte here
ebdf: 4a lsr A
ebe0: 85 03 sta $03 ;set horizontal flip bit here (will not be used)
ebe2: bc ec 06 ldy Block_SprDataOffset,x ;get sprite data offset
ebe5: a2 00 ldx #$00 ;reset X for use as offset to tile data
ebe7: bd cd eb DBlkLoop lda DefaultBlockObjTiles,x ;get left tile number
ebea: 85 00 sta $00 ;set here
ebec: bd ce eb lda DefaultBlockObjTiles+1,x ;get right tile number
ebef: 20 b2 eb jsr DrawOneSpriteRow ;do sub to write tile numbers to first row of sprites
ebf2: e0 04 cpx #$04 ;check incremented offset
ebf4: d0 f1 bne DBlkLoop ;and loop back until all four sprites are done
ebf6: a6 08 ldx ObjectOffset ;get block object offset
ebf8: bc ec 06 ldy Block_SprDataOffset,x ;get sprite data offset
ebfb: ad 4e 07 lda AreaType
ebfe: c9 01 cmp #$01 ;check for ground level type area
ec00: f0 08 beq ChkRep ;if found, branch to next part
ec02: a9 86 lda #$86
ec04: 99 01 02 sta Sprite_Tilenumber,y ;otherwise remove brick tiles with lines
ec07: 99 05 02 sta Sprite_Tilenumber+4,y ;and replace then with lineless brick tiles
ec0a: bd e8 03 ChkRep lda Block_Metatile,x ;check replacement metatile
ec0d: c9 c4 cmp #$c4 ;if not used block metatile, then
ec0f: d0 24 bne BlkOffscr ; branch ahead to use current graphics
ec11: a9 87 lda #$87 ;set A for used block tile
ec13: c8 iny ;increment Y to write to tile bytes
ec14: 20 bb e5 jsr DumpFourSpr ;do sub to dump into all four sprites
ec17: 88 dey ;return Y to original offset
ec18: a9 03 lda #$03 ;set palette bits
ec1a: ae 4e 07 ldx AreaType
ec1d: ca dex ;check for ground level type area again
ec1e: f0 01 beq SetBFlip ;if found, use current palette bits
ec20: 4a lsr A ;otherwise set to $01
ec21: a6 08 SetBFlip ldx ObjectOffset ;put block object offset back in X
ec23: 99 02 02 sta Sprite_Attributes,y ;store attribute byte as-is in first sprite
ec26: 09 40 ora #$40
ec28: 99 06 02 sta Sprite_Attributes+4,y ;set horizontal flip bit for second sprite
ec2b: 09 80 ora #$80
ec2d: 99 0e 02 sta Sprite_Attributes+12,y ;set both flip bits for fourth sprite
ec30: 29 83 and #$83
ec32: 99 0a 02 sta Sprite_Attributes+8,y ;set vertical flip bit for third sprite
ec35: ad d4 03 BlkOffscr lda Block_OffscreenBits ;get offscreen bits for block object
ec38: 48 pha ;save to stack
ec39: 29 04 and #%00000100 ;check to see if d2 in offscreen bits are set
ec3b: f0 08 beq PullOfsB ;if not set, branch, otherwise move sprites offscreen
ec3d: a9 f8 lda #$f8 ;move offscreen two OAMs
ec3f: 99 04 02 sta Sprite_Y_Position+4,y ; on the right side
ec42: 99 0c 02 sta Sprite_Y_Position+12,y
ec45: 68 PullOfsB pla ;pull offscreen bits from stack
ec46: 29 08 ChkLeftCo and #%00001000 ;check to see if d3 in offscreen bits are set
ec48: f0 08 beq ExDBlk ;if not set, branch, otherwise move sprites offscreen
MoveColOffscreen
ec4a: a9 f8 lda #$f8 ;move offscreen two OAMs
ec4c: 99 00 02 sta Sprite_Y_Position,y ; on the left side (or two rows of enemy on either side
ec4f: 99 08 02 sta Sprite_Y_Position+8,y ; if branched here from enemy graphics handler)
ec52: 60 ExDBlk rts
; -----------------------------------------------------------------------------
; $00 - used to hold palette bits for attribute byte or relative X position
ec53: a9 02 DrawBrickChunks lda #$02 ;set palette bits here
ec55: 85 00 sta $00
ec57: a9 75 lda #$75 ;set tile number for ball (something residual, likely)
ec59: a4 0e ldy GameEngineSubroutine
ec5b: c0 05 cpy #$05 ;if end-of-level routine running,
ec5d: f0 06 beq DChunks ; use palette and tile number assigned
ec5f: a9 03 lda #$03 ;otherwise set different palette bits
ec61: 85 00 sta $00
ec63: a9 84 lda #$84 ;and set tile number for brick chunks
ec65: bc ec 06 DChunks ldy Block_SprDataOffset,x ;get OAM data offset
ec68: c8 iny ;increment to start with tile bytes in OAM
ec69: 20 bb e5 jsr DumpFourSpr ;do sub to dump tile number into all four sprites
ec6c: a5 09 lda FrameCounter ;get frame counter
ec6e: 0a asl A
ec6f: 0a asl A
ec70: 0a asl A ;move low nybble to high
ec71: 0a asl A
ec72: 29 c0 and #$c0 ;get what was originally d3-d2 of low nybble
ec74: 05 00 ora $00 ;add palette bits
ec76: c8 iny ;increment offset for attribute bytes
ec77: 20 bb e5 jsr DumpFourSpr ;do sub to dump attribute data into all four sprites
ec7a: 88 dey
ec7b: 88 dey ;decrement offset to Y coordinate
ec7c: ad bc 03 lda Block_Rel_YPos ;get first block object's relative vertical coordinate
ec7f: 20 c1 e5 jsr DumpTwoSpr ;do sub to dump current Y coordinate into two sprites
ec82: ad b1 03 lda Block_Rel_XPos ;get first block object's relative horizontal coordinate
ec85: 99 03 02 sta Sprite_X_Position,y ;save into X coordinate of first sprite
ec88: bd f1 03 lda Block_Orig_XPos,x ;get original horizontal coordinate
ec8b: 38 sec
ec8c: ed 1c 07 sbc ScreenLeft_X_Pos ;subtract coordinate of left side from original coordinate
ec8f: 85 00 sta $00 ;store result as relative horizontal coordinate of original
ec91: 38 sec
ec92: ed b1 03 sbc Block_Rel_XPos ;get difference of relative positions of original - current
ec95: 65 00 adc $00 ;add original relative position to result
ec97: 69 06 adc #$06 ;plus 6 pixels to position second brick chunk correctly
ec99: 99 07 02 sta Sprite_X_Position+4,y ;save into X coordinate of second sprite
ec9c: ad bd 03 lda Block_Rel_YPos+1 ;get second block object's relative vertical coordinate
ec9f: 99 08 02 sta Sprite_Y_Position+8,y
eca2: 99 0c 02 sta Sprite_Y_Position+12,y ;dump into Y coordinates of third and fourth sprites
eca5: ad b2 03 lda Block_Rel_XPos+1 ;get second block object's relative horizontal coordinate
eca8: 99 0b 02 sta Sprite_X_Position+8,y ;save into X coordinate of third sprite
ecab: a5 00 lda $00 ;use original relative horizontal position
ecad: 38 sec
ecae: ed b2 03 sbc Block_Rel_XPos+1 ;get difference of relative positions of original - current
ecb1: 65 00 adc $00 ;add original relative position to result
ecb3: 69 06 adc #$06 ;plus 6 pixels to position fourth brick chunk correctly
ecb5: 99 0f 02 sta Sprite_X_Position+12,y ;save into X coordinate of fourth sprite
ecb8: ad d4 03 lda Block_OffscreenBits ;get offscreen bits for block object
ecbb: 20 46 ec jsr ChkLeftCo ;do sub to move left half of sprites offscreen if necessary
ecbe: ad d4 03 lda Block_OffscreenBits ;get offscreen bits again
ecc1: 0a asl A ;shift d7 into carry
ecc2: 90 05 bcc ChnkOfs ;if d7 not set, branch to last part
ecc4: a9 f8 lda #$f8
ecc6: 20 c1 e5 jsr DumpTwoSpr ;otherwise move top sprites offscreen
ecc9: a5 00 ChnkOfs lda $00 ;if relative position on left side of screen,
eccb: 10 10 bpl ExBCDr ; go ahead and leave
eccd: b9 03 02 lda Sprite_X_Position,y ;otherwise compare left-side X coordinate
ecd0: d9 07 02 cmp Sprite_X_Position+4,y ; to right-side X coordinate
ecd3: 90 08 bcc ExBCDr ;branch to leave if less
ecd5: a9 f8 lda #$f8 ;otherwise move right half of sprites offscreen
ecd7: 99 04 02 sta Sprite_Y_Position+4,y
ecda: 99 0c 02 sta Sprite_Y_Position+12,y
ecdd: 60 ExBCDr rts ;leave
; -----------------------------------------------------------------------------
ecde: bc f1 06 DrawFireball ldy FBall_SprDataOffset,x ;get fireball's sprite data offset
ece1: ad ba 03 lda Fireball_Rel_YPos ;get relative vertical coordinate
ece4: 99 00 02 sta Sprite_Y_Position,y ;store as sprite Y coordinate
ece7: ad af 03 lda Fireball_Rel_XPos ;get relative horizontal coordinate
ecea: 99 03 02 sta Sprite_X_Position,y ;store as sprite X coordinate, then do shared code
eced: a5 09 DrawFirebar lda FrameCounter ;get frame counter
ecef: 4a lsr A ;divide by four
ecf0: 4a lsr A
ecf1: 48 pha ;save result to stack
ecf2: 29 01 and #$01 ;mask out all but last bit
ecf4: 49 64 eor #$64 ;set either tile $64 or $65 as fireball tile
ecf6: 99 01 02 sta Sprite_Tilenumber,y ;thus tile changes every four frames
ecf9: 68 pla ;get from stack
ecfa: 4a lsr A ;divide by four again
ecfb: 4a lsr A
ecfc: a9 02 lda #$02 ;load value $02 to set palette in attrib byte
ecfe: 90 02 bcc FireA ;if last bit shifted out was not set, skip this
ed00: 09 c0 ora #%11000000 ;otherwise flip both ways every eight frames
ed02: 99 02 02 FireA sta Sprite_Attributes,y ;store attribute byte and leave
ed05: 60 rts
; -----------------------------------------------------------------------------
ed06: 68 67 66 ExplosionTiles .bulk $68,$67,$66
DrawExplosion_Fireball
ed09: bc ec 06 ldy Alt_SprDataOffset,x ;get OAM data offset of alternate sort for fireball's explosion
ed0c: b5 24 lda Fireball_State,x ;load fireball state
ed0e: f6 24 inc Fireball_State,x ;increment state for next frame
ed10: 4a lsr A ;divide by 2
ed11: 29 07 and #%00000111 ;mask out all but d3-d1
ed13: c9 03 cmp #$03 ;check to see if time to kill fireball
ed15: b0 4a bcs KillFireBall ;branch if so, otherwise continue to draw explosion
DrawExplosion_Fireworks
ed17: aa tax ;use whatever's in A for offset
ed18: bd 06 ed lda ExplosionTiles,x ;get tile number using offset
ed1b: c8 iny ;increment Y (contains sprite data offset)
ed1c: 20 bb e5 jsr DumpFourSpr ; and dump into tile number part of sprite data
ed1f: 88 dey ;decrement Y so we have the proper offset again
ed20: a6 08 ldx ObjectOffset ;return enemy object buffer offset to X
ed22: ad ba 03 lda Fireball_Rel_YPos ;get relative vertical coordinate
ed25: 38 sec ;subtract four pixels vertically
ed26: e9 04 sbc #$04 ; for first and third sprites
ed28: 99 00 02 sta Sprite_Y_Position,y
ed2b: 99 08 02 sta Sprite_Y_Position+8,y
ed2e: 18 clc ;add eight pixels vertically
ed2f: 69 08 adc #$08 ; for second and fourth sprites
ed31: 99 04 02 sta Sprite_Y_Position+4,y
ed34: 99 0c 02 sta Sprite_Y_Position+12,y
ed37: ad af 03 lda Fireball_Rel_XPos ;get relative horizontal coordinate
ed3a: 38 sec ;subtract four pixels horizontally
ed3b: e9 04 sbc #$04 ; for first and second sprites
ed3d: 99 03 02 sta Sprite_X_Position,y
ed40: 99 07 02 sta Sprite_X_Position+4,y
ed43: 18 clc ;add eight pixels horizontally
ed44: 69 08 adc #$08 ; for third and fourth sprites
ed46: 99 0b 02 sta Sprite_X_Position+8,y
ed49: 99 0f 02 sta Sprite_X_Position+12,y
ed4c: a9 02 lda #$02 ;set palette attributes for all sprites, but
ed4e: 99 02 02 sta Sprite_Attributes,y ; set no flip at all for first sprite
ed51: a9 82 lda #$82
ed53: 99 06 02 sta Sprite_Attributes+4,y ;set vertical flip for second sprite
ed56: a9 42 lda #$42
ed58: 99 0a 02 sta Sprite_Attributes+8,y ;set horizontal flip for third sprite
ed5b: a9 c2 lda #$c2
ed5d: 99 0e 02 sta Sprite_Attributes+12,y ;set both flips for fourth sprite
ed60: 60 rts ;we are done
ed61: a9 00 KillFireBall lda #$00 ;clear fireball state to kill it
ed63: 95 24 sta Fireball_State,x
ed65: 60 rts
; -----------------------------------------------------------------------------
DrawSmallPlatform
ed66: bc e5 06 ldy Enemy_SprDataOffset,x ;get OAM data offset
ed69: a9 5b lda #$5b ;load tile number for small platforms
ed6b: c8 iny ;increment offset for tile numbers
ed6c: 20 b5 e5 jsr DumpSixSpr ;dump tile number into all six sprites
ed6f: c8 iny ;increment offset for attributes
ed70: a9 02 lda #$02 ;load palette controls
ed72: 20 b5 e5 jsr DumpSixSpr ;dump attributes into all six sprites
ed75: 88 dey ;decrement for original offset
ed76: 88 dey
ed77: ad ae 03 lda Enemy_Rel_XPos ;get relative horizontal coordinate
ed7a: 99 03 02 sta Sprite_X_Position,y
ed7d: 99 0f 02 sta Sprite_X_Position+12,y ;dump as X coordinate into first and fourth sprites
ed80: 18 clc
ed81: 69 08 adc #$08 ;add eight pixels
ed83: 99 07 02 sta Sprite_X_Position+4,y ;dump into second and fifth sprites
ed86: 99 13 02 sta Sprite_X_Position+16,y
ed89: 18 clc
ed8a: 69 08 adc #$08 ;add eight more pixels
ed8c: 99 0b 02 sta Sprite_X_Position+8,y ;dump into third and sixth sprites
ed8f: 99 17 02 sta Sprite_X_Position+20,y
ed92: b5 cf lda Enemy_Y_Position,x ;get vertical coordinate
ed94: aa tax
ed95: 48 pha ;save to stack
ed96: e0 20 cpx #$20 ;if vertical coordinate below status bar,
ed98: b0 02 bcs ToSP ; do not mess with it
ed9a: a9 f8 lda #$f8 ;otherwise move first three sprites offscreen
ed9c: 20 be e5 ToSP jsr DumpThreeSpr ;dump vertical coordinate into Y coordinates
ed9f: 68 pla ;pull from stack
eda0: 18 clc
eda1: 69 80 adc #$80 ;add 128 pixels
eda3: aa tax
eda4: e0 20 cpx #$20 ;if below status bar (taking wrap into account)
eda6: b0 02 bcs BotSP ;then do not change altered coordinate
eda8: a9 f8 lda #$f8 ;otherwise move last three sprites offscreen
edaa: 99 0c 02 BotSP sta Sprite_Y_Position+12,y ;dump vertical coordinate + 128 pixels
edad: 99 10 02 sta Sprite_Y_Position+16,y ; into Y coordinates
edb0: 99 14 02 sta Sprite_Y_Position+20,y
edb3: ad d1 03 lda Enemy_OffscreenBits ;get offscreen bits
edb6: 48 pha ;save to stack
edb7: 29 08 and #%00001000 ;check d3
edb9: f0 08 beq SOfs
edbb: a9 f8 lda #$f8 ;if d3 was set, move first and
edbd: 99 00 02 sta Sprite_Y_Position,y ; fourth sprites offscreen
edc0: 99 0c 02 sta Sprite_Y_Position+12,y
edc3: 68 SOfs pla ;move out and back into stack
edc4: 48 pha
edc5: 29 04 and #%00000100 ;check d2
edc7: f0 08 beq SOfs2
edc9: a9 f8 lda #$f8 ;if d2 was set, move second and
edcb: 99 04 02 sta Sprite_Y_Position+4,y ; fifth sprites offscreen
edce: 99 10 02 sta Sprite_Y_Position+16,y
edd1: 68 SOfs2 pla ;get from stack
edd2: 29 02 and #%00000010 ;check d1
edd4: f0 08 beq ExSPl
edd6: a9 f8 lda #$f8 ;if d1 was set, move third and
edd8: 99 08 02 sta Sprite_Y_Position+8,y ; sixth sprites offscreen
eddb: 99 14 02 sta Sprite_Y_Position+20,y
edde: a6 08 ExSPl ldx ObjectOffset ;get enemy object offset and leave
ede0: 60 rts
; -----------------------------------------------------------------------------
ede1: a4 b5 DrawBubble ldy Player_Y_HighPos ;if player's vertical high position
ede3: 88 dey ; not within screen, skip all of this
ede4: d0 20 bne ExDBub
ede6: ad d3 03 lda Bubble_OffscreenBits ;check air bubble's offscreen bits
ede9: 29 08 and #%00001000
edeb: d0 19 bne ExDBub ;if bit set, branch to leave
eded: bc ee 06 ldy Bubble_SprDataOffset,x ;get air bubble's OAM data offset
edf0: ad b0 03 lda Bubble_Rel_XPos ;get relative horizontal coordinate
edf3: 99 03 02 sta Sprite_X_Position,y ;store as X coordinate here
edf6: ad bb 03 lda Bubble_Rel_YPos ;get relative vertical coordinate
edf9: 99 00 02 sta Sprite_Y_Position,y ;store as Y coordinate here
edfc: a9 74 lda #$74
edfe: 99 01 02 sta Sprite_Tilenumber,y ;put air bubble tile into OAM data
ee01: a9 02 lda #$02
ee03: 99 02 02 sta Sprite_Attributes,y ;set attribute byte
ee06: 60 ExDBub rts ;leave
; -----------------------------------------------------------------------------
; $00 - used to store player's vertical offscreen bits
PlayerGfxTblOffsets
ee07: 20 28 c8 18+ .bulk $20,$28,$c8,$18,$00,$40,$50,$58,$80,$88,$b8,$78,$60,$a0,$b0,$b8
;
; tiles arranged in order, 2 tiles per row, top to bottom
;
; big player table
PlayerGraphicsTable
ee17: 00 01 02 03+ .bulk $00,$01,$02,$03,$04,$05,$06,$07 ;walking frame 1
ee1f: 08 09 0a 0b+ .bulk $08,$09,$0a,$0b,$0c,$0d,$0e,$0f ; frame 2
ee27: 10 11 12 13+ .bulk $10,$11,$12,$13,$14,$15,$16,$17 ; frame 3
ee2f: 18 19 1a 1b+ .bulk $18,$19,$1a,$1b,$1c,$1d,$1e,$1f ;skidding
ee37: 20 21 22 23+ .bulk $20,$21,$22,$23,$24,$25,$26,$27 ;jumping
ee3f: 08 09 28 29+ .bulk $08,$09,$28,$29,$2a,$2b,$2c,$2d ;swimming frame 1
ee47: 08 09 0a 0b+ .bulk $08,$09,$0a,$0b,$0c,$30,$2c,$2d ; frame 2
ee4f: 08 09 0a 0b+ .bulk $08,$09,$0a,$0b,$2e,$2f,$2c,$2d ; frame 3
ee57: 08 09 28 29+ .bulk $08,$09,$28,$29,$2a,$2b,$5c,$5d ;climbing frame 1
ee5f: 08 09 0a 0b+ .bulk $08,$09,$0a,$0b,$0c,$0d,$5e,$5f ; frame 2
ee67: fc fc 08 09+ .bulk $fc,$fc,$08,$09,$58,$59,$5a,$5a ;crouching
ee6f: 08 09 28 29+ .bulk $08,$09,$28,$29,$2a,$2b,$0e,$0f ;fireball throwing
; small player table
ee77: fc fc fc fc+ .bulk $fc,$fc,$fc,$fc,$32,$33,$34,$35 ;walking frame 1
ee7f: fc fc fc fc+ .bulk $fc,$fc,$fc,$fc,$36,$37,$38,$39 ; frame 2
ee87: fc fc fc fc+ .bulk $fc,$fc,$fc,$fc,$3a,$37,$3b,$3c ; frame 3
ee8f: fc fc fc fc+ .bulk $fc,$fc,$fc,$fc,$3d,$3e,$3f,$40 ;skidding
ee97: fc fc fc fc+ .bulk $fc,$fc,$fc,$fc,$32,$41,$42,$43 ;jumping
ee9f: fc fc fc fc+ SwimTiles .bulk $fc,$fc,$fc,$fc,$32,$33,$44,$45 ;swimming frame 1
eea7: fc fc fc fc+ .bulk $fc,$fc,$fc,$fc,$32,$33,$44,$47 ; frame 2
eeaf: fc fc fc fc+ .bulk $fc,$fc,$fc,$fc,$32,$33,$48,$49 ; frame 3
eeb7: fc fc fc fc+ .bulk $fc,$fc,$fc,$fc,$32,$33,$90,$91 ;climbing frame 1
eebf: fc fc fc fc+ .bulk $fc,$fc,$fc,$fc,$3a,$37,$92,$93 ; frame 2
eec7: fc fc fc fc+ .bulk $fc,$fc,$fc,$fc,$9e,$9e,$9f,$9f ;killed
; used by both player sizes
eecf: fc fc fc fc+ .bulk $fc,$fc,$fc,$fc,$3a,$37,$4f,$4f ;small player standing
eed7: fc fc 00 01+ .bulk $fc,$fc,$00,$01,$4c,$4d,$4e,$4e ;intermediate grow frame
eedf: 00 01 4c 4d+ .bulk $00,$01,$4c,$4d,$4a,$4a,$4b,$4b ;big player standing
eee7: 31 46 SwimKickTileNum .bulk $31,$46
PlayerGfxHandler
eee9: ad 9e 07 lda InjuryTimer ;if player's injured invincibility timer
eeec: f0 05 beq CntPl ; not set, skip checkpoint and continue code
eeee: a5 09 lda FrameCounter
eef0: 4a lsr A ;otherwise check frame counter and branch
eef1: b0 40 bcs ExPGH ; to leave on every other frame (when d0 is set)
eef3: a5 0e CntPl lda GameEngineSubroutine ;if executing specific game engine routine,
eef5: c9 0b cmp #$0b ; branch ahead to some other part
eef7: f0 47 beq PlayerKilled
eef9: ad 0b 07 lda PlayerChangeSizeFlag ;if grow/shrink flag set
eefc: d0 3c bne DoChangeSize ; then branch to some other code
eefe: ac 04 07 ldy SwimmingFlag ;if swimming flag set, branch to
ef01: f0 31 beq FindPlayerAction ; different part, do not return
ef03: a5 1d lda Player_State
ef05: c9 00 cmp #$00 ;if player status normal,
ef07: f0 2b beq FindPlayerAction ; branch and do not return
ef09: 20 34 ef jsr FindPlayerAction ;otherwise jump and return
ef0c: a5 09 lda FrameCounter
ef0e: 29 04 and #%00000100 ;check frame counter for d2 set (8 frames every
ef10: d0 21 bne ExPGH ; eighth frame), and branch if set to leave
ef12: aa tax ;initialize X to zero
ef13: ac e4 06 ldy SprDataOffset ;get player sprite data offset
ef16: a5 33 lda PlayerFacingDir ;get player's facing direction
ef18: 4a lsr A
ef19: b0 04 bcs SwimKT ;if player facing to the right, use current offset
ef1b: c8 iny
ef1c: c8 iny ;otherwise move to next OAM data
ef1d: c8 iny
ef1e: c8 iny
ef1f: ad 54 07 SwimKT lda PlayerSize ;check player's size
ef22: f0 09 beq BigKTS ;if big, use first tile
ef24: b9 19 02 lda Sprite_Tilenumber+24,y ;check tile number of seventh/eighth sprite
ef27: cd b5 ee cmp SwimTiles+22 ; against tile number in player graphics table
ef2a: f0 07 beq ExPGH ;if spr7/spr8 tile number = value, branch to leave
ef2c: e8 inx ;otherwise increment X for second tile
ef2d: bd e7 ee BigKTS lda SwimKickTileNum,x ;overwrite tile number in sprite 7/8
ef30: 99 19 02 sta Sprite_Tilenumber+24,y ; to animate player's feet when swimming
ef33: 60 ExPGH rts ;then leave
FindPlayerAction
ef34: 20 ec ef jsr ProcessPlayerAction ;find proper offset to graphics table by player's actions
ef37: 4c 45 ef jmp PlayerGfxProcessing ;draw player, then process for fireball throwing
ef3a: 20 b0 f0 DoChangeSize jsr HandleChangeSize ;find proper offset to graphics table for grow/shrink
ef3d: 4c 45 ef jmp PlayerGfxProcessing ;draw player, then process for fireball throwing
ef40: a0 0e PlayerKilled ldy #$0e ;load offset for player killed
ef42: b9 07 ee lda PlayerGfxTblOffsets,y ;get offset to graphics table
PlayerGfxProcessing
ef45: 8d d5 06 sta PlayerGfxOffset ;store offset to graphics table here
ef48: a9 04 lda #$04
ef4a: 20 be ef jsr RenderPlayerSub ;draw player based on offset loaded
ef4d: 20 e9 f0 jsr ChkForPlayerAttrib ;set horizontal flip bits as necessary
ef50: ad 11 07 lda FireballThrowingTimer
ef53: f0 25 beq PlayerOffscreenChk ;if fireball throw timer not set, skip to the end
ef55: a0 00 ldy #$00 ;set value to initialize by default
ef57: ad 81 07 lda PlayerAnimTimer ;get animation frame timer
ef5a: cd 11 07 cmp FireballThrowingTimer ;compare to fireball throw timer
ef5d: 8c 11 07 sty FireballThrowingTimer ;initialize fireball throw timer
ef60: b0 18 bcs PlayerOffscreenChk ;if animation frame timer => fireball throw timer skip to end
ef62: 8d 11 07 sta FireballThrowingTimer ;otherwise store animation timer into fireball throw timer
ef65: a0 07 ldy #$07 ;load offset for throwing
ef67: b9 07 ee lda PlayerGfxTblOffsets,y ;get offset to graphics table
ef6a: 8d d5 06 sta PlayerGfxOffset ;store it for use later
ef6d: a0 04 ldy #$04 ;set to update four sprite rows by default
ef6f: a5 57 lda Player_X_Speed
ef71: 05 0c ora Left_Right_Buttons ;check for horizontal speed or left/right button press
ef73: f0 01 beq SUpdR ;if no speed or button press, branch using set value in Y
ef75: 88 dey ;otherwise set to update only three sprite rows
ef76: 98 SUpdR tya ;save in A for use
ef77: 20 be ef jsr RenderPlayerSub ;in sub, draw player object again
PlayerOffscreenChk
ef7a: ad d0 03 lda Player_OffscreenBits ;get player's offscreen bits
ef7d: 4a lsr A
ef7e: 4a lsr A ;move vertical bits to low nybble
ef7f: 4a lsr A
ef80: 4a lsr A
ef81: 85 00 sta $00 ;store here
ef83: a2 03 ldx #$03 ;check all four rows of player sprites
ef85: ad e4 06 lda SprDataOffset ;get player's sprite data offset
ef88: 18 clc
ef89: 69 18 adc #$18 ;add 24 bytes to start at bottom row
ef8b: a8 tay ;set as offset here
ef8c: a9 f8 PROfsLoop lda #$f8 ;load offscreen Y coordinate just in case
ef8e: 46 00 lsr $00 ;shift bit into carry
ef90: 90 03 bcc NPROffscr ;if bit not set, skip, do not move sprites
ef92: 20 c1 e5 jsr DumpTwoSpr ;otherwise dump offscreen Y coordinate into sprite data
ef95: 98 NPROffscr tya
ef96: 38 sec ;subtract eight bytes to do
ef97: e9 08 sbc #$08 ; next row up
ef99: a8 tay
ef9a: ca dex ;decrement row counter
ef9b: 10 ef bpl PROfsLoop ;do this until all sprite rows are checked
ef9d: 60 rts ;then we are done!
; -----------------------------------------------------------------------------
IntermediatePlayerData
ef9e: 58 01 00 60+ .bulk $58,$01,$00,$60,$ff,$04
DrawPlayer_Intermediate
efa4: a2 05 ldx #$05 ;store data into zero page memory
efa6: bd 9e ef PIntLoop lda IntermediatePlayerData,x ;load data to display player as he always
efa9: 95 02 sta $02,x ; appears on world/lives display
efab: ca dex
efac: 10 f8 bpl PIntLoop ;do this until all data is loaded
efae: a2 b8 ldx #$b8 ;load offset for small standing
efb0: a0 04 ldy #$04 ;load sprite data offset
efb2: 20 dc ef jsr DrawPlayerLoop ;draw player accordingly
efb5: ad 26 02 lda Sprite_Attributes+36 ;get empty sprite attributes
efb8: 09 40 ora #%01000000 ;set horizontal flip bit for bottom-right sprite
efba: 8d 22 02 sta Sprite_Attributes+32 ;store and leave
efbd: 60 rts
; -----------------------------------------------------------------------------
; $00-$01 - used to hold tile numbers, $00 also used to hold upper extent of
; animation frames
; $02 - vertical position
; $03 - facing direction, used as horizontal flip control
; $04 - attributes
; $05 - horizontal position
; $07 - number of rows to draw
;
; these also used in IntermediatePlayerData
efbe: 85 07 RenderPlayerSub sta $07 ;store number of rows of sprites to draw
efc0: ad ad 03 lda Player_Rel_XPos
efc3: 8d 55 07 sta Player_Pos_ForScroll ;store player's relative horizontal position
efc6: 85 05 sta $05 ;store it here also
efc8: ad b8 03 lda Player_Rel_YPos
efcb: 85 02 sta $02 ;store player's vertical position
efcd: a5 33 lda PlayerFacingDir
efcf: 85 03 sta $03 ;store player's facing direction
efd1: ad c4 03 lda Player_SprAttrib
efd4: 85 04 sta $04 ;store player's sprite attributes
efd6: ae d5 06 ldx PlayerGfxOffset ;load graphics table offset
efd9: ac e4 06 ldy SprDataOffset ;get player's sprite data offset
efdc: bd 17 ee DrawPlayerLoop lda PlayerGraphicsTable,x ;load player's left side
efdf: 85 00 sta $00
efe1: bd 18 ee lda PlayerGraphicsTable+1,x ;now load right side
efe4: 20 b2 eb jsr DrawOneSpriteRow
efe7: c6 07 dec $07 ;decrement rows of sprites to draw
efe9: d0 f1 bne DrawPlayerLoop ;do this until all rows are drawn
efeb: 60 rts
ProcessPlayerAction
efec: a5 1d lda Player_State ;get player's state
efee: c9 03 cmp #$03
eff0: f0 52 beq ActionClimbing ;if climbing, branch here
eff2: c9 02 cmp #$02
eff4: f0 3e beq ActionFalling ;if falling, branch here
eff6: c9 01 cmp #$01
eff8: d0 11 bne ProcOnGroundActs ;if not jumping, branch here
effa: ad 04 07 lda SwimmingFlag
effd: d0 51 bne ActionSwimming ;if swimming flag set, branch elsewhere
efff: a0 06 ldy #$06 ;load offset for crouching
f001: ad 14 07 lda CrouchingFlag ;get crouching flag
f004: d0 22 bne NonAnimatedActs ;if set, branch to get offset for graphics table
f006: a0 00 ldy #$00 ;otherwise load offset for jumping
f008: 4c 28 f0 jmp NonAnimatedActs ;go to get offset to graphics table
ProcOnGroundActs
f00b: a0 06 ldy #$06 ;load offset for crouching
f00d: ad 14 07 lda CrouchingFlag ;get crouching flag
f010: d0 16 bne NonAnimatedActs ;if set, branch to get offset for graphics table
f012: a0 02 ldy #$02 ;load offset for standing
f014: a5 57 lda Player_X_Speed ;check player's horizontal speed
f016: 05 0c ora Left_Right_Buttons ; and left/right controller bits
f018: f0 0e beq NonAnimatedActs ;if no speed or buttons pressed, use standing offset
f01a: ad 00 07 lda Player_XSpeedAbsolute ;load walking/running speed
f01d: c9 09 cmp #$09
f01f: 90 1b bcc ActionWalkRun ;if less than a certain amount, branch, too slow to skid
f021: a5 45 lda Player_MovingDir ;otherwise check to see if moving direction
f023: 25 33 and PlayerFacingDir ; and facing direction are the same
f025: d0 15 bne ActionWalkRun ;if moving direction = facing direction, branch, don't skid
f027: c8 iny ;otherwise increment to skid offset ($03)
f028: 20 91 f0 NonAnimatedActs jsr GetGfxOffsetAdder ;do a sub here to get offset adder for graphics table
f02b: a9 00 lda #$00
f02d: 8d 0d 07 sta PlayerAnimCtrl ;initialize animation frame control
f030: b9 07 ee lda PlayerGfxTblOffsets,y ;load offset to graphics table using size as offset
f033: 60 rts
f034: a0 04 ActionFalling ldy #$04 ;load offset for walking/running
f036: 20 91 f0 jsr GetGfxOffsetAdder ;get offset to graphics table
f039: 4c 62 f0 jmp GetCurrentAnimOffset ;execute instructions for falling state
f03c: a0 04 ActionWalkRun ldy #$04 ;load offset for walking/running
f03e: 20 91 f0 jsr GetGfxOffsetAdder ;get offset to graphics table
f041: 4c 68 f0 jmp FourFrameExtent ;execute instructions for normal state
f044: a0 05 ActionClimbing ldy #$05 ;load offset for climbing
f046: a5 9f lda Player_Y_Speed ;check player's vertical speed
f048: f0 de beq NonAnimatedActs ;if no speed, branch, use offset as-is
f04a: 20 91 f0 jsr GetGfxOffsetAdder ;otherwise get offset for graphics table
f04d: 4c 6d f0 jmp ThreeFrameExtent ;then skip ahead to more code
f050: a0 01 ActionSwimming ldy #$01 ;load offset for swimming
f052: 20 91 f0 jsr GetGfxOffsetAdder
f055: ad 82 07 lda JumpSwimTimer ;check jump/swim timer
f058: 0d 0d 07 ora PlayerAnimCtrl ; and animation frame control
f05b: d0 0b bne FourFrameExtent ;if any one of these set, branch ahead
f05d: a5 0a lda A_B_Buttons
f05f: 0a asl A ;check for A button pressed
f060: b0 06 bcs FourFrameExtent ;branch to same place if A button pressed
GetCurrentAnimOffset
f062: ad 0d 07 lda PlayerAnimCtrl ;get animation frame control
f065: 4c d0 f0 jmp GetOffsetFromAnimCtrl ;jump to get proper offset to graphics table
f068: a9 03 FourFrameExtent lda #$03 ;load upper extent for frame control
f06a: 4c 6f f0 jmp AnimationControl ;jump to get offset and animate player object
ThreeFrameExtent
f06d: a9 02 lda #$02 ;load upper extent for frame control for climbing
AnimationControl
f06f: 85 00 sta $00 ;store upper extent here
f071: 20 62 f0 jsr GetCurrentAnimOffset ;get proper offset to graphics table
f074: 48 pha ;save offset to stack
f075: ad 81 07 lda PlayerAnimTimer ;load animation frame timer
f078: d0 15 bne ExAnimC ;branch if not expired
f07a: ad 0c 07 lda PlayerAnimTimerSet ;get animation frame timer amount
f07d: 8d 81 07 sta PlayerAnimTimer ;and set timer accordingly
f080: ad 0d 07 lda PlayerAnimCtrl
f083: 18 clc ;add one to animation frame control
f084: 69 01 adc #$01
f086: c5 00 cmp $00 ;compare to upper extent
f088: 90 02 bcc SetAnimC ;if frame control + 1 < upper extent, use as next
f08a: a9 00 lda #$00 ;otherwise initialize frame control
f08c: 8d 0d 07 SetAnimC sta PlayerAnimCtrl ;store as new animation frame control
f08f: 68 ExAnimC pla ;get offset to graphics table from stack and leave
f090: 60 rts
GetGfxOffsetAdder
f091: ad 54 07 lda PlayerSize ;get player's size
f094: f0 05 beq SzOfs ;if player big, use current offset as-is
f096: 98 tya ; for big player
f097: 18 clc ;otherwise add eight bytes to offset
f098: 69 08 adc #$08 ; for small player
f09a: a8 tay ;go back
f09b: 60 SzOfs rts
ChangeSizeOffsetAdder
f09c: 00 01 00 01+ .bulk $00,$01,$00,$01,$00,$01,$02,$00,$01,$02,$02,$00,$02,$00,$02,$00
+ $02,$00,$02,$00
HandleChangeSize
f0b0: ac 0d 07 ldy PlayerAnimCtrl ;get animation frame control
f0b3: a5 09 lda FrameCounter
f0b5: 29 03 and #%00000011 ;get frame counter and execute this code every
f0b7: d0 0d bne GorSLog ; fourth frame, otherwise branch ahead
f0b9: c8 iny ;increment frame control
f0ba: c0 0a cpy #$0a ;check for preset upper extent
f0bc: 90 05 bcc CszNext ;if not there yet, skip ahead to use
f0be: a0 00 ldy #$00 ;otherwise initialize both grow/shrink flag
f0c0: 8c 0b 07 sty PlayerChangeSizeFlag ; and animation frame control
f0c3: 8c 0d 07 CszNext sty PlayerAnimCtrl ;store proper frame control
f0c6: ad 54 07 GorSLog lda PlayerSize ;get player's size
f0c9: d0 0c bne ShrinkPlayer ;if player small, skip ahead to next part
f0cb: b9 9c f0 lda ChangeSizeOffsetAdder,y ;get offset adder based on frame control as offset
f0ce: a0 0f ldy #$0f ;load offset for player growing
GetOffsetFromAnimCtrl
f0d0: 0a asl A ;multiply animation frame control
f0d1: 0a asl A ; by eight to get proper amount
f0d2: 0a asl A ; to add to our offset
f0d3: 79 07 ee adc PlayerGfxTblOffsets,y ;add to offset to graphics table
f0d6: 60 rts ; and return with result in A
f0d7: 98 ShrinkPlayer tya ;add ten bytes to frame control as offset
f0d8: 18 clc
f0d9: 69 0a adc #$0a ;this thing apparently uses two of the swimming frames
f0db: aa tax ; to draw the player shrinking
f0dc: a0 09 ldy #$09 ;load offset for small player swimming
f0de: bd 9c f0 lda ChangeSizeOffsetAdder,x ;get what would normally be offset adder
f0e1: d0 02 bne ShrPlF ; and branch to use offset if nonzero
f0e3: a0 01 ldy #$01 ;otherwise load offset for big player swimming
f0e5: b9 07 ee ShrPlF lda PlayerGfxTblOffsets,y ;get offset to graphics table based on offset loaded
f0e8: 60 rts ;and leave
ChkForPlayerAttrib
f0e9: ac e4 06 ldy SprDataOffset ;get sprite data offset
f0ec: a5 0e lda GameEngineSubroutine
f0ee: c9 0b cmp #$0b ;if executing specific game engine routine,
f0f0: f0 13 beq KilledAtt ; branch to change third and fourth row OAM attributes
f0f2: ad d5 06 lda PlayerGfxOffset ;get graphics table offset
f0f5: c9 50 cmp #$50
f0f7: f0 1e beq C_S_IGAtt ;if crouch offset, either standing offset,
f0f9: c9 b8 cmp #$b8 ; or intermediate growing offset,
f0fb: f0 1a beq C_S_IGAtt ; go ahead and execute code to change
f0fd: c9 c0 cmp #$c0 ; fourth row OAM attributes only
f0ff: f0 16 beq C_S_IGAtt
f101: c9 c8 cmp #$c8
f103: d0 24 bne ExPlyrAt ;if none of these, branch to leave
f105: b9 12 02 KilledAtt lda Sprite_Attributes+16,y
f108: 29 3f and #%00111111 ;mask out horizontal and vertical flip bits
f10a: 99 12 02 sta Sprite_Attributes+16,y ; for third row sprites and save
f10d: b9 16 02 lda Sprite_Attributes+20,y
f110: 29 3f and #%00111111
f112: 09 40 ora #%01000000 ;set horizontal flip bit for second
f114: 99 16 02 sta Sprite_Attributes+20,y ; sprite in the third row
f117: b9 1a 02 C_S_IGAtt lda Sprite_Attributes+24,y
f11a: 29 3f and #%00111111 ;mask out horizontal and vertical flip bits
f11c: 99 1a 02 sta Sprite_Attributes+24,y ; for fourth row sprites and save
f11f: b9 1e 02 lda Sprite_Attributes+28,y
f122: 29 3f and #%00111111
f124: 09 40 ora #%01000000 ;set horizontal flip bit for second
f126: 99 1e 02 sta Sprite_Attributes+28,y ; sprite in the fourth row
f129: 60 ExPlyrAt rts ;leave
; -----------------------------------------------------------------------------
; $00 - used in adding to get proper offset
RelativePlayerPosition
f12a: a2 00 ldx #$00 ;set offsets for relative cooordinates
f12c: a0 00 ldy #$00 ; routine to correspond to player object
f12e: 4c 42 f1 jmp RelWOfs ;get the coordinates
RelativeBubblePosition
f131: a0 01 ldy #$01 ;set for air bubble offsets
f133: 20 a8 f1 jsr GetProperObjOffset ;modify X to get proper air bubble offset
f136: a0 03 ldy #$03
f138: 4c 42 f1 jmp RelWOfs ;get the coordinates
RelativeFireballPosition
f13b: a0 00 ldy #$00 ;set for fireball offsets
f13d: 20 a8 f1 jsr GetProperObjOffset ;modify X to get proper fireball offset
f140: a0 02 ldy #$02
f142: 20 71 f1 RelWOfs jsr GetObjRelativePosition ;get the coordinates
f145: a6 08 ldx ObjectOffset ;return original offset
f147: 60 rts ;leave
RelativeMiscPosition
f148: a0 02 ldy #$02 ;set for misc object offsets
f14a: 20 a8 f1 jsr GetProperObjOffset ;modify X to get proper misc object offset
f14d: a0 06 ldy #$06
f14f: 4c 42 f1 jmp RelWOfs ;get the coordinates
RelativeEnemyPosition
f152: a9 01 lda #$01 ;get coordinates of enemy object
f154: a0 01 ldy #$01 ; relative to the screen
f156: 4c 65 f1 jmp VariableObjOfsRelPos
RelativeBlockPosition
f159: a9 09 lda #$09 ;get coordinates of one block object
f15b: a0 04 ldy #$04 ; relative to the screen
f15d: 20 65 f1 jsr VariableObjOfsRelPos
f160: e8 inx ;adjust offset for other block object if any
f161: e8 inx
f162: a9 09 lda #$09
f164: c8 iny ;adjust other and get coordinates for other one
VariableObjOfsRelPos
f165: 86 00 stx $00 ;store value to add to A here
f167: 18 clc
f168: 65 00 adc $00 ;add A to value stored
f16a: aa tax ;use as enemy offset
f16b: 20 71 f1 jsr GetObjRelativePosition
f16e: a6 08 ldx ObjectOffset ;reload old object offset and leave
f170: 60 rts
GetObjRelativePosition
f171: b5 ce lda SprObject_Y_Position,x ;load vertical coordinate low
f173: 99 b8 03 sta SprObject_Rel_YPos,y ;store here
f176: b5 86 lda SprObject_X_Position,x ;load horizontal coordinate
f178: 38 sec ;subtract left edge coordinate
f179: ed 1c 07 sbc ScreenLeft_X_Pos
f17c: 99 ad 03 sta SprObject_Rel_XPos,y ;store result here
f17f: 60 rts
; -----------------------------------------------------------------------------
; $00 - used as temp variable to hold offscreen bits
GetPlayerOffscreenBits
f180: a2 00 ldx #$00 ;set offsets for player-specific variables
f182: a0 00 ldy #$00 ; and get offscreen information about player
f184: 4c c0 f1 jmp GetOffScreenBitsSet
GetFireballOffscreenBits
f187: a0 00 ldy #$00 ;set for fireball offsets
f189: 20 a8 f1 jsr GetProperObjOffset ;modify X to get proper fireball offset
f18c: a0 02 ldy #$02 ;set other offset for fireball's offscreen bits
f18e: 4c c0 f1 jmp GetOffScreenBitsSet ;and get offscreen information about fireball
GetBubbleOffscreenBits
f191: a0 01 ldy #$01 ;set for air bubble offsets
f193: 20 a8 f1 jsr GetProperObjOffset ;modify X to get proper air bubble offset
f196: a0 03 ldy #$03 ;set other offset for airbubble's offscreen bits
f198: 4c c0 f1 jmp GetOffScreenBitsSet ;and get offscreen information about air bubble
GetMiscOffscreenBits
f19b: a0 02 ldy #$02 ;set for misc object offsets
f19d: 20 a8 f1 jsr GetProperObjOffset ;modify X to get proper misc object offset
f1a0: a0 06 ldy #$06 ;set other offset for misc object's offscreen bits
f1a2: 4c c0 f1 jmp GetOffScreenBitsSet ;and get offscreen information about misc object
f1a5: 07 16 0d ObjOffsetData .bulk $07,$16,$0d
GetProperObjOffset
f1a8: 8a txa ;move offset to A
f1a9: 18 clc
f1aa: 79 a5 f1 adc ObjOffsetData,y ;add amount of bytes to offset depending on setting in Y
f1ad: aa tax ;put back in X and leave
f1ae: 60 rts
GetEnemyOffscreenBits
f1af: a9 01 lda #$01 ;set A to add 1 byte in order to get enemy offset
f1b1: a0 01 ldy #$01 ;set Y to put offscreen bits in Enemy_OffscreenBits
f1b3: 4c ba f1 jmp SetOffscrBitsOffset
GetBlockOffscreenBits
f1b6: a9 09 lda #$09 ;set A to add 9 bytes in order to get block obj offset
f1b8: a0 04 ldy #$04 ;set Y to put offscreen bits in Block_OffscreenBits
SetOffscrBitsOffset
f1ba: 86 00 stx $00
f1bc: 18 clc ;add contents of X to A to get
f1bd: 65 00 adc $00 ; appropriate offset, then give back to X
f1bf: aa tax
GetOffScreenBitsSet
f1c0: 98 tya ;save offscreen bits offset to stack for now
f1c1: 48 pha
f1c2: 20 d7 f1 jsr RunOffscrBitsSubs
f1c5: 0a asl A ;move low nybble to high nybble
f1c6: 0a asl A
f1c7: 0a asl A
f1c8: 0a asl A
f1c9: 05 00 ora $00 ;mask together with previously saved low nybble
f1cb: 85 00 sta $00 ;store both here
f1cd: 68 pla ;get offscreen bits offset from stack
f1ce: a8 tay
f1cf: a5 00 lda $00 ;get value here and store elsewhere
f1d1: 99 d0 03 sta SprObject_OffscrBits,y
f1d4: a6 08 ldx ObjectOffset
f1d6: 60 rts
RunOffscrBitsSubs
f1d7: 20 f6 f1 jsr GetXOffscreenBits ;do subroutine here
f1da: 4a lsr A ;move high nybble to low
f1db: 4a lsr A
f1dc: 4a lsr A
f1dd: 4a lsr A
f1de: 85 00 sta $00 ;store here
f1e0: 4c 39 f2 jmp GetYOffscreenBits
; -----------------------------------------------------------------------------
; (these apply to these three subsections)
; $04 - used to store proper offset
; $05 - used as adder in DividePDiff
; $06 - used to store preset value used to compare to pixel difference in $07
; $07 - used to store difference between coordinates of object and screen edges
XOffscreenBitsData
f1e3: 7f 3f 1f 0f+ .bulk $7f,$3f,$1f,$0f,$07,$03,$01,$00,$80,$c0,$e0,$f0,$f8,$fc,$fe,$ff
DefaultXOnscreenOfs
f1f3: 07 0f 07 .bulk $07,$0f,$07
GetXOffscreenBits
f1f6: 86 04 stx $04 ;save position in buffer to here
f1f8: a0 01 ldy #$01 ;start with right side of screen
f1fa: b9 1c 07 XOfsLoop lda ScreenLeft_X_Pos,y ;get pixel coordinate of edge
f1fd: 38 sec ;get difference between pixel coordinate of edge
f1fe: f5 86 sbc SprObject_X_Position,x ; and pixel coordinate of object position
f200: 85 07 sta $07 ;store here
f202: b9 1a 07 lda ScreenLeft_PageLoc,y ;get page location of edge
f205: f5 6d sbc SprObject_PageLoc,x ;subtract from page location of object position
f207: be f3 f1 ldx DefaultXOnscreenOfs,y ;load offset value here
f20a: c9 00 cmp #$00
f20c: 30 10 bmi XLdBData ;if beyond right edge or in front of left edge, branch
f20e: be f4 f1 ldx DefaultXOnscreenOfs+1,y ;if not, load alternate offset value here
f211: c9 01 cmp #$01
f213: 10 09 bpl XLdBData ;if one page or more to the left of either edge, branch
f215: a9 38 lda #$38 ;if no branching, load value here and store
f217: 85 06 sta $06
f219: a9 08 lda #$08 ;load some other value and execute subroutine
f21b: 20 6d f2 jsr DividePDiff
f21e: bd e3 f1 XLdBData lda XOffscreenBitsData,x ;get bits here
f221: a6 04 ldx $04 ;reobtain position in buffer
f223: c9 00 cmp #$00 ;if bits not zero, branch to leave
f225: d0 03 bne ExXofsBS
f227: 88 dey ;otherwise, do left side of screen now
f228: 10 d0 bpl XOfsLoop ;branch if not already done with left side
f22a: 60 ExXofsBS rts
; -----------------------------------------------------------------------------
YOffscreenBitsData
f22b: 00 08 0c 0e+ .bulk $00,$08,$0c,$0e,$0f,$07,$03,$01,$00
DefaultYOnscreenOfs
f234: 04 00 04 .bulk $04,$00,$04
f237: ff 00 HighPosUnitData .bulk $ff,$00
GetYOffscreenBits
f239: 86 04 stx $04 ;save position in buffer to here
f23b: a0 01 ldy #$01 ;start with top of screen
f23d: b9 37 f2 YOfsLoop lda HighPosUnitData,y ;load coordinate for edge of vertical unit
f240: 38 sec
f241: f5 ce sbc SprObject_Y_Position,x ;subtract from vertical coordinate of object
f243: 85 07 sta $07 ;store here
f245: a9 01 lda #$01 ;subtract one from vertical high byte of object
f247: f5 b5 sbc SprObject_Y_HighPos,x
f249: be 34 f2 ldx DefaultYOnscreenOfs,y ;load offset value here
f24c: c9 00 cmp #$00
f24e: 30 10 bmi YLdBData ;if under top of the screen or beyond bottom, branch
f250: be 35 f2 ldx DefaultYOnscreenOfs+1,y ;if not, load alternate offset value here
f253: c9 01 cmp #$01
f255: 10 09 bpl YLdBData ;if one vertical unit or more above the screen, branch
f257: a9 20 lda #$20 ;if no branching, load value here and store
f259: 85 06 sta $06
f25b: a9 04 lda #$04 ;load some other value and execute subroutine
f25d: 20 6d f2 jsr DividePDiff
f260: bd 2b f2 YLdBData lda YOffscreenBitsData,x ;get offscreen data bits using offset
f263: a6 04 ldx $04 ;reobtain position in buffer
f265: c9 00 cmp #$00
f267: d0 03 bne ExYOfsBS ;if bits not zero, branch to leave
f269: 88 dey ;otherwise, do bottom of the screen now
f26a: 10 d1 bpl YOfsLoop
f26c: 60 ExYOfsBS rts
; -----------------------------------------------------------------------------
f26d: 85 05 DividePDiff sta $05 ;store current value in A here
f26f: a5 07 lda $07 ;get pixel difference
f271: c5 06 cmp $06 ;compare to preset value
f273: b0 0c bcs ExDivPD ;if pixel difference >= preset value, branch
f275: 4a lsr A ;divide by eight
f276: 4a lsr A
f277: 4a lsr A
f278: 29 07 and #$07 ;mask out all but 3 LSB
f27a: c0 01 cpy #$01 ;right side of the screen or top?
f27c: b0 02 bcs SetOscrO ;if so, branch, use difference / 8 as offset
f27e: 65 05 adc $05 ;if not, add value to difference / 8
f280: aa SetOscrO tax ;use as offset
f281: 60 ExDivPD rts ;leave
; -----------------------------------------------------------------------------
; $00-$01 - tile numbers
; $02 - Y coordinate
; $03 - flip control
; $04 - sprite attributes
; $05 - X coordinate
DrawSpriteObject
f282: a5 03 lda $03 ;get saved flip control bits
f284: 4a lsr A
f285: 4a lsr A ;move d1 into carry
f286: a5 00 lda $00
f288: 90 0c bcc NoHFlip ;if d1 not set, branch
f28a: 99 05 02 sta Sprite_Tilenumber+4,y ;store first tile into second sprite
f28d: a5 01 lda $01 ; and second into first sprite
f28f: 99 01 02 sta Sprite_Tilenumber,y
f292: a9 40 lda #$40 ;activate horizontal flip OAM attribute
f294: d0 0a bne SetHFAt ; and unconditionally branch
f296: 99 01 02 NoHFlip sta Sprite_Tilenumber,y ;store first tile into first sprite
f299: a5 01 lda $01 ; and second into second sprite
f29b: 99 05 02 sta Sprite_Tilenumber+4,y
f29e: a9 00 lda #$00 ;clear bit for horizontal flip
f2a0: 05 04 SetHFAt ora $04 ; add other OAM attributes if necessary
f2a2: 99 02 02 sta Sprite_Attributes,y ;store sprite attributes
f2a5: 99 06 02 sta Sprite_Attributes+4,y
f2a8: a5 02 lda $02 ;now the y coordinates
f2aa: 99 00 02 sta Sprite_Y_Position,y ;note because they are
f2ad: 99 04 02 sta Sprite_Y_Position+4,y ; side by side, they are the same
f2b0: a5 05 lda $05
f2b2: 99 03 02 sta Sprite_X_Position,y ;store x coordinate, then
f2b5: 18 clc ; add 8 pixels and store another to
f2b6: 69 08 adc #$08 ; put them side by side
f2b8: 99 07 02 sta Sprite_X_Position+4,y
f2bb: a5 02 lda $02 ;add eight pixels to the next y
f2bd: 18 clc ; coordinate
f2be: 69 08 adc #$08
f2c0: 85 02 sta $02
f2c2: 98 tya ;add eight to the offset in Y to
f2c3: 18 clc ; move to the next two sprites
f2c4: 69 08 adc #$08
f2c6: a8 tay
f2c7: e8 inx ;increment offset to return it to the
f2c8: e8 inx ; routine that called this subroutine
f2c9: 60 rts
; -----------------------------------------------------------------------------
f2ca: ff ff ff ff+ .bulk $ff,$ff,$ff,$ff,$ff,$ff
; -----------------------------------------------------------------------------
f2d0: ad 70 07 SoundEngine lda OperMode ;are we in title screen mode?
f2d3: d0 04 bne SndOn
f2d5: 8d 15 40 sta SND_CHN ;if so, disable sound and leave
f2d8: 60 rts
f2d9: a9 ff SndOn lda #$ff
f2db: 8d 17 40 sta JOY2 ;disable irqs and set frame counter mode???
f2de: a9 0f lda #$0f
f2e0: 8d 15 40 sta SND_CHN ;enable first four channels
f2e3: ad c6 07 lda PauseModeFlag ;is sound already in pause mode?
f2e6: d0 06 bne InPause
f2e8: a5 fa lda PauseSoundQueue ;if not, check pause sfx queue
f2ea: c9 01 cmp #$01
f2ec: d0 5d bne RunSoundSubroutines ;if queue is empty, skip pause mode routine
f2ee: ad b2 07 InPause lda PauseSoundBuffer ;check pause sfx buffer
f2f1: d0 23 bne ContPau
f2f3: a5 fa lda PauseSoundQueue ;check pause queue
f2f5: f0 66 beq SkipSoundSubroutines
f2f7: 8d b2 07 sta PauseSoundBuffer ;if queue full, store in buffer and activate
f2fa: 8d c6 07 sta PauseModeFlag ; pause mode to interrupt game sounds
f2fd: a9 00 lda #$00 ;disable sound and clear sfx buffers
f2ff: 8d 15 40 sta SND_CHN
f302: 85 f1 sta Square1SoundBuffer
f304: 85 f2 sta Square2SoundBuffer
f306: 85 f3 sta NoiseSoundBuffer
f308: a9 0f lda #$0f
f30a: 8d 15 40 sta SND_CHN ;enable sound again
f30d: a9 2a lda #$2a ;store length of sound in pause counter
f30f: 8d bb 07 sta Squ1_SfxLenCounter
f312: a9 44 PTone1F lda #$44 ;play first tone
f314: d0 11 bne PTRegC ;unconditional branch
f316: ad bb 07 ContPau lda Squ1_SfxLenCounter ;check pause length left
f319: c9 24 cmp #$24 ;time to play second?
f31b: f0 08 beq PTone2F
f31d: c9 1e cmp #$1e ;time to play first again?
f31f: f0 f1 beq PTone1F
f321: c9 18 cmp #$18 ;time to play second again?
f323: d0 09 bne DecPauC ;only load regs during times, otherwise skip
f325: a9 64 PTone2F lda #$64 ;store reg contents and play the pause sfx
f327: a2 84 PTRegC ldx #$84
f329: a0 7f ldy #$7f
f32b: 20 88 f3 jsr PlaySqu1Sfx
f32e: ce bb 07 DecPauC dec Squ1_SfxLenCounter ;decrement pause sfx counter
f331: d0 2a bne SkipSoundSubroutines
f333: a9 00 lda #$00 ;disable sound if in pause mode and
f335: 8d 15 40 sta SND_CHN ; not currently playing the pause sfx
f338: ad b2 07 lda PauseSoundBuffer ;if no longer playing pause sfx, check to see
f33b: c9 02 cmp #$02 ;if we need to be playing sound again
f33d: d0 05 bne SkipPIn
f33f: a9 00 lda #$00 ;clear pause mode to allow game sounds again
f341: 8d c6 07 sta PauseModeFlag
f344: a9 00 SkipPIn lda #$00 ;clear pause sfx buffer
f346: 8d b2 07 sta PauseSoundBuffer
f349: f0 12 beq SkipSoundSubroutines
RunSoundSubroutines
f34b: 20 1b f4 jsr Square1SfxHandler ;play sfx on square channel 1
f34e: 20 7c f5 jsr Square2SfxHandler ; '' '' '' square channel 2
f351: 20 67 f6 jsr NoiseSfxHandler ; '' '' '' noise channel
f354: 20 94 f6 jsr MusicHandler ;play music on all channels
f357: a9 00 lda #$00 ;clear the music queues
f359: 85 fb sta AreaMusicQueue
f35b: 85 fc sta EventMusicQueue
SkipSoundSubroutines
f35d: a9 00 lda #$00 ;clear the sound effects queues
f35f: 85 ff sta Square1SoundQueue
f361: 85 fe sta Square2SoundQueue
f363: 85 fd sta NoiseSoundQueue
f365: 85 fa sta PauseSoundQueue
f367: ac c0 07 ldy DAC_Counter ;load some sort of counter
f36a: a5 f4 lda AreaMusicBuffer
f36c: 29 03 and #%00000011 ;check for specific music
f36e: f0 07 beq NoIncDAC
f370: ee c0 07 inc DAC_Counter ;increment and check counter
f373: c0 30 cpy #$30
f375: 90 06 bcc StrWave ;if not there yet, just store it
f377: 98 NoIncDAC tya
f378: f0 03 beq StrWave ;if we are at zero, do not decrement
f37a: ce c0 07 dec DAC_Counter ;decrement counter
f37d: 8c 11 40 StrWave sty DMC_RAW ;store into DMC load register (??)
f380: 60 rts ;we are done here
; -----------------------------------------------------------------------------
f381: 8c 01 40 Dump_Squ1_Regs sty SQ1_SWEEP ;dump the contents of X and Y into square 1's control regs
f384: 8e 00 40 stx SQ1_VOL
f387: 60 rts
f388: 20 81 f3 PlaySqu1Sfx jsr Dump_Squ1_Regs ;do sub to set ctrl regs for square 1, then set frequency regs
f38b: a2 00 SetFreq_Squ1 ldx #$00 ;set frequency reg offset for square 1 sound channel
f38d: a8 Dump_Freq_Regs tay
f38e: b9 01 ff lda FreqRegLookupTbl+1,y ;use previous contents of A for sound reg offset
f391: f0 0b beq NoTone ;if zero, then do not load
f393: 9d 02 40 sta SQ1_LO,x ;first byte goes into LSB of frequency divider
f396: b9 00 ff lda FreqRegLookupTbl,y ;second byte goes into 3 MSB plus extra bit for
f399: 09 08 ora #%00001000 ;length counter
f39b: 9d 03 40 sta SQ1_HI,x
f39e: 60 NoTone rts
f39f: 8e 04 40 Dump_Sq2_Regs stx SQ2_VOL ;dump the contents of X and Y into square 2's control regs
f3a2: 8c 05 40 sty SQ2_SWEEP
f3a5: 60 rts
f3a6: 20 9f f3 PlaySqu2Sfx jsr Dump_Sq2_Regs ;do sub to set ctrl regs for square 2, then set frequency regs
f3a9: a2 04 SetFreq_Squ2 ldx #$04 ;set frequency reg offset for square 2 sound channel
f3ab: d0 e0 bne Dump_Freq_Regs ;unconditional branch
f3ad: a2 08 SetFreq_Tri ldx #$08 ;set frequency reg offset for triangle sound channel
f3af: d0 dc bne Dump_Freq_Regs ;unconditional branch
; -----------------------------------------------------------------------------
SwimStompEnvelopeData
f3b1: 9f 9b 98 96+ .bulk $9f,$9b,$98,$96,$95,$94,$92,$90,$90,$9a,$97,$95,$93,$92
PlayFlagpoleSlide
f3bf: a9 40 lda #$40 ;store length of flagpole sound
f3c1: 8d bb 07 sta Squ1_SfxLenCounter
f3c4: a9 62 lda #$62 ;load part of reg contents for flagpole sound
f3c6: 20 8b f3 jsr SetFreq_Squ1
f3c9: a2 99 ldx #$99 ;now load the rest
f3cb: d0 25 bne FPS2nd
f3cd: a9 26 PlaySmallJump lda #$26 ;branch here for small mario jumping sound
f3cf: d0 02 bne JumpRegContents
f3d1: a9 18 PlayBigJump lda #$18 ;branch here for big mario jumping sound
f3d3: a2 82 JumpRegContents ldx #$82 ;note that small and big jump borrow each others' reg contents
f3d5: a0 a7 ldy #$a7 ;anyway, this loads the first part of mario's jumping sound
f3d7: 20 88 f3 jsr PlaySqu1Sfx
f3da: a9 28 lda #$28 ;store length of sfx for both jumping sounds
f3dc: 8d bb 07 sta Squ1_SfxLenCounter ;then continue on here
f3df: ad bb 07 ContinueSndJump lda Squ1_SfxLenCounter ;jumping sounds seem to be composed of three parts
f3e2: c9 25 cmp #$25 ;check for time to play second part yet
f3e4: d0 06 bne N2Prt
f3e6: a2 5f ldx #$5f ;load second part
f3e8: a0 f6 ldy #$f6
f3ea: d0 08 bne DmpJpFPS ;unconditional branch
f3ec: c9 20 N2Prt cmp #$20 ;check for third part
f3ee: d0 29 bne DecJpFPS
f3f0: a2 48 ldx #$48 ;load third part
f3f2: a0 bc FPS2nd ldy #$bc ;the flagpole slide sound shares part of third part
f3f4: 20 81 f3 DmpJpFPS jsr Dump_Squ1_Regs
f3f7: d0 20 bne DecJpFPS ;unconditional branch outta here
PlayFireballThrow
f3f9: a9 05 lda #$05
f3fb: a0 99 ldy #$99 ;load reg contents for fireball throw sound
f3fd: d0 04 bne Fthrow ;unconditional branch
f3ff: a9 0a PlayBump lda #$0a ;load length of sfx and reg contents for bump sound
f401: a0 93 ldy #$93
f403: a2 9e Fthrow ldx #$9e ;the fireball sound shares reg contents with the bump sound
f405: 8d bb 07 sta Squ1_SfxLenCounter
f408: a9 0c lda #$0c ;load offset for bump sound
f40a: 20 88 f3 jsr PlaySqu1Sfx
ContinueBumpThrow
f40d: ad bb 07 lda Squ1_SfxLenCounter ;check for second part of bump sound
f410: c9 06 cmp #$06
f412: d0 05 bne DecJpFPS
f414: a9 bb lda #$bb ;load second part directly
f416: 8d 01 40 sta SQ1_SWEEP
f419: d0 60 DecJpFPS bne BranchToDecLength1 ;unconditional branch
Square1SfxHandler
f41b: a4 ff ldy Square1SoundQueue ;check for sfx in queue
f41d: f0 20 beq CheckSfx1Buffer
f41f: 84 f1 sty Square1SoundBuffer ;if found, put in buffer
f421: 30 aa bmi PlaySmallJump ;small jump
f423: 46 ff lsr Square1SoundQueue
f425: b0 aa bcs PlayBigJump ;big jump
f427: 46 ff lsr Square1SoundQueue
f429: b0 d4 bcs PlayBump ;bump
f42b: 46 ff lsr Square1SoundQueue
f42d: b0 2c bcs PlaySwimStomp ;swim/stomp
f42f: 46 ff lsr Square1SoundQueue
f431: b0 4a bcs PlaySmackEnemy ;smack enemy
f433: 46 ff lsr Square1SoundQueue
f435: b0 7f bcs PlayPipeDownInj ;pipedown/injury
f437: 46 ff lsr Square1SoundQueue
f439: b0 be bcs PlayFireballThrow ;fireball throw
f43b: 46 ff lsr Square1SoundQueue
f43d: b0 80 bcs PlayFlagpoleSlide ;slide flagpole
f43f: a5 f1 CheckSfx1Buffer lda Square1SoundBuffer ;check for sfx in buffer
f441: f0 17 beq ExS1H ;if not found, exit sub
f443: 30 9a bmi ContinueSndJump ;small mario jump
f445: 4a lsr A
f446: b0 97 bcs ContinueSndJump ;big mario jump
f448: 4a lsr A
f449: b0 c2 bcs ContinueBumpThrow ;bump
f44b: 4a lsr A
f44c: b0 1b bcs ContinueSwimStomp ;swim/stomp
f44e: 4a lsr A
f44f: b0 3c bcs ContinueSmackEnemy ;smack enemy
f451: 4a lsr A
f452: b0 67 bcs ContinuePipeDownInj ;pipedown/injury
f454: 4a lsr A
f455: b0 b6 bcs ContinueBumpThrow ;fireball throw
f457: 4a lsr A
f458: b0 48 bcs DecrementSfx1Length ;slide flagpole
f45a: 60 ExS1H rts
f45b: a9 0e PlaySwimStomp lda #$0e ;store length of swim/stomp sound
f45d: 8d bb 07 sta Squ1_SfxLenCounter
f460: a0 9c ldy #$9c ;store reg contents for swim/stomp sound
f462: a2 9e ldx #$9e
f464: a9 26 lda #$26
f466: 20 88 f3 jsr PlaySqu1Sfx
ContinueSwimStomp
f469: ac bb 07 ldy Squ1_SfxLenCounter ;look up reg contents in data section based on
f46c: b9 b0 f3 lda SwimStompEnvelopeData-1,y ; length of sound left, used to control sound's
f46f: 8d 00 40 sta SQ1_VOL ; envelope
f472: c0 06 cpy #$06
f474: d0 05 bne BranchToDecLength1
f476: a9 9e lda #$9e ;when the length counts down to a certain point, put this
f478: 8d 02 40 sta SQ1_LO ; directly into the LSB of square 1's frequency divider
BranchToDecLength1
f47b: d0 25 bne DecrementSfx1Length ;unconditional branch (regardless of how we got here)
f47d: a9 0e PlaySmackEnemy lda #$0e ;store length of smack enemy sound
f47f: a0 cb ldy #$cb
f481: a2 9f ldx #$9f
f483: 8d bb 07 sta Squ1_SfxLenCounter
f486: a9 28 lda #$28 ;store reg contents for smack enemy sound
f488: 20 88 f3 jsr PlaySqu1Sfx
f48b: d0 15 bne DecrementSfx1Length ;unconditional branch
ContinueSmackEnemy
f48d: ac bb 07 ldy Squ1_SfxLenCounter ;check about halfway through
f490: c0 08 cpy #$08
f492: d0 09 bne SmSpc
f494: a9 a0 lda #$a0 ;if we're at the about-halfway point, make the second tone
f496: 8d 02 40 sta SQ1_LO ; in the smack enemy sound
f499: a9 9f lda #$9f
f49b: d0 02 bne SmTick
f49d: a9 90 SmSpc lda #$90 ;this creates spaces in the sound, giving it its distinct noise
f49f: 8d 00 40 SmTick sta SQ1_VOL
DecrementSfx1Length
f4a2: ce bb 07 dec Squ1_SfxLenCounter ;decrement length of sfx
f4a5: d0 0e bne ExSfx1
f4a7: a2 00 StopSquare1Sfx ldx #$00 ;if end of sfx reached, clear buffer
f4a9: 86 f1 stx Square1SoundBuffer ; and stop making the sfx
f4ab: a2 0e ldx #$0e
f4ad: 8e 15 40 stx SND_CHN
f4b0: a2 0f ldx #$0f
f4b2: 8e 15 40 stx SND_CHN
f4b5: 60 ExSfx1 rts
f4b6: a9 2f PlayPipeDownInj lda #$2f ;load length of pipedown sound
f4b8: 8d bb 07 sta Squ1_SfxLenCounter
ContinuePipeDownInj
f4bb: ad bb 07 lda Squ1_SfxLenCounter ;some bitwise logic, forces the regs
f4be: 4a lsr A ; to be written to only during six specific times
f4bf: b0 10 bcs NoPDwnL ; during which d3 must be set and d1-0 must be clear
f4c1: 4a lsr A
f4c2: b0 0d bcs NoPDwnL
f4c4: 29 02 and #%00000010
f4c6: f0 09 beq NoPDwnL
f4c8: a0 91 ldy #$91 ;and this is where it actually gets written in
f4ca: a2 9a ldx #$9a
f4cc: a9 44 lda #$44
f4ce: 20 88 f3 jsr PlaySqu1Sfx
f4d1: 4c a2 f4 NoPDwnL jmp DecrementSfx1Length
; -----------------------------------------------------------------------------
f4d4: 58 02 54 56+ .bulk $58,$02,$54,$56,$4e,$44
PowerUpGrabFreqData
f4da: 4c 52 4c 48+ .bulk $4c,$52,$4c,$48,$3e,$36,$3e,$36,$30,$28,$4a,$50,$4a,$64,$3c,$32
+ $3c,$32,$2c,$24,$3a,$64,$3a,$34,$2c,$22,$2c
f4f5: 22 1c 14 .bulk $22,$1c,$14 ;residual frequency data
PUp_VGrow_FreqData
f4f8: 14 04 22 24+ .bulk $14,$04,$22,$24,$16,$04,$24,$26 ;used by both
f500: 18 04 26 28+ .bulk $18,$04,$26,$28,$1a,$04,$28,$2a
f508: 1c 04 2a 2c+ .bulk $1c,$04,$2a,$2c,$1e,$04,$2c,$2e ;used by vinegrow
f510: 20 04 2e 30+ .bulk $20,$04,$2e,$30,$22,$04,$30,$32
f518: a9 35 PlayCoinGrab lda #$35 ;load length of coin grab sound
f51a: a2 8d ldx #$8d ; and part of reg contents
f51c: d0 04 bne CGrab_TTickRegL
f51e: a9 06 PlayTimerTick lda #$06 ;load length of timer tick sound
f520: a2 98 ldx #$98 ; and part of reg contents
f522: 8d bd 07 CGrab_TTickRegL sta Squ2_SfxLenCounter
f525: a0 7f ldy #$7f ;load the rest of reg contents
f527: a9 42 lda #$42 ; of coin grab and timer tick sound
f529: 20 a6 f3 jsr PlaySqu2Sfx
ContinueCGrabTTick
f52c: ad bd 07 lda Squ2_SfxLenCounter ;check for time to play second tone yet
f52f: c9 30 cmp #$30 ;timer tick sound also executes this, not sure why
f531: d0 05 bne N2Tone
f533: a9 54 lda #$54 ;if so, load the tone directly into the reg
f535: 8d 06 40 sta SQ2_LO
f538: d0 2e N2Tone bne DecrementSfx2Length
f53a: a9 20 PlayBlast lda #$20 ;load length of fireworks/gunfire sound
f53c: 8d bd 07 sta Squ2_SfxLenCounter
f53f: a0 94 ldy #$94 ;load reg contents of fireworks/gunfire sound
f541: a9 5e lda #$5e
f543: d0 0b bne SBlasJ
f545: ad bd 07 ContinueBlast lda Squ2_SfxLenCounter ;check for time to play second part
f548: c9 18 cmp #$18
f54a: d0 1c bne DecrementSfx2Length
f54c: a0 93 ldy #$93 ;load second part reg contents then
f54e: a9 18 lda #$18
f550: d0 7f SBlasJ bne BlstSJp ;unconditional branch to load rest of reg contents
f552: a9 36 PlayPowerUpGrab lda #$36 ;load length of power-up grab sound
f554: 8d bd 07 sta Squ2_SfxLenCounter
ContinuePowerUpGrab
f557: ad bd 07 lda Squ2_SfxLenCounter ;load frequency reg based on length left over
f55a: 4a lsr A ;divide by 2
f55b: b0 0b bcs DecrementSfx2Length ;alter frequency every other frame
f55d: a8 tay
f55e: b9 d9 f4 lda PowerUpGrabFreqData-1,y ;use length left over / 2 for frequency offset
f561: a2 5d ldx #$5d ;store reg contents of power-up grab sound
f563: a0 7f ldy #$7f
f565: 20 a6 f3 LoadSqu2Regs jsr PlaySqu2Sfx
DecrementSfx2Length
f568: ce bd 07 dec Squ2_SfxLenCounter ;decrement length of sfx
f56b: d0 0e bne EsSfx2
f56d: a2 00 EmptySfx2Buffer ldx #$00 ;initialize square 2's sound effects buffer
f56f: 86 f2 stx Square2SoundBuffer
f571: a2 0d StopSquare2Sfx ldx #$0d ;stop playing the sfx
f573: 8e 15 40 stx SND_CHN
f576: a2 0f ldx #$0f
f578: 8e 15 40 stx SND_CHN
f57b: 60 EsSfx2 rts
Square2SfxHandler
f57c: a5 f2 lda Square2SoundBuffer ;special handling for the 1-up sound to keep it
f57e: 29 40 and #Sfx_ExtraLife ; from being interrupted by other sounds on square 2
f580: d0 65 bne ContinueExtraLife
f582: a4 fe ldy Square2SoundQueue ;check for sfx in queue
f584: f0 20 beq CheckSfx2Buffer
f586: 84 f2 sty Square2SoundBuffer ;if found, put in buffer and check for the following
f588: 30 3e bmi PlayBowserFall ;bowser fall
f58a: 46 fe lsr Square2SoundQueue
f58c: b0 8a bcs PlayCoinGrab ;coin grab
f58e: 46 fe lsr Square2SoundQueue
f590: b0 6a bcs PlayGrowPowerUp ;power-up reveal
f592: 46 fe lsr Square2SoundQueue
f594: b0 6a bcs PlayGrowVine ;vine grow
f596: 46 fe lsr Square2SoundQueue
f598: b0 a0 bcs PlayBlast ;fireworks/gunfire
f59a: 46 fe lsr Square2SoundQueue
f59c: b0 80 bcs PlayTimerTick ;timer tick
f59e: 46 fe lsr Square2SoundQueue
f5a0: b0 b0 bcs PlayPowerUpGrab ;power-up grab
f5a2: 46 fe lsr Square2SoundQueue
f5a4: b0 3c bcs PlayExtraLife ;1-up
f5a6: a5 f2 CheckSfx2Buffer lda Square2SoundBuffer ;check for sfx in buffer
f5a8: f0 17 beq ExS2H ;if not found, exit sub
f5aa: 30 27 bmi ContinueBowserFall ;bowser fall
f5ac: 4a lsr A
f5ad: b0 13 bcs Cont_CGrab_TTick ;coin grab
f5af: 4a lsr A
f5b0: b0 5d bcs ContinueGrowItems ;power-up reveal
f5b2: 4a lsr A
f5b3: b0 5a bcs ContinueGrowItems ;vine grow
f5b5: 4a lsr A
f5b6: b0 8d bcs ContinueBlast ;fireworks/gunfire
f5b8: 4a lsr A
f5b9: b0 07 bcs Cont_CGrab_TTick ;timer tick
f5bb: 4a lsr A
f5bc: b0 99 bcs ContinuePowerUpGrab ;power-up grab
f5be: 4a lsr A
f5bf: b0 26 bcs ContinueExtraLife ;1-up
f5c1: 60 ExS2H rts
Cont_CGrab_TTick
f5c2: 4c 2c f5 jmp ContinueCGrabTTick
JumpToDecLength2
f5c5: 4c 68 f5 jmp DecrementSfx2Length
f5c8: a9 38 PlayBowserFall lda #$38 ;load length of bowser defeat sound
f5ca: 8d bd 07 sta Squ2_SfxLenCounter
f5cd: a0 c4 ldy #$c4 ;load contents of reg for bowser defeat sound
f5cf: a9 18 lda #$18
f5d1: d0 0b BlstSJp bne PBFRegs
ContinueBowserFall
f5d3: ad bd 07 lda Squ2_SfxLenCounter ;check for almost near the end
f5d6: c9 08 cmp #$08
f5d8: d0 8e bne DecrementSfx2Length
f5da: a0 a4 ldy #$a4 ;if so, load the rest of reg contents for bowser defeat sound
f5dc: a9 5a lda #$5a
f5de: a2 9f PBFRegs ldx #$9f ;the fireworks/gunfire sound shares part of reg contents here
f5e0: d0 83 EL_LRegs bne LoadSqu2Regs ;this is an unconditional branch outta here
f5e2: a9 30 lda #$30 ;load length of 1-up sound
f5e4: 8d bd 07 sta Squ2_SfxLenCounter
f5e7: ad bd 07 lda Squ2_SfxLenCounter
f5ea: a2 03 ldx #$03 ;load new tones only every eight frames
f5ec: 4a DivLLoop lsr A
f5ed: b0 d6 bcs JumpToDecLength2 ;if any bits set here, branch to dec the length
f5ef: ca dex
f5f0: d0 fa bne DivLLoop ;do this until all bits checked, if none set, continue
f5f2: a8 tay
f5f3: b9 d3 f4 lda ExtraLifeFreqData-1,y ;load our reg contents
f5f6: a2 82 ldx #$82
f5f8: a0 7f ldy #$7f
f5fa: d0 e4 bne EL_LRegs ;unconditional branch
f5fc: a9 10 PlayGrowPowerUp lda #$10 ;load length of power-up reveal sound
f5fe: d0 02 bne GrowItemRegs
f600: a9 20 PlayGrowVine lda #$20 ;load length of vine grow sound
f602: 8d bd 07 GrowItemRegs sta Squ2_SfxLenCounter
f605: a9 7f lda #$7f ;load contents of reg for both sounds directly
f607: 8d 05 40 sta SQ2_SWEEP
f60a: a9 00 lda #$00 ;start secondary counter for both sounds
f60c: 8d be 07 sta Sfx_SecondaryCounter
ContinueGrowItems
f60f: ee be 07 inc Sfx_SecondaryCounter ;increment secondary counter for both sounds
f612: ad be 07 lda Sfx_SecondaryCounter ;this sound doesn't decrement the usual counter
f615: 4a lsr A ;divide by 2 to get the offset
f616: a8 tay
f617: cc bd 07 cpy Squ2_SfxLenCounter ;have we reached the end yet?
f61a: f0 0c beq StopGrowItems ;if so, branch to jump, and stop playing sounds
f61c: a9 9d lda #$9d ;load contents of other reg directly
f61e: 8d 04 40 sta SQ2_VOL
f621: b9 f8 f4 lda PUp_VGrow_FreqData,y ;use secondary counter / 2 as offset for frequency regs
f624: 20 a9 f3 jsr SetFreq_Squ2
f627: 60 rts
f628: 4c 6d f5 StopGrowItems jmp EmptySfx2Buffer ;branch to stop playing sounds
; -----------------------------------------------------------------------------
BrickShatterFreqData
f62b: 01 0e 0e 0d+ .bulk $01,$0e,$0e,$0d,$0b,$06,$0c,$0f,$0a,$09,$03,$0d,$08,$0d,$06,$0c
PlayBrickShatter
f63b: a9 20 lda #$20 ;load length of brick shatter sound
f63d: 8d bf 07 sta Noise_SfxLenCounter
ContinueBrickShatter
f640: ad bf 07 lda Noise_SfxLenCounter
f643: 4a lsr A ;divide by 2 and check for bit set to use offset
f644: 90 12 bcc DecrementSfx3Length
f646: a8 tay
f647: be 2b f6 ldx BrickShatterFreqData,y ;load reg contents of brick shatter sound
f64a: b9 ea ff lda BrickShatterEnvData,y
f64d: 8d 0c 40 PlayNoiseSfx sta NOISE_VOL ;play the sfx
f650: 8e 0e 40 stx NOISE_LO
f653: a9 18 lda #$18
f655: 8d 0f 40 sta NOISE_HI
DecrementSfx3Length
f658: ce bf 07 dec Noise_SfxLenCounter ;decrement length of sfx
f65b: d0 09 bne ExSfx3
f65d: a9 f0 lda #$f0 ;if done, stop playing the sfx
f65f: 8d 0c 40 sta NOISE_VOL
f662: a9 00 lda #$00
f664: 85 f3 sta NoiseSoundBuffer
f666: 60 ExSfx3 rts
f667: a4 fd NoiseSfxHandler ldy NoiseSoundQueue ;check for sfx in queue
f669: f0 0a beq CheckNoiseBuffer
f66b: 84 f3 sty NoiseSoundBuffer ;if found, put in buffer
f66d: 46 fd lsr NoiseSoundQueue
f66f: b0 ca bcs PlayBrickShatter ;brick shatter
f671: 46 fd lsr NoiseSoundQueue
f673: b0 0b bcs PlayBowserFlame ;bowser flame
CheckNoiseBuffer
f675: a5 f3 lda NoiseSoundBuffer ;check for sfx in buffer
f677: f0 06 beq ExNH ;if not found, exit sub
f679: 4a lsr A
f67a: b0 c4 bcs ContinueBrickShatter ;brick shatter
f67c: 4a lsr A
f67d: b0 06 bcs ContinueBowserFlame ;bowser flame
f67f: 60 ExNH rts
f680: a9 40 PlayBowserFlame lda #$40 ;load length of bowser flame sound
f682: 8d bf 07 sta Noise_SfxLenCounter
ContinueBowserFlame
f685: ad bf 07 lda Noise_SfxLenCounter
f688: 4a lsr A
f689: a8 tay
f68a: a2 0f ldx #$0f ;load reg contents of bowser flame sound
f68c: b9 c9 ff lda BowserFlameEnvData-1,y
f68f: d0 bc bne PlayNoiseSfx ;unconditional branch here
f691: 4c 3a f7 ContinueMusic jmp HandleSquare2Music ;if we have music, start with square 2 channel
; -----------------------------------------------------------------------------
f694: a5 fc MusicHandler lda EventMusicQueue ;check event music queue
f696: d0 0c bne LoadEventMusic
f698: a5 fb lda AreaMusicQueue ;check area music queue
f69a: d0 2c bne LoadAreaMusic
f69c: ad b1 07 lda EventMusicBuffer ;check both buffers
f69f: 05 f4 ora AreaMusicBuffer
f6a1: d0 ee bne ContinueMusic
f6a3: 60 rts ;no music, then leave
f6a4: 8d b1 07 LoadEventMusic sta EventMusicBuffer ;copy event music queue contents to buffer
f6a7: c9 01 cmp #DeathMusic ;is it death music?
f6a9: d0 06 bne NoStopSfx ;if not, jump elsewhere
f6ab: 20 a7 f4 jsr StopSquare1Sfx ;stop sfx in square 1 and 2
f6ae: 20 71 f5 jsr StopSquare2Sfx ; but clear only square 1's sfx buffer
f6b1: a6 f4 NoStopSfx ldx AreaMusicBuffer
f6b3: 8e c5 07 stx AreaMusicBuffer_Alt ;save current area music buffer to be re-obtained later
f6b6: a0 00 ldy #$00
f6b8: 8c c4 07 sty NoteLengthTblAdder ;default value for additional length byte offset
f6bb: 84 f4 sty AreaMusicBuffer ;clear area music buffer
f6bd: c9 40 cmp #TimeRunningOutMusic ;is it time running out music?
f6bf: d0 30 bne FindEventMusicHeader
f6c1: a2 08 ldx #$08 ;load offset to be added to length byte of header
f6c3: 8e c4 07 stx NoteLengthTblAdder
f6c6: d0 29 bne FindEventMusicHeader ;unconditional branch
f6c8: c9 04 LoadAreaMusic cmp #$04 ;is it underground music?
f6ca: d0 03 bne NoStop1 ;no, do not stop square 1 sfx
f6cc: 20 a7 f4 jsr StopSquare1Sfx
f6cf: a0 10 NoStop1 ldy #$10 ;start counter used only by ground level music
f6d1: 8c c7 07 GMLoopB sty GroundMusicHeaderOfs
HandleAreaMusicLoopB
f6d4: a0 00 ldy #$00 ;clear event music buffer
f6d6: 8c b1 07 sty EventMusicBuffer
f6d9: 85 f4 sta AreaMusicBuffer ;copy area music queue contents to buffer
f6db: c9 01 cmp #$01 ;is it ground level music?
f6dd: d0 0e bne FindAreaMusicHeader
f6df: ee c7 07 inc GroundMusicHeaderOfs ;increment but only if playing ground level music
f6e2: ac c7 07 ldy GroundMusicHeaderOfs ;is it time to loopback ground level music?
f6e5: c0 32 cpy #$32
f6e7: d0 0c bne LoadHeader ;branch ahead with alternate offset
f6e9: a0 11 ldy #$11
f6eb: d0 e4 bne GMLoopB ;unconditional branch
f6ed: a0 08 ldy #$08 ;load Y for offset of area music
f6ef: 84 f7 sty MusicOffset_Square2 ;residual instruction here
f6f1: c8 iny ;increment Y pointer based on previously loaded queue contents
f6f2: 4a lsr A ;bit shift and increment until we find a set bit for music
f6f3: 90 fc bcc FindEventMusicHeader
f6f5: b9 0c f9 lda MusicHeaderData-1,y ;load offset for header
f6f8: a8 tay
f6f9: b9 0d f9 lda MusicHeaderData,y ;now load the header
f6fc: 85 f0 sta NoteLenLookupTblOfs
f6fe: b9 0e f9 lda MusicHeaderData+1,y
f701: 85 f5 sta MusicData
f703: b9 0f f9 lda MusicHeaderData+2,y
f706: 85 f6 sta MusicData+1
f708: b9 10 f9 lda MusicHeaderData+3,y
f70b: 85 f9 sta MusicOffset_Triangle
f70d: b9 11 f9 lda MusicHeaderData+4,y
f710: 85 f8 sta MusicOffset_Square1
f712: b9 12 f9 lda MusicHeaderData+5,y
f715: 8d b0 07 sta MusicOffset_Noise
f718: 8d c1 07 sta NoiseDataLoopbackOfs
f71b: a9 01 lda #$01 ;initialize music note counters
f71d: 8d b4 07 sta Squ2_NoteLenCounter
f720: 8d b6 07 sta Squ1_NoteLenCounter
f723: 8d b9 07 sta Tri_NoteLenCounter
f726: 8d ba 07 sta Noise_BeatLenCounter
f729: a9 00 lda #$00 ;initialize music data offset for square 2
f72b: 85 f7 sta MusicOffset_Square2
f72d: 8d ca 07 sta AltRegContentFlag ;initialize alternate control reg data used by square 1
f730: a9 0b lda #$0b ;disable triangle channel and reenable it
f732: 8d 15 40 sta SND_CHN
f735: a9 0f lda #$0f
f737: 8d 15 40 sta SND_CHN
HandleSquare2Music
f73a: ce b4 07 dec Squ2_NoteLenCounter ;decrement square 2 note length
f73d: d0 5f bne MiscSqu2MusicTasks ;is it time for more data? if not, branch to end tasks
f73f: a4 f7 ldy MusicOffset_Square2 ;increment square 2 music offset and fetch data
f741: e6 f7 inc MusicOffset_Square2
f743: b1 f5 lda (MusicData),y
f745: f0 04 beq EndOfMusicData ;if zero, the data is a null terminator
f747: 10 3d bpl Squ2NoteHandler ;if non-negative, data is a note
f749: d0 2f bne Squ2LengthHandler ;otherwise it is length data
f74b: ad b1 07 EndOfMusicData lda EventMusicBuffer ;check secondary buffer for time running out music
f74e: c9 40 cmp #TimeRunningOutMusic
f750: d0 05 bne NotTRO
f752: ad c5 07 lda AreaMusicBuffer_Alt ;load previously saved contents of primary buffer
f755: d0 1d bne MusicLoopBack ; and start playing the song again if there is one
f757: 29 04 NotTRO and #VictoryMusic ;check for victory music (the only secondary that loops)
f759: d0 1c bne VictoryMLoopBack
f75b: a5 f4 lda AreaMusicBuffer ;check primary buffer for any music except pipe intro
f75d: 29 5f and #%01011111
f75f: d0 13 bne MusicLoopBack ;if any area music except pipe intro, music loops
f761: a9 00 lda #$00 ;clear primary and secondary buffers and initialize
f763: 85 f4 sta AreaMusicBuffer ; control regs of square and triangle channels
f765: 8d b1 07 sta EventMusicBuffer
f768: 8d 08 40 sta TRI_LINEAR
f76b: a9 90 lda #$90
f76d: 8d 00 40 sta SQ1_VOL
f770: 8d 04 40 sta SQ2_VOL
f773: 60 rts
f774: 4c d4 f6 MusicLoopBack jmp HandleAreaMusicLoopB
VictoryMLoopBack
f777: 4c a4 f6 jmp LoadEventMusic
Squ2LengthHandler
f77a: 20 cb f8 jsr ProcessLengthData ;store length of note
f77d: 8d b3 07 sta Squ2_NoteLenBuffer
f780: a4 f7 ldy MusicOffset_Square2 ;fetch another byte (MUST NOT BE LENGTH BYTE!)
f782: e6 f7 inc MusicOffset_Square2
f784: b1 f5 lda (MusicData),y
f786: a6 f2 Squ2NoteHandler ldx Square2SoundBuffer ;is there a sound playing on this channel?
f788: d0 0e bne SkipFqL1
f78a: 20 a9 f3 jsr SetFreq_Squ2 ;no, then play the note
f78d: f0 03 beq Rest ;check to see if note is rest
f78f: 20 d8 f8 jsr LoadControlRegs ;if not, load control regs for square 2
f792: 8d b5 07 Rest sta Squ2_EnvelopeDataCtrl ;save contents of A
f795: 20 9f f3 jsr Dump_Sq2_Regs ;dump X and Y into square 2 control regs
f798: ad b3 07 SkipFqL1 lda Squ2_NoteLenBuffer ;save length in square 2 note counter
f79b: 8d b4 07 sta Squ2_NoteLenCounter
MiscSqu2MusicTasks
f79e: a5 f2 lda Square2SoundBuffer ;is there a sound playing on square 2?
f7a0: d0 1a bne HandleSquare1Music
f7a2: ad b1 07 lda EventMusicBuffer ;check for death music or d4 set on secondary buffer
f7a5: 29 91 and #%10010001 ;note that regs for death music or d4 are loaded by default
f7a7: d0 13 bne HandleSquare1Music
f7a9: ac b5 07 ldy Squ2_EnvelopeDataCtrl ;check for contents saved from LoadControlRegs
f7ac: f0 03 beq NoDecEnv1
f7ae: ce b5 07 dec Squ2_EnvelopeDataCtrl ;decrement unless already zero
f7b1: 20 f4 f8 NoDecEnv1 jsr LoadEnvelopeData ;do a load of envelope data to replace default
f7b4: 8d 04 40 sta SQ2_VOL ;based on offset set by first load unless playing
f7b7: a2 7f ldx #$7f ;death music or d4 set on secondary buffer
f7b9: 8e 05 40 stx SQ2_SWEEP
HandleSquare1Music
f7bc: a4 f8 ldy MusicOffset_Square1 ;is there a nonzero offset here?
f7be: f0 5a beq HandleTriangleMusic ;if not, skip ahead to the triangle channel
f7c0: ce b6 07 dec Squ1_NoteLenCounter ;decrement square 1 note length
f7c3: d0 32 bne MiscSqu1MusicTasks ;is it time for more data?
FetchSqu1MusicData
f7c5: a4 f8 ldy MusicOffset_Square1 ;increment square 1 music offset and fetch data
f7c7: e6 f8 inc MusicOffset_Square1
f7c9: b1 f5 lda (MusicData),y
f7cb: d0 0f bne Squ1NoteHandler ;if nonzero, then skip this part
f7cd: a9 83 lda #$83
f7cf: 8d 00 40 sta SQ1_VOL ;store some data into control regs for square 1
f7d2: a9 94 lda #$94 ; and fetch another byte of data, used to give
f7d4: 8d 01 40 sta SQ1_SWEEP ; death music its unique sound
f7d7: 8d ca 07 sta AltRegContentFlag
f7da: d0 e9 bne FetchSqu1MusicData ;unconditional branch
f7dc: 20 c5 f8 Squ1NoteHandler jsr AlternateLengthNalder
f7df: 8d b6 07 sta Squ1_NoteLenCounter ;save contents of A in square 1 note counter
f7e2: a4 f1 ldy Square1SoundBuffer ;is there a sound playing on square 1?
f7e4: d0 34 bne HandleTriangleMusic
f7e6: 8a txa
f7e7: 29 3e and #%00111110 ;change saved data to appropriate note format
f7e9: 20 8b f3 jsr SetFreq_Squ1 ;play the note
f7ec: f0 03 beq SkipCtrlL
f7ee: 20 d8 f8 jsr LoadControlRegs
f7f1: 8d b7 07 SkipCtrlL sta Squ1_EnvelopeDataCtrl ;save envelope offset
f7f4: 20 81 f3 jsr Dump_Squ1_Regs
MiscSqu1MusicTasks
f7f7: a5 f1 lda Square1SoundBuffer ;is there a sound playing on square 1?
f7f9: d0 1f bne HandleTriangleMusic
f7fb: ad b1 07 lda EventMusicBuffer ;check for death music or d4 set on secondary buffer
f7fe: 29 91 and #%10010001
f800: d0 0e bne DeathMAltReg
f802: ac b7 07 ldy Squ1_EnvelopeDataCtrl ;check saved envelope offset
f805: f0 03 beq NoDecEnv2
f807: ce b7 07 dec Squ1_EnvelopeDataCtrl ;decrement unless already zero
f80a: 20 f4 f8 NoDecEnv2 jsr LoadEnvelopeData ;do a load of envelope data
f80d: 8d 00 40 sta SQ1_VOL ; based on offset set by first load
f810: ad ca 07 DeathMAltReg lda AltRegContentFlag ;check for alternate control reg data
f813: d0 02 bne DoAltLoad
f815: a9 7f lda #$7f ;load this value if zero, the alternate value
f817: 8d 01 40 DoAltLoad sta SQ1_SWEEP ;if nonzero, and let's move on
HandleTriangleMusic
f81a: a5 f9 lda MusicOffset_Triangle
f81c: ce b9 07 dec Tri_NoteLenCounter ;decrement triangle note length
f81f: d0 4c bne HandleNoiseMusic ;is it time for more data?
f821: a4 f9 ldy MusicOffset_Triangle ;increment square 1 music offset and fetch data
f823: e6 f9 inc MusicOffset_Triangle
f825: b1 f5 lda (MusicData),y
f827: f0 41 beq LoadTriCtrlReg ;if zero, skip all this and move on to noise
f829: 10 13 bpl TriNoteHandler ;if non-negative, data is note
f82b: 20 cb f8 jsr ProcessLengthData ;otherwise, it is length data
f82e: 8d b8 07 sta Tri_NoteLenBuffer ;save contents of A
f831: a9 1f lda #$1f
f833: 8d 08 40 sta TRI_LINEAR ;load some default data for triangle control reg
f836: a4 f9 ldy MusicOffset_Triangle ;fetch another byte
f838: e6 f9 inc MusicOffset_Triangle
f83a: b1 f5 lda (MusicData),y
f83c: f0 2c beq LoadTriCtrlReg ;check once more for nonzero data
f83e: 20 ad f3 TriNoteHandler jsr SetFreq_Tri
f841: ae b8 07 ldx Tri_NoteLenBuffer ;save length in triangle note counter
f844: 8e b9 07 stx Tri_NoteLenCounter
f847: ad b1 07 lda EventMusicBuffer
f84a: 29 6e and #%01101110 ;check for death music or d4 set on secondary buffer
f84c: d0 06 bne NotDOrD4 ;if playing any other secondary, skip primary buffer check
f84e: a5 f4 lda AreaMusicBuffer ;check primary buffer for water or castle level music
f850: 29 0a and #%00001010
f852: f0 19 beq HandleNoiseMusic ;if playing any other primary, or death or d4, go on to noise routine
f854: 8a NotDOrD4 txa ;if playing water or castle music or any secondary
f855: c9 12 cmp #$12 ; besides death music or d4 set, check length of note
f857: b0 0f bcs LongN
f859: ad b1 07 lda EventMusicBuffer ;check for win castle music again if not playing a long note
f85c: 29 08 and #EndOfCastleMusic
f85e: f0 04 beq MediN
f860: a9 0f lda #$0f ;load value $0f if playing the win castle music and playing a short
f862: d0 06 bne LoadTriCtrlReg ; note, load value $1f if playing water or castle level music or any
f864: a9 1f MediN lda #$1f ; secondary besides death and d4 except win castle or win castle and playing
f866: d0 02 bne LoadTriCtrlReg ; a short note, and load value $ff if playing a long note on water, castle
f868: a9 ff LongN lda #$ff ; or any secondary (including win castle) except death and d4
f86a: 8d 08 40 LoadTriCtrlReg sta TRI_LINEAR ;save final contents of A into control reg for triangle
HandleNoiseMusic
f86d: a5 f4 lda AreaMusicBuffer ;check if playing underground or castle music
f86f: 29 f3 and #%11110011
f871: f0 51 beq ExitMusicHandler ;if so, skip the noise routine
f873: ce ba 07 dec Noise_BeatLenCounter ;decrement noise beat length
f876: d0 4c bne ExitMusicHandler ;is it time for more data?
FetchNoiseBeatData
f878: ac b0 07 ldy MusicOffset_Noise ;increment noise beat offset and fetch data
f87b: ee b0 07 inc MusicOffset_Noise
f87e: b1 f5 lda (MusicData),y ;get noise beat data, if nonzero, branch to handle
f880: d0 08 bne NoiseBeatHandler
f882: ad c1 07 lda NoiseDataLoopbackOfs ;if data is zero, reload original noise beat offset
f885: 8d b0 07 sta MusicOffset_Noise ; and loopback next time around
f888: d0 ee bne FetchNoiseBeatData ;unconditional branch
NoiseBeatHandler
f88a: 20 c5 f8 jsr AlternateLengthNalder
f88d: 8d ba 07 sta Noise_BeatLenCounter ;store length in noise beat counter
f890: 8a txa
f891: 29 3e and #%00111110 ;reload data and erase length bits
f893: f0 24 beq SilentBeat ;if no beat data, silence
f895: c9 30 cmp #$30 ;check the beat data and play the appropriate
f897: f0 18 beq LongBeat ;noise accordingly
f899: c9 20 cmp #$20
f89b: f0 0c beq StrongBeat
f89d: 29 10 and #$10
f89f: f0 18 beq SilentBeat
f8a1: a9 1c lda #$1c ;short beat data
f8a3: a2 03 ldx #$03
f8a5: a0 18 ldy #$18
f8a7: d0 12 bne PlayBeat
f8a9: a9 1c StrongBeat lda #$1c ;strong beat data
f8ab: a2 0c ldx #$0c
f8ad: a0 18 ldy #$18
f8af: d0 0a bne PlayBeat
f8b1: a9 1c LongBeat lda #$1c ;long beat data
f8b3: a2 03 ldx #$03
f8b5: a0 58 ldy #$58
f8b7: d0 02 bne PlayBeat
f8b9: a9 10 SilentBeat lda #$10 ;silence
f8bb: 8d 0c 40 PlayBeat sta NOISE_VOL ;load beat data into noise regs
f8be: 8e 0e 40 stx NOISE_LO
f8c1: 8c 0f 40 sty NOISE_HI
ExitMusicHandler
f8c4: 60 rts
AlternateLengthNalder
f8c5: aa tax ;save a copy of original byte into X
f8c6: 6a ror A ;save LSB from original byte into carry
f8c7: 8a txa ;reload original byte and rotate three times
f8c8: 2a rol A ;turning xx00000x into 00000xxx, with the
f8c9: 2a rol A ;bit in carry as the MSB here
f8ca: 2a rol A
ProcessLengthData
f8cb: 29 07 and #%00000111 ;clear all but the three LSBs
f8cd: 18 clc
f8ce: 65 f0 adc NoteLenLookupTblOfs ;add offset loaded from first header byte
f8d0: 6d c4 07 adc NoteLengthTblAdder ;add extra if time running out music
f8d3: a8 tay
f8d4: b9 66 ff lda MusicLengthLookupTbl,y ;load length
f8d7: 60 rts
f8d8: ad b1 07 LoadControlRegs lda EventMusicBuffer ;check secondary buffer for win castle music
f8db: 29 08 and #EndOfCastleMusic
f8dd: f0 04 beq NotECstlM
f8df: a9 04 lda #$04 ;this value is only used for win castle music
f8e1: d0 0c bne AllMus ;unconditional branch
f8e3: a5 f4 NotECstlM lda AreaMusicBuffer
f8e5: 29 7d and #%01111101 ;check primary buffer for water music
f8e7: f0 04 beq WaterMus
f8e9: a9 08 lda #$08 ;this is the default value for all other music
f8eb: d0 02 bne AllMus
f8ed: a9 28 WaterMus lda #$28 ;this value is used for water music and all other event music
f8ef: a2 82 AllMus ldx #$82 ;load contents of other sound regs for square 2
f8f1: a0 7f ldy #$7f
f8f3: 60 rts
LoadEnvelopeData
f8f4: ad b1 07 lda EventMusicBuffer ;check secondary buffer for win castle music
f8f7: 29 08 and #EndOfCastleMusic
f8f9: f0 04 beq LoadUsualEnvData
f8fb: b9 96 ff lda EndOfCastleMusicEnvData,y ;load data from offset for win castle music
f8fe: 60 rts
LoadUsualEnvData
f8ff: a5 f4 lda AreaMusicBuffer ;check primary buffer for water music
f901: 29 7d and #%01111101
f903: f0 04 beq LoadWaterEventMusEnvData
f905: b9 9a ff lda AreaMusicEnvData,y ;load default data from offset for all other music
f908: 60 rts
LoadWaterEventMusEnvData
f909: b9 a2 ff lda WaterEventMusEnvData,y ;load data from offset for water music and all other event music
f90c: 60 rts
; -----------------------------------------------------------------------------
;
; music header offsets
;
; ||(these are single-byte offsets from MusicHeaderData; no good way to
; represent these in SourceGen)
f90d: a5 59 54 64+ .bulk $a5,$59,$54,$64,$59,$3c,$31,$4b ;event music
f915: 69 5e 46 4f+ .bulk $69,$5e,$46,$4f,$36,$8d,$36,$4b ;area music
f91d: 8d 69 69 6f+ .bulk $8d,$69,$69,$6f,$75,$6f,$7b,$6f,$75,$6f,$7b,$81,$87,$81,$8d,$69 ;ground level music layout
+ $69,$93,$99,$93,$9f,$93,$99,$93,$9f,$81,$87,$81,$8d,$93,$99,$93
+ $9f
;
; music headers
; header format is as follows:
; 1 byte - length byte offset
; 2 bytes - music data address
; 1 byte - triangle data offset
; 1 byte - square 1 data offset
; 1 byte - noise data offset (not used by secondary music)
TimeRunningOutHdr
f93e: 08 .dd1 $08
f93f: 72 .dd1 <TimeRunOutMusData
f940: fc .dd1 >TimeRunOutMusData
f941: 27 18 .bulk $27,$18
f943: 20 Str_CloudHdr .dd1 $20
f944: b8 .dd1 <Star_CloudMData
f945: f9 .dd1 >Star_CloudMData
f946: 2e 1a 40 .bulk $2e,$1a,$40
EndOfLevelMusHdr
f949: 20 .dd1 $20
f94a: b0 .dd1 <WinLevelMusData
f94b: fc .dd1 >WinLevelMusData
f94c: 3d 21 .bulk $3d,$21
f94e: 20 .dd1 $20
f94f: c4 fc .dd2 $fcc4
f951: 3f 1d .bulk $3f,$1d
UndergroundMusHdr
f953: 18 .dd1 $18
f954: 11 .dd1 <UndergroundMusData
f955: fd 00 00 .bulk $fd,$00,$00
f958: 08 SilenceHdr .dd1 $08
f959: 1c .dd1 <SilenceData
f95a: fa .dd1 >SilenceData
f95b: 00 .dd1 $00
f95c: 00 CastleMusHdr .dd1 $00
f95d: a4 .dd1 <CastleMusData
f95e: fb .dd1 >CastleMusData
f95f: 93 62 .bulk $93,$62
f961: 10 VictoryMusHdr .dd1 $10
f962: c8 .dd1 <VictoryMusData
f963: fe .dd1 >VictoryMusData
f964: 24 14 .bulk $24,$14
f966: 18 GameOverMusHdr .dd1 $18
f967: 45 .dd1 <GameOverMusData
f968: fc .dd1 >GameOverMusData
f969: 1e 14 .bulk $1e,$14
f96b: 08 WaterMusHdr .dd1 $08
f96c: 52 .dd1 <WaterMusData
f96d: fd .dd1 >WaterMusData
f96e: a0 70 68 .bulk $a0,$70,$68
f971: 08 WinCastleMusHdr .dd1 $08
f972: 51 .dd1 <EndOfCastleMusData
f973: fe .dd1 >EndOfCastleMusData
f974: 4c 24 .bulk $4c,$24
GroundLevelPart1Hdr
f976: 18 .dd1 $18
f977: 01 .dd1 <GroundM_P1Data
f978: fa .dd1 >GroundM_P1Data
f979: 2d 1c b8 .bulk $2d,$1c,$b8
GroundLevelPart2AHdr
f97c: 18 .dd1 $18
f97d: 49 .dd1 <GroundM_P2AData
f97e: fa .dd1 >GroundM_P2AData
f97f: 20 12 70 .bulk $20,$12,$70
GroundLevelPart2BHdr
f982: 18 .dd1 $18
f983: 75 .dd1 <GroundM_P2BData
f984: fa .dd1 >GroundM_P2BData
f985: 1b 10 44 .bulk $1b,$10,$44
GroundLevelPart2CHdr
f988: 18 .dd1 $18
f989: 9d .dd1 <GroundM_P2CData
f98a: fa .dd1 >GroundM_P2CData
f98b: 11 0a 1c .bulk $11,$0a,$1c
GroundLevelPart3AHdr
f98e: 18 .dd1 $18
f98f: c2 .dd1 <GroundM_P3AData
f990: fa .dd1 >GroundM_P3AData
f991: 2d 10 58 .bulk $2d,$10,$58
GroundLevelPart3BHdr
f994: 18 .dd1 $18
f995: db .dd1 <GroundM_P3BData
f996: fa .dd1 >GroundM_P3BData
f997: 14 0d 3f .bulk $14,$0d,$3f
GroundLevelLeadInHdr
f99a: 18 .dd1 $18
f99b: f9 .dd1 <GroundMLdInData
f99c: fa .dd1 >GroundMLdInData
f99d: 15 0d 21 .bulk $15,$0d,$21
GroundLevelPart4AHdr
f9a0: 18 .dd1 $18
f9a1: 25 .dd1 <GroundM_P4AData
f9a2: fb .dd1 >GroundM_P4AData
f9a3: 18 10 7a .bulk $18,$10,$7a
GroundLevelPart4BHdr
f9a6: 18 .dd1 $18
f9a7: 4b .dd1 <GroundM_P4BData
f9a8: fb .dd1 >GroundM_P4BData
f9a9: 19 0f 54 .bulk $19,$0f,$54
GroundLevelPart4CHdr
f9ac: 18 .dd1 $18
f9ad: 74 .dd1 <GroundM_P4CData
f9ae: fb .dd1 >GroundM_P4CData
f9af: 1e 12 2b .bulk $1e,$12,$2b
f9b2: 18 DeathMusHdr .dd1 $18
f9b3: 72 .dd1 <DeathMusData
f9b4: fb .dd1 >DeathMusData
f9b5: 1e 0f 2d .bulk $1e,$0f,$2d
; -----------------------------------------------------------------------------
; MUSIC DATA
;
; square 2/triangle format
; d7 - length byte flag (0-note, 1-length)
; if d7 is set to 0 and d6-d0 is nonzero:
; d6-d0 - note offset in frequency look-up table (must be even)
; if d7 is set to 1:
; d6-d3 - unused
; d2-d0 - length offset in length look-up table
; value of $00 in square 2 data is used as null terminator, affects all sound
; channels
; value of $00 in triangle data causes routine to skip note
;
; square 1 format
; d7-d6, d0 - length offset in length look-up table (bit order is d0,d7,d6)
; d5-d1 - note offset in frequency look-up table
; value of $00 in square 1 data is flag alternate control reg data to be loaded
;
; noise format
; d7-d6, d0 - length offset in length look-up table (bit order is d0,d7,d6)
; d5-d4 - beat type (0 - rest, 1 - short, 2 - strong, 3 - long)
; d3-d1 - unused
; value of $00 in noise data is used as null terminator, affects only noise
;
; all music data is organized into sections (unless otherwise stated): square 2,
; square 1, triangle, noise
f9b8: 84 2c 2c 2c+ Star_CloudMData .bulk $84,$2c,$2c,$2c,$82,$04,$2c,$04,$85,$2c,$84,$2c,$2c,$2a,$2a,$2a
+ $82,$04,$2a,$04,$85,$2a,$84,$2a,$2a,$00
f9d2: 1f 1f 1f 98+ .bulk $1f,$1f,$1f,$98,$1f,$1f,$98,$9e,$98,$1f,$1d,$1d,$1d,$94,$1d,$1d
+ $94,$9c,$94,$1d
f9e6: 86 18 85 26+ .bulk $86,$18,$85,$26,$30,$84,$04,$26,$30,$86,$14,$85,$22,$2c,$84,$04
+ $22,$2c
f9f8: 21 d0 c4 d0+ .bulk $21,$d0,$c4,$d0,$31,$d0,$c4,$d0,$00
fa01: 85 2c 22 1c+ GroundM_P1Data .bulk $85,$2c,$22,$1c,$84,$26,$2a,$82,$28,$26,$04,$87,$22,$34,$3a,$82
+ $40,$04,$36,$84,$3a,$34,$82,$2c,$30,$85,$2a
fa1c: 00 SilenceData .dd1 $00
fa1d: 5d 55 4d 15+ .bulk $5d,$55,$4d,$15,$19,$96,$15,$d5,$e3,$eb,$2d,$a6,$2b,$27,$9c,$9e
+ $59,$85,$22,$1c,$14,$84,$1e,$22,$82,$20,$1e,$04,$87,$1c,$2c,$34
+ $82,$36,$04,$30,$34,$04,$2c,$04,$26,$2a,$85,$22
fa49: 84 04 82 3a+ GroundM_P2AData .bulk $84,$04,$82,$3a,$38,$36,$32,$04,$34,$04,$24,$26,$2c,$04,$26,$2c
+ $30,$00,$05,$b4,$b2,$b0,$2b,$ac,$84,$9c,$9e,$a2,$84,$94,$9c,$9e
+ $85,$14,$22,$84,$2c,$85,$1e,$82,$2c,$84,$2c,$1e
fa75: 84 04 82 3a+ GroundM_P2BData .bulk $84,$04,$82,$3a,$38,$36,$32,$04,$34,$04,$64,$04,$64,$86,$64,$00
+ $05,$b4,$b2,$b0,$2b,$ac,$84,$37,$b6,$b6,$45,$85,$14,$1c,$82,$22
+ $84,$2c,$4e,$82,$4e,$84,$4e,$22
fa9d: 84 04 85 32+ GroundM_P2CData .bulk $84,$04,$85,$32,$85,$30,$86,$2c,$04,$00,$05,$a4,$05,$9e,$05,$9d
+ $85,$84,$14,$85,$24,$28,$2c,$82,$22,$84,$22,$14,$21,$d0,$c4,$d0
+ $31,$d0,$c4,$d0,$00
fac2: 82 2c 84 2c+ GroundM_P3AData .bulk $82,$2c,$84,$2c,$2c,$82,$2c,$30,$04,$34,$2c,$04,$26,$86,$22,$00
+ $a4,$25,$25,$a4,$29,$a2,$1d,$9c,$95
fadb: 82 2c 2c 04+ GroundM_P3BData .bulk $82,$2c,$2c,$04,$2c,$04,$2c,$30,$85,$34,$04,$04,$00,$a4,$25,$25
+ $a4,$a8,$63,$04
; triangle data used by both sections of third part
faef: 85 0e 1a 84+ .bulk $85,$0e,$1a,$84,$24,$85,$22,$14,$84,$0c
faf9: 82 34 84 34+ GroundMLdInData .bulk $82,$34,$84,$34,$34,$82,$2c,$84,$34,$86,$3a,$04,$00,$a0,$21,$21
+ $a0,$21,$2b,$05,$a3,$82,$18,$84,$18,$18,$82,$18,$18,$04,$86,$3a
+ $22
; noise data used by lead-in and third part sections
fb1a: 31 90 31 90+ .bulk $31,$90,$31,$90,$31,$71,$31,$90,$90,$90,$00
fb25: 82 34 84 2c+ GroundM_P4AData .bulk $82,$34,$84,$2c,$85,$22,$84,$24,$82,$26,$36,$04,$36,$86,$26,$00
+ $ac,$27,$5d,$1d,$9e,$2d,$ac,$9f,$85,$14,$82,$20,$84,$22,$2c,$1e
+ $1e,$82,$2c,$2c,$1e,$04
fb4b: 87 2a 40 40+ GroundM_P4BData .bulk $87,$2a,$40,$40,$40,$3a,$36,$82,$34,$2c,$04,$26,$86,$22,$00,$e3
+ $f7,$f7,$f7,$f5,$f1,$ac,$27,$9e,$9d,$85,$18,$82,$1e,$84,$22,$2a
+ $22,$22,$82,$2c,$2c,$22,$04
fb72: 86 04 DeathMusData .bulk $86,$04 ;death music share data with fourth part c of ground level music
fb74: 82 2a 36 04+ GroundM_P4CData .bulk $82,$2a,$36,$04,$36,$87,$36,$34,$30,$86,$2c,$04,$00
fb81: 00 68 6a 6c+ .bulk $00,$68,$6a,$6c,$45 ;death music only
fb86: a2 31 b0 f1+ .bulk $a2,$31,$b0,$f1,$ed,$eb,$a2,$1d,$9c,$95
fb90: 86 04 .bulk $86,$04 ;death music only
fb92: 85 22 82 22+ .bulk $85,$22,$82,$22,$87,$22,$26,$2a,$84,$2c,$22,$86,$14
; noise data used by fourth part sections
fb9f: 51 90 31 11+ .bulk $51,$90,$31,$11,$00
fba4: 80 22 28 22+ CastleMusData .bulk $80,$22,$28,$22,$26,$22,$24,$22,$26,$22,$28,$22,$2a,$22,$28,$22
+ $26,$22,$28,$22,$26,$22,$24,$22,$26,$22,$28,$22,$2a,$22,$28,$22
+ $26,$20,$26,$20,$24,$20,$26,$20,$28,$20,$26,$20,$28,$20,$26,$20
+ $24,$20,$26,$20,$24,$20,$26,$20,$28,$20,$26,$20,$28,$20,$26,$20
+ $24,$28,$30,$28,$32,$28,$30,$28,$2e,$28,$30,$28,$2e,$28,$2c,$28
+ $2e,$28,$30,$28,$32,$28,$30,$28,$2e,$28,$30,$28,$2e,$28,$2c,$28
+ $2e,$00
fc06: 04 70 6e 6c+ .bulk $04,$70,$6e,$6c,$6e,$70,$72,$70,$6e,$70,$6e,$6c,$6e,$70,$72,$70
+ $6e,$6e,$6c,$6e,$70,$6e,$70,$6e,$6c,$6e,$6c,$6e,$70,$6e,$70,$6e
+ $6c,$76,$78,$76,$74,$76,$74,$72,$74,$76,$78,$76,$74,$76,$74,$72
+ $74
fc37: 84 1a 83 18+ .bulk $84,$1a,$83,$18,$20,$84,$1e,$83,$1c,$28,$26,$1c,$1a,$1c
fc45: 82 2c 04 04+ GameOverMusData .bulk $82,$2c,$04,$04,$22,$04,$04,$84,$1c,$87,$26,$2a,$26,$84,$24,$28
+ $24,$80,$22,$00,$9c,$05,$94,$05,$0d,$9f,$1e,$9c,$98,$9d,$82,$22
+ $04,$04,$1c,$04,$04,$84,$14,$86,$1e,$80,$16,$80,$14
TimeRunOutMusData
fc72: 81 1c 30 04+ .bulk $81,$1c,$30,$04,$30,$30,$04,$1e,$32,$04,$32,$32,$04,$20,$34,$04
+ $34,$34,$04,$36,$04,$84,$36,$00,$46,$a4,$64,$a4,$48,$a6,$66,$a6
+ $4a,$a8,$68,$a8,$6a,$44,$2b,$81,$2a,$42,$04,$42,$42,$04,$2c,$64
+ $04,$64,$64,$04,$2e,$46,$04,$46,$46,$04,$22,$04,$84,$22
fcb0: 87 04 06 0c+ WinLevelMusData .bulk $87,$04,$06,$0c,$14,$1c,$22,$86,$2c,$22,$87,$04,$60,$0e,$14,$1a
+ $24,$86,$2c,$24,$87,$04,$08,$10,$18,$1e,$28,$86,$30,$30,$80,$64
+ $00,$cd,$d5,$dd,$e3,$ed,$f5,$bb,$b5,$cf,$d5,$db,$e5,$ed,$f3,$bd
+ $b3,$d1,$d9,$df,$e9,$f1,$f7,$bf,$ff,$ff,$ff,$34
fcec: 00 .dd1 $00 ;unused byte
fced: 86 04 87 14+ .bulk $86,$04,$87,$14,$1c,$22,$86,$34,$84,$2c,$04,$04,$04,$87,$14,$1a
+ $24,$86,$32,$84,$2c,$04,$86,$04,$87,$18,$1e,$28,$86,$36,$87,$30
+ $30,$30,$80,$2c
; square 2 and triangle use the same data, square 1 is unused
UndergroundMusData
fd11: 82 14 2c 62+ .bulk $82,$14,$2c,$62,$26,$10,$28,$80,$04,$82,$14,$2c,$62,$26,$10,$28
+ $80,$04,$82,$08,$1e,$5e,$18,$60,$1a,$80,$04,$82,$08,$1e,$5e,$18
+ $60,$1a,$86,$04,$83,$1a,$18,$16,$84,$14,$1a,$18,$0e,$0c,$16,$83
+ $14,$20,$1e,$1c,$28,$26,$87,$24,$1a,$12,$10,$62,$0e,$80,$04,$04
+ $00
; noise data directly follows square 2 here unlike in other songs
fd52: 82 18 1c 20+ WaterMusData .bulk $82,$18,$1c,$20,$22,$26,$28,$81,$2a,$2a,$2a,$04,$2a,$04,$83,$2a
+ $82,$22,$86,$34,$32,$34,$81,$04,$22,$26,$2a,$2c,$30,$86,$34,$83
+ $32,$82,$36,$84,$34,$85,$04,$81,$22,$86,$30,$2e,$30,$81,$04,$22
+ $26,$2a,$2c,$2e,$86,$30,$83,$22,$82,$36,$84,$34,$85,$04,$81,$22
+ $86,$3a,$3a,$3a,$82,$3a,$81,$40,$82,$04,$81,$3a,$86,$36,$36,$36
+ $82,$36,$81,$3a,$82,$04,$81,$36,$86,$34,$82,$26,$2a,$36,$81,$34
+ $34,$85,$34,$81,$2a,$86,$2c,$00
fdba: 84 90 b0 84+ .bulk $84,$90,$b0,$84,$50,$50,$b0,$00
fdc2: 98 96 94 92+ .bulk $98,$96,$94,$92,$94,$96,$58,$58,$58,$44,$5c,$44,$9f,$a3,$a1,$a3
+ $85,$a3,$e0,$a6,$23,$c4,$9f,$9d,$9f,$85,$9f,$d2,$a6,$23,$c4,$b5
+ $b1,$af,$85,$b1,$af,$ad,$85,$95,$9e,$a2,$aa,$6a,$6a,$6b,$5e,$9d
fdf2: 84 04 04 82+ .bulk $84,$04,$04,$82,$22,$86,$22,$82,$14,$22,$2c,$12,$22,$2a,$14,$22
+ $2c,$1c,$22,$2c,$14,$22,$2c,$12,$22,$2a,$14,$22,$2c,$1c,$22,$2c
+ $18,$22,$2a,$16,$20,$28,$18,$22,$2a,$12,$22,$2a,$18,$22,$2a,$12
+ $22,$2a,$14,$22,$2c,$0c,$22,$2c,$14,$22,$34,$12,$22,$30,$10,$22
+ $2e,$16,$22,$34,$18,$26,$36,$16,$26,$36,$14,$26,$36,$12,$22,$36
+ $5c,$22,$34,$0c,$22,$22,$81,$1e,$1e,$85,$1e,$81,$12,$86,$14
EndOfCastleMusData
fe51: 81 2c 22 1c+ .bulk $81,$2c,$22,$1c,$2c,$22,$1c,$85,$2c,$04,$81,$2e,$24,$1e,$2e,$24
+ $1e,$85,$2e,$04,$81,$32,$28,$22,$32,$28,$22,$85,$32,$87,$36,$36
+ $36,$84,$3a,$00
fe75: 5c 54 4c 5c+ .bulk $5c,$54,$4c,$5c,$54,$4c,$5c,$1c,$1c,$5c,$5c,$5c,$5c,$5e,$56,$4e
+ $5e,$56,$4e,$5e,$1e,$1e,$5e,$5e,$5e,$5e,$62,$5a,$50,$62,$5a,$50
+ $62,$22,$22,$62,$e7,$e7,$e7,$2b
fe9d: 86 14 81 14+ .bulk $86,$14,$81,$14,$80,$14,$14,$81,$14,$14,$14,$14,$86,$16,$81,$16
+ $80,$16,$16,$81,$16,$16,$16,$16,$81,$28,$22,$1a,$28,$22,$1a,$28
+ $80,$28,$28,$81,$28,$87,$2c,$2c,$2c,$84,$30
fec8: 83 04 84 0c+ VictoryMusData .bulk $83,$04,$84,$0c,$83,$62,$10,$84,$12,$83,$1c,$22,$1e,$22,$26,$18
+ $1e,$04,$1c,$00
fedc: e3 e1 e3 1d+ .bulk $e3,$e1,$e3,$1d,$de,$e0,$23,$ec,$75,$74,$f0,$f4,$f6,$ea,$31,$2d
feec: 83 12 14 04+ .bulk $83,$12,$14,$04,$18,$1a,$1c,$14,$26,$22,$1e,$1c,$18,$1e,$22,$0c
+ $14
; unused space
fefd: ff ff ff .bulk $ff,$ff,$ff
FreqRegLookupTbl
ff00: 00 88 00 2f+ .bulk $00,$88,$00,$2f,$00,$00,$02,$a6,$02,$80,$02,$5c,$02,$3a,$02,$1a
+ $01,$df,$01,$c4,$01,$ab,$01,$93,$01,$7c,$01,$67,$01,$53,$01,$40
+ $01,$2e,$01,$1d,$01,$0d,$00,$fe,$00,$ef,$00,$e2,$00,$d5,$00,$c9
+ $00,$be,$00,$b3,$00,$a9,$00,$a0,$00,$97,$00,$8e,$00,$86,$00,$77
+ $00,$7e,$00,$71,$00,$54,$00,$64,$00,$5f,$00,$59,$00,$50,$00,$47
+ $00,$43,$00,$3b,$00,$35,$00,$2a,$00,$23,$04,$75,$03,$57,$02,$f9
+ $02,$cf,$01,$fc,$00,$6a
MusicLengthLookupTbl
ff66: 05 0a 14 28+ .bulk $05,$0a,$14,$28,$50,$1e,$3c,$02,$04,$08,$10,$20,$40,$18,$30,$0c
+ $03,$06,$0c,$18,$30,$12,$24,$08,$36,$03,$09,$06,$12,$1b,$24,$0c
+ $24,$02,$06,$04,$0c,$12,$18,$08,$12,$01,$03,$02,$06,$09,$0c,$04
EndOfCastleMusicEnvData
ff96: 98 99 9a 9b .bulk $98,$99,$9a,$9b
AreaMusicEnvData
ff9a: 90 94 94 95+ .bulk $90,$94,$94,$95,$95,$96,$97,$98
WaterEventMusEnvData
ffa2: 90 91 92 92+ .bulk $90,$91,$92,$92,$93,$93,$93,$94,$94,$94,$94,$94,$94,$95,$95,$95
+ $95,$95,$95,$96,$96,$96,$96,$96,$96,$96,$96,$96,$96,$96,$96,$96
+ $96,$96,$96,$96,$95,$95,$94,$93
BowserFlameEnvData
ffca: 15 16 16 17+ .bulk $15,$16,$16,$17,$17,$18,$19,$19,$1a,$1a,$1c,$1d,$1d,$1e,$1e,$1f
+ $1f,$1f,$1f,$1e,$1d,$1c,$1e,$1f,$1f,$1e,$1d,$1c,$1a,$18,$16,$14
BrickShatterEnvData
ffea: 15 16 16 17+ .bulk $15,$16,$16,$17,$17,$18,$19,$19,$1a,$1a,$1c,$1d,$1d,$1e,$1e,$1f
;
fffa: 82 80 .dd2 NonMaskableInterrupt ;NMI vector
fffc: 00 80 .dd2 Start ;reset vector
fffe: f0 ff .dd2 BrickShatterEnvData+6 ;IRQ vector (unused)
.adrend β $8000
;
; CHR block. This is not directly addressable on the 6502.
;
; The label ("CHR_ROM") is used by the visualizer. Don't rename it.
;
.addrs NA
0000: 03 0f 1f 1f+ CHR_ROM .bulk $03,$0f,$1f,$1f,$1c,$24,$26,$66,$00,$00,$00,$00,$1f,$3f,$3f,$7f
0010: e0 c0 80 fc+ .bulk $e0,$c0,$80,$fc,$80,$c0,$00,$20,$00,$20,$60,$00,$f0,$fc,$fe,$fe
0020: 60 70 18 07+ .bulk $60,$70,$18,$07,$0f,$1f,$3f,$7f,$7f,$7f,$1f,$07,$00,$1e,$3f,$7f
0030: fc 7c 00 00+ .bulk $fc,$7c,$00,$00,$e0,$f0,$f8,$f8,$fc,$fc,$f8,$c0,$c2,$67,$2f,$37
0040: 7f 7f ff ff+ .bulk $7f,$7f,$ff,$ff,$07,$07,$0f,$0f,$7f,$7e,$fc,$f0,$f8,$f8,$f0,$70
0050: fd fe b4 f8+ .bulk $fd,$fe,$b4,$f8,$f8,$f9,$fb,$ff,$37,$36,$5c,$00,$00,$01,$03,$1f
0060: 1f 3f ff ff+ .bulk $1f,$3f,$ff,$ff,$fc,$70,$70,$38,$08,$24,$e3,$f0,$f8,$70,$70,$38
0070: ff ff ff 1f+ .bulk $ff,$ff,$ff,$1f,$00,$00,$00,$00,$1f,$1f,$1f,$1f,$00,$00,$00,$00
0080: 00 00 01 07+ .bulk $00,$00,$01,$07,$0f,$0f,$0e,$12,$00,$00,$00,$00,$00,$00,$0f,$1f
0090: 00 00 f0 e0+ .bulk $00,$00,$f0,$e0,$c0,$fe,$40,$60,$00,$00,$00,$10,$30,$00,$f8,$fe
00a0: 13 33 30 18+ .bulk $13,$33,$30,$18,$04,$0f,$1f,$1f,$1f,$3f,$3f,$1f,$07,$08,$17,$17
00b0: 00 10 7e 3e+ .bulk $00,$10,$7e,$3e,$00,$00,$c0,$e0,$ff,$ff,$fe,$fe,$fc,$e0,$40,$a0
00c0: 3f 3f 3f 1f+ .bulk $3f,$3f,$3f,$1f,$1f,$1f,$1f,$1f,$37,$27,$23,$03,$01,$00,$00,$00
00d0: f0 f0 f0 f8+ .bulk $f0,$f0,$f0,$f8,$f8,$f8,$f8,$f8,$cc,$ff,$ff,$ff,$ff,$70,$00,$08
00e0: ff ff ff fe+ .bulk $ff,$ff,$ff,$fe,$f0,$c0,$80,$00,$f0,$f0,$f0,$f0,$f0,$c0,$80,$00
00f0: fc fc f8 78+ .bulk $fc,$fc,$f8,$78,$78,$78,$7e,$7e,$10,$60,$80,$00,$78,$78,$7e,$7e
0100: 00 03 0f 1f+ .bulk $00,$03,$0f,$1f,$1f,$1c,$24,$26,$00,$00,$00,$00,$00,$1f,$3f,$3f
0110: 00 e0 c0 80+ .bulk $00,$e0,$c0,$80,$fc,$80,$c0,$00,$00,$00,$20,$60,$00,$f0,$fc,$fe
0120: 66 60 30 18+ .bulk $66,$60,$30,$18,$0f,$1f,$3f,$3f,$7f,$7f,$3f,$1f,$00,$16,$2f,$2f
0130: 20 fc 7c 00+ .bulk $20,$fc,$7c,$00,$00,$e0,$e0,$f0,$fe,$fc,$fc,$f8,$c0,$60,$20,$30
0140: 3f 3f 3f 3f+ .bulk $3f,$3f,$3f,$3f,$3f,$3f,$3f,$1f,$2f,$2f,$2f,$0f,$07,$03,$00,$00
0150: f0 90 00 08+ .bulk $f0,$90,$00,$08,$0c,$1c,$fc,$f8,$10,$f0,$f0,$f0,$f0,$e0,$c0,$e0
0160: 0f 0f 07 07+ .bulk $0f,$0f,$07,$07,$07,$0f,$0f,$03,$01,$03,$01,$04,$07,$0f,$0f,$03
0170: f8 f0 e0 f0+ .bulk $f8,$f0,$e0,$f0,$b0,$80,$e0,$e0,$f8,$f0,$e0,$70,$b0,$80,$e0,$e0
0180: 03 3f 7f 19+ .bulk $03,$3f,$7f,$19,$09,$09,$28,$5c,$00,$30,$70,$7f,$ff,$ff,$f7,$f3
0190: f8 e0 e0 fc+ .bulk $f8,$e0,$e0,$fc,$26,$30,$80,$10,$00,$18,$10,$00,$f8,$f8,$fe,$ff
01a0: 3e 1e 3f 38+ .bulk $3e,$1e,$3f,$38,$30,$30,$00,$3a,$e7,$0f,$0f,$1f,$1f,$1f,$0f,$07
01b0: 78 1e 80 fe+ .bulk $78,$1e,$80,$fe,$7e,$7e,$7f,$7f,$ff,$fe,$fc,$c6,$8e,$ee,$ff,$ff
01c0: 3c 3f 1f 0f+ .bulk $3c,$3f,$1f,$0f,$07,$3f,$21,$20,$03,$00,$00,$0e,$07,$3f,$3f,$3f
01d0: ff ff ff fe+ .bulk $ff,$ff,$ff,$fe,$fe,$fe,$fc,$70,$ff,$7f,$3f,$0e,$c0,$c0,$e0,$e0
01e0: 0f 9f cf ff+ .bulk $0f,$9f,$cf,$ff,$7f,$3f,$1e,$0e,$00,$80,$c8,$fe,$7f,$3f,$1e,$0e
01f0: 20 c0 80 80+ .bulk $20,$c0,$80,$80,$00,$00,$00,$00,$e0,$00,$00,$00,$00,$00,$00,$00
0200: 00 00 03 0f+ .bulk $00,$00,$03,$0f,$1f,$1f,$1c,$24,$00,$00,$00,$00,$00,$00,$1f,$3f
0210: 00 04 e6 e0+ .bulk $00,$04,$e6,$e0,$ff,$ff,$8f,$83,$0e,$1f,$1f,$1f,$1f,$03,$ff,$ff
0220: 26 26 60 78+ .bulk $26,$26,$60,$78,$18,$0f,$7f,$ff,$3f,$3f,$7f,$7f,$1f,$00,$7e,$ff
0230: 01 21 fe 7a+ .bulk $01,$21,$fe,$7a,$06,$fe,$fc,$fc,$ff,$ff,$fe,$fe,$fe,$de,$5c,$6c
0240: ff cf 87 07+ .bulk $ff,$cf,$87,$07,$07,$0f,$1f,$1f,$ff,$ff,$fe,$fc,$f8,$b0,$60,$00
0250: f8 f8 f0 b8+ .bulk $f8,$f8,$f0,$b8,$f8,$f9,$fb,$ff,$28,$30,$18,$40,$00,$01,$03,$0f
0260: 1f ff ff ff+ .bulk $1f,$ff,$ff,$ff,$ff,$fe,$c0,$80,$10,$ec,$e3,$e0,$e0,$e0,$c0,$80
0270: ff ff ff 3f+ .bulk $ff,$ff,$ff,$3f,$00,$00,$00,$00,$0f,$0f,$0f,$0f,$00,$00,$00,$00
0280: 13 33 30 18+ .bulk $13,$33,$30,$18,$04,$0f,$1f,$1f,$1f,$3f,$3f,$1f,$07,$09,$13,$17
0290: 00 10 7e 30+ .bulk $00,$10,$7e,$30,$e0,$f0,$f0,$e0,$ff,$ff,$fe,$ff,$fe,$fc,$f8,$e0
02a0: 1f 1f 0f 0f+ .bulk $1f,$1f,$0f,$0f,$0f,$1f,$1f,$1f,$17,$17,$03,$00,$00,$00,$00,$00
02b0: f0 f0 f8 f8+ .bulk $f0,$f0,$f8,$f8,$b8,$f8,$f8,$f8,$d0,$90,$18,$08,$40,$00,$00,$00
02c0: 3f ff ff ff+ .bulk $3f,$ff,$ff,$ff,$f6,$c6,$84,$00,$30,$f0,$f0,$f1,$f6,$c6,$84,$00
02d0: f0 e0 80 00+ .bulk $f0,$e0,$80,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
02e0: 1f 1f 3f 3f+ .bulk $1f,$1f,$3f,$3f,$1f,$0f,$0f,$1f,$1f,$1f,$3f,$3e,$7c,$78,$f0,$e0
02f0: f0 f0 f8 f8+ .bulk $f0,$f0,$f8,$f8,$b8,$f8,$f8,$f0,$b0,$90,$18,$08,$40,$00,$00,$00
0300: e0 f0 f0 f0+ .bulk $e0,$f0,$f0,$f0,$f0,$f0,$f8,$f0,$c0,$e0,$fc,$fe,$ff,$7f,$03,$00
0310: 1f 1f 1f 3f+ .bulk $1f,$1f,$1f,$3f,$3e,$3c,$38,$18,$00,$00,$10,$38,$3e,$3c,$38,$18
0320: 00 03 07 07+ .bulk $00,$03,$07,$07,$0a,$0b,$0c,$00,$00,$00,$00,$07,$0f,$0f,$0f,$03
0330: 00 e0 fc 20+ .bulk $00,$e0,$fc,$20,$20,$10,$3c,$00,$00,$00,$00,$f0,$fc,$fe,$fc,$f8
0340: 07 07 07 1f+ .bulk $07,$07,$07,$1f,$1f,$3e,$21,$01,$07,$0f,$1b,$18,$10,$30,$21,$01
0350: e0 e0 e0 f0+ .bulk $e0,$e0,$e0,$f0,$f0,$e0,$c0,$e0,$a8,$fc,$f8,$00,$00,$00,$c0,$e0
0360: 07 0f 0e 14+ .bulk $07,$0f,$0e,$14,$16,$18,$00,$3f,$00,$00,$0f,$1f,$1f,$1f,$07,$3c
0370: c0 f8 40 40+ .bulk $c0,$f8,$40,$40,$20,$78,$00,$c0,$00,$00,$e0,$f8,$fc,$f8,$f0,$c0
0380: 3f 0e 0f 1f+ .bulk $3f,$0e,$0f,$1f,$3f,$7c,$70,$38,$fc,$ed,$c0,$00,$00,$60,$70,$38
0390: f0 f8 e4 fc+ .bulk $f0,$f8,$e4,$fc,$fc,$7c,$00,$00,$7e,$1e,$04,$0c,$0c,$0c,$00,$00
03a0: 07 0f 0e 14+ .bulk $07,$0f,$0e,$14,$16,$18,$00,$0f,$00,$00,$0f,$1f,$1f,$1f,$07,$0d
03b0: 1f 1f 1f 1c+ .bulk $1f,$1f,$1f,$1c,$0c,$07,$07,$07,$1e,$1c,$1e,$0f,$07,$00,$07,$07
03c0: e0 60 f0 70+ .bulk $e0,$60,$f0,$70,$e0,$e0,$f0,$80,$60,$90,$00,$80,$00,$e0,$f0,$80
03d0: 07 1f 3f 12+ .bulk $07,$1f,$3f,$12,$13,$08,$1f,$31,$00,$10,$3f,$7f,$7f,$3f,$03,$0f
03e0: c0 f0 40 00+ .bulk $c0,$f0,$40,$00,$30,$18,$c0,$f8,$00,$00,$e0,$f8,$fc,$f8,$b0,$38
03f0: 31 39 1f 1f+ .bulk $31,$39,$1f,$1f,$0f,$5f,$7e,$3c,$1f,$07,$00,$0e,$0f,$53,$7c,$3c
0400: f8 f8 f0 e0+ .bulk $f8,$f8,$f0,$e0,$e0,$c0,$00,$00,$f8,$f8,$f0,$00,$00,$80,$00,$00
0410: 00 e0 fc 27+ .bulk $00,$e0,$fc,$27,$27,$11,$3e,$04,$07,$07,$03,$f7,$ff,$ff,$fe,$fc
0420: 3f 7f 3f 0f+ .bulk $3f,$7f,$3f,$0f,$1f,$3f,$7f,$4f,$3e,$7f,$ff,$e2,$50,$38,$70,$40
0430: f8 f9 f9 b7+ .bulk $f8,$f9,$f9,$b7,$ff,$ff,$e0,$00,$e8,$71,$01,$4b,$03,$03,$00,$00
0440: 07 07 0f 3f+ .bulk $07,$07,$0f,$3f,$3f,$3f,$26,$04,$05,$03,$01,$30,$30,$30,$26,$04
0450: f0 f0 f0 e0+ .bulk $f0,$f0,$f0,$e0,$c0,$00,$00,$00,$fe,$fc,$e0,$00,$00,$00,$00,$00
0460: 07 07 0f 1f+ .bulk $07,$07,$0f,$1f,$3f,$0f,$1c,$18,$05,$03,$01,$10,$30,$0c,$1c,$18
0470: e0 e0 e0 e0+ .bulk $e0,$e0,$e0,$e0,$c0,$80,$00,$00,$c0,$e0,$f0,$78,$18,$08,$00,$00
0480: 07 0f 1f 0f+ .bulk $07,$0f,$1f,$0f,$3f,$0f,$1c,$18,$07,$0f,$3e,$7c,$30,$0c,$1c,$18
0490: e0 e0 e0 40+ .bulk $e0,$e0,$e0,$40,$c0,$80,$00,$00,$60,$60,$60,$80,$00,$00,$00,$00
04a0: 7f ff ff fb+ .bulk $7f,$ff,$ff,$fb,$0f,$0f,$0f,$1f,$73,$f3,$f0,$f4,$f0,$f0,$70,$60
04b0: 3f 7e 7c 7c+ .bulk $3f,$7e,$7c,$7c,$3c,$3c,$fc,$fc,$00,$00,$00,$00,$3c,$3c,$fc,$fc
04c0: 60 70 18 08+ .bulk $60,$70,$18,$08,$0f,$1f,$3f,$7f,$7f,$7f,$1f,$07,$0b,$1b,$3b,$7b
04d0: fc 7c 00 20+ .bulk $fc,$7c,$00,$20,$f0,$f8,$fc,$fe,$fc,$fc,$f8,$e0,$d0,$d8,$dc,$de
04e0: 0b 0f 1f 1e+ .bulk $0b,$0f,$1f,$1e,$3c,$3c,$3c,$7c,$c4,$e0,$e0,$40,$00,$3c,$3c,$7c
04f0: 1f 3f 0d 07+ .bulk $1f,$3f,$0d,$07,$0f,$0e,$1c,$3c,$1d,$3c,$3a,$38,$30,$00,$1c,$3c
0500: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$00,$00,$00,$22,$55,$55,$55,$55,$55,$77,$22
0510: 00 07 1f ff+ .bulk $00,$07,$1f,$ff,$07,$1f,$0f,$06,$00,$00,$00,$00,$00,$00,$00,$00
0520: 3f ff ff ff+ .bulk $3f,$ff,$ff,$ff,$ff,$ff,$fb,$76,$00,$00,$cf,$07,$7f,$00,$00,$00
0530: 20 f8 ff c3+ .bulk $20,$f8,$ff,$c3,$fd,$fe,$f0,$40,$00,$00,$3c,$fc,$fe,$e0,$00,$00
0540: 40 e0 40 40+ .bulk $40,$e0,$40,$40,$41,$41,$4f,$47,$40,$e0,$40,$3f,$3e,$3e,$30,$38
0550: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$00,$e0,$c0,$00,$00,$00,$f8,$f8,$f8,$18,$38
0560: 43 46 44 40+ .bulk $43,$46,$44,$40,$40,$40,$40,$40,$3c,$39,$3b,$3f,$00,$00,$00,$00
0570: 80 c0 40 00+ .bulk $80,$c0,$40,$00,$00,$00,$00,$00,$78,$38,$b8,$f8,$00,$00,$00,$00
0580: 31 30 38 7c+ .bulk $31,$30,$38,$7c,$7f,$ff,$ff,$fb,$3f,$3f,$0f,$77,$77,$f7,$f7,$f7
0590: 10 7e 3e 00+ .bulk $10,$7e,$3e,$00,$1e,$fe,$ff,$ff,$ff,$fe,$fe,$fe,$fa,$fa,$f3,$e7
05a0: ff ff e3 c3+ .bulk $ff,$ff,$e3,$c3,$87,$48,$3c,$fc,$f0,$f8,$fc,$7c,$78,$38,$3c,$fc
05b0: 00 ff c3 83+ .bulk $00,$ff,$c3,$83,$83,$ff,$ff,$ff,$ff,$00,$c3,$81,$81,$c3,$ff,$00
05c0: 1f 1f 0f 07+ .bulk $1f,$1f,$0f,$07,$01,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
05d0: f0 fb ff ff+ .bulk $f0,$fb,$ff,$ff,$fe,$3e,$0c,$04,$00,$0b,$1f,$1f,$1e,$3e,$0c,$04
05e0: 1f 1f 0f 0f+ .bulk $1f,$1f,$0f,$0f,$07,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
05f0: fb ff ff ff+ .bulk $fb,$ff,$ff,$ff,$ff,$00,$00,$00,$03,$0f,$0f,$0f,$0f,$00,$00,$00
0600: 00 18 3c 7e+ .bulk $00,$18,$3c,$7e,$6e,$df,$df,$df,$00,$18,$3c,$7e,$76,$fb,$fb,$fb
0610: 00 18 18 3c+ .bulk $00,$18,$18,$3c,$3c,$3c,$3c,$1c,$00,$10,$10,$20,$20,$20,$20,$20
0620: 00 08 08 08+ .bulk $00,$08,$08,$08,$08,$08,$08,$00,$00,$08,$08,$08,$08,$08,$08,$08
0630: 00 08 08 04+ .bulk $00,$08,$08,$04,$04,$04,$04,$04,$00,$10,$10,$38,$38,$38,$38,$38
0640: 3c 7e 77 fb+ .bulk $3c,$7e,$77,$fb,$9f,$5f,$8e,$20,$00,$18,$3c,$0e,$0e,$04,$00,$00
0650: 5c 2e 8f 3f+ .bulk $5c,$2e,$8f,$3f,$7b,$77,$7e,$3c,$00,$00,$04,$06,$1e,$3c,$18,$00
0660: 13 4f 3f bf+ .bulk $13,$4f,$3f,$bf,$3f,$7a,$f8,$f8,$00,$00,$01,$0a,$17,$0f,$2f,$1f
0670: 00 08 05 0f+ .bulk $00,$08,$05,$0f,$2f,$1d,$1c,$3c,$00,$00,$00,$00,$05,$07,$0f,$07
0680: 00 00 00 00+ .bulk $00,$00,$00,$00,$02,$0b,$07,$0f,$00,$00,$00,$00,$00,$00,$01,$03
0690: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$08,$04,$04,$00,$60,$f0,$f8,$7c,$3e,$7e,$7f
06a0: 02 02 02 05+ .bulk $02,$02,$02,$05,$71,$7f,$7f,$7f,$3f,$5f,$7f,$3e,$0e,$0a,$51,$20
06b0: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$00,$00,$04,$00,$00,$00,$00,$00,$00,$0e,$1f
06c0: 02 02 00 01+ .bulk $02,$02,$00,$01,$13,$3f,$7f,$7f,$3f,$7f,$7f,$fe,$ec,$ca,$51,$20
06d0: 00 40 60 70+ .bulk $00,$40,$60,$70,$73,$27,$0f,$1f,$00,$40,$63,$77,$7c,$38,$f8,$e4
06e0: 00 00 00 00+ .bulk $00,$00,$00,$00,$03,$07,$0f,$1f,$00,$00,$03,$07,$0c,$18,$f8,$e4
06f0: 7f 7f 3f 3f+ .bulk $7f,$7f,$3f,$3f,$1f,$1f,$0f,$07,$03,$44,$28,$10,$08,$04,$03,$04
0700: 03 07 0f 1f+ .bulk $03,$07,$0f,$1f,$3f,$77,$77,$f5,$03,$07,$0f,$1f,$27,$7b,$78,$fb
0710: c0 e0 f0 f8+ .bulk $c0,$e0,$f0,$f8,$fc,$ee,$ee,$af,$c0,$e0,$f0,$f8,$e4,$de,$1e,$df
0720: f1 ff 78 00+ .bulk $f1,$ff,$78,$00,$00,$18,$1c,$0e,$ff,$ff,$7f,$0f,$0f,$07,$03,$00
0730: 8f ff 1e 00+ .bulk $8f,$ff,$1e,$00,$0c,$3e,$7e,$7c,$ff,$ff,$fe,$f0,$f0,$c0,$80,$00
0740: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$18,$24,$24,$18,$00,$00
0750: 00 02 41 41+ .bulk $00,$02,$41,$41,$61,$33,$06,$3c,$3c,$7e,$ff,$ff,$ff,$ff,$7e,$3c
0760: 03 07 0f 1f+ .bulk $03,$07,$0f,$1f,$3f,$7f,$7f,$ff,$03,$07,$0f,$1f,$3f,$63,$41,$c1
0770: c0 e0 f0 f8+ .bulk $c0,$e0,$f0,$f8,$fc,$fe,$fe,$ff,$c0,$80,$00,$00,$8c,$fe,$fe,$f3
0780: ff ff ff 78+ .bulk $ff,$ff,$ff,$78,$00,$00,$00,$00,$c1,$e3,$ff,$47,$0f,$0f,$0f,$07
0790: ff ff ff 1e+ .bulk $ff,$ff,$ff,$1e,$00,$20,$20,$40,$f1,$f9,$ff,$e2,$f0,$f0,$f0,$e0
07a0: 16 1f 3f 7f+ .bulk $16,$1f,$3f,$7f,$3d,$1d,$3f,$1f,$16,$1f,$00,$00,$05,$0d,$3f,$1f
07b0: 80 80 c0 e0+ .bulk $80,$80,$c0,$e0,$f0,$f0,$f0,$f8,$80,$80,$00,$00,$00,$a0,$a0,$e0
07c0: 3c fa b1 72+ .bulk $3c,$fa,$b1,$72,$f2,$db,$df,$5f,$00,$04,$4e,$8c,$0c,$7f,$ff,$ff
07d0: 00 00 00 01+ .bulk $00,$00,$00,$01,$01,$01,$06,$1e,$00,$00,$00,$00,$00,$00,$01,$01
07e0: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$00,$00,$00,$ff,$7f,$3f,$1f,$0f,$07,$03,$01
07f0: 00 7c d6 92+ .bulk $00,$7c,$d6,$92,$ba,$ee,$fe,$38,$ff,$83,$29,$6d,$45,$11,$01,$c7
0800: 00 15 3f 62+ .bulk $00,$15,$3f,$62,$5f,$ff,$9f,$7d,$08,$08,$02,$1f,$22,$02,$02,$00
0810: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$00,$00,$00,$08,$08,$08,$08,$08,$08,$08,$08
0820: 2f 1e 2f 2f+ .bulk $2f,$1e,$2f,$2f,$2f,$15,$0d,$0e,$10,$1e,$10,$50,$10,$08,$00,$00
0830: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$fe,$00,$00,$00,$00
0840: 1c 3e 7f ff+ .bulk $1c,$3e,$7f,$ff,$ff,$fe,$7c,$38,$1c,$2a,$77,$ee,$dd,$aa,$74,$28
0850: 00 ff ff ff+ .bulk $00,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$fe,$fe,$00,$ef,$ef,$ef,$00
0860: ff ff ff ff+ .bulk $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$fe,$fe,$fe,$00,$ef,$ef,$ef,$00
0870: 7f ff ff ff+ .bulk $7f,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$00,$7f,$5f,$7f,$7f,$7f,$7f,$7f
0880: 68 4e e0 e0+ .bulk $68,$4e,$e0,$e0,$e0,$f0,$f8,$fc,$b8,$9e,$80,$c0,$e0,$f0,$f8,$7c
0890: 3f 5c 39 3b+ .bulk $3f,$5c,$39,$3b,$bb,$f9,$fc,$fe,$00,$23,$57,$4f,$57,$27,$c3,$21
08a0: c0 f0 f0 f0+ .bulk $c0,$f0,$f0,$f0,$f0,$e0,$c0,$00,$00,$30,$70,$70,$f0,$e0,$c0,$00
08b0: fe fc 61 0f+ .bulk $fe,$fc,$61,$0f,$ff,$fe,$f0,$e0,$13,$0f,$1e,$f0,$fc,$f8,$f0,$e0
08c0: 6e 40 e0 e0+ .bulk $6e,$40,$e0,$e0,$e0,$e0,$e0,$c0,$be,$90,$80,$c0,$c0,$80,$00,$00
08d0: 01 01 03 03+ .bulk $01,$01,$03,$03,$07,$7f,$7f,$3f,$01,$01,$03,$03,$07,$7f,$7d,$3d
08e0: 06 07 3f 3c+ .bulk $06,$07,$3f,$3c,$19,$7b,$7f,$3f,$06,$04,$30,$23,$06,$64,$60,$00
08f0: 3f 7f 7f 1f+ .bulk $3f,$7f,$7f,$1f,$3f,$3f,$07,$06,$00,$60,$60,$00,$20,$30,$04,$06
0900: 03 07 0f 0f+ .bulk $03,$07,$0f,$0f,$0f,$0f,$07,$03,$00,$01,$01,$00,$00,$00,$00,$00
0910: f8 f8 f8 a0+ .bulk $f8,$f8,$f8,$a0,$e1,$ff,$ff,$ff,$fe,$ff,$ff,$40,$01,$03,$03,$03
0920: 0f 0f 0f 1f+ .bulk $0f,$0f,$0f,$1f,$1f,$1f,$0f,$07,$01,$01,$00,$00,$00,$00,$00,$00
0930: e0 f8 f8 f8+ .bulk $e0,$f8,$f8,$f8,$ff,$fe,$f0,$c0,$e0,$fe,$ff,$7f,$03,$02,$00,$00
0940: 01 0f 0f 1f+ .bulk $01,$0f,$0f,$1f,$39,$33,$37,$7f,$01,$0d,$08,$00,$36,$2c,$08,$60
0950: 7f 3f 3f 3f+ .bulk $7f,$3f,$3f,$3f,$1f,$0f,$0f,$01,$60,$00,$20,$30,$00,$08,$0d,$01
0960: 00 00 03 03+ .bulk $00,$00,$03,$03,$47,$67,$77,$77,$01,$01,$03,$43,$67,$77,$7b,$78
0970: 00 00 00 00+ .bulk $00,$00,$00,$00,$88,$98,$f8,$f0,$00,$00,$80,$84,$cc,$dc,$bc,$3c
0980: 7e 7f ff 1f+ .bulk $7e,$7f,$ff,$1f,$07,$30,$1c,$0c,$33,$07,$07,$e3,$38,$3f,$1c,$0c
0990: 7e 38 f6 ed+ .bulk $7e,$38,$f6,$ed,$df,$38,$70,$60,$98,$c7,$c8,$92,$30,$f8,$70,$60
09a0: 00 00 00 03+ .bulk $00,$00,$00,$03,$03,$47,$67,$77,$00,$01,$01,$03,$43,$67,$77,$7b
09b0: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$88,$98,$f8,$00,$00,$00,$80,$84,$cc,$dc,$bc
09c0: 77 7e 7f ff+ .bulk $77,$7e,$7f,$ff,$1f,$07,$70,$f0,$78,$33,$07,$07,$e3,$38,$7f,$f0
09d0: f0 7e 38 f6+ .bulk $f0,$7e,$38,$f6,$ed,$df,$38,$3c,$3c,$98,$c7,$c8,$92,$30,$f8,$3c
09e0: 03 07 0a 1a+ .bulk $03,$07,$0a,$1a,$1c,$1e,$0b,$08,$00,$10,$7f,$7f,$7f,$1f,$0f,$0f
09f0: 1c 3f 3f 3d+ .bulk $1c,$3f,$3f,$3d,$3f,$1f,$00,$00,$03,$33,$39,$3a,$38,$18,$00,$00
0a00: 00 00 04 4c+ .bulk $00,$00,$04,$4c,$4e,$4e,$46,$6f,$10,$38,$3c,$74,$76,$76,$7e,$7d
0a10: 00 1f 3f 3f+ .bulk $00,$1f,$3f,$3f,$4f,$5f,$7f,$7f,$00,$00,$11,$0a,$34,$2a,$51,$20
0a20: 7f 67 a3 b0+ .bulk $7f,$67,$a3,$b0,$d8,$de,$dc,$c8,$7f,$67,$63,$70,$38,$3e,$7c,$b8
0a30: 7f 7f 7f 1f+ .bulk $7f,$7f,$7f,$1f,$47,$70,$70,$39,$51,$0a,$04,$ea,$79,$7f,$70,$39
0a40: e8 e8 e0 c0+ .bulk $e8,$e8,$e0,$c0,$10,$70,$e0,$c0,$58,$38,$10,$30,$f0,$f0,$e0,$c0
0a50: 00 00 00 20+ .bulk $00,$00,$00,$20,$66,$66,$66,$62,$00,$08,$1c,$3c,$7a,$7a,$7a,$7e
0a60: 00 00 1f 3f+ .bulk $00,$00,$1f,$3f,$7f,$4f,$5f,$7f,$00,$00,$00,$11,$0a,$34,$2a,$51
0a70: 77 7f 3f b7+ .bulk $77,$7f,$3f,$b7,$b3,$db,$da,$d8,$7f,$7d,$3f,$37,$33,$3b,$3a,$78
0a80: 7f 7f 7f 7f+ .bulk $7f,$7f,$7f,$7f,$1f,$07,$70,$f0,$20,$51,$0a,$04,$ea,$39,$7f,$f0
0a90: cc e8 e8 e0+ .bulk $cc,$e8,$e8,$e0,$c0,$18,$7c,$3e,$bc,$58,$38,$10,$30,$f8,$fc,$3e
0aa0: 03 0f 1f 3f+ .bulk $03,$0f,$1f,$3f,$3b,$3f,$7f,$7f,$00,$00,$00,$06,$0e,$0c,$00,$00
0ab0: 80 f0 f8 fc+ .bulk $80,$f0,$f8,$fc,$fe,$fe,$ff,$fe,$00,$00,$00,$00,$00,$00,$0f,$18
0ac0: 7f 7f 7f 7f+ .bulk $7f,$7f,$7f,$7f,$ff,$0f,$03,$00,$00,$00,$00,$00,$f8,$3e,$3b,$18
0ad0: fe fb ff ff+ .bulk $fe,$fb,$ff,$ff,$f6,$e0,$c0,$00,$10,$14,$10,$10,$38,$78,$f8,$30
0ae0: 00 03 0f 1f+ .bulk $00,$03,$0f,$1f,$3f,$3b,$3f,$7f,$00,$00,$00,$00,$06,$0e,$0c,$00
0af0: 00 c0 f0 f8+ .bulk $00,$c0,$f0,$f8,$fc,$fe,$fe,$ff,$00,$00,$00,$00,$00,$00,$00,$0f
0b00: 7f 7f 7f 7f+ .bulk $7f,$7f,$7f,$7f,$7f,$ff,$0f,$03,$00,$00,$00,$00,$00,$f8,$7e,$f3
0b10: fe fe fb ff+ .bulk $fe,$fe,$fb,$ff,$ff,$f6,$e0,$c0,$18,$10,$14,$10,$10,$38,$7c,$de
0b20: 00 01 01 01+ .bulk $00,$01,$01,$01,$01,$00,$00,$08,$00,$0d,$1e,$1e,$1e,$1f,$0f,$07
0b30: 78 f0 f8 e4+ .bulk $78,$f0,$f8,$e4,$c0,$ca,$ca,$c0,$78,$f0,$00,$1a,$3f,$35,$35,$3f
0b40: 0f 1f 9f ff+ .bulk $0f,$1f,$9f,$ff,$ff,$7f,$74,$20,$00,$00,$80,$e0,$e0,$70,$73,$21
0b50: e4 ff fe fc+ .bulk $e4,$ff,$fe,$fc,$9c,$1e,$00,$00,$1a,$07,$0c,$18,$78,$fe,$fc,$f0
0b60: 00 01 03 03+ .bulk $00,$01,$03,$03,$07,$03,$01,$00,$00,$01,$02,$00,$38,$7c,$7e,$3f
0b70: 00 5f 7f 7f+ .bulk $00,$5f,$7f,$7f,$3f,$3f,$14,$00,$3f,$40,$60,$60,$20,$30,$13,$01
0b80: c0 e0 f0 30+ .bulk $c0,$e0,$f0,$30,$38,$3c,$3c,$fc,$c0,$e0,$30,$d0,$d0,$d0,$d0,$00
0b90: 07 0f 1f 22+ .bulk $07,$0f,$1f,$22,$20,$25,$25,$1f,$07,$0f,$02,$1d,$1f,$1a,$1a,$02
0ba0: fe fe 7e 3a+ .bulk $fe,$fe,$7e,$3a,$02,$01,$41,$41,$38,$7c,$fc,$fc,$fc,$fe,$be,$be
0bb0: 1f 3f 7e 5c+ .bulk $1f,$3f,$7e,$5c,$40,$80,$82,$82,$1c,$3e,$3f,$3f,$3f,$7f,$7d,$7d
0bc0: 82 80 a0 44+ .bulk $82,$80,$a0,$44,$43,$40,$21,$1e,$7d,$7f,$5f,$3b,$3c,$3f,$1e,$00
0bd0: 1c 3f 3e 3c+ .bulk $1c,$3f,$3e,$3c,$40,$80,$82,$82,$1c,$3e,$3f,$1f,$3f,$7f,$7d,$7d
0be0: 00 00 80 80+ .bulk $00,$00,$80,$80,$92,$9d,$c7,$ef,$00,$00,$00,$60,$62,$65,$3f,$1f
0bf0: 00 23 33 3f+ .bulk $00,$23,$33,$3f,$3f,$7f,$7f,$7f,$70,$3c,$3c,$18,$00,$00,$02,$07
0c00: fe f8 a0 00+ .bulk $fe,$f8,$a0,$00,$00,$00,$80,$80,$cf,$7a,$5a,$10,$00,$00,$c0,$80
0c10: 7e 7f 7d 3f+ .bulk $7e,$7f,$7d,$3f,$1e,$8f,$8f,$19,$85,$84,$86,$c6,$e7,$73,$73,$e1
0c20: e0 0e 73 f3+ .bulk $e0,$0e,$73,$f3,$f9,$f9,$f8,$70,$80,$4e,$77,$f3,$fb,$f9,$fa,$78
0c30: 0e 66 e2 f6+ .bulk $0e,$66,$e2,$f6,$ff,$ff,$1f,$98,$11,$39,$7d,$39,$00,$00,$e0,$e7
0c40: 00 00 00 04+ .bulk $00,$00,$00,$04,$0f,$0f,$1f,$07,$00,$00,$07,$07,$16,$10,$00,$38
0c50: f3 e7 ee ec+ .bulk $f3,$e7,$ee,$ec,$cd,$cf,$cf,$df,$cf,$1f,$17,$10,$33,$30,$30,$20
0c60: 27 3f 3f 78+ .bulk $27,$3f,$3f,$78,$3c,$1f,$1f,$73,$38,$30,$40,$c7,$07,$66,$e0,$6c
0c70: 9f 3e 7c fc+ .bulk $9f,$3e,$7c,$fc,$f8,$f8,$c0,$40,$60,$c0,$80,$04,$9e,$ff,$f0,$f8
0c80: 7f 7e 78 01+ .bulk $7f,$7e,$78,$01,$07,$1f,$3c,$7c,$24,$01,$07,$fe,$ff,$7f,$3f,$7f
0c90: fc f8 a0 fe+ .bulk $fc,$f8,$a0,$fe,$fc,$f0,$80,$00,$cf,$7a,$0a,$fe,$fc,$00,$00,$00
0ca0: 7e 7f 7f 3f+ .bulk $7e,$7f,$7f,$3f,$1f,$8f,$8f,$18,$85,$86,$83,$c3,$e1,$70,$70,$e0
0cb0: 9f 3e 7c f8+ .bulk $9f,$3e,$7c,$f8,$f8,$3c,$18,$f8,$60,$c0,$80,$00,$98,$fc,$fe,$ff
0cc0: 7f 7f 78 01+ .bulk $7f,$7f,$78,$01,$07,$13,$f1,$03,$24,$00,$07,$fe,$ff,$7f,$ff,$03
0cd0: 00 00 1c 1d+ .bulk $00,$00,$1c,$1d,$1b,$c3,$e3,$e1,$03,$0f,$23,$62,$64,$3c,$1c,$1e
0ce0: e0 cd 1d 4f+ .bulk $e0,$cd,$1d,$4f,$ee,$ff,$3f,$3f,$1f,$3d,$6d,$4f,$ee,$f3,$20,$03
0cf0: 3f 3f 00 00+ .bulk $3f,$3f,$00,$00,$70,$b8,$fc,$fc,$07,$07,$1f,$3f,$0f,$47,$03,$00
0d00: 07 0f 1f 3f+ .bulk $07,$0f,$1f,$3f,$3e,$7c,$78,$78,$00,$00,$03,$07,$0f,$0f,$1f,$1f
0d10: 3f 5c 39 3b+ .bulk $3f,$5c,$39,$3b,$bf,$ff,$fe,$fe,$00,$23,$57,$4f,$57,$2f,$df,$21
0d20: c0 c0 80 80+ .bulk $c0,$c0,$80,$80,$80,$80,$00,$00,$00,$00,$00,$00,$80,$80,$00,$00
0d30: fe fc 61 0f+ .bulk $fe,$fc,$61,$0f,$7f,$3f,$1f,$1e,$23,$0f,$1e,$f0,$1c,$3f,$1f,$1e
0d40: f0 78 e4 c8+ .bulk $f0,$78,$e4,$c8,$cc,$be,$be,$3e,$00,$80,$18,$30,$34,$fe,$fe,$fe
0d50: 00 01 00 07+ .bulk $00,$01,$00,$07,$07,$07,$07,$1f,$00,$00,$01,$04,$06,$06,$07,$07
0d60: 00 00 0f 3f+ .bulk $00,$00,$0f,$3f,$3f,$0f,$00,$00,$0f,$3f,$7f,$f8,$f8,$7f,$3f,$0f
0d70: 78 7c 7e 7f+ .bulk $78,$7c,$7e,$7f,$3f,$3f,$1b,$09,$1f,$1f,$1f,$0b,$01,$01,$00,$00
0d80: 0c 00 00 00+ .bulk $0c,$00,$00,$00,$07,$7f,$7c,$00,$03,$1f,$3f,$3f,$78,$00,$03,$ff
0d90: 01 e1 71 79+ .bulk $01,$e1,$71,$79,$3d,$3d,$1f,$03,$00,$00,$00,$00,$00,$00,$00,$00
0da0: 3f 3f 1f 1b+ .bulk $3f,$3f,$1f,$1b,$36,$30,$7f,$3f,$23,$27,$1f,$07,$0f,$1f,$7f,$3f
0db0: f8 f8 f8 b8+ .bulk $f8,$f8,$f8,$b8,$18,$d8,$d8,$b8,$e0,$80,$80,$40,$e0,$e0,$e0,$c0
0dc0: 01 02 04 04+ .bulk $01,$02,$04,$04,$08,$08,$10,$10,$03,$07,$0f,$1f,$3f,$7f,$ff,$1f
0dd0: 00 0f 13 0d+ .bulk $00,$0f,$13,$0d,$0d,$13,$0c,$20,$1f,$10,$0c,$12,$12,$2c,$3f,$3f
0de0: 00 24 00 24+ .bulk $00,$24,$00,$24,$00,$04,$00,$00,$37,$36,$36,$36,$16,$16,$12,$02
0df0: 0f 41 00 88+ .bulk $0f,$41,$00,$88,$00,$44,$00,$00,$10,$7e,$ff,$ff,$f6,$76,$3a,$1a
0e00: 38 7c fe fe+ .bulk $38,$7c,$fe,$fe,$3b,$03,$03,$03,$00,$00,$38,$04,$00,$00,$00,$00
0e10: 03 33 7b 7f+ .bulk $03,$33,$7b,$7f,$ff,$fb,$03,$03,$00,$00,$00,$38,$40,$00,$00,$00
0e20: dc c0 e0 e0+ .bulk $dc,$c0,$e0,$e0,$e0,$e0,$e0,$c0,$fc,$a0,$80,$80,$00,$00,$00,$00
0e30: 3f 5f 3f 3f+ .bulk $3f,$5f,$3f,$3f,$bb,$f8,$fe,$fe,$07,$27,$57,$4f,$57,$27,$c1,$21
0e40: 1f 0f 0f 1f+ .bulk $1f,$0f,$0f,$1f,$1f,$1e,$38,$30,$1d,$0f,$0f,$1f,$1f,$1e,$38,$30
0e50: 00 20 60 60+ .bulk $00,$20,$60,$60,$70,$f0,$f8,$f8,$00,$00,$38,$10,$4c,$18,$86,$24
0e60: f8 fc fc 7e+ .bulk $f8,$fc,$fc,$7e,$7e,$3e,$1f,$07,$00,$42,$0a,$40,$10,$02,$08,$02
0e70: 00 c0 70 b8+ .bulk $00,$c0,$70,$b8,$f4,$f2,$f5,$7b,$00,$00,$80,$40,$08,$0c,$0a,$84
0e80: 00 df 10 ff+ .bulk $00,$df,$10,$ff,$df,$ff,$ff,$f9,$00,$00,$cf,$20,$20,$20,$26,$2e
0e90: 1f 1f 3e fc+ .bulk $1f,$1f,$3e,$fc,$f8,$f0,$c0,$00,$e0,$e0,$c0,$00,$00,$00,$00,$00
0ea0: f8 fc fe ff+ .bulk $f8,$fc,$fe,$ff,$ff,$df,$df,$00,$2f,$23,$21,$20,$20,$00,$00,$00
0eb0: c1 f1 79 7d+ .bulk $c1,$f1,$79,$7d,$3d,$3f,$1f,$03,$c1,$b1,$59,$6d,$35,$3b,$1f,$03
0ec0: 02 06 0e 0e+ .bulk $02,$06,$0e,$0e,$1e,$1e,$3e,$3e,$00,$02,$00,$08,$02,$00,$28,$00
0ed0: 3e 3e 3e 3e+ .bulk $3e,$3e,$3e,$3e,$1e,$1e,$0e,$02,$04,$10,$02,$10,$04,$00,$0a,$00
0ee0: c1 f1 79 7d+ .bulk $c1,$f1,$79,$7d,$3d,$3f,$1f,$03,$c1,$b1,$59,$6d,$35,$3b,$1f,$03
0ef0: 7c 00 00 ff+ .bulk $7c,$00,$00,$ff,$c3,$7f,$1f,$03,$00,$0f,$1f,$ff,$fc,$63,$1f,$03
0f00: ff ff 7c 00+ .bulk $ff,$ff,$7c,$00,$00,$7c,$ff,$ff,$00,$00,$fe,$c6,$c6,$fe,$00,$00
0f10: ff ff 00 04+ .bulk $ff,$ff,$00,$04,$0c,$18,$30,$00,$00,$00,$06,$06,$0c,$18,$70,$60
0f20: ff ff 00 04+ .bulk $ff,$ff,$00,$04,$04,$04,$08,$08,$00,$00,$06,$06,$04,$04,$08,$08
0f30: 08 10 10 00+ .bulk $08,$10,$10,$00,$00,$10,$10,$08,$08,$10,$30,$30,$30,$30,$10,$08
0f40: 7f 3f 3f 3e+ .bulk $7f,$3f,$3f,$3e,$1f,$0f,$03,$00,$00,$00,$01,$03,$01,$00,$00,$00
0f50: 03 0f ff 7f+ .bulk $03,$0f,$ff,$7f,$7f,$7f,$7f,$7f,$03,$0e,$f8,$00,$00,$00,$00,$00
0f60: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$00,$00,$00,$22,$65,$25,$25,$25,$25,$77,$72
0f70: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$00,$00,$00,$62,$95,$15,$25,$45,$85,$f7,$f2
0f80: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$00,$00,$00,$a2,$a5,$a5,$a5,$f5,$f5,$27,$22
0f90: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$00,$00,$00,$f2,$85,$85,$e5,$15,$15,$f7,$e2
0fa0: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$00,$00,$00,$62,$95,$55,$65,$b5,$95,$97,$62
0fb0: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$00,$00,$00,$20,$50,$50,$50,$50,$50,$70,$20
0fc0: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
0fd0: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$00,$00,$00,$66,$e6,$66,$66,$66,$67,$f3,$00
0fe0: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$00,$00,$00,$5e,$59,$59,$59,$5e,$d8,$98,$00
0ff0: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$7c,$38,$00,$00,$00,$00,$00,$00,$04,$08,$00
1000: 38 4c c6 c6+ .bulk $38,$4c,$c6,$c6,$c6,$64,$38,$00,$00,$00,$00,$00,$00,$00,$00,$00
1010: 18 38 18 18+ .bulk $18,$38,$18,$18,$18,$18,$7e,$00,$00,$00,$00,$00,$00,$00,$00,$00
1020: 7c c6 0e 3c+ .bulk $7c,$c6,$0e,$3c,$78,$e0,$fe,$00,$00,$00,$00,$00,$00,$00,$00,$00
1030: 7e 0c 18 3c+ .bulk $7e,$0c,$18,$3c,$06,$c6,$7c,$00,$00,$00,$00,$00,$00,$00,$00,$00
1040: 1c 3c 6c cc+ .bulk $1c,$3c,$6c,$cc,$fe,$0c,$0c,$00,$00,$00,$00,$00,$00,$00,$00,$00
1050: fc c0 fc 06+ .bulk $fc,$c0,$fc,$06,$06,$c6,$7c,$00,$00,$00,$00,$00,$00,$00,$00,$00
1060: 3c 60 c0 fc+ .bulk $3c,$60,$c0,$fc,$c6,$c6,$7c,$00,$00,$00,$00,$00,$00,$00,$00,$00
1070: fe c6 0c 18+ .bulk $fe,$c6,$0c,$18,$30,$30,$30,$00,$00,$00,$00,$00,$00,$00,$00,$00
1080: 7c c6 c6 7c+ .bulk $7c,$c6,$c6,$7c,$c6,$c6,$7c,$00,$00,$00,$00,$00,$00,$00,$00,$00
1090: 7c c6 c6 7e+ .bulk $7c,$c6,$c6,$7e,$06,$0c,$78,$00,$00,$00,$00,$00,$00,$00,$00,$00
10a0: 38 6c c6 c6+ .bulk $38,$6c,$c6,$c6,$fe,$c6,$c6,$00,$00,$00,$00,$00,$00,$00,$00,$00
10b0: fc c6 c6 fc+ .bulk $fc,$c6,$c6,$fc,$c6,$c6,$fc,$00,$00,$00,$00,$00,$00,$00,$00,$00
10c0: 3c 66 c0 c0+ .bulk $3c,$66,$c0,$c0,$c0,$66,$3c,$00,$00,$00,$00,$00,$00,$00,$00,$00
10d0: f8 cc c6 c6+ .bulk $f8,$cc,$c6,$c6,$c6,$cc,$f8,$00,$00,$00,$00,$00,$00,$00,$00,$00
10e0: fe c0 c0 fc+ .bulk $fe,$c0,$c0,$fc,$c0,$c0,$fe,$00,$00,$00,$00,$00,$00,$00,$00,$00
10f0: fe c0 c0 fc+ .bulk $fe,$c0,$c0,$fc,$c0,$c0,$c0,$00,$00,$00,$00,$00,$00,$00,$00,$00
1100: 3e 60 c0 ce+ .bulk $3e,$60,$c0,$ce,$c6,$66,$3e,$00,$00,$00,$00,$00,$00,$00,$00,$00
1110: c6 c6 c6 fe+ .bulk $c6,$c6,$c6,$fe,$c6,$c6,$c6,$00,$00,$00,$00,$00,$00,$00,$00,$00
1120: 7e 18 18 18+ .bulk $7e,$18,$18,$18,$18,$18,$7e,$00,$00,$00,$00,$00,$00,$00,$00,$00
1130: 1e 06 06 06+ .bulk $1e,$06,$06,$06,$c6,$c6,$7c,$00,$00,$00,$00,$00,$00,$00,$00,$00
1140: c6 cc d8 f0+ .bulk $c6,$cc,$d8,$f0,$f8,$dc,$ce,$00,$00,$00,$00,$00,$00,$00,$00,$00
1150: 60 60 60 60+ .bulk $60,$60,$60,$60,$60,$60,$7e,$00,$00,$00,$00,$00,$00,$00,$00,$00
1160: c6 ee fe fe+ .bulk $c6,$ee,$fe,$fe,$d6,$c6,$c6,$00,$00,$00,$00,$00,$00,$00,$00,$00
1170: c6 e6 f6 fe+ .bulk $c6,$e6,$f6,$fe,$de,$ce,$c6,$00,$00,$00,$00,$00,$00,$00,$00,$00
1180: 7c c6 c6 c6+ .bulk $7c,$c6,$c6,$c6,$c6,$c6,$7c,$00,$00,$00,$00,$00,$00,$00,$00,$00
1190: fc c6 c6 c6+ .bulk $fc,$c6,$c6,$c6,$fc,$c0,$c0,$00,$00,$00,$00,$00,$00,$00,$00,$00
11a0: 7c c6 c6 c6+ .bulk $7c,$c6,$c6,$c6,$de,$cc,$7a,$00,$00,$00,$00,$00,$00,$00,$00,$00
11b0: fc c6 c6 ce+ .bulk $fc,$c6,$c6,$ce,$f8,$dc,$ce,$00,$00,$00,$00,$00,$00,$00,$00,$00
11c0: 78 cc c0 7c+ .bulk $78,$cc,$c0,$7c,$06,$c6,$7c,$00,$00,$00,$00,$00,$00,$00,$00,$00
11d0: 7e 18 18 18+ .bulk $7e,$18,$18,$18,$18,$18,$18,$00,$00,$00,$00,$00,$00,$00,$00,$00
11e0: c6 c6 c6 c6+ .bulk $c6,$c6,$c6,$c6,$c6,$c6,$7c,$00,$00,$00,$00,$00,$00,$00,$00,$00
11f0: c6 c6 c6 ee+ .bulk $c6,$c6,$c6,$ee,$7c,$38,$10,$00,$00,$00,$00,$00,$00,$00,$00,$00
1200: c6 c6 d6 fe+ .bulk $c6,$c6,$d6,$fe,$fe,$ee,$c6,$00,$00,$00,$00,$00,$00,$00,$00,$00
1210: c6 ee 7c 38+ .bulk $c6,$ee,$7c,$38,$7c,$ee,$c6,$00,$00,$00,$00,$00,$00,$00,$00,$00
1220: 66 66 66 3c+ .bulk $66,$66,$66,$3c,$18,$18,$18,$00,$00,$00,$00,$00,$00,$00,$00,$00
1230: fe 0e 1c 38+ .bulk $fe,$0e,$1c,$38,$70,$e0,$fe,$00,$00,$00,$00,$00,$00,$00,$00,$00
1240: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
1250: ff ff ff ff+ .bulk $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$00,$00,$00,$00,$00,$00,$00,$00
1260: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$00,$00,$00,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
1270: ff ff ff ff+ .bulk $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
1280: 00 00 00 7e+ .bulk $00,$00,$00,$7e,$7e,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
1290: 00 00 44 28+ .bulk $00,$00,$44,$28,$10,$28,$44,$00,$00,$00,$00,$00,$00,$00,$00,$00
12a0: ff ff ff ff+ .bulk $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$7f,$7f,$7f,$7f,$7f,$7f,$7f,$7f
12b0: 18 3c 3c 3c+ .bulk $18,$3c,$3c,$3c,$18,$18,$00,$18,$00,$00,$00,$00,$00,$00,$00,$00
12c0: ff 7f 7f 7f+ .bulk $ff,$7f,$7f,$7f,$7f,$ff,$e3,$c1,$ff,$80,$80,$80,$80,$00,$1c,$3e
12d0: 80 80 80 c1+ .bulk $80,$80,$80,$c1,$e3,$ff,$ff,$ff,$7f,$7f,$7f,$3e,$1c,$00,$00,$ff
12e0: 38 7c 7c 7c+ .bulk $38,$7c,$7c,$7c,$7c,$7c,$38,$00,$08,$04,$04,$04,$04,$04,$08,$00
12f0: 03 06 0c 0c+ .bulk $03,$06,$0c,$0c,$08,$08,$04,$03,$03,$05,$0b,$0b,$0f,$0f,$07,$03
1300: 01 02 04 08+ .bulk $01,$02,$04,$08,$10,$20,$40,$80,$01,$03,$07,$0f,$1f,$3f,$7f,$ff
1310: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$07,$38,$c0,$00,$00,$00,$00,$00,$07,$3f,$ff
1320: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$e0,$1c,$03,$00,$00,$00,$00,$00,$e0,$fc,$ff
1330: 80 40 20 10+ .bulk $80,$40,$20,$10,$08,$04,$02,$01,$80,$c0,$e0,$f0,$f8,$fc,$fe,$ff
1340: 04 0e 0e 0e+ .bulk $04,$0e,$0e,$0e,$6e,$64,$60,$60,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
1350: 07 0f 1f 1f+ .bulk $07,$0f,$1f,$1f,$7f,$ff,$ff,$7f,$07,$08,$10,$00,$60,$80,$80,$40
1360: 03 07 1f 3f+ .bulk $03,$07,$1f,$3f,$3f,$3f,$79,$f7,$03,$04,$18,$20,$20,$20,$46,$88
1370: c0 e0 f0 f4+ .bulk $c0,$e0,$f0,$f4,$fe,$bf,$df,$ff,$c0,$20,$10,$14,$0a,$41,$21,$01
1380: 90 b8 f8 fa+ .bulk $90,$b8,$f8,$fa,$ff,$ff,$ff,$fe,$90,$a8,$48,$0a,$05,$01,$01,$02
1390: 3b 1d 0e 0f+ .bulk $3b,$1d,$0e,$0f,$07,$00,$00,$00,$24,$12,$09,$08,$07,$00,$00,$00
13a0: ff bf 1c c0+ .bulk $ff,$bf,$1c,$c0,$f3,$ff,$7e,$1c,$00,$40,$e3,$3f,$0c,$81,$62,$1c
13b0: bf 7f 3d 83+ .bulk $bf,$7f,$3d,$83,$c7,$ff,$ff,$3c,$40,$80,$c2,$7c,$38,$00,$c3,$3c
13c0: fc fe ff fe+ .bulk $fc,$fe,$ff,$fe,$fe,$f8,$60,$00,$04,$02,$01,$00,$06,$98,$60,$00
13d0: c0 20 10 10+ .bulk $c0,$20,$10,$10,$10,$10,$20,$c0,$c0,$e0,$f0,$f0,$f0,$f0,$e0,$c0
13e0: 00 00 00 00+ .bulk $00,$00,$00,$00,$3f,$7f,$e0,$c0,$00,$00,$00,$00,$00,$00,$1c,$3e
13f0: 88 9c 88 80+ .bulk $88,$9c,$88,$80,$80,$80,$80,$80,$7f,$7f,$7f,$3e,$1c,$00,$00,$00
1400: fe fe fe fe+ .bulk $fe,$fe,$fe,$fe,$fe,$fe,$fe,$fe,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
1410: 08 14 24 c4+ .bulk $08,$14,$24,$c4,$03,$40,$a1,$26,$00,$08,$18,$38,$fc,$bf,$5e,$d9
1420: ff ff ff ff+ .bulk $ff,$ff,$ff,$ff,$7f,$7f,$7f,$7f,$81,$81,$81,$81,$81,$81,$81,$81
1430: ff ff ff ff+ .bulk $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$01,$01,$01,$01,$01,$01,$01,$01
1440: 7f 80 80 98+ .bulk $7f,$80,$80,$98,$9c,$8c,$80,$80,$00,$7f,$7f,$67,$67,$7f,$7f,$7f
1450: ff 01 01 ff+ .bulk $ff,$01,$01,$ff,$10,$10,$10,$ff,$00,$ff,$ff,$ff,$ff,$ff,$ff,$ff
1460: 80 80 80 80+ .bulk $80,$80,$80,$80,$80,$80,$80,$80,$7f,$7f,$7f,$7f,$7f,$7f,$7f,$7f
1470: 01 01 01 ff+ .bulk $01,$01,$01,$ff,$10,$10,$10,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
1480: ff 00 00 00+ .bulk $ff,$00,$00,$00,$00,$00,$00,$00,$00,$ff,$ff,$ff,$ff,$ff,$ff,$ff
1490: fe 01 01 19+ .bulk $fe,$01,$01,$19,$1d,$0d,$01,$01,$00,$ff,$ff,$e7,$e7,$ff,$ff,$ff
14a0: 01 01 01 01+ .bulk $01,$01,$01,$01,$01,$01,$01,$01,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
14b0: 3f 7f 7f ff+ .bulk $3f,$7f,$7f,$ff,$ff,$ff,$ff,$ff,$3f,$60,$40,$c0,$80,$80,$80,$80
14c0: ff ff ff ff+ .bulk $ff,$ff,$ff,$ff,$ff,$ff,$7e,$3c,$80,$80,$80,$80,$80,$81,$42,$3c
14d0: ff ff ff ff+ .bulk $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$00,$00,$00,$00,$00,$00,$00
14e0: ff ff ff ff+ .bulk $ff,$ff,$ff,$ff,$ff,$ff,$fe,$7c,$00,$00,$00,$00,$00,$01,$82,$7c
14f0: ff ff ff ff+ .bulk $ff,$ff,$ff,$ff,$ff,$ff,$fe,$7c,$00,$00,$00,$00,$00,$01,$83,$ff
1500: f8 fc fe fe+ .bulk $f8,$fc,$fe,$fe,$ff,$ff,$ff,$ff,$f8,$04,$02,$02,$01,$01,$01,$01
1510: ff ff ff ff+ .bulk $ff,$ff,$ff,$ff,$ff,$ff,$7e,$3c,$01,$01,$01,$01,$01,$81,$42,$3c
1520: 00 08 08 08+ .bulk $00,$08,$08,$08,$10,$10,$10,$00,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
1530: 00 7f 7f 78+ .bulk $00,$7f,$7f,$78,$73,$73,$73,$7f,$7f,$80,$a0,$87,$8f,$8e,$8e,$86
1540: 00 ff ff 3f+ .bulk $00,$ff,$ff,$3f,$9f,$9f,$9f,$1f,$fe,$01,$05,$c1,$e1,$71,$71,$f1
1550: 7e 7e 7f 7e+ .bulk $7e,$7e,$7f,$7e,$7e,$7f,$7f,$ff,$81,$81,$80,$81,$81,$a0,$80,$ff
1560: 7f 7f ff 7f+ .bulk $7f,$7f,$ff,$7f,$7f,$ff,$ff,$ff,$f1,$c1,$c1,$81,$c1,$c5,$01,$ff
1570: 7f 80 a0 80+ .bulk $7f,$80,$a0,$80,$80,$80,$80,$80,$7f,$ff,$ff,$ff,$ff,$ff,$ff,$ff
1580: fe 01 05 01+ .bulk $fe,$01,$05,$01,$01,$01,$01,$01,$fe,$ff,$ff,$ff,$ff,$ff,$ff,$ff
1590: 80 80 80 80+ .bulk $80,$80,$80,$80,$80,$a0,$80,$7f,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$7f
15a0: 01 01 01 01+ .bulk $01,$01,$01,$01,$01,$05,$01,$fe,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$fe
15b0: 00 00 00 00+ .bulk $00,$00,$00,$00,$fc,$fe,$07,$03,$00,$00,$00,$00,$00,$00,$38,$7c
15c0: 11 39 11 01+ .bulk $11,$39,$11,$01,$01,$01,$01,$01,$fe,$fe,$fe,$7c,$38,$00,$00,$00
15d0: ef 28 28 28+ .bulk $ef,$28,$28,$28,$28,$28,$ef,$00,$20,$e7,$e7,$e7,$e7,$e7,$ef,$00
15e0: fe 82 82 82+ .bulk $fe,$82,$82,$82,$82,$82,$fe,$00,$02,$7e,$7e,$7e,$7e,$7e,$fe,$00
15f0: 80 80 80 98+ .bulk $80,$80,$80,$98,$9c,$8c,$80,$7f,$7f,$7f,$7f,$67,$67,$7f,$7f,$7f
1600: ff ff 83 f3+ .bulk $ff,$ff,$83,$f3,$f3,$f3,$f3,$f3,$ff,$80,$fc,$8c,$8c,$8c,$8c,$8c
1610: ff ff f0 f6+ .bulk $ff,$ff,$f0,$f6,$f6,$f6,$f6,$f6,$ff,$00,$0f,$09,$09,$09,$09,$09
1620: ff ff 00 00+ .bulk $ff,$ff,$00,$00,$00,$00,$00,$00,$ff,$00,$ff,$ff,$ff,$ff,$ff,$ff
1630: ff ff 01 57+ .bulk $ff,$ff,$01,$57,$2f,$57,$2f,$57,$ff,$01,$ff,$a9,$d1,$a9,$d1,$a9
1640: f3 f3 f3 f3+ .bulk $f3,$f3,$f3,$f3,$f3,$f3,$ff,$3f,$8c,$8c,$8c,$8c,$8c,$8c,$ff,$3f
1650: f6 f6 f6 f6+ .bulk $f6,$f6,$f6,$f6,$f6,$f6,$ff,$ff,$09,$09,$09,$09,$09,$09,$ff,$ff
1660: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$00,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
1670: 2f 57 2f 57+ .bulk $2f,$57,$2f,$57,$2f,$57,$ff,$fc,$d1,$a9,$d1,$a9,$d1,$a9,$ff,$fc
1680: 3c 3c 3c 3c+ .bulk $3c,$3c,$3c,$3c,$3c,$3c,$3c,$3c,$23,$23,$23,$23,$23,$23,$23,$23
1690: fb fb fb fb+ .bulk $fb,$fb,$fb,$fb,$fb,$fb,$fb,$fb,$04,$04,$04,$04,$04,$04,$04,$04
16a0: bc 5c bc 5c+ .bulk $bc,$5c,$bc,$5c,$bc,$5c,$bc,$5c,$44,$a4,$44,$a4,$44,$a4,$44,$a4
16b0: 1f 20 40 40+ .bulk $1f,$20,$40,$40,$80,$80,$80,$81,$1f,$3f,$7f,$7f,$ff,$ff,$ff,$fe
16c0: ff 80 80 c0+ .bulk $ff,$80,$80,$c0,$ff,$ff,$fe,$fe,$ff,$7f,$7f,$3f,$00,$00,$01,$01
16d0: ff 7f 7f ff+ .bulk $ff,$7f,$7f,$ff,$ff,$07,$03,$03,$ff,$80,$80,$00,$00,$f8,$fc,$fc
16e0: ff 00 00 00+ .bulk $ff,$00,$00,$00,$00,$81,$c3,$ff,$ff,$ff,$ff,$ff,$ff,$7e,$3c,$00
16f0: f8 fc fe fe+ .bulk $f8,$fc,$fe,$fe,$e3,$c1,$81,$81,$f8,$04,$02,$02,$1d,$3f,$7f,$7f
1700: 83 ff ff ff+ .bulk $83,$ff,$ff,$ff,$ff,$ff,$7f,$1f,$fc,$80,$80,$80,$80,$80,$60,$1f
1710: fc fc fc fc+ .bulk $fc,$fc,$fc,$fc,$fe,$fe,$ff,$ff,$03,$03,$03,$03,$01,$01,$00,$ff
1720: 01 01 01 01+ .bulk $01,$01,$01,$01,$03,$03,$07,$ff,$fe,$fe,$fe,$fe,$fc,$fc,$f8,$ff
1730: ff ff ff ff+ .bulk $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$00,$00,$00,$00,$00,$00,$00,$ff
1740: 81 c1 e3 ff+ .bulk $81,$c1,$e3,$ff,$ff,$ff,$ff,$fe,$7f,$3f,$1d,$01,$01,$01,$03,$fe
1750: ff ff ff ff+ .bulk $ff,$ff,$ff,$ff,$ff,$fb,$b5,$ce,$80,$80,$80,$80,$80,$84,$ca,$b1
1760: ff ff ff ff+ .bulk $ff,$ff,$ff,$ff,$ff,$df,$ad,$73,$01,$01,$01,$01,$01,$21,$53,$8d
1770: 77 77 77 77+ .bulk $77,$77,$77,$77,$77,$77,$77,$77,$00,$00,$00,$00,$77,$ff,$ff,$ff
1780: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$00,$00,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
1790: 77 77 77 77+ .bulk $77,$77,$77,$77,$00,$00,$00,$00,$ff,$ff,$ff,$77,$77,$77,$77,$77
17a0: 01 01 01 19+ .bulk $01,$01,$01,$19,$1d,$0d,$01,$fe,$ff,$ff,$ff,$e7,$e7,$ff,$ff,$fe
17b0: 20 78 7f fe+ .bulk $20,$78,$7f,$fe,$fe,$fe,$fe,$fe,$00,$21,$21,$41,$41,$41,$41,$41
17c0: 04 9a fa fd+ .bulk $04,$9a,$fa,$fd,$fd,$fd,$fd,$fd,$00,$80,$80,$80,$80,$80,$80,$80
17d0: 7e 38 21 00+ .bulk $7e,$38,$21,$00,$01,$00,$01,$00,$21,$21,$01,$01,$01,$01,$01,$01
17e0: fa 8a 84 80+ .bulk $fa,$8a,$84,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80
17f0: 02 04 00 10+ .bulk $02,$04,$00,$10,$00,$40,$80,$00,$01,$01,$06,$08,$18,$20,$20,$c0
1800: 0b 0b 3b 0b+ .bulk $0b,$0b,$3b,$0b,$fb,$0b,$0b,$0a,$04,$04,$c4,$f4,$f4,$04,$04,$05
1810: 90 10 1f 10+ .bulk $90,$10,$1f,$10,$1f,$10,$10,$90,$70,$f0,$f0,$ff,$ff,$f0,$f0,$70
1820: 3f 78 e7 cf+ .bulk $3f,$78,$e7,$cf,$58,$58,$50,$90,$c0,$87,$18,$b0,$e7,$e7,$ef,$ef
1830: b0 fc e2 c1+ .bulk $b0,$fc,$e2,$c1,$c1,$83,$8f,$7e,$6f,$43,$5d,$3f,$3f,$7f,$7f,$ff
1840: fe 03 0f 91+ .bulk $fe,$03,$0f,$91,$70,$60,$20,$31,$03,$ff,$f1,$6e,$cf,$df,$ff,$ff
1850: 3f 3f 1d 39+ .bulk $3f,$3f,$1d,$39,$7b,$f3,$86,$fe,$fd,$fb,$fb,$f7,$f7,$0f,$7f,$ff
1860: ff ff ff ff+ .bulk $ff,$ff,$ff,$ff,$ff,$80,$80,$ff,$ff,$80,$80,$80,$80,$ff,$ff,$80
1870: fe ff ff ff+ .bulk $fe,$ff,$ff,$ff,$ff,$03,$03,$ff,$fe,$03,$03,$03,$03,$ff,$ff,$03
1880: 00 ff ff ff+ .bulk $00,$ff,$ff,$ff,$ff,$ff,$00,$00,$00,$ff,$00,$00,$00,$00,$ff,$ff
1890: 3c fc fc fc+ .bulk $3c,$fc,$fc,$fc,$fc,$fc,$04,$04,$23,$f3,$0b,$0b,$0b,$07,$ff,$ff
18a0: ff ff ff ff+ .bulk $ff,$ff,$ff,$ff,$80,$ff,$ff,$ff,$80,$80,$80,$80,$ff,$80,$80,$80
18b0: ff ff ff ff+ .bulk $ff,$ff,$ff,$ff,$03,$ff,$ff,$ff,$03,$03,$03,$03,$ff,$03,$03,$03
18c0: ff ff ff ff+ .bulk $ff,$ff,$ff,$ff,$ff,$00,$ff,$ff,$00,$00,$00,$00,$00,$ff,$00,$00
18d0: fc fc fe fe+ .bulk $fc,$fc,$fe,$fe,$fe,$02,$fe,$fe,$07,$07,$03,$03,$03,$ff,$03,$03
18e0: ff 80 80 80+ .bulk $ff,$80,$80,$80,$80,$80,$80,$80,$80,$ff,$ff,$ff,$ff,$ff,$ff,$ff
18f0: ff 03 03 03+ .bulk $ff,$03,$03,$03,$03,$03,$03,$03,$03,$ff,$ff,$ff,$ff,$ff,$ff,$ff
1900: 02 02 02 02+ .bulk $02,$02,$02,$02,$02,$02,$04,$04,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
1910: 80 80 aa d5+ .bulk $80,$80,$aa,$d5,$aa,$ff,$ff,$ff,$ff,$ff,$d5,$aa,$d5,$80,$80,$ff
1920: 03 03 ab 57+ .bulk $03,$03,$ab,$57,$ab,$ff,$ff,$fe,$ff,$ff,$57,$ab,$57,$03,$03,$fe
1930: 00 55 aa 55+ .bulk $00,$55,$aa,$55,$ff,$ff,$ff,$00,$ff,$aa,$55,$aa,$00,$00,$ff,$00
1940: 04 54 ac 5c+ .bulk $04,$54,$ac,$5c,$fc,$fc,$fc,$3c,$ff,$af,$57,$ab,$0b,$0b,$f3,$23
1950: 3f 3f 3f 3f+ .bulk $3f,$3f,$3f,$3f,$00,$00,$00,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
1960: 7e 7c 7c 78+ .bulk $7e,$7c,$7c,$78,$00,$00,$00,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
1970: 1f 0f 0f 07+ .bulk $1f,$0f,$0f,$07,$00,$00,$00,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
1980: fe fc fc f8+ .bulk $fe,$fc,$fc,$f8,$00,$00,$00,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
1990: 00 00 00 00+ .bulk $00,$00,$00,$00,$ff,$ff,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
19a0: 18 18 18 18+ .bulk $18,$18,$18,$18,$18,$18,$18,$18,$00,$00,$00,$00,$00,$00,$00,$00
19b0: 07 1f 3f ff+ .bulk $07,$1f,$3f,$ff,$7f,$7f,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
19c0: e1 f9 fd ff+ .bulk $e1,$f9,$fd,$ff,$fe,$fe,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
19d0: f0 10 10 10+ .bulk $f0,$10,$10,$10,$10,$10,$10,$ff,$00,$e0,$e0,$e0,$e0,$e0,$e0,$e0
19e0: 1f 10 10 10+ .bulk $1f,$10,$10,$10,$10,$10,$10,$ff,$00,$0f,$0f,$0f,$0f,$0f,$0f,$0f
19f0: 92 92 92 fe+ .bulk $92,$92,$92,$fe,$fe,$00,$00,$00,$48,$48,$6c,$00,$00,$00,$fe,$00
1a00: 0a 0a 3a 0a+ .bulk $0a,$0a,$3a,$0a,$fb,$0b,$0b,$0b,$05,$05,$c5,$f5,$f4,$04,$04,$04
1a10: 90 90 9f 90+ .bulk $90,$90,$9f,$90,$9f,$90,$90,$90,$70,$70,$70,$7f,$7f,$70,$70,$70
1a20: 01 01 01 01+ .bulk $01,$01,$01,$01,$01,$01,$01,$01,$00,$00,$00,$00,$00,$00,$00,$00
1a30: 80 80 80 80+ .bulk $80,$80,$80,$80,$80,$80,$80,$80,$00,$00,$00,$00,$00,$00,$00,$00
1a40: 08 88 91 d1+ .bulk $08,$88,$91,$d1,$53,$53,$73,$3f,$ff,$ff,$ff,$ff,$ff,$fe,$be,$ce
1a50: 00 00 07 0f+ .bulk $00,$00,$07,$0f,$0c,$1b,$1b,$1b,$00,$00,$00,$00,$03,$04,$04,$04
1a60: 00 00 e0 f0+ .bulk $00,$00,$e0,$f0,$f0,$f8,$f8,$f8,$00,$00,$60,$30,$30,$98,$98,$98
1a70: 1b 1b 1b 1b+ .bulk $1b,$1b,$1b,$1b,$1b,$0f,$0f,$07,$04,$04,$04,$04,$04,$03,$00,$00
1a80: f8 f8 f8 f8+ .bulk $f8,$f8,$f8,$f8,$f8,$f0,$f0,$e0,$98,$98,$98,$98,$98,$30,$30,$60
1a90: f1 11 11 1f+ .bulk $f1,$11,$11,$1f,$10,$10,$10,$ff,$0f,$ef,$ef,$ef,$ef,$ef,$ef,$e0
1aa0: 1f 10 10 f0+ .bulk $1f,$10,$10,$f0,$10,$10,$10,$ff,$e0,$ef,$ef,$ef,$ef,$ef,$ef,$0f
1ab0: 7f bf df ef+ .bulk $7f,$bf,$df,$ef,$f0,$f0,$f0,$f0,$80,$40,$20,$10,$0f,$0f,$0f,$0f
1ac0: f0 f0 f0 f0+ .bulk $f0,$f0,$f0,$f0,$ff,$ff,$ff,$ff,$0f,$0f,$0f,$0f,$1f,$3f,$7f,$ff
1ad0: ff ff ff ff+ .bulk $ff,$ff,$ff,$ff,$0f,$0f,$0f,$0f,$01,$03,$07,$0f,$ff,$ff,$ff,$ff
1ae0: 0f 0f 0f 0f+ .bulk $0f,$0f,$0f,$0f,$f7,$fb,$fd,$fe,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
1af0: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$00,$18,$18,$00,$00,$00,$00,$00,$00,$00,$00
1b00: 1f 3f 7f 7f+ .bulk $1f,$3f,$7f,$7f,$7f,$ff,$ff,$ff,$1f,$20,$40,$40,$40,$80,$82,$82
1b10: ff ff ff 7f+ .bulk $ff,$ff,$ff,$7f,$7f,$7f,$3f,$1e,$82,$80,$a0,$44,$43,$40,$21,$1e
1b20: f8 fc fe fe+ .bulk $f8,$fc,$fe,$fe,$fe,$ff,$ff,$ff,$f8,$04,$02,$02,$02,$01,$41,$41
1b30: ff ff ff fe+ .bulk $ff,$ff,$ff,$fe,$fe,$fe,$fc,$78,$41,$01,$05,$22,$c2,$02,$84,$78
1b40: 7f 80 80 80+ .bulk $7f,$80,$80,$80,$80,$80,$80,$80,$80,$7f,$7f,$7f,$7f,$7f,$7f,$7f
1b50: de 61 61 61+ .bulk $de,$61,$61,$61,$71,$5e,$7f,$61,$61,$df,$df,$df,$df,$ff,$c1,$df
1b60: 80 80 c0 f0+ .bulk $80,$80,$c0,$f0,$bf,$8f,$81,$7e,$7f,$7f,$ff,$3f,$4f,$71,$7f,$ff
1b70: 61 61 c1 c1+ .bulk $61,$61,$c1,$c1,$81,$81,$83,$fe,$df,$df,$bf,$bf,$7f,$7f,$7f,$7f
1b80: 00 00 03 0f+ .bulk $00,$00,$03,$0f,$1f,$3f,$7f,$7f,$00,$00,$03,$0c,$10,$20,$40,$40
1b90: 00 00 c0 f0+ .bulk $00,$00,$c0,$f0,$f8,$fc,$fe,$fe,$00,$00,$c0,$30,$08,$04,$02,$02
1ba0: ff ff ff ff+ .bulk $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$80,$80,$80,$80,$80,$80,$80,$80
1bb0: ff ff ff ff+ .bulk $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$01,$01,$01,$01,$01,$01,$01,$01
1bc0: 7f 7f 7f 3f+ .bulk $7f,$7f,$7f,$3f,$3f,$1f,$0f,$07,$40,$40,$40,$20,$30,$1c,$0f,$07
1bd0: fe fe fe fc+ .bulk $fe,$fe,$fe,$fc,$fc,$f8,$f0,$f0,$02,$02,$02,$04,$0c,$38,$f0,$f0
1be0: 0f 0f 0f 0f+ .bulk $0f,$0f,$0f,$0f,$0f,$0f,$07,$0f,$08,$08,$08,$08,$08,$0c,$05,$0a
1bf0: f0 f0 f0 f0+ .bulk $f0,$f0,$f0,$f0,$f0,$f0,$e0,$f0,$10,$50,$50,$50,$50,$30,$a0,$50
1c00: 81 c1 a3 a3+ .bulk $81,$c1,$a3,$a3,$9d,$81,$81,$81,$00,$41,$22,$22,$1c,$00,$00,$00
1c10: e3 f7 c1 c1+ .bulk $e3,$f7,$c1,$c1,$c1,$c1,$f7,$e3,$e3,$14,$3e,$3e,$3e,$3e,$14,$e3
1c20: 00 00 07 0f+ .bulk $00,$00,$07,$0f,$0c,$1b,$1b,$1b,$ff,$ff,$f8,$f0,$f0,$e0,$e0,$e0
1c30: 00 00 e0 f0+ .bulk $00,$00,$e0,$f0,$f0,$f8,$f8,$f8,$ff,$ff,$7f,$3f,$3f,$9f,$9f,$9f
1c40: 1b 1b 1b 1b+ .bulk $1b,$1b,$1b,$1b,$1b,$0f,$0f,$07,$e0,$e0,$e0,$e0,$e0,$f3,$f0,$f8
1c50: f8 f8 f8 f8+ .bulk $f8,$f8,$f8,$f8,$f8,$f0,$f0,$e0,$9f,$9f,$9f,$9f,$9f,$3f,$3f,$7f
1c60: e0 ff ff ff+ .bulk $e0,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$00,$70,$1f,$10,$70,$7f,$7f,$7f
1c70: 07 ff ff ff+ .bulk $07,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$00,$03,$f8,$00,$03,$fb,$fb,$fb
1c80: ff ff ff ff+ .bulk $ff,$ff,$ff,$ff,$ff,$fe,$ff,$ef,$7c,$7b,$76,$75,$75,$77,$17,$67
1c90: ff df ef af+ .bulk $ff,$df,$ef,$af,$af,$6f,$ef,$e7,$3b,$fb,$7b,$fb,$fb,$f3,$f8,$f3
1ca0: 1f 1f 3f 3f+ .bulk $1f,$1f,$3f,$3f,$70,$63,$e7,$e5,$0f,$0f,$1f,$1f,$3f,$3c,$78,$7a
1cb0: f0 f0 f8 f8+ .bulk $f0,$f0,$f8,$f8,$0c,$c4,$e4,$a6,$f8,$f8,$fc,$fc,$fe,$3e,$1e,$5f
1cc0: e9 e9 e9 ef+ .bulk $e9,$e9,$e9,$ef,$e2,$e3,$f0,$ff,$76,$76,$76,$70,$7d,$7c,$7f,$7f
1cd0: 96 96 96 f6+ .bulk $96,$96,$96,$f6,$46,$c6,$0e,$fe,$6f,$6f,$6f,$0f,$bf,$3f,$ff,$ff
1ce0: 00 00 00 00+ .bulk $00,$00,$00,$00,$00,$00,$7e,$3c,$3c,$7e,$7e,$ff,$ff,$ff,$42,$00
1cf0: 3c 42 99 a1+ .bulk $3c,$42,$99,$a1,$a1,$99,$42,$3c,$00,$00,$00,$00,$00,$00,$00,$00
1d00: 0f 1f 1f 3f+ .bulk $0f,$1f,$1f,$3f,$3f,$7f,$7f,$7f,$f0,$e0,$e0,$c0,$c0,$80,$80,$80
1d10: f0 f8 f8 fc+ .bulk $f0,$f8,$f8,$fc,$fc,$fe,$fe,$fe,$0f,$07,$07,$03,$03,$01,$01,$01
1d20: 7f 7f 3f 3f+ .bulk $7f,$7f,$3f,$3f,$3f,$3f,$1f,$1f,$80,$80,$c0,$c0,$e0,$f8,$fe,$ff
1d30: fe ff ff ff+ .bulk $fe,$ff,$ff,$ff,$fc,$fc,$fe,$fe,$ff,$7f,$1f,$07,$03,$03,$01,$81
1d40: 7f 7f 7f 3f+ .bulk $7f,$7f,$7f,$3f,$3f,$3f,$3f,$1f,$80,$80,$80,$c0,$c0,$e0,$e0,$f0
1d50: fe fe ff ff+ .bulk $fe,$fe,$ff,$ff,$ff,$ff,$ff,$fe,$01,$01,$01,$03,$03,$07,$07,$0f
1d60: 1f 0f 0f 07+ .bulk $1f,$0f,$0f,$07,$00,$00,$00,$00,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
1d70: fe fc fc f8+ .bulk $fe,$fc,$fc,$f8,$00,$00,$00,$00,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
1d80: 7e 7e 7e 7e+ .bulk $7e,$7e,$7e,$7e,$7f,$7f,$7f,$7f,$81,$81,$81,$81,$81,$81,$81,$81
1d90: ff ff ff ff+ .bulk $ff,$ff,$ff,$ff,$ff,$ff,$ff,$fe,$01,$01,$01,$03,$03,$07,$07,$0f
1da0: fe fe fe fe+ .bulk $fe,$fe,$fe,$fe,$ff,$ff,$ff,$ff,$01,$01,$01,$01,$01,$01,$01,$01
1db0: 7f 7f 7f 7f+ .bulk $7f,$7f,$7f,$7f,$7f,$7f,$7f,$7f,$81,$81,$81,$81,$81,$81,$81,$81
1dc0: ff ff ff ff+ .bulk $ff,$ff,$ff,$ff,$fc,$fe,$fe,$7e,$ff,$03,$03,$03,$03,$03,$03,$ff
1dd0: ff ff ff ff+ .bulk $ff,$ff,$ff,$ff,$00,$00,$00,$00,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
1de0: 7f 7f 7f 7f+ .bulk $7f,$7f,$7f,$7f,$7f,$7f,$7f,$7f,$80,$80,$80,$80,$80,$80,$80,$80
1df0: ff ff ff ff+ .bulk $ff,$ff,$ff,$ff,$ff,$ff,$ff,$fe,$01,$01,$01,$03,$07,$03,$01,$01
1e00: 7e 7e 7f 7f+ .bulk $7e,$7e,$7f,$7f,$7f,$7f,$7f,$7f,$81,$81,$81,$81,$81,$81,$81,$81
1e10: 3f 3f 3f 3f+ .bulk $3f,$3f,$3f,$3f,$00,$00,$00,$00,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
1e20: 7e 7c 7c 78+ .bulk $7e,$7c,$7c,$78,$00,$00,$00,$00,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
1e30: fe fe ff ff+ .bulk $fe,$fe,$ff,$ff,$7f,$7f,$7f,$7f,$81,$81,$81,$81,$81,$81,$81,$81
1e40: 7f 7f 3f 3f+ .bulk $7f,$7f,$3f,$3f,$3f,$3f,$1f,$1f,$80,$80,$c0,$c0,$e0,$f8,$fe,$ff
1e50: 3f bf ff ff+ .bulk $3f,$bf,$ff,$ff,$fc,$fc,$fe,$fe,$ff,$7f,$1f,$07,$03,$03,$01,$81
1e60: 7f 7f 7e 7e+ .bulk $7f,$7f,$7e,$7e,$7f,$7f,$7f,$7f,$81,$81,$81,$81,$81,$81,$81,$81
1e70: 7e 7e 7e 7e+ .bulk $7e,$7e,$7e,$7e,$7f,$7f,$7f,$7f,$81,$81,$81,$81,$81,$81,$81,$81
1e80: 81 c3 c3 e7+ .bulk $81,$c3,$c3,$e7,$e7,$ff,$ff,$ff,$7e,$3c,$3c,$18,$18,$00,$00,$00
1e90: 0f 43 5b 53+ .bulk $0f,$43,$5b,$53,$31,$19,$0f,$07,$f2,$fe,$fe,$ff,$ff,$ef,$f7,$f8
1ea0: c1 c3 c6 84+ .bulk $c1,$c3,$c6,$84,$fc,$fc,$0e,$02,$bf,$be,$bd,$7b,$7b,$07,$f3,$fd
1eb0: 10 20 22 ba+ .bulk $10,$20,$22,$ba,$e6,$e1,$c0,$c0,$ff,$ff,$ff,$67,$59,$9e,$bf,$bf
1ec0: 20 a6 54 26+ .bulk $20,$a6,$54,$26,$20,$c6,$54,$26,$20,$e6,$54,$26,$21,$06,$54,$26
1ed0: 20 85 01 44+ .bulk $20,$85,$01,$44,$20,$86,$54,$48,$20,$9a,$01,$49,$20,$a5,$c9,$46
1ee0: 20 ba c9 4a+ .bulk $20,$ba,$c9,$4a,$20,$a6,$0a,$d0,$d1,$d8,$d8,$de,$d1,$d0,$da,$de
1ef0: d1 20 c6 0a+ .bulk $d1,$20,$c6,$0a,$d2,$d3,$db,$db,$db,$d9,$db,$dc,$db,$df,$20,$e6
1f00: 0a d4 d5 d4+ .bulk $0a,$d4,$d5,$d4,$d9,$db,$e2,$d4,$da,$db,$e0,$21,$06,$0a,$d6,$d7
1f10: d6 d7 e1 26+ .bulk $d6,$d7,$e1,$26,$d6,$dd,$e1,$e1,$21,$26,$14,$d0,$e8,$d1,$d0,$d1
1f20: de d1 d8 d0+ .bulk $de,$d1,$d8,$d0,$d1,$26,$de,$d1,$de,$d1,$d0,$d1,$d0,$d1,$26,$21
1f30: 46 14 db 42+ .bulk $46,$14,$db,$42,$42,$db,$42,$db,$42,$db,$db,$42,$26,$db,$42,$db
1f40: 42 db 42 db+ .bulk $42,$db,$42,$db,$42,$26,$21,$66,$46,$db,$21,$6c,$0e,$df,$db,$db
1f50: db 26 db df+ .bulk $db,$26,$db,$df,$db,$df,$db,$db,$e4,$e5,$26,$21,$86,$14,$db,$db
1f60: db de 43 db+ .bulk $db,$de,$43,$db,$e0,$db,$db,$db,$26,$db,$e3,$db,$e0,$db,$db,$e6
1f70: e3 26 21 a6+ .bulk $e3,$26,$21,$a6,$14,$db,$db,$db,$db,$42,$db,$db,$db,$d4,$d9,$26
1f80: db d9 db db+ .bulk $db,$d9,$db,$db,$d4,$d9,$d4,$d9,$e7,$21,$c5,$16,$5f,$95,$95,$95
1f90: 95 95 95 95+ .bulk $95,$95,$95,$95,$95,$97,$98,$78,$95,$96,$95,$95,$97,$98,$97,$98
1fa0: 95 7a 21 ed+ .bulk $95,$7a,$21,$ed,$0e,$cf,$01,$09,$08,$05,$24,$17,$12,$17,$1d,$0e
1fb0: 17 0d 18 22+ .bulk $17,$0d,$18,$22,$4b,$0d,$01,$24,$19,$15,$0a,$22,$0e,$1b,$24,$10
1fc0: 0a 16 0e 22+ .bulk $0a,$16,$0e,$22,$8b,$0d,$02,$24,$19,$15,$0a,$22,$0e,$1b,$24,$10
1fd0: 0a 16 0e 22+ .bulk $0a,$16,$0e,$22,$ec,$04,$1d,$18,$19,$28,$22,$f6,$01,$00,$23,$c9
1fe0: 56 55 23 e2+ .bulk $56,$55,$23,$e2,$04,$99,$aa,$aa,$aa,$23,$ea,$04,$99,$aa,$aa,$aa
1ff0: 00 ff ff ff+ .bulk $00,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
.adrend β NA