********************************************************************************
* 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