mirror of
https://github.com/lscharen/iigs-game-engine.git
synced 2024-11-29 11:50:25 +00:00
16382 lines
1022 KiB
ArmAsm
16382 lines
1022 KiB
ArmAsm
;SMBDIS.ASM - A COMPREHENSIVE SUPER MARIO BROS. DISASSEMBLY
|
|
;by doppelganger (doppelheathen@gmail.com)
|
|
|
|
;This file is provided for your own use as-is. It will require the character rom data
|
|
;and an iNES file header to get it to work.
|
|
|
|
;There are so many people I have to thank for this, that taking all the credit for
|
|
;myself would be an unforgivable act of arrogance. Without their help this would
|
|
;probably not be possible. So I thank all the peeps in the nesdev scene whose insight into
|
|
;the 6502 and the NES helped me learn how it works (you guys know who you are, there's no
|
|
;way I could have done this without your help), as well as the authors of x816 and SMB
|
|
;Utility, and the reverse-engineers who did the original Super Mario Bros. Hacking Project,
|
|
;which I compared notes with but did not copy from. Last but certainly not least, I thank
|
|
;Nintendo for creating this game and the NES, without which this disassembly would
|
|
;only be theory.
|
|
|
|
;Assembles with x816.
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;DEFINES
|
|
|
|
;NES specific hardware defines
|
|
|
|
PPU_CTRL_REG1 = $2000
|
|
PPU_CTRL_REG2 = $2001
|
|
PPU_STATUS = $2002
|
|
PPU_SPR_ADDR = $2003
|
|
PPU_SPR_DATA = $2004
|
|
PPU_SCROLL_REG = $2005
|
|
PPU_ADDRESS = $2006
|
|
PPU_DATA = $2007
|
|
|
|
SND_REGISTER = $4000
|
|
SND_SQUARE1_REG = $4000
|
|
SND_SQUARE2_REG = $4004
|
|
SND_TRIANGLE_REG = $4008
|
|
SND_NOISE_REG = $400c
|
|
SND_DELTA_REG = $4010
|
|
SND_MASTERCTRL_REG = $4015
|
|
|
|
SPR_DMA = $4014
|
|
JOYPAD_PORT = $4016
|
|
JOYPAD_PORT1 = $4016
|
|
JOYPAD_PORT2 = $4017
|
|
|
|
; GAME SPECIFIC DEFINES
|
|
|
|
ObjectOffset = $08
|
|
|
|
FrameCounter = $09
|
|
|
|
SavedJoypadBits = $06fc
|
|
SavedJoypad1Bits = $06fc
|
|
SavedJoypad2Bits = $06fd
|
|
JoypadBitMask = $074a
|
|
JoypadOverride = $0758
|
|
|
|
A_B_Buttons = $0a
|
|
PreviousA_B_Buttons = $0d
|
|
Up_Down_Buttons = $0b
|
|
Left_Right_Buttons = $0c
|
|
|
|
GameEngineSubroutine = $0e
|
|
|
|
Mirror_PPU_CTRL_REG1 = $0778
|
|
Mirror_PPU_CTRL_REG2 = $0779
|
|
|
|
OperMode = $0770
|
|
OperMode_Task = $0772
|
|
ScreenRoutineTask = $073c
|
|
|
|
GamePauseStatus = $0776
|
|
GamePauseTimer = $0777
|
|
|
|
DemoAction = $0717
|
|
DemoActionTimer = $0718
|
|
|
|
TimerControl = $0747
|
|
IntervalTimerControl = $077f
|
|
|
|
Timers = $0780
|
|
SelectTimer = $0780
|
|
PlayerAnimTimer = $0781
|
|
JumpSwimTimer = $0782
|
|
RunningTimer = $0783
|
|
BlockBounceTimer = $0784
|
|
SideCollisionTimer = $0785
|
|
JumpspringTimer = $0786
|
|
GameTimerCtrlTimer = $0787
|
|
ClimbSideTimer = $0789
|
|
EnemyFrameTimer = $078a
|
|
FrenzyEnemyTimer = $078f
|
|
BowserFireBreathTimer = $0790
|
|
StompTimer = $0791
|
|
AirBubbleTimer = $0792
|
|
ScrollIntervalTimer = $0795
|
|
EnemyIntervalTimer = $0796
|
|
BrickCoinTimer = $079d
|
|
InjuryTimer = $079e
|
|
StarInvincibleTimer = $079f
|
|
ScreenTimer = $07a0
|
|
WorldEndTimer = $07a1
|
|
DemoTimer = $07a2
|
|
|
|
Sprite_Data = $0200
|
|
|
|
Sprite_Y_Position = $0200
|
|
Sprite_Tilenumber = $0201
|
|
Sprite_Attributes = $0202
|
|
Sprite_X_Position = $0203
|
|
|
|
ScreenEdge_PageLoc = $071a
|
|
ScreenEdge_X_Pos = $071c
|
|
ScreenLeft_PageLoc = $071a
|
|
ScreenRight_PageLoc = $071b
|
|
ScreenLeft_X_Pos = $071c
|
|
ScreenRight_X_Pos = $071d
|
|
|
|
PlayerFacingDir = $33
|
|
DestinationPageLoc = $34
|
|
VictoryWalkControl = $35
|
|
ScrollFractional = $0768
|
|
PrimaryMsgCounter = $0719
|
|
SecondaryMsgCounter = $0749
|
|
|
|
HorizontalScroll = $073f
|
|
VerticalScroll = $0740
|
|
ScrollLock = $0723
|
|
ScrollThirtyTwo = $073d
|
|
Player_X_Scroll = $06ff
|
|
Player_Pos_ForScroll = $0755
|
|
ScrollAmount = $0775
|
|
|
|
AreaData = $e7
|
|
AreaDataLow = $e7
|
|
AreaDataHigh = $e8
|
|
EnemyData = $e9
|
|
EnemyDataLow = $e9
|
|
EnemyDataHigh = $ea
|
|
|
|
AreaParserTaskNum = $071f
|
|
ColumnSets = $071e
|
|
CurrentPageLoc = $0725
|
|
CurrentColumnPos = $0726
|
|
BackloadingFlag = $0728
|
|
BehindAreaParserFlag = $0729
|
|
AreaObjectPageLoc = $072a
|
|
AreaObjectPageSel = $072b
|
|
AreaDataOffset = $072c
|
|
AreaObjOffsetBuffer = $072d
|
|
AreaObjectLength = $0730
|
|
StaircaseControl = $0734
|
|
AreaObjectHeight = $0735
|
|
MushroomLedgeHalfLen = $0736
|
|
EnemyDataOffset = $0739
|
|
EnemyObjectPageLoc = $073a
|
|
EnemyObjectPageSel = $073b
|
|
MetatileBuffer = $06a1
|
|
BlockBufferColumnPos = $06a0
|
|
CurrentNTAddr_Low = $0721
|
|
CurrentNTAddr_High = $0720
|
|
AttributeBuffer = $03f9
|
|
|
|
LoopCommand = $0745
|
|
|
|
DisplayDigits = $07d7
|
|
TopScoreDisplay = $07d7
|
|
ScoreAndCoinDisplay = $07dd
|
|
PlayerScoreDisplay = $07dd
|
|
GameTimerDisplay = $07f8
|
|
DigitModifier = $0134
|
|
|
|
VerticalFlipFlag = $0109
|
|
FloateyNum_Control = $0110
|
|
ShellChainCounter = $0125
|
|
FloateyNum_Timer = $012c
|
|
FloateyNum_X_Pos = $0117
|
|
FloateyNum_Y_Pos = $011e
|
|
FlagpoleFNum_Y_Pos = $010d
|
|
FlagpoleFNum_YMFDummy = $010e
|
|
FlagpoleScore = $010f
|
|
FlagpoleCollisionYPos = $070f
|
|
StompChainCounter = $0484
|
|
|
|
VRAM_Buffer1_Offset = $0300
|
|
VRAM_Buffer1 = $0301
|
|
VRAM_Buffer2_Offset = $0340
|
|
VRAM_Buffer2 = $0341
|
|
VRAM_Buffer_AddrCtrl = $0773
|
|
Sprite0HitDetectFlag = $0722
|
|
DisableScreenFlag = $0774
|
|
DisableIntermediate = $0769
|
|
ColorRotateOffset = $06d4
|
|
|
|
TerrainControl = $0727
|
|
AreaStyle = $0733
|
|
ForegroundScenery = $0741
|
|
BackgroundScenery = $0742
|
|
CloudTypeOverride = $0743
|
|
BackgroundColorCtrl = $0744
|
|
AreaType = $074e
|
|
AreaAddrsLOffset = $074f
|
|
AreaPointer = $0750
|
|
|
|
PlayerEntranceCtrl = $0710
|
|
GameTimerSetting = $0715
|
|
AltEntranceControl = $0752
|
|
EntrancePage = $0751
|
|
NumberOfPlayers = $077a
|
|
WarpZoneControl = $06d6
|
|
ChangeAreaTimer = $06de
|
|
|
|
MultiLoopCorrectCntr = $06d9
|
|
MultiLoopPassCntr = $06da
|
|
|
|
FetchNewGameTimerFlag = $0757
|
|
GameTimerExpiredFlag = $0759
|
|
|
|
PrimaryHardMode = $076a
|
|
SecondaryHardMode = $06cc
|
|
WorldSelectNumber = $076b
|
|
WorldSelectEnableFlag = $07fc
|
|
ContinueWorld = $07fd
|
|
|
|
CurrentPlayer = $0753
|
|
PlayerSize = $0754
|
|
PlayerStatus = $0756
|
|
|
|
OnscreenPlayerInfo = $075a
|
|
NumberofLives = $075a ;used by current player
|
|
HalfwayPage = $075b
|
|
LevelNumber = $075c ;the actual dash number
|
|
Hidden1UpFlag = $075d
|
|
CoinTally = $075e
|
|
WorldNumber = $075f
|
|
AreaNumber = $0760 ;internal number used to find areas
|
|
|
|
CoinTallyFor1Ups = $0748
|
|
|
|
OffscreenPlayerInfo = $0761
|
|
OffScr_NumberofLives = $0761 ;used by offscreen player
|
|
OffScr_HalfwayPage = $0762
|
|
OffScr_LevelNumber = $0763
|
|
OffScr_Hidden1UpFlag = $0764
|
|
OffScr_CoinTally = $0765
|
|
OffScr_WorldNumber = $0766
|
|
OffScr_AreaNumber = $0767
|
|
|
|
BalPlatformAlignment = $03a0
|
|
Platform_X_Scroll = $03a1
|
|
PlatformCollisionFlag = $03a2
|
|
YPlatformTopYPos = $0401
|
|
YPlatformCenterYPos = $58
|
|
|
|
BrickCoinTimerFlag = $06bc
|
|
StarFlagTaskControl = $0746
|
|
|
|
PseudoRandomBitReg = $07a7
|
|
WarmBootValidation = $07ff
|
|
|
|
SprShuffleAmtOffset = $06e0
|
|
SprShuffleAmt = $06e1
|
|
SprDataOffset = $06e4
|
|
Player_SprDataOffset = $06e4
|
|
Enemy_SprDataOffset = $06e5
|
|
Block_SprDataOffset = $06ec
|
|
Alt_SprDataOffset = $06ec
|
|
Bubble_SprDataOffset = $06ee
|
|
FBall_SprDataOffset = $06f1
|
|
Misc_SprDataOffset = $06f3
|
|
SprDataOffset_Ctrl = $03ee
|
|
|
|
Player_State = $1d
|
|
Enemy_State = $1e
|
|
Fireball_State = $24
|
|
Block_State = $26
|
|
Misc_State = $2a
|
|
|
|
Player_MovingDir = $45
|
|
Enemy_MovingDir = $46
|
|
|
|
SprObject_X_Speed = $57
|
|
Player_X_Speed = $57
|
|
Enemy_X_Speed = $58
|
|
Fireball_X_Speed = $5e
|
|
Block_X_Speed = $60
|
|
Misc_X_Speed = $64
|
|
|
|
Jumpspring_FixedYPos = $58
|
|
JumpspringAnimCtrl = $070e
|
|
JumpspringForce = $06db
|
|
|
|
SprObject_PageLoc = $6d
|
|
Player_PageLoc = $6d
|
|
Enemy_PageLoc = $6e
|
|
Fireball_PageLoc = $74
|
|
Block_PageLoc = $76
|
|
Misc_PageLoc = $7a
|
|
Bubble_PageLoc = $83
|
|
|
|
SprObject_X_Position = $86
|
|
Player_X_Position = $86
|
|
Enemy_X_Position = $87
|
|
Fireball_X_Position = $8d
|
|
Block_X_Position = $8f
|
|
Misc_X_Position = $93
|
|
Bubble_X_Position = $9c
|
|
|
|
SprObject_Y_Speed = $9f
|
|
Player_Y_Speed = $9f
|
|
Enemy_Y_Speed = $a0
|
|
Fireball_Y_Speed = $a6
|
|
Block_Y_Speed = $a8
|
|
Misc_Y_Speed = $ac
|
|
|
|
SprObject_Y_HighPos = $b5
|
|
Player_Y_HighPos = $b5
|
|
Enemy_Y_HighPos = $b6
|
|
Fireball_Y_HighPos = $bc
|
|
Block_Y_HighPos = $be
|
|
Misc_Y_HighPos = $c2
|
|
Bubble_Y_HighPos = $cb
|
|
|
|
SprObject_Y_Position = $ce
|
|
Player_Y_Position = $ce
|
|
Enemy_Y_Position = $cf
|
|
Fireball_Y_Position = $d5
|
|
Block_Y_Position = $d7
|
|
Misc_Y_Position = $db
|
|
Bubble_Y_Position = $e4
|
|
|
|
SprObject_Rel_XPos = $03ad
|
|
Player_Rel_XPos = $03ad
|
|
Enemy_Rel_XPos = $03ae
|
|
Fireball_Rel_XPos = $03af
|
|
Bubble_Rel_XPos = $03b0
|
|
Block_Rel_XPos = $03b1
|
|
Misc_Rel_XPos = $03b3
|
|
|
|
SprObject_Rel_YPos = $03b8
|
|
Player_Rel_YPos = $03b8
|
|
Enemy_Rel_YPos = $03b9
|
|
Fireball_Rel_YPos = $03ba
|
|
Bubble_Rel_YPos = $03bb
|
|
Block_Rel_YPos = $03bc
|
|
Misc_Rel_YPos = $03be
|
|
|
|
SprObject_SprAttrib = $03c4
|
|
Player_SprAttrib = $03c4
|
|
Enemy_SprAttrib = $03c5
|
|
|
|
SprObject_X_MoveForce = $0400
|
|
Enemy_X_MoveForce = $0401
|
|
|
|
SprObject_YMF_Dummy = $0416
|
|
Player_YMF_Dummy = $0416
|
|
Enemy_YMF_Dummy = $0417
|
|
Bubble_YMF_Dummy = $042c
|
|
|
|
SprObject_Y_MoveForce = $0433
|
|
Player_Y_MoveForce = $0433
|
|
Enemy_Y_MoveForce = $0434
|
|
Block_Y_MoveForce = $043c
|
|
|
|
DisableCollisionDet = $0716
|
|
Player_CollisionBits = $0490
|
|
Enemy_CollisionBits = $0491
|
|
|
|
SprObj_BoundBoxCtrl = $0499
|
|
Player_BoundBoxCtrl = $0499
|
|
Enemy_BoundBoxCtrl = $049a
|
|
Fireball_BoundBoxCtrl = $04a0
|
|
Misc_BoundBoxCtrl = $04a2
|
|
|
|
EnemyFrenzyBuffer = $06cb
|
|
EnemyFrenzyQueue = $06cd
|
|
Enemy_Flag = $0f
|
|
Enemy_ID = $16
|
|
|
|
PlayerGfxOffset = $06d5
|
|
Player_XSpeedAbsolute = $0700
|
|
FrictionAdderHigh = $0701
|
|
FrictionAdderLow = $0702
|
|
RunningSpeed = $0703
|
|
SwimmingFlag = $0704
|
|
Player_X_MoveForce = $0705
|
|
DiffToHaltJump = $0706
|
|
JumpOrigin_Y_HighPos = $0707
|
|
JumpOrigin_Y_Position = $0708
|
|
VerticalForce = $0709
|
|
VerticalForceDown = $070a
|
|
PlayerChangeSizeFlag = $070b
|
|
PlayerAnimTimerSet = $070c
|
|
PlayerAnimCtrl = $070d
|
|
DeathMusicLoaded = $0712
|
|
FlagpoleSoundQueue = $0713
|
|
CrouchingFlag = $0714
|
|
MaximumLeftSpeed = $0450
|
|
MaximumRightSpeed = $0456
|
|
|
|
SprObject_OffscrBits = $03d0
|
|
Player_OffscreenBits = $03d0
|
|
Enemy_OffscreenBits = $03d1
|
|
FBall_OffscreenBits = $03d2
|
|
Bubble_OffscreenBits = $03d3
|
|
Block_OffscreenBits = $03d4
|
|
Misc_OffscreenBits = $03d6
|
|
EnemyOffscrBitsMasked = $03d8
|
|
|
|
Cannon_Offset = $046a
|
|
Cannon_PageLoc = $046b
|
|
Cannon_X_Position = $0471
|
|
Cannon_Y_Position = $0477
|
|
Cannon_Timer = $047d
|
|
|
|
Whirlpool_Offset = $046a
|
|
Whirlpool_PageLoc = $046b
|
|
Whirlpool_LeftExtent = $0471
|
|
Whirlpool_Length = $0477
|
|
Whirlpool_Flag = $047d
|
|
|
|
VineFlagOffset = $0398
|
|
VineHeight = $0399
|
|
VineObjOffset = $039a
|
|
VineStart_Y_Position = $039d
|
|
|
|
Block_Orig_YPos = $03e4
|
|
Block_BBuf_Low = $03e6
|
|
Block_Metatile = $03e8
|
|
Block_PageLoc2 = $03ea
|
|
Block_RepFlag = $03ec
|
|
Block_ResidualCounter = $03f0
|
|
Block_Orig_XPos = $03f1
|
|
|
|
BoundingBox_UL_XPos = $04ac
|
|
BoundingBox_UL_YPos = $04ad
|
|
BoundingBox_DR_XPos = $04ae
|
|
BoundingBox_DR_YPos = $04af
|
|
BoundingBox_UL_Corner = $04ac
|
|
BoundingBox_LR_Corner = $04ae
|
|
EnemyBoundingBoxCoord = $04b0
|
|
|
|
PowerUpType = $39
|
|
|
|
FireballBouncingFlag = $3a
|
|
FireballCounter = $06ce
|
|
FireballThrowingTimer = $0711
|
|
|
|
HammerEnemyOffset = $06ae
|
|
JumpCoinMiscOffset = $06b7
|
|
|
|
Block_Buffer_1 = $0500
|
|
Block_Buffer_2 = $05d0
|
|
|
|
HammerThrowingTimer = $03a2
|
|
HammerBroJumpTimer = $3c
|
|
Misc_Collision_Flag = $06be
|
|
|
|
RedPTroopaOrigXPos = $0401
|
|
RedPTroopaCenterYPos = $58
|
|
|
|
XMovePrimaryCounter = $a0
|
|
XMoveSecondaryCounter = $58
|
|
|
|
CheepCheepMoveMFlag = $58
|
|
CheepCheepOrigYPos = $0434
|
|
BitMFilter = $06dd
|
|
|
|
LakituReappearTimer = $06d1
|
|
LakituMoveSpeed = $58
|
|
LakituMoveDirection = $a0
|
|
|
|
FirebarSpinState_Low = $58
|
|
FirebarSpinState_High = $a0
|
|
FirebarSpinSpeed = $0388
|
|
FirebarSpinDirection = $34
|
|
|
|
DuplicateObj_Offset = $06cf
|
|
NumberofGroupEnemies = $06d3
|
|
|
|
BlooperMoveCounter = $a0
|
|
BlooperMoveSpeed = $58
|
|
|
|
BowserBodyControls = $0363
|
|
BowserFeetCounter = $0364
|
|
BowserMovementSpeed = $0365
|
|
BowserOrigXPos = $0366
|
|
BowserFlameTimerCtrl = $0367
|
|
BowserFront_Offset = $0368
|
|
BridgeCollapseOffset = $0369
|
|
BowserGfxFlag = $036a
|
|
BowserHitPoints = $0483
|
|
MaxRangeFromOrigin = $06dc
|
|
|
|
BowserFlamePRandomOfs = $0417
|
|
|
|
PiranhaPlantUpYPos = $0417
|
|
PiranhaPlantDownYPos = $0434
|
|
PiranhaPlant_Y_Speed = $58
|
|
PiranhaPlant_MoveFlag = $a0
|
|
|
|
FireworksCounter = $06d7
|
|
ExplosionGfxCounter = $58
|
|
ExplosionTimerCounter = $a0
|
|
|
|
;sound related defines
|
|
Squ2_NoteLenBuffer = $07b3
|
|
Squ2_NoteLenCounter = $07b4
|
|
Squ2_EnvelopeDataCtrl = $07b5
|
|
Squ1_NoteLenCounter = $07b6
|
|
Squ1_EnvelopeDataCtrl = $07b7
|
|
Tri_NoteLenBuffer = $07b8
|
|
Tri_NoteLenCounter = $07b9
|
|
Noise_BeatLenCounter = $07ba
|
|
Squ1_SfxLenCounter = $07bb
|
|
Squ2_SfxLenCounter = $07bd
|
|
Sfx_SecondaryCounter = $07be
|
|
Noise_SfxLenCounter = $07bf
|
|
|
|
PauseSoundQueue = $fa
|
|
Square1SoundQueue = $ff
|
|
Square2SoundQueue = $fe
|
|
NoiseSoundQueue = $fd
|
|
AreaMusicQueue = $fb
|
|
EventMusicQueue = $fc
|
|
|
|
Square1SoundBuffer = $f1
|
|
Square2SoundBuffer = $f2
|
|
NoiseSoundBuffer = $f3
|
|
AreaMusicBuffer = $f4
|
|
EventMusicBuffer = $07b1
|
|
PauseSoundBuffer = $07b2
|
|
|
|
MusicData = $f5
|
|
MusicDataLow = $f5
|
|
MusicDataHigh = $f6
|
|
MusicOffset_Square2 = $f7
|
|
MusicOffset_Square1 = $f8
|
|
MusicOffset_Triangle = $f9
|
|
MusicOffset_Noise = $07b0
|
|
|
|
NoteLenLookupTblOfs = $f0
|
|
DAC_Counter = $07c0
|
|
NoiseDataLoopbackOfs = $07c1
|
|
NoteLengthTblAdder = $07c4
|
|
AreaMusicBuffer_Alt = $07c5
|
|
PauseModeFlag = $07c6
|
|
GroundMusicHeaderOfs = $07c7
|
|
AltRegContentFlag = $07ca
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;CONSTANTS
|
|
|
|
;sound effects constants
|
|
Sfx_SmallJump = %10000000
|
|
Sfx_Flagpole = %01000000
|
|
Sfx_Fireball = %00100000
|
|
Sfx_PipeDown_Injury = %00010000
|
|
Sfx_EnemySmack = %00001000
|
|
Sfx_EnemyStomp = %00000100
|
|
Sfx_Bump = %00000010
|
|
Sfx_BigJump = %00000001
|
|
|
|
Sfx_BowserFall = %10000000
|
|
Sfx_ExtraLife = %01000000
|
|
Sfx_PowerUpGrab = %00100000
|
|
Sfx_TimerTick = %00010000
|
|
Sfx_Blast = %00001000
|
|
Sfx_GrowVine = %00000100
|
|
Sfx_GrowPowerUp = %00000010
|
|
Sfx_CoinGrab = %00000001
|
|
|
|
Sfx_BowserFlame = %00000010
|
|
Sfx_BrickShatter = %00000001
|
|
|
|
;music constants
|
|
Silence = %10000000
|
|
|
|
StarPowerMusic = %01000000
|
|
PipeIntroMusic = %00100000
|
|
CloudMusic = %00010000
|
|
CastleMusic = %00001000
|
|
UndergroundMusic = %00000100
|
|
WaterMusic = %00000010
|
|
GroundMusic = %00000001
|
|
|
|
TimeRunningOutMusic = %01000000
|
|
EndOfLevelMusic = %00100000
|
|
AltGameOverMusic = %00010000
|
|
EndOfCastleMusic = %00001000
|
|
VictoryMusic = %00000100
|
|
GameOverMusic = %00000010
|
|
DeathMusic = %00000001
|
|
|
|
;enemy object constants
|
|
GreenKoopa = $00
|
|
BuzzyBeetle = $02
|
|
RedKoopa = $03
|
|
HammerBro = $05
|
|
Goomba = $06
|
|
Bloober = $07
|
|
BulletBill_FrenzyVar = $08
|
|
GreyCheepCheep = $0a
|
|
RedCheepCheep = $0b
|
|
Podoboo = $0c
|
|
PiranhaPlant = $0d
|
|
GreenParatroopaJump = $0e
|
|
RedParatroopa = $0f
|
|
GreenParatroopaFly = $10
|
|
Lakitu = $11
|
|
Spiny = $12
|
|
FlyCheepCheepFrenzy = $14
|
|
FlyingCheepCheep = $14
|
|
BowserFlame = $15
|
|
Fireworks = $16
|
|
BBill_CCheep_Frenzy = $17
|
|
Stop_Frenzy = $18
|
|
Bowser = $2d
|
|
PowerUpObject = $2e
|
|
VineObject = $2f
|
|
FlagpoleFlagObject = $30
|
|
StarFlagObject = $31
|
|
JumpspringObject = $32
|
|
BulletBill_CannonVar = $33
|
|
RetainerObject = $35
|
|
TallEnemy = $09
|
|
|
|
;other constants
|
|
World1 = 0
|
|
World2 = 1
|
|
World3 = 2
|
|
World4 = 3
|
|
World5 = 4
|
|
World6 = 5
|
|
World7 = 6
|
|
World8 = 7
|
|
Level1 = 0
|
|
Level2 = 1
|
|
Level3 = 2
|
|
Level4 = 3
|
|
|
|
WarmBootOffset = <$07d6
|
|
ColdBootOffset = <$07fe
|
|
TitleScreenDataOffset = $1ec0
|
|
SoundMemory = $07b0
|
|
SwimTileRepOffset = PlayerGraphicsTable+$9e
|
|
MusicHeaderOffsetData = MusicHeaderData-1
|
|
MHD = MusicHeaderData
|
|
|
|
A_Button = %10000000
|
|
B_Button = %01000000
|
|
Select_Button = %00100000
|
|
Start_Button = %00010000
|
|
Up_Dir = %00001000
|
|
Down_Dir = %00000100
|
|
Left_Dir = %00000010
|
|
Right_Dir = %00000001
|
|
|
|
TitleScreenModeValue = 0
|
|
GameModeValue = 1
|
|
VictoryModeValue = 2
|
|
GameOverModeValue = 3
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;DIRECTIVES
|
|
|
|
; .index 8
|
|
; .mem 8
|
|
|
|
org $8000
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
mx %11
|
|
; External wrapper is responsible for setting the stack
|
|
Start
|
|
; sei ;pretty standard 6502 type init here
|
|
; cld
|
|
lda #%00010000 ;init PPU control register 1
|
|
sta PPU_CTRL_REG1
|
|
; ldx #$ff ;reset stack pointer
|
|
; txs
|
|
VBlank1 lda PPU_STATUS ;wait two frames
|
|
bpl VBlank1
|
|
VBlank2 lda PPU_STATUS
|
|
bpl VBlank2
|
|
ldy #ColdBootOffset ;load default cold boot pointer
|
|
ldx #$05 ;this is where we check for a warm boot
|
|
WBootCheck lda TopScoreDisplay,x ;check each score digit in the top score
|
|
cmp #10 ;to see if we have a valid digit
|
|
bcs ColdBoot ;if not, give up and proceed with cold boot
|
|
dex
|
|
bpl WBootCheck
|
|
lda WarmBootValidation ;second checkpoint, check to see if
|
|
cmp #$a5 ;another location has a specific value
|
|
bne ColdBoot
|
|
ldy #WarmBootOffset ;if passed both, load warm boot pointer
|
|
ColdBoot jsr InitializeMemory ;clear memory using pointer in Y
|
|
sta SND_DELTA_REG+1 ;reset delta counter load register
|
|
sta OperMode ;reset primary mode of operation
|
|
lda #$a5 ;set warm boot flag
|
|
sta WarmBootValidation
|
|
sta PseudoRandomBitReg ;set seed for pseudorandom register
|
|
lda #%00001111
|
|
sta SND_MASTERCTRL_REG ;enable all sound channels except dmc
|
|
lda #%00000110
|
|
sta PPU_CTRL_REG2 ;turn off clipping for OAM and background
|
|
jsr MoveAllSpritesOffscreen
|
|
jsr InitializeNameTables ;initialize both name tables
|
|
inc DisableScreenFlag ;set flag to disable screen output
|
|
lda Mirror_PPU_CTRL_REG1
|
|
ora #%10000000 ;enable NMIs
|
|
jsr WritePPUReg1
|
|
; EndlessLoop jmp EndlessLoop ;endless loop, need I say more?
|
|
rtl ; GTE - Return to caller
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$00 - vram buffer address table low, also used for pseudorandom bit
|
|
;$01 - vram buffer address table high
|
|
|
|
VRAM_AddrTable_Low
|
|
db <VRAM_Buffer1,<WaterPaletteData,
|
|
db <UndergroundPaletteData,<CastlePaletteData,
|
|
db <VRAM_Buffer2,<VRAM_Buffer2,
|
|
db <DaySnowPaletteData,<NightSnowPaletteData,
|
|
db <MarioThanksMessage,<LuigiThanksMessage,
|
|
db <PrincessSaved1,<PrincessSaved2,
|
|
db <WorldSelectMessage2
|
|
|
|
VRAM_AddrTable_High
|
|
db >VRAM_Buffer1,>WaterPaletteData,
|
|
db >UndergroundPaletteData,>CastlePaletteData,
|
|
db >VRAM_Buffer2,>VRAM_Buffer2,
|
|
db >DaySnowPaletteData,>NightSnowPaletteData,
|
|
db >MarioThanksMessage,>LuigiThanksMessage,
|
|
db >PrincessSaved1,>PrincessSaved2,
|
|
db >WorldSelectMessage2
|
|
|
|
VRAM_Buffer_Offset
|
|
db <VRAM_Buffer1_Offset,<VRAM_Buffer2_Offset
|
|
|
|
; This is the actual entry point (60 times per second to keep speeed). Uncomment hardware
|
|
; stuf that doesn't need to be communicated to the GTE wrapper
|
|
NonMaskableInterrupt
|
|
; lda Mirror_PPU_CTRL_REG1 ;disable NMIs in mirror reg
|
|
; and #%01111111 ;save all other bits
|
|
; sta Mirror_PPU_CTRL_REG1
|
|
and #%01111110 ;alter name table address to be $2800
|
|
sta PPU_CTRL_REG1 ;(essentially $2000) but save other bits
|
|
lda Mirror_PPU_CTRL_REG2 ;disable OAM and background display by default
|
|
and #%11100110
|
|
ldy DisableScreenFlag ;get screen disable flag
|
|
bne ScreenOff ;if set, used bits as-is
|
|
lda Mirror_PPU_CTRL_REG2 ;otherwise reenable bits and save them
|
|
ora #%00011110
|
|
ScreenOff sta Mirror_PPU_CTRL_REG2 ;save bits for later but not in register at the moment
|
|
and #%11100111 ;disable screen for now
|
|
sta PPU_CTRL_REG2
|
|
ldx PPU_STATUS ;reset flip-flop and reset scroll registers to zero
|
|
lda #$00
|
|
jsr InitScroll
|
|
sta PPU_SPR_ADDR ;reset spr-ram address register
|
|
lda #$02 ;perform spr-ram DMA access on $0200-$02ff
|
|
sta SPR_DMA
|
|
ldx VRAM_Buffer_AddrCtrl ;load control for pointer to buffer contents
|
|
lda VRAM_AddrTable_Low,x ;set indirect at $00 to pointer
|
|
sta $00
|
|
lda VRAM_AddrTable_High,x
|
|
sta $01
|
|
jsr UpdateScreen ;update screen with buffer contents
|
|
ldy #$00
|
|
ldx VRAM_Buffer_AddrCtrl ;check for usage of $0341
|
|
cpx #$06
|
|
bne InitBuffer
|
|
iny ;get offset based on usage
|
|
InitBuffer ldx VRAM_Buffer_Offset,y
|
|
lda #$00 ;clear buffer header at last location
|
|
sta VRAM_Buffer1_Offset,x
|
|
sta VRAM_Buffer1,x
|
|
sta VRAM_Buffer_AddrCtrl ;reinit address control to $0301
|
|
lda Mirror_PPU_CTRL_REG2 ;copy mirror of $2001 to register
|
|
sta PPU_CTRL_REG2
|
|
jsr SoundEngine ;play sound
|
|
jsr ReadJoypads ;read joypads
|
|
jsr PauseRoutine ;handle pause
|
|
jsr UpdateTopScore
|
|
lda GamePauseStatus ;check for pause status
|
|
lsr
|
|
bcs PauseSkip
|
|
lda TimerControl ;if master timer control not set, decrement
|
|
beq DecTimers ;all frame and interval timers
|
|
dec TimerControl
|
|
bne NoDecTimers
|
|
DecTimers ldx #$14 ;load end offset for end of frame timers
|
|
dec IntervalTimerControl ;decrement interval timer control,
|
|
bpl DecTimersLoop ;if not expired, only frame timers will decrement
|
|
lda #$14
|
|
sta IntervalTimerControl ;if control for interval timers expired,
|
|
ldx #$23 ;interval timers will decrement along with frame timers
|
|
DecTimersLoop lda Timers,x ;check current timer
|
|
beq SkipExpTimer ;if current timer expired, branch to skip,
|
|
dec Timers,x ;otherwise decrement the current timer
|
|
SkipExpTimer dex ;move onto next timer
|
|
bpl DecTimersLoop ;do this until all timers are dealt with
|
|
NoDecTimers inc FrameCounter ;increment frame counter
|
|
PauseSkip ldx #$00
|
|
ldy #$07
|
|
lda PseudoRandomBitReg ;get first memory location of LSFR bytes
|
|
and #%00000010 ;mask out all but d1
|
|
sta $00 ;save here
|
|
lda PseudoRandomBitReg+1 ;get second memory location
|
|
and #%00000010 ;mask out all but d1
|
|
eor $00 ;perform exclusive-OR on d1 from first and second bytes
|
|
clc ;if neither or both are set, carry will be clear
|
|
beq RotPRandomBit
|
|
sec ;if one or the other is set, carry will be set
|
|
RotPRandomBit ror PseudoRandomBitReg,x ;rotate carry into d7, and rotate last bit into carry
|
|
inx ;increment to next byte
|
|
dey ;decrement for loop
|
|
bne RotPRandomBit
|
|
lda Sprite0HitDetectFlag ;check for flag here
|
|
beq SkipSprite0
|
|
Sprite0Clr lda PPU_STATUS ;wait for sprite 0 flag to clear, which will
|
|
and #%01000000 ;not happen until vblank has ended
|
|
bne Sprite0Clr
|
|
lda GamePauseStatus ;if in pause mode, do not bother with sprites at all
|
|
lsr
|
|
bcs Sprite0Hit
|
|
jsr MoveSpritesOffscreen
|
|
jsr SpriteShuffler
|
|
Sprite0Hit lda PPU_STATUS ;do sprite #0 hit detection
|
|
and #%01000000
|
|
beq Sprite0Hit
|
|
ldy #$14 ;small delay, to wait until we hit horizontal blank time
|
|
HBlankDelay dey
|
|
bne HBlankDelay
|
|
SkipSprite0 lda HorizontalScroll ;set scroll registers from variables
|
|
sta PPU_SCROLL_REG
|
|
lda VerticalScroll
|
|
sta PPU_SCROLL_REG
|
|
lda Mirror_PPU_CTRL_REG1 ;load saved mirror of $2000
|
|
pha
|
|
sta PPU_CTRL_REG1
|
|
lda GamePauseStatus ;if in pause mode, do not perform operation mode stuff
|
|
lsr
|
|
bcs SkipMainOper
|
|
jsr OperModeExecutionTree ;otherwise do one of many, many possible subroutines
|
|
SkipMainOper lda PPU_STATUS ;reset flip-flop
|
|
pla
|
|
ora #%10000000 ;reactivate NMIs
|
|
sta PPU_CTRL_REG1
|
|
; rti ;we are done until the next frame!
|
|
rtl
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
PauseRoutine
|
|
lda OperMode ;are we in victory mode?
|
|
cmp #VictoryModeValue ;if so, go ahead
|
|
beq ChkPauseTimer
|
|
cmp #GameModeValue ;are we in game mode?
|
|
bne ExitPause ;if not, leave
|
|
lda OperMode_Task ;if we are in game mode, are we running game engine?
|
|
cmp #$03
|
|
bne ExitPause ;if not, leave
|
|
ChkPauseTimer lda GamePauseTimer ;check if pause timer is still counting down
|
|
beq ChkStart
|
|
dec GamePauseTimer ;if so, decrement and leave
|
|
rts
|
|
ChkStart lda SavedJoypad1Bits ;check to see if start is pressed
|
|
and #Start_Button ;on controller 1
|
|
beq ClrPauseTimer
|
|
lda GamePauseStatus ;check to see if timer flag is set
|
|
and #%10000000 ;and if so, do not reset timer (residual,
|
|
bne ExitPause ;joypad reading routine makes this unnecessary)
|
|
lda #$2b ;set pause timer
|
|
sta GamePauseTimer
|
|
lda GamePauseStatus
|
|
tay
|
|
iny ;set pause sfx queue for next pause mode
|
|
sty PauseSoundQueue
|
|
eor #%00000001 ;invert d0 and set d7
|
|
ora #%10000000
|
|
bne SetPause ;unconditional branch
|
|
ClrPauseTimer lda GamePauseStatus ;clear timer flag if timer is at zero and start button
|
|
and #%01111111 ;is not pressed
|
|
SetPause sta GamePauseStatus
|
|
ExitPause rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$00 - used for preset value
|
|
|
|
SpriteShuffler
|
|
ldy AreaType ;load level type, likely residual code
|
|
lda #$28 ;load preset value which will put it at
|
|
sta $00 ;sprite #10
|
|
ldx #$0e ;start at the end of OAM data offsets
|
|
ShuffleLoop lda SprDataOffset,x ;check for offset value against
|
|
cmp $00 ;the preset value
|
|
bcc NextSprOffset ;if less, skip this part
|
|
ldy SprShuffleAmtOffset ;get current offset to preset value we want to add
|
|
clc
|
|
adc SprShuffleAmt,y ;get shuffle amount, add to current sprite offset
|
|
bcc StrSprOffset ;if not exceeded $ff, skip second add
|
|
clc
|
|
adc $00 ;otherwise add preset value $28 to offset
|
|
StrSprOffset sta SprDataOffset,x ;store new offset here or old one if branched to here
|
|
NextSprOffset dex ;move backwards to next one
|
|
bpl ShuffleLoop
|
|
ldx SprShuffleAmtOffset ;load offset
|
|
inx
|
|
cpx #$03 ;check if offset + 1 goes to 3
|
|
bne SetAmtOffset ;if offset + 1 not 3, store
|
|
ldx #$00 ;otherwise, init to 0
|
|
SetAmtOffset stx SprShuffleAmtOffset
|
|
ldx #$08 ;load offsets for values and storage
|
|
ldy #$02
|
|
SetMiscOffset lda SprDataOffset+5,y ;load one of three OAM data offsets
|
|
sta Misc_SprDataOffset-2,x ;store first one unmodified, but
|
|
clc ;add eight to the second and eight
|
|
adc #$08 ;more to the third one
|
|
sta Misc_SprDataOffset-1,x ;note that due to the way X is set up,
|
|
clc ;this code loads into the misc sprite offsets
|
|
adc #$08
|
|
sta Misc_SprDataOffset,x
|
|
dex
|
|
dex
|
|
dex
|
|
dey
|
|
bpl SetMiscOffset ;do this until all misc spr offsets are loaded
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
OperModeExecutionTree
|
|
lda OperMode ;this is the heart of the entire program,
|
|
jsr JumpEngine ;most of what goes on starts here
|
|
|
|
dw TitleScreenMode
|
|
dw GameMode
|
|
dw VictoryMode
|
|
dw GameOverMode
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
MoveAllSpritesOffscreen
|
|
ldy #$00 ;this routine moves all sprites off the screen
|
|
db $2c ;BIT instruction opcode
|
|
|
|
MoveSpritesOffscreen
|
|
ldy #$04 ;this routine moves all but sprite 0
|
|
lda #$f8 ;off the screen
|
|
SprInitLoop sta Sprite_Y_Position,y ;write 248 into OAM data's Y coordinate
|
|
iny ;which will move it off the screen
|
|
iny
|
|
iny
|
|
iny
|
|
bne SprInitLoop
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
TitleScreenMode
|
|
lda OperMode_Task
|
|
jsr JumpEngine
|
|
|
|
dw InitializeGame
|
|
dw ScreenRoutines
|
|
dw PrimaryGameSetup
|
|
dw GameMenuRoutine
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
WSelectBufferTemplate
|
|
db $04,$20,$73,$01,$00,$00
|
|
|
|
GameMenuRoutine
|
|
ldy #$00
|
|
lda SavedJoypad1Bits ;check to see if either player pressed
|
|
ora SavedJoypad2Bits ;only the start button (either joypad)
|
|
cmp #Start_Button
|
|
beq StartGame
|
|
cmp #A_Button+Start_Button ;check to see if A + start was pressed
|
|
bne ChkSelect ;if not, branch to check select button
|
|
StartGame jmp ChkContinue ;if either start or A + start, execute here
|
|
ChkSelect cmp #Select_Button ;check to see if the select button was pressed
|
|
beq SelectBLogic ;if so, branch reset demo timer
|
|
ldx DemoTimer ;otherwise check demo timer
|
|
bne ChkWorldSel ;if demo timer not expired, branch to check world selection
|
|
sta SelectTimer ;set controller bits here if running demo
|
|
jsr DemoEngine ;run through the demo actions
|
|
bcs ResetTitle ;if carry flag set, demo over, thus branch
|
|
jmp RunDemo ;otherwise, run game engine for demo
|
|
ChkWorldSel ldx WorldSelectEnableFlag ;check to see if world selection has been enabled
|
|
beq NullJoypad
|
|
cmp #B_Button ;if so, check to see if the B button was pressed
|
|
bne NullJoypad
|
|
iny ;if so, increment Y and execute same code as select
|
|
SelectBLogic lda DemoTimer ;if select or B pressed, check demo timer one last time
|
|
beq ResetTitle ;if demo timer expired, branch to reset title screen mode
|
|
lda #$18 ;otherwise reset demo timer
|
|
sta DemoTimer
|
|
lda SelectTimer ;check select/B button timer
|
|
bne NullJoypad ;if not expired, branch
|
|
lda #$10 ;otherwise reset select button timer
|
|
sta SelectTimer
|
|
cpy #$01 ;was the B button pressed earlier? if so, branch
|
|
beq IncWorldSel ;note this will not be run if world selection is disabled
|
|
lda NumberOfPlayers ;if no, must have been the select button, therefore
|
|
eor #%00000001 ;change number of players and draw icon accordingly
|
|
sta NumberOfPlayers
|
|
jsr DrawMushroomIcon
|
|
jmp NullJoypad
|
|
IncWorldSel ldx WorldSelectNumber ;increment world select number
|
|
inx
|
|
txa
|
|
and #%00000111 ;mask out higher bits
|
|
sta WorldSelectNumber ;store as current world select number
|
|
jsr GoContinue
|
|
UpdateShroom lda WSelectBufferTemplate,x ;write template for world select in vram buffer
|
|
sta VRAM_Buffer1-1,x ;do this until all bytes are written
|
|
inx
|
|
cpx #$06
|
|
bmi UpdateShroom
|
|
ldy WorldNumber ;get world number from variable and increment for
|
|
iny ;proper display, and put in blank byte before
|
|
sty VRAM_Buffer1+3 ;null terminator
|
|
NullJoypad lda #$00 ;clear joypad bits for player 1
|
|
sta SavedJoypad1Bits
|
|
RunDemo jsr GameCoreRoutine ;run game engine
|
|
lda GameEngineSubroutine ;check to see if we're running lose life routine
|
|
cmp #$06
|
|
bne ExitMenu ;if not, do not do all the resetting below
|
|
ResetTitle lda #$00 ;reset game modes, disable
|
|
sta OperMode ;sprite 0 check and disable
|
|
sta OperMode_Task ;screen output
|
|
sta Sprite0HitDetectFlag
|
|
inc DisableScreenFlag
|
|
rts
|
|
ChkContinue ldy DemoTimer ;if timer for demo has expired, reset modes
|
|
beq ResetTitle
|
|
asl ;check to see if A button was also pushed
|
|
bcc StartWorld1 ;if not, don't load continue function's world number
|
|
lda ContinueWorld ;load previously saved world number for secret
|
|
jsr GoContinue ;continue function when pressing A + start
|
|
StartWorld1 jsr LoadAreaPointer
|
|
inc Hidden1UpFlag ;set 1-up box flag for both players
|
|
inc OffScr_Hidden1UpFlag
|
|
inc FetchNewGameTimerFlag ;set fetch new game timer flag
|
|
inc OperMode ;set next game mode
|
|
lda WorldSelectEnableFlag ;if world select flag is on, then primary
|
|
sta PrimaryHardMode ;hard mode must be on as well
|
|
lda #$00
|
|
sta OperMode_Task ;set game mode here, and clear demo timer
|
|
sta DemoTimer
|
|
ldx #$17
|
|
lda #$00
|
|
InitScores sta ScoreAndCoinDisplay,x ;clear player scores and coin displays
|
|
dex
|
|
bpl InitScores
|
|
ExitMenu rts
|
|
GoContinue sta WorldNumber ;start both players at the first area
|
|
sta OffScr_WorldNumber ;of the previously saved world number
|
|
ldx #$00 ;note that on power-up using this function
|
|
stx AreaNumber ;will make no difference
|
|
stx OffScr_AreaNumber
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
MushroomIconData
|
|
db $07,$22,$49,$83,$ce,$24,$24,$00
|
|
|
|
DrawMushroomIcon
|
|
ldy #$07 ;read eight bytes to be read by transfer routine
|
|
IconDataRead lda MushroomIconData,y ;note that the default position is set for a
|
|
sta VRAM_Buffer1-1,y ;1-player game
|
|
dey
|
|
bpl IconDataRead
|
|
lda NumberOfPlayers ;check number of players
|
|
beq ExitIcon ;if set to 1-player game, we're done
|
|
lda #$24 ;otherwise, load blank tile in 1-player position
|
|
sta VRAM_Buffer1+3
|
|
lda #$ce ;then load shroom icon tile in 2-player position
|
|
sta VRAM_Buffer1+5
|
|
ExitIcon rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
DemoActionData
|
|
db $01,$80,$02,$81,$41,$80,$01
|
|
db $42,$c2,$02,$80,$41,$c1,$41,$c1
|
|
db $01,$c1,$01,$02,$80,$00
|
|
|
|
DemoTimingData
|
|
db $9b,$10,$18,$05,$2c,$20,$24
|
|
db $15,$5a,$10,$20,$28,$30,$20,$10
|
|
db $80,$20,$30,$30,$01,$ff,$00
|
|
|
|
DemoEngine
|
|
ldx DemoAction ;load current demo action
|
|
lda DemoActionTimer ;load current action timer
|
|
bne DoAction ;if timer still counting down, skip
|
|
inx
|
|
inc DemoAction ;if expired, increment action, X, and
|
|
sec ;set carry by default for demo over
|
|
lda DemoTimingData-1,x ;get next timer
|
|
sta DemoActionTimer ;store as current timer
|
|
beq DemoOver ;if timer already at zero, skip
|
|
DoAction lda DemoActionData-1,x ;get and perform action (current or next)
|
|
sta SavedJoypad1Bits
|
|
dec DemoActionTimer ;decrement action timer
|
|
clc ;clear carry if demo still going
|
|
DemoOver rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
VictoryMode
|
|
jsr VictoryModeSubroutines ;run victory mode subroutines
|
|
lda OperMode_Task ;get current task of victory mode
|
|
beq AutoPlayer ;if on bridge collapse, skip enemy processing
|
|
ldx #$00
|
|
stx ObjectOffset ;otherwise reset enemy object offset
|
|
jsr EnemiesAndLoopsCore ;and run enemy code
|
|
AutoPlayer jsr RelativePlayerPosition ;get player's relative coordinates
|
|
jmp PlayerGfxHandler ;draw the player, then leave
|
|
|
|
VictoryModeSubroutines
|
|
lda OperMode_Task
|
|
jsr JumpEngine
|
|
|
|
dw BridgeCollapse
|
|
dw SetupVictoryMode
|
|
dw PlayerVictoryWalk
|
|
dw PrintVictoryMessages
|
|
dw PlayerEndWorld
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
SetupVictoryMode
|
|
ldx ScreenRight_PageLoc ;get page location of right side of screen
|
|
inx ;increment to next page
|
|
stx DestinationPageLoc ;store here
|
|
lda #EndOfCastleMusic
|
|
sta EventMusicQueue ;play win castle music
|
|
jmp IncModeTask_B ;jump to set next major task in victory mode
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
PlayerVictoryWalk
|
|
ldy #$00 ;set value here to not walk player by default
|
|
sty VictoryWalkControl
|
|
lda Player_PageLoc ;get player's page location
|
|
cmp DestinationPageLoc ;compare with destination page location
|
|
bne PerformWalk ;if page locations don't match, branch
|
|
lda Player_X_Position ;otherwise get player's horizontal position
|
|
cmp #$60 ;compare with preset horizontal position
|
|
bcs DontWalk ;if still on other page, branch ahead
|
|
PerformWalk inc VictoryWalkControl ;otherwise increment value and Y
|
|
iny ;note Y will be used to walk the player
|
|
DontWalk tya ;put contents of Y in A and
|
|
jsr AutoControlPlayer ;use A to move player to the right or not
|
|
lda ScreenLeft_PageLoc ;check page location of left side of screen
|
|
cmp DestinationPageLoc ;against set value here
|
|
beq ExitVWalk ;branch if equal to change modes if necessary
|
|
lda ScrollFractional
|
|
clc ;do fixed point math on fractional part of scroll
|
|
adc #$80
|
|
sta ScrollFractional ;save fractional movement amount
|
|
lda #$01 ;set 1 pixel per frame
|
|
adc #$00 ;add carry from previous addition
|
|
tay ;use as scroll amount
|
|
jsr ScrollScreen ;do sub to scroll the screen
|
|
jsr UpdScrollVar ;do another sub to update screen and scroll variables
|
|
inc VictoryWalkControl ;increment value to stay in this routine
|
|
ExitVWalk lda VictoryWalkControl ;load value set here
|
|
beq IncModeTask_A ;if zero, branch to change modes
|
|
rts ;otherwise leave
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
PrintVictoryMessages
|
|
lda SecondaryMsgCounter ;load secondary message counter
|
|
bne IncMsgCounter ;if set, branch to increment message counters
|
|
lda PrimaryMsgCounter ;otherwise load primary message counter
|
|
beq ThankPlayer ;if set to zero, branch to print first message
|
|
cmp #$09 ;if at 9 or above, branch elsewhere (this comparison
|
|
bcs IncMsgCounter ;is residual code, counter never reaches 9)
|
|
ldy WorldNumber ;check world number
|
|
cpy #World8
|
|
bne MRetainerMsg ;if not at world 8, skip to next part
|
|
cmp #$03 ;check primary message counter again
|
|
bcc IncMsgCounter ;if not at 3 yet (world 8 only), branch to increment
|
|
sbc #$01 ;otherwise subtract one
|
|
jmp ThankPlayer ;and skip to next part
|
|
MRetainerMsg cmp #$02 ;check primary message counter
|
|
bcc IncMsgCounter ;if not at 2 yet (world 1-7 only), branch
|
|
ThankPlayer tay ;put primary message counter into Y
|
|
bne SecondPartMsg ;if counter nonzero, skip this part, do not print first message
|
|
lda CurrentPlayer ;otherwise get player currently on the screen
|
|
beq EvalForMusic ;if mario, branch
|
|
iny ;otherwise increment Y once for luigi and
|
|
bne EvalForMusic ;do an unconditional branch to the same place
|
|
SecondPartMsg iny ;increment Y to do world 8's message
|
|
lda WorldNumber
|
|
cmp #World8 ;check world number
|
|
beq EvalForMusic ;if at world 8, branch to next part
|
|
dey ;otherwise decrement Y for world 1-7's message
|
|
cpy #$04 ;if counter at 4 (world 1-7 only)
|
|
bcs SetEndTimer ;branch to set victory end timer
|
|
cpy #$03 ;if counter at 3 (world 1-7 only)
|
|
bcs IncMsgCounter ;branch to keep counting
|
|
EvalForMusic cpy #$03 ;if counter not yet at 3 (world 8 only), branch
|
|
bne PrintMsg ;to print message only (note world 1-7 will only
|
|
lda #VictoryMusic ;reach this code if counter = 0, and will always branch)
|
|
sta EventMusicQueue ;otherwise load victory music first (world 8 only)
|
|
PrintMsg tya ;put primary message counter in A
|
|
clc ;add $0c or 12 to counter thus giving an appropriate value,
|
|
adc #$0c ;($0c-$0d = first), ($0e = world 1-7's), ($0f-$12 = world 8's)
|
|
sta VRAM_Buffer_AddrCtrl ;write message counter to vram address controller
|
|
IncMsgCounter lda SecondaryMsgCounter
|
|
clc
|
|
adc #$04 ;add four to secondary message counter
|
|
sta SecondaryMsgCounter
|
|
lda PrimaryMsgCounter
|
|
adc #$00 ;add carry to primary message counter
|
|
sta PrimaryMsgCounter
|
|
cmp #$07 ;check primary counter one more time
|
|
SetEndTimer bcc ExitMsgs ;if not reached value yet, branch to leave
|
|
lda #$06
|
|
sta WorldEndTimer ;otherwise set world end timer
|
|
IncModeTask_A inc OperMode_Task ;move onto next task in mode
|
|
ExitMsgs rts ;leave
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
PlayerEndWorld
|
|
lda WorldEndTimer ;check to see if world end timer expired
|
|
bne EndExitOne ;branch to leave if not
|
|
ldy WorldNumber ;check world number
|
|
cpy #World8 ;if on world 8, player is done with game,
|
|
bcs EndChkBButton ;thus branch to read controller
|
|
lda #$00
|
|
sta AreaNumber ;otherwise initialize area number used as offset
|
|
sta LevelNumber ;and level number control to start at area 1
|
|
sta OperMode_Task ;initialize secondary mode of operation
|
|
inc WorldNumber ;increment world number to move onto the next world
|
|
jsr LoadAreaPointer ;get area address offset for the next area
|
|
inc FetchNewGameTimerFlag ;set flag to load game timer from header
|
|
lda #GameModeValue
|
|
sta OperMode ;set mode of operation to game mode
|
|
EndExitOne rts ;and leave
|
|
EndChkBButton lda SavedJoypad1Bits
|
|
ora SavedJoypad2Bits ;check to see if B button was pressed on
|
|
and #B_Button ;either controller
|
|
beq EndExitTwo ;branch to leave if not
|
|
lda #$01 ;otherwise set world selection flag
|
|
sta WorldSelectEnableFlag
|
|
lda #$ff ;remove onscreen player's lives
|
|
sta NumberofLives
|
|
jsr TerminateGame ;do sub to continue other player or end game
|
|
EndExitTwo rts ;leave
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
;data is used as tiles for numbers
|
|
;that appear when you defeat enemies
|
|
FloateyNumTileData
|
|
db $ff,$ff ;dummy
|
|
db $f6,$fb ; "100"
|
|
db $f7,$fb ; "200"
|
|
db $f8,$fb ; "400"
|
|
db $f9,$fb ; "500"
|
|
db $fa,$fb ; "800"
|
|
db $f6,$50 ; "1000"
|
|
db $f7,$50 ; "2000"
|
|
db $f8,$50 ; "4000"
|
|
db $f9,$50 ; "5000"
|
|
db $fa,$50 ; "8000"
|
|
db $fd,$fe ; "1-UP"
|
|
|
|
;high nybble is digit number, low nybble is number to
|
|
;add to the digit of the player's score
|
|
ScoreUpdateData
|
|
db $ff ;dummy
|
|
db $41,$42,$44,$45,$48
|
|
db $31,$32,$34,$35,$38,$00
|
|
|
|
FloateyNumbersRoutine
|
|
lda FloateyNum_Control,x ;load control for floatey number
|
|
beq EndExitOne ;if zero, branch to leave
|
|
cmp #$0b ;if less than $0b, branch
|
|
bcc ChkNumTimer
|
|
lda #$0b ;otherwise set to $0b, thus keeping
|
|
sta FloateyNum_Control,x ;it in range
|
|
ChkNumTimer tay ;use as Y
|
|
lda FloateyNum_Timer,x ;check value here
|
|
bne DecNumTimer ;if nonzero, branch ahead
|
|
sta FloateyNum_Control,x ;initialize floatey number control and leave
|
|
rts
|
|
DecNumTimer dec FloateyNum_Timer,x ;decrement value here
|
|
cmp #$2b ;if not reached a certain point, branch
|
|
bne ChkTallEnemy
|
|
cpy #$0b ;check offset for $0b
|
|
bne LoadNumTiles ;branch ahead if not found
|
|
inc NumberofLives ;give player one extra life (1-up)
|
|
lda #Sfx_ExtraLife
|
|
sta Square2SoundQueue ;and play the 1-up sound
|
|
LoadNumTiles lda ScoreUpdateData,y ;load point value here
|
|
lsr ;move high nybble to low
|
|
lsr
|
|
lsr
|
|
lsr
|
|
tax ;use as X offset, essentially the digit
|
|
lda ScoreUpdateData,y ;load again and this time
|
|
and #%00001111 ;mask out the high nybble
|
|
sta DigitModifier,x ;store as amount to add to the digit
|
|
jsr AddToScore ;update the score accordingly
|
|
ChkTallEnemy ldy Enemy_SprDataOffset,x ;get OAM data offset for enemy object
|
|
lda Enemy_ID,x ;get enemy object identifier
|
|
cmp #Spiny
|
|
beq FloateyPart ;branch if spiny
|
|
cmp #PiranhaPlant
|
|
beq FloateyPart ;branch if piranha plant
|
|
cmp #HammerBro
|
|
beq GetAltOffset ;branch elsewhere if hammer bro
|
|
cmp #GreyCheepCheep
|
|
beq FloateyPart ;branch if cheep-cheep of either color
|
|
cmp #RedCheepCheep
|
|
beq FloateyPart
|
|
cmp #TallEnemy
|
|
bcs GetAltOffset ;branch elsewhere if enemy object => $09
|
|
lda Enemy_State,x
|
|
cmp #$02 ;if enemy state defeated or otherwise
|
|
bcs FloateyPart ;$02 or greater, branch beyond this part
|
|
GetAltOffset ldx SprDataOffset_Ctrl ;load some kind of control bit
|
|
ldy Alt_SprDataOffset,x ;get alternate OAM data offset
|
|
ldx ObjectOffset ;get enemy object offset again
|
|
FloateyPart lda FloateyNum_Y_Pos,x ;get vertical coordinate for
|
|
cmp #$18 ;floatey number, if coordinate in the
|
|
bcc SetupNumSpr ;status bar, branch
|
|
sbc #$01
|
|
sta FloateyNum_Y_Pos,x ;otherwise subtract one and store as new
|
|
SetupNumSpr lda FloateyNum_Y_Pos,x ;get vertical coordinate
|
|
sbc #$08 ;subtract eight and dump into the
|
|
jsr DumpTwoSpr ;left and right sprite's Y coordinates
|
|
lda FloateyNum_X_Pos,x ;get horizontal coordinate
|
|
sta Sprite_X_Position,y ;store into X coordinate of left sprite
|
|
clc
|
|
adc #$08 ;add eight pixels and store into X
|
|
sta Sprite_X_Position+4,y ;coordinate of right sprite
|
|
lda #$02
|
|
sta Sprite_Attributes,y ;set palette control in attribute bytes
|
|
sta Sprite_Attributes+4,y ;of left and right sprites
|
|
lda FloateyNum_Control,x
|
|
asl ;multiply our floatey number control by 2
|
|
tax ;and use as offset for look-up table
|
|
lda FloateyNumTileData,x
|
|
sta Sprite_Tilenumber,y ;display first half of number of points
|
|
lda FloateyNumTileData+1,x
|
|
sta Sprite_Tilenumber+4,y ;display the second half
|
|
ldx ObjectOffset ;get enemy object offset and leave
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
ScreenRoutines
|
|
lda ScreenRoutineTask ;run one of the following subroutines
|
|
jsr JumpEngine
|
|
|
|
dw InitScreen
|
|
dw SetupIntermediate
|
|
dw WriteTopStatusLine
|
|
dw WriteBottomStatusLine
|
|
dw DisplayTimeUp
|
|
dw ResetSpritesAndScreenTimer
|
|
dw DisplayIntermediate
|
|
dw ResetSpritesAndScreenTimer
|
|
dw AreaParserTaskControl
|
|
dw GetAreaPalette
|
|
dw GetBackgroundColor
|
|
dw GetAlternatePalette1
|
|
dw DrawTitleScreen
|
|
dw ClearBuffersDrawIcon
|
|
dw WriteTopScore
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
InitScreen
|
|
jsr MoveAllSpritesOffscreen ;initialize all sprites including sprite #0
|
|
jsr InitializeNameTables ;and erase both name and attribute tables
|
|
lda OperMode
|
|
beq NextSubtask ;if mode still 0, do not load
|
|
ldx #$03 ;into buffer pointer
|
|
jmp SetVRAMAddr_A
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
SetupIntermediate
|
|
lda BackgroundColorCtrl ;save current background color control
|
|
pha ;and player status to stack
|
|
lda PlayerStatus
|
|
pha
|
|
lda #$00 ;set background color to black
|
|
sta PlayerStatus ;and player status to not fiery
|
|
lda #$02 ;this is the ONLY time background color control
|
|
sta BackgroundColorCtrl ;is set to less than 4
|
|
jsr GetPlayerColors
|
|
pla ;we only execute this routine for
|
|
sta PlayerStatus ;the intermediate lives display
|
|
pla ;and once we're done, we return bg
|
|
sta BackgroundColorCtrl ;color ctrl and player status from stack
|
|
jmp IncSubtask ;then move onto the next task
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
AreaPalette
|
|
db $01,$02,$03,$04
|
|
|
|
GetAreaPalette
|
|
ldy AreaType ;select appropriate palette to load
|
|
ldx AreaPalette,y ;based on area type
|
|
SetVRAMAddr_A stx VRAM_Buffer_AddrCtrl ;store offset into buffer control
|
|
NextSubtask jmp IncSubtask ;move onto next task
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$00 - used as temp counter in GetPlayerColors
|
|
|
|
BGColorCtrl_Addr
|
|
db $00,$09,$0a,$04
|
|
|
|
BackgroundColors
|
|
db $22,$22,$0f,$0f ;used by area type if bg color ctrl not set
|
|
db $0f,$22,$0f,$0f ;used by background color control if set
|
|
|
|
PlayerColors
|
|
db $22,$16,$27,$18 ;mario's colors
|
|
db $22,$30,$27,$19 ;luigi's colors
|
|
db $22,$37,$27,$16 ;fiery (used by both)
|
|
|
|
GetBackgroundColor
|
|
ldy BackgroundColorCtrl ;check background color control
|
|
beq NoBGColor ;if not set, increment task and fetch palette
|
|
lda BGColorCtrl_Addr-4,y ;put appropriate palette into vram
|
|
sta VRAM_Buffer_AddrCtrl ;note that if set to 5-7,$0301 will not be read
|
|
NoBGColor inc ScreenRoutineTask ;increment to next subtask and plod on through
|
|
|
|
GetPlayerColors
|
|
ldx VRAM_Buffer1_Offset ;get current buffer offset
|
|
ldy #$00
|
|
lda CurrentPlayer ;check which player is on the screen
|
|
beq ChkFiery
|
|
ldy #$04 ;load offset for luigi
|
|
ChkFiery lda PlayerStatus ;check player status
|
|
cmp #$02
|
|
bne StartClrGet ;if fiery, load alternate offset for fiery player
|
|
ldy #$08
|
|
StartClrGet lda #$03 ;do four colors
|
|
sta $00
|
|
ClrGetLoop lda PlayerColors,y ;fetch player colors and store them
|
|
sta VRAM_Buffer1+3,x ;in the buffer
|
|
iny
|
|
inx
|
|
dec $00
|
|
bpl ClrGetLoop
|
|
ldx VRAM_Buffer1_Offset ;load original offset from before
|
|
ldy BackgroundColorCtrl ;if this value is four or greater, it will be set
|
|
bne SetBGColor ;therefore use it as offset to background color
|
|
ldy AreaType ;otherwise use area type bits from area offset as offset
|
|
SetBGColor lda BackgroundColors,y ;to background color instead
|
|
sta VRAM_Buffer1+3,x
|
|
lda #$3f ;set for sprite palette address
|
|
sta VRAM_Buffer1,x ;save to buffer
|
|
lda #$10
|
|
sta VRAM_Buffer1+1,x
|
|
lda #$04 ;write length byte to buffer
|
|
sta VRAM_Buffer1+2,x
|
|
lda #$00 ;now the null terminator
|
|
sta VRAM_Buffer1+7,x
|
|
txa ;move the buffer pointer ahead 7 bytes
|
|
clc ;in case we want to write anything else later
|
|
adc #$07
|
|
SetVRAMOffset sta VRAM_Buffer1_Offset ;store as new vram buffer offset
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
GetAlternatePalette1
|
|
lda AreaStyle ;check for mushroom level style
|
|
cmp #$01
|
|
bne NoAltPal
|
|
lda #$0b ;if found, load appropriate palette
|
|
SetVRAMAddr_B sta VRAM_Buffer_AddrCtrl
|
|
NoAltPal jmp IncSubtask ;now onto the next task
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
WriteTopStatusLine
|
|
lda #$00 ;select main status bar
|
|
jsr WriteGameText ;output it
|
|
jmp IncSubtask ;onto the next task
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
WriteBottomStatusLine
|
|
jsr GetSBNybbles ;write player's score and coin tally to screen
|
|
ldx VRAM_Buffer1_Offset
|
|
lda #$20 ;write address for world-area number on screen
|
|
sta VRAM_Buffer1,x
|
|
lda #$73
|
|
sta VRAM_Buffer1+1,x
|
|
lda #$03 ;write length for it
|
|
sta VRAM_Buffer1+2,x
|
|
ldy WorldNumber ;first the world number
|
|
iny
|
|
tya
|
|
sta VRAM_Buffer1+3,x
|
|
lda #$28 ;next the dash
|
|
sta VRAM_Buffer1+4,x
|
|
ldy LevelNumber ;next the level number
|
|
iny ;increment for proper number display
|
|
tya
|
|
sta VRAM_Buffer1+5,x
|
|
lda #$00 ;put null terminator on
|
|
sta VRAM_Buffer1+6,x
|
|
txa ;move the buffer offset up by 6 bytes
|
|
clc
|
|
adc #$06
|
|
sta VRAM_Buffer1_Offset
|
|
jmp IncSubtask
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
DisplayTimeUp
|
|
lda GameTimerExpiredFlag ;if game timer not expired, increment task
|
|
beq NoTimeUp ;control 2 tasks forward, otherwise, stay here
|
|
lda #$00
|
|
sta GameTimerExpiredFlag ;reset timer expiration flag
|
|
lda #$02 ;output time-up screen to buffer
|
|
jmp OutputInter
|
|
NoTimeUp inc ScreenRoutineTask ;increment control task 2 tasks forward
|
|
jmp IncSubtask
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
DisplayIntermediate
|
|
lda OperMode ;check primary mode of operation
|
|
beq NoInter ;if in title screen mode, skip this
|
|
cmp #GameOverModeValue ;are we in game over mode?
|
|
beq GameOverInter ;if so, proceed to display game over screen
|
|
lda AltEntranceControl ;otherwise check for mode of alternate entry
|
|
bne NoInter ;and branch if found
|
|
ldy AreaType ;check if we are on castle level
|
|
cpy #$03 ;and if so, branch (possibly residual)
|
|
beq PlayerInter
|
|
lda DisableIntermediate ;if this flag is set, skip intermediate lives display
|
|
bne NoInter ;and jump to specific task, otherwise
|
|
PlayerInter jsr DrawPlayer_Intermediate ;put player in appropriate place for
|
|
lda #$01 ;lives display, then output lives display to buffer
|
|
OutputInter jsr WriteGameText
|
|
jsr ResetScreenTimer
|
|
lda #$00
|
|
sta DisableScreenFlag ;reenable screen output
|
|
rts
|
|
GameOverInter lda #$12 ;set screen timer
|
|
sta ScreenTimer
|
|
lda #$03 ;output game over screen to buffer
|
|
jsr WriteGameText
|
|
jmp IncModeTask_B
|
|
NoInter lda #$08 ;set for specific task and leave
|
|
sta ScreenRoutineTask
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
AreaParserTaskControl
|
|
inc DisableScreenFlag ;turn off screen
|
|
TaskLoop jsr AreaParserTaskHandler ;render column set of current area
|
|
lda AreaParserTaskNum ;check number of tasks
|
|
bne TaskLoop ;if tasks still not all done, do another one
|
|
dec ColumnSets ;do we need to render more column sets?
|
|
bpl OutputCol
|
|
inc ScreenRoutineTask ;if not, move on to the next task
|
|
OutputCol lda #$06 ;set vram buffer to output rendered column set
|
|
sta VRAM_Buffer_AddrCtrl ;on next NMI
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
;$00 - vram buffer address table low
|
|
;$01 - vram buffer address table high
|
|
|
|
DrawTitleScreen
|
|
lda OperMode ;are we in title screen mode?
|
|
bne IncModeTask_B ;if not, exit
|
|
lda #>TitleScreenDataOffset ;load address $1ec0 into
|
|
sta PPU_ADDRESS ;the vram address register
|
|
lda #<TitleScreenDataOffset
|
|
sta PPU_ADDRESS
|
|
lda #$03 ;put address $0300 into
|
|
sta $01 ;the indirect at $00
|
|
ldy #$00
|
|
sty $00
|
|
lda PPU_DATA ;do one garbage read
|
|
OutputTScr lda PPU_DATA ;get title screen from chr-rom
|
|
sta ($00),y ;store 256 bytes into buffer
|
|
iny
|
|
bne ChkHiByte ;if not past 256 bytes, do not increment
|
|
inc $01 ;otherwise increment high byte of indirect
|
|
ChkHiByte lda $01 ;check high byte?
|
|
cmp #$04 ;at $0400?
|
|
bne OutputTScr ;if not, loop back and do another
|
|
cpy #$3a ;check if offset points past end of data
|
|
bcc OutputTScr ;if not, loop back and do another
|
|
lda #$05 ;set buffer transfer control to $0300,
|
|
jmp SetVRAMAddr_B ;increment task and exit
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
ClearBuffersDrawIcon
|
|
lda OperMode ;check game mode
|
|
bne IncModeTask_B ;if not title screen mode, leave
|
|
ldx #$00 ;otherwise, clear buffer space
|
|
TScrClear sta VRAM_Buffer1-1,x
|
|
sta VRAM_Buffer1-1+$100,x
|
|
dex
|
|
bne TScrClear
|
|
jsr DrawMushroomIcon ;draw player select icon
|
|
IncSubtask inc ScreenRoutineTask ;move onto next task
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
WriteTopScore
|
|
lda #$fa ;run display routine to display top score on title
|
|
jsr UpdateNumber
|
|
IncModeTask_B inc OperMode_Task ;move onto next mode
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
GameText
|
|
TopStatusBarLine
|
|
db $20,$43,$05,$16,$0a,$1b,$12,$18 ; "MARIO"
|
|
db $20,$52,$0b,$20,$18,$1b,$15,$0d ; "WORLD TIME"
|
|
db $24,$24,$1d,$12,$16,$0e
|
|
db $20,$68,$05,$00,$24,$24,$2e,$29 ; score trailing digit and coin display
|
|
db $23,$c0,$7f,$aa ; attribute table data, clears name table 0 to palette 2
|
|
db $23,$c2,$01,$ea ; attribute table data, used for coin icon in status bar
|
|
db $ff ; end of data block
|
|
|
|
WorldLivesDisplay
|
|
db $21,$cd,$07,$24,$24 ; cross with spaces used on
|
|
db $29,$24,$24,$24,$24 ; lives display
|
|
db $21,$4b,$09,$20,$18 ; "WORLD - " used on lives display
|
|
db $1b,$15,$0d,$24,$24,$28,$24
|
|
db $22,$0c,$47,$24 ; possibly used to clear time up
|
|
db $23,$dc,$01,$ba ; attribute table data for crown if more than 9 lives
|
|
db $ff
|
|
|
|
TwoPlayerTimeUp
|
|
db $21,$cd,$05,$16,$0a,$1b,$12,$18 ; "MARIO"
|
|
OnePlayerTimeUp
|
|
db $22,$0c,$07,$1d,$12,$16,$0e,$24,$1e,$19 ; "TIME UP"
|
|
db $ff
|
|
|
|
TwoPlayerGameOver
|
|
db $21,$cd,$05,$16,$0a,$1b,$12,$18 ; "MARIO"
|
|
OnePlayerGameOver
|
|
db $22,$0b,$09,$10,$0a,$16,$0e,$24 ; "GAME OVER"
|
|
db $18,$1f,$0e,$1b
|
|
db $ff
|
|
|
|
WarpZoneWelcome
|
|
db $25,$84,$15,$20,$0e,$15,$0c,$18,$16 ; "WELCOME TO WARP ZONE!"
|
|
db $0e,$24,$1d,$18,$24,$20,$0a,$1b,$19
|
|
db $24,$23,$18,$17,$0e,$2b
|
|
db $26,$25,$01,$24 ; placeholder for left pipe
|
|
db $26,$2d,$01,$24 ; placeholder for middle pipe
|
|
db $26,$35,$01,$24 ; placeholder for right pipe
|
|
db $27,$d9,$46,$aa ; attribute data
|
|
db $27,$e1,$45,$aa
|
|
db $ff
|
|
|
|
LuigiName
|
|
db $15,$1e,$12,$10,$12 ; "LUIGI", no address or length
|
|
|
|
WarpZoneNumbers
|
|
db $04,$03,$02,$00 ; warp zone numbers, note spaces on middle
|
|
db $24,$05,$24,$00 ; zone, partly responsible for
|
|
db $08,$07,$06,$00 ; the minus world
|
|
|
|
GameTextOffsets
|
|
db TopStatusBarLine-GameText,TopStatusBarLine-GameText
|
|
db WorldLivesDisplay-GameText,WorldLivesDisplay-GameText
|
|
db TwoPlayerTimeUp-GameText,OnePlayerTimeUp-GameText
|
|
db TwoPlayerGameOver-GameText,OnePlayerGameOver-GameText
|
|
db WarpZoneWelcome-GameText,WarpZoneWelcome-GameText
|
|
|
|
WriteGameText
|
|
pha ;save text number to stack
|
|
asl
|
|
tay ;multiply by 2 and use as offset
|
|
cpy #$04 ;if set to do top status bar or world/lives display,
|
|
bcc LdGameText ;branch to use current offset as-is
|
|
cpy #$08 ;if set to do time-up or game over,
|
|
bcc Chk2Players ;branch to check players
|
|
ldy #$08 ;otherwise warp zone, therefore set offset
|
|
Chk2Players lda NumberOfPlayers ;check for number of players
|
|
bne LdGameText ;if there are two, use current offset to also print name
|
|
iny ;otherwise increment offset by one to not print name
|
|
LdGameText ldx GameTextOffsets,y ;get offset to message we want to print
|
|
ldy #$00
|
|
GameTextLoop lda GameText,x ;load message data
|
|
cmp #$ff ;check for terminator
|
|
beq EndGameText ;branch to end text if found
|
|
sta VRAM_Buffer1,y ;otherwise write data to buffer
|
|
inx ;and increment increment
|
|
iny
|
|
bne GameTextLoop ;do this for 256 bytes if no terminator found
|
|
EndGameText lda #$00 ;put null terminator at end
|
|
sta VRAM_Buffer1,y
|
|
pla ;pull original text number from stack
|
|
tax
|
|
cmp #$04 ;are we printing warp zone?
|
|
bcs PrintWarpZoneNumbers
|
|
dex ;are we printing the world/lives display?
|
|
bne CheckPlayerName ;if not, branch to check player's name
|
|
lda NumberofLives ;otherwise, check number of lives
|
|
clc ;and increment by one for display
|
|
adc #$01
|
|
cmp #10 ;more than 9 lives?
|
|
bcc PutLives
|
|
sbc #10 ;if so, subtract 10 and put a crown tile
|
|
ldy #$9f ;next to the difference...strange things happen if
|
|
sty VRAM_Buffer1+7 ;the number of lives exceeds 19
|
|
PutLives sta VRAM_Buffer1+8
|
|
ldy WorldNumber ;write world and level numbers (incremented for display)
|
|
iny ;to the buffer in the spaces surrounding the dash
|
|
sty VRAM_Buffer1+19
|
|
ldy LevelNumber
|
|
iny
|
|
sty VRAM_Buffer1+21 ;we're done here
|
|
rts
|
|
|
|
CheckPlayerName
|
|
lda NumberOfPlayers ;check number of players
|
|
beq ExitChkName ;if only 1 player, leave
|
|
lda CurrentPlayer ;load current player
|
|
dex ;check to see if current message number is for time up
|
|
bne ChkLuigi
|
|
ldy OperMode ;check for game over mode
|
|
cpy #GameOverModeValue
|
|
beq ChkLuigi
|
|
eor #%00000001 ;if not, must be time up, invert d0 to do other player
|
|
ChkLuigi lsr
|
|
bcc ExitChkName ;if mario is current player, do not change the name
|
|
ldy #$04
|
|
NameLoop lda LuigiName,y ;otherwise, replace "MARIO" with "LUIGI"
|
|
sta VRAM_Buffer1+3,y
|
|
dey
|
|
bpl NameLoop ;do this until each letter is replaced
|
|
ExitChkName rts
|
|
|
|
PrintWarpZoneNumbers
|
|
sbc #$04 ;subtract 4 and then shift to the left
|
|
asl ;twice to get proper warp zone number
|
|
asl ;offset
|
|
tax
|
|
ldy #$00
|
|
WarpNumLoop lda WarpZoneNumbers,x ;print warp zone numbers into the
|
|
sta VRAM_Buffer1+27,y ;placeholders from earlier
|
|
inx
|
|
iny ;put a number in every fourth space
|
|
iny
|
|
iny
|
|
iny
|
|
cpy #$0c
|
|
bcc WarpNumLoop
|
|
lda #$2c ;load new buffer pointer at end of message
|
|
jmp SetVRAMOffset
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
ResetSpritesAndScreenTimer
|
|
lda ScreenTimer ;check if screen timer has expired
|
|
bne NoReset ;if not, branch to leave
|
|
jsr MoveAllSpritesOffscreen ;otherwise reset sprites now
|
|
|
|
ResetScreenTimer
|
|
lda #$07 ;reset timer again
|
|
sta ScreenTimer
|
|
inc ScreenRoutineTask ;move onto next task
|
|
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
|
|
lda CurrentColumnPos ;store LSB of where we're at
|
|
and #$01
|
|
sta $05
|
|
ldy VRAM_Buffer2_Offset ;store vram buffer offset
|
|
sty $00
|
|
lda CurrentNTAddr_Low ;get current name table address we're supposed to render
|
|
sta VRAM_Buffer2+1,y
|
|
lda CurrentNTAddr_High
|
|
sta VRAM_Buffer2,y
|
|
lda #$9a ;store length byte of 26 here with d7 set
|
|
sta VRAM_Buffer2+2,y ;to increment by 32 (in columns)
|
|
lda #$00 ;init attribute row
|
|
sta $04
|
|
tax
|
|
DrawMTLoop stx $01 ;store init value of 0 or incremented offset for buffer
|
|
lda MetatileBuffer,x ;get first metatile number, and mask out all but 2 MSB
|
|
and #%11000000
|
|
sta $03 ;store attribute table bits here
|
|
asl ;note that metatile format is
|
|
rol ;%xx000000 - attribute table bits,
|
|
rol ;%00xxxxxx - metatile number
|
|
tay ;rotate bits to d1-d0 and use as offset here
|
|
lda MetatileGraphics_Low,y ;get address to graphics table from here
|
|
sta $06
|
|
lda MetatileGraphics_High,y
|
|
sta $07
|
|
lda MetatileBuffer,x ;get metatile number again
|
|
asl ;multiply by 4 and use as tile offset
|
|
asl
|
|
sta $02
|
|
lda AreaParserTaskNum ;get current task number for level processing and
|
|
and #%00000001 ;mask out all but LSB, then invert LSB, multiply by 2
|
|
eor #%00000001 ;to get the correct column position in the metatile,
|
|
asl ;then add to the tile offset so we can draw either side
|
|
adc $02 ;of the metatiles
|
|
tay
|
|
ldx $00 ;use vram buffer offset from before as X
|
|
lda ($06),y
|
|
sta VRAM_Buffer2+3,x ;get first tile number (top left or top right) and store
|
|
iny
|
|
lda ($06),y ;now get the second (bottom left or bottom right) and store
|
|
sta VRAM_Buffer2+4,x
|
|
ldy $04 ;get current attribute row
|
|
lda $05 ;get LSB of current column where we're at, and
|
|
bne RightCheck ;branch if set (clear = left attrib, set = right)
|
|
lda $01 ;get current row we're rendering
|
|
lsr ;branch if LSB set (clear = top left, set = bottom left)
|
|
bcs LLeft
|
|
rol $03 ;rotate attribute bits 3 to the left
|
|
rol $03 ;thus in d1-d0, for upper left square
|
|
rol $03
|
|
jmp SetAttrib
|
|
RightCheck lda $01 ;get LSB of current row we're rendering
|
|
lsr ;branch if set (clear = top right, set = bottom right)
|
|
bcs NextMTRow
|
|
lsr $03 ;shift attribute bits 4 to the right
|
|
lsr $03 ;thus in d3-d2, for upper right square
|
|
lsr $03
|
|
lsr $03
|
|
jmp SetAttrib
|
|
LLeft lsr $03 ;shift attribute bits 2 to the right
|
|
lsr $03 ;thus in d5-d4 for lower left square
|
|
NextMTRow inc $04 ;move onto next attribute row
|
|
SetAttrib lda AttributeBuffer,y ;get previously saved bits from before
|
|
ora $03 ;if any, and put new bits, if any, onto
|
|
sta AttributeBuffer,y ;the old, and store
|
|
inc $00 ;increment vram buffer offset by 2
|
|
inc $00
|
|
ldx $01 ;get current gfx buffer row, and check for
|
|
inx ;the bottom of the screen
|
|
cpx #$0d
|
|
bcc DrawMTLoop ;if not there yet, loop back
|
|
ldy $00 ;get current vram buffer offset, increment by 3
|
|
iny ;(for name table address and length bytes)
|
|
iny
|
|
iny
|
|
lda #$00
|
|
sta VRAM_Buffer2,y ;put null terminator at end of data for name table
|
|
sty VRAM_Buffer2_Offset ;store new buffer offset
|
|
inc CurrentNTAddr_Low ;increment name table address low
|
|
lda CurrentNTAddr_Low ;check current low byte
|
|
and #%00011111 ;if no wraparound, just skip this part
|
|
bne ExitDrawM
|
|
lda #$80 ;if wraparound occurs, make sure low byte stays
|
|
sta CurrentNTAddr_Low ;just under the status bar
|
|
lda CurrentNTAddr_High ;and then invert d2 of the name table address high
|
|
eor #%00000100 ;to move onto the next appropriate name table
|
|
sta CurrentNTAddr_High
|
|
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
|
|
lda CurrentNTAddr_Low ;get low byte of next name table address
|
|
and #%00011111 ;to be written to, mask out all but 5 LSB,
|
|
sec ;subtract four
|
|
sbc #$04
|
|
and #%00011111 ;mask out bits again and store
|
|
sta $01
|
|
lda CurrentNTAddr_High ;get high byte and branch if borrow not set
|
|
bcs SetATHigh
|
|
eor #%00000100 ;otherwise invert d2
|
|
SetATHigh and #%00000100 ;mask out all other bits
|
|
ora #$23 ;add $2300 to the high byte and store
|
|
sta $00
|
|
lda $01 ;get low byte - 4, divide by 4, add offset for
|
|
lsr ;attribute table and store
|
|
lsr
|
|
adc #$c0 ;we should now have the appropriate block of
|
|
sta $01 ;attribute table in our temp address
|
|
ldx #$00
|
|
ldy VRAM_Buffer2_Offset ;get buffer offset
|
|
AttribLoop lda $00
|
|
sta VRAM_Buffer2,y ;store high byte of attribute table address
|
|
lda $01
|
|
clc ;get low byte, add 8 because we want to start
|
|
adc #$08 ;below the status bar, and store
|
|
sta VRAM_Buffer2+1,y
|
|
sta $01 ;also store in temp again
|
|
lda AttributeBuffer,x ;fetch current attribute table byte and store
|
|
sta VRAM_Buffer2+3,y ;in the buffer
|
|
lda #$01
|
|
sta VRAM_Buffer2+2,y ;store length of 1 in buffer
|
|
lsr
|
|
sta AttributeBuffer,x ;clear current byte in attribute buffer
|
|
iny ;increment buffer offset by 4 bytes
|
|
iny
|
|
iny
|
|
iny
|
|
inx ;increment attribute offset and check to see
|
|
cpx #$07 ;if we're at the end yet
|
|
bcc AttribLoop
|
|
sta VRAM_Buffer2,y ;put null terminator at the end
|
|
sty VRAM_Buffer2_Offset ;store offset in case we want to do any more
|
|
SetVRAMCtrl lda #$06
|
|
sta VRAM_Buffer_AddrCtrl ;set buffer to $0341 and leave
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
;$00 - used as temporary counter in ColorRotation
|
|
|
|
ColorRotatePalette
|
|
db $27,$27,$27,$17,$07,$17
|
|
|
|
BlankPalette
|
|
db $3f,$0c,$04,$ff,$ff,$ff,$ff,$00
|
|
|
|
;used based on area type
|
|
Palette3Data
|
|
db $0f,$07,$12,$0f
|
|
db $0f,$07,$17,$0f
|
|
db $0f,$07,$17,$1c
|
|
db $0f,$07,$17,$00
|
|
|
|
ColorRotation
|
|
lda FrameCounter ;get frame counter
|
|
and #$07 ;mask out all but three LSB
|
|
bne ExitColorRot ;branch if not set to zero to do this every eighth frame
|
|
ldx VRAM_Buffer1_Offset ;check vram buffer offset
|
|
cpx #$31
|
|
bcs ExitColorRot ;if offset over 48 bytes, branch to leave
|
|
tay ;otherwise use frame counter's 3 LSB as offset here
|
|
GetBlankPal lda BlankPalette,y ;get blank palette for palette 3
|
|
sta VRAM_Buffer1,x ;store it in the vram buffer
|
|
inx ;increment offsets
|
|
iny
|
|
cpy #$08
|
|
bcc GetBlankPal ;do this until all bytes are copied
|
|
ldx VRAM_Buffer1_Offset ;get current vram buffer offset
|
|
lda #$03
|
|
sta $00 ;set counter here
|
|
lda AreaType ;get area type
|
|
asl ;multiply by 4 to get proper offset
|
|
asl
|
|
tay ;save as offset here
|
|
GetAreaPal lda Palette3Data,y ;fetch palette to be written based on area type
|
|
sta VRAM_Buffer1+3,x ;store it to overwrite blank palette in vram buffer
|
|
iny
|
|
inx
|
|
dec $00 ;decrement counter
|
|
bpl GetAreaPal ;do this until the palette is all copied
|
|
ldx VRAM_Buffer1_Offset ;get current vram buffer offset
|
|
ldy ColorRotateOffset ;get color cycling offset
|
|
lda ColorRotatePalette,y
|
|
sta VRAM_Buffer1+4,x ;get and store current color in second slot of palette
|
|
lda VRAM_Buffer1_Offset
|
|
clc ;add seven bytes to vram buffer offset
|
|
adc #$07
|
|
sta VRAM_Buffer1_Offset
|
|
inc ColorRotateOffset ;increment color cycling offset
|
|
lda ColorRotateOffset
|
|
cmp #$06 ;check to see if it's still in range
|
|
bcc ExitColorRot ;if so, branch to leave
|
|
lda #$00
|
|
sta ColorRotateOffset ;otherwise, init to keep it in range
|
|
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
|
|
|
|
BlockGfxData
|
|
db $45,$45,$47,$47
|
|
db $47,$47,$47,$47
|
|
db $57,$58,$59,$5a
|
|
db $24,$24,$24,$24
|
|
db $26,$26,$26,$26
|
|
|
|
RemoveCoin_Axe
|
|
ldy #$41 ;set low byte so offset points to $0341
|
|
lda #$03 ;load offset for default blank metatile
|
|
ldx AreaType ;check area type
|
|
bne WriteBlankMT ;if not water type, use offset
|
|
lda #$04 ;otherwise load offset for blank metatile used in water
|
|
WriteBlankMT jsr PutBlockMetatile ;do a sub to write blank metatile to vram buffer
|
|
lda #$06
|
|
sta VRAM_Buffer_AddrCtrl ;set vram address controller to $0341 and leave
|
|
rts
|
|
|
|
ReplaceBlockMetatile
|
|
jsr WriteBlockMetatile ;write metatile to vram buffer to replace block object
|
|
inc Block_ResidualCounter ;increment unused counter (residual code)
|
|
dec Block_RepFlag,x ;decrement flag (residual code)
|
|
rts ;leave
|
|
|
|
DestroyBlockMetatile
|
|
lda #$00 ;force blank metatile if branched/jumped to this point
|
|
|
|
WriteBlockMetatile
|
|
ldy #$03 ;load offset for blank metatile
|
|
cmp #$00 ;check contents of A for blank metatile
|
|
beq UseBOffset ;branch if found (unconditional if branched from 8a6b)
|
|
ldy #$00 ;load offset for brick metatile w/ line
|
|
cmp #$58
|
|
beq UseBOffset ;use offset if metatile is brick with coins (w/ line)
|
|
cmp #$51
|
|
beq UseBOffset ;use offset if metatile is breakable brick w/ line
|
|
iny ;increment offset for brick metatile w/o line
|
|
cmp #$5d
|
|
beq UseBOffset ;use offset if metatile is brick with coins (w/o line)
|
|
cmp #$52
|
|
beq UseBOffset ;use offset if metatile is breakable brick w/o line
|
|
iny ;if any other metatile, increment offset for empty block
|
|
UseBOffset tya ;put Y in A
|
|
ldy VRAM_Buffer1_Offset ;get vram buffer offset
|
|
iny ;move onto next byte
|
|
jsr PutBlockMetatile ;get appropriate block data and write to vram buffer
|
|
MoveVOffset dey ;decrement vram buffer offset
|
|
tya ;add 10 bytes to it
|
|
clc
|
|
adc #10
|
|
jmp SetVRAMOffset ;branch to store as new vram buffer offset
|
|
|
|
PutBlockMetatile
|
|
stx $00 ;store control bit from SprDataOffset_Ctrl
|
|
sty $01 ;store vram buffer offset for next byte
|
|
asl
|
|
asl ;multiply A by four and use as X
|
|
tax
|
|
ldy #$20 ;load high byte for name table 0
|
|
lda $06 ;get low byte of block buffer pointer
|
|
cmp #$d0 ;check to see if we're on odd-page block buffer
|
|
bcc SaveHAdder ;if not, use current high byte
|
|
ldy #$24 ;otherwise load high byte for name table 1
|
|
SaveHAdder sty $03 ;save high byte here
|
|
and #$0f ;mask out high nybble of block buffer pointer
|
|
asl ;multiply by 2 to get appropriate name table low byte
|
|
sta $04 ;and then store it here
|
|
lda #$00
|
|
sta $05 ;initialize temp high byte
|
|
lda $02 ;get vertical high nybble offset used in block buffer routine
|
|
clc
|
|
adc #$20 ;add 32 pixels for the status bar
|
|
asl
|
|
rol $05 ;shift and rotate d7 onto d0 and d6 into carry
|
|
asl
|
|
rol $05 ;shift and rotate d6 onto d0 and d5 into carry
|
|
adc $04 ;add low byte of name table and carry to vertical high nybble
|
|
sta $04 ;and store here
|
|
lda $05 ;get whatever was in d7 and d6 of vertical high nybble
|
|
adc #$00 ;add carry
|
|
clc
|
|
adc $03 ;then add high byte of name table
|
|
sta $05 ;store here
|
|
ldy $01 ;get vram buffer offset to be used
|
|
RemBridge lda BlockGfxData,x ;write top left and top right
|
|
sta VRAM_Buffer1+2,y ;tile numbers into first spot
|
|
lda BlockGfxData+1,x
|
|
sta VRAM_Buffer1+3,y
|
|
lda BlockGfxData+2,x ;write bottom left and bottom
|
|
sta VRAM_Buffer1+7,y ;right tiles numbers into
|
|
lda BlockGfxData+3,x ;second spot
|
|
sta VRAM_Buffer1+8,y
|
|
lda $04
|
|
sta VRAM_Buffer1,y ;write low byte of name table
|
|
clc ;into first slot as read
|
|
adc #$20 ;add 32 bytes to value
|
|
sta VRAM_Buffer1+5,y ;write low byte of name table
|
|
lda $05 ;plus 32 bytes into second slot
|
|
sta VRAM_Buffer1-1,y ;write high byte of name
|
|
sta VRAM_Buffer1+4,y ;table address to both slots
|
|
lda #$02
|
|
sta VRAM_Buffer1+1,y ;put length of 2 in
|
|
sta VRAM_Buffer1+6,y ;both slots
|
|
lda #$00
|
|
sta VRAM_Buffer1+9,y ;put null terminator at end
|
|
ldx $00 ;get offset control bit here
|
|
rts ;and leave
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;METATILE GRAPHICS TABLE
|
|
|
|
MetatileGraphics_Low
|
|
db <Palette0_MTiles,<Palette1_MTiles,
|
|
|
|
MetatileGraphics_High
|
|
db >Palette0_MTiles,>Palette1_MTiles,
|
|
|
|
Palette0_MTiles
|
|
db $24,$24,$24,$24 ;blank
|
|
db $27,$27,$27,$27 ;black metatile
|
|
db $24,$24,$24,$35 ;bush left
|
|
db $36,$25,$37,$25 ;bush middle
|
|
db $24,$38,$24,$24 ;bush right
|
|
db $24,$30,$30,$26 ;mountain left
|
|
db $26,$26,$34,$26 ;mountain left bottom/middle center
|
|
db $24,$31,$24,$32 ;mountain middle top
|
|
db $33,$26,$24,$33 ;mountain right
|
|
db $34,$26,$26,$26 ;mountain right bottom
|
|
db $26,$26,$26,$26 ;mountain middle bottom
|
|
db $24,$c0,$24,$c0 ;bridge guardrail
|
|
db $24,$7f,$7f,$24 ;chain
|
|
db $b8,$ba,$b9,$bb ;tall tree top, top half
|
|
db $b8,$bc,$b9,$bd ;short tree top
|
|
db $ba,$bc,$bb,$bd ;tall tree top, bottom half
|
|
db $60,$64,$61,$65 ;warp pipe end left, points up
|
|
db $62,$66,$63,$67 ;warp pipe end right, points up
|
|
db $60,$64,$61,$65 ;decoration pipe end left, points up
|
|
db $62,$66,$63,$67 ;decoration pipe end right, points up
|
|
db $68,$68,$69,$69 ;pipe shaft left
|
|
db $26,$26,$6a,$6a ;pipe shaft right
|
|
db $4b,$4c,$4d,$4e ;tree ledge left edge
|
|
db $4d,$4f,$4d,$4f ;tree ledge middle
|
|
db $4d,$4e,$50,$51 ;tree ledge right edge
|
|
db $6b,$70,$2c,$2d ;mushroom left edge
|
|
db $6c,$71,$6d,$72 ;mushroom middle
|
|
db $6e,$73,$6f,$74 ;mushroom right edge
|
|
db $86,$8a,$87,$8b ;sideways pipe end top
|
|
db $88,$8c,$88,$8c ;sideways pipe shaft top
|
|
db $89,$8d,$69,$69 ;sideways pipe joint top
|
|
db $8e,$91,$8f,$92 ;sideways pipe end bottom
|
|
db $26,$93,$26,$93 ;sideways pipe shaft bottom
|
|
db $90,$94,$69,$69 ;sideways pipe joint bottom
|
|
db $a4,$e9,$ea,$eb ;seaplant
|
|
db $24,$24,$24,$24 ;blank, used on bricks or blocks that are hit
|
|
db $24,$2f,$24,$3d ;flagpole ball
|
|
db $a2,$a2,$a3,$a3 ;flagpole shaft
|
|
db $24,$24,$24,$24 ;blank, used in conjunction with vines
|
|
|
|
Palette1_MTiles
|
|
db $a2,$a2,$a3,$a3 ;vertical rope
|
|
db $99,$24,$99,$24 ;horizontal rope
|
|
db $24,$a2,$3e,$3f ;left pulley
|
|
db $5b,$5c,$24,$a3 ;right pulley
|
|
db $24,$24,$24,$24 ;blank used for balance rope
|
|
db $9d,$47,$9e,$47 ;castle top
|
|
db $47,$47,$27,$27 ;castle window left
|
|
db $47,$47,$47,$47 ;castle brick wall
|
|
db $27,$27,$47,$47 ;castle window right
|
|
db $a9,$47,$aa,$47 ;castle top w/ brick
|
|
db $9b,$27,$9c,$27 ;entrance top
|
|
db $27,$27,$27,$27 ;entrance bottom
|
|
db $52,$52,$52,$52 ;green ledge stump
|
|
db $80,$a0,$81,$a1 ;fence
|
|
db $be,$be,$bf,$bf ;tree trunk
|
|
db $75,$ba,$76,$bb ;mushroom stump top
|
|
db $ba,$ba,$bb,$bb ;mushroom stump bottom
|
|
db $45,$47,$45,$47 ;breakable brick w/ line
|
|
db $47,$47,$47,$47 ;breakable brick
|
|
db $45,$47,$45,$47 ;breakable brick (not used)
|
|
db $b4,$b6,$b5,$b7 ;cracked rock terrain
|
|
db $45,$47,$45,$47 ;brick with line (power-up)
|
|
db $45,$47,$45,$47 ;brick with line (vine)
|
|
db $45,$47,$45,$47 ;brick with line (star)
|
|
db $45,$47,$45,$47 ;brick with line (coins)
|
|
db $45,$47,$45,$47 ;brick with line (1-up)
|
|
db $47,$47,$47,$47 ;brick (power-up)
|
|
db $47,$47,$47,$47 ;brick (vine)
|
|
db $47,$47,$47,$47 ;brick (star)
|
|
db $47,$47,$47,$47 ;brick (coins)
|
|
db $47,$47,$47,$47 ;brick (1-up)
|
|
db $24,$24,$24,$24 ;hidden block (1 coin)
|
|
db $24,$24,$24,$24 ;hidden block (1-up)
|
|
db $ab,$ac,$ad,$ae ;solid block (3-d block)
|
|
db $5d,$5e,$5d,$5e ;solid block (white wall)
|
|
db $c1,$24,$c1,$24 ;bridge
|
|
db $c6,$c8,$c7,$c9 ;bullet bill cannon barrel
|
|
db $ca,$cc,$cb,$cd ;bullet bill cannon top
|
|
db $2a,$2a,$40,$40 ;bullet bill cannon bottom
|
|
db $24,$24,$24,$24 ;blank used for jumpspring
|
|
db $24,$47,$24,$47 ;half brick used for jumpspring
|
|
db $82,$83,$84,$85 ;solid block (water level, green rock)
|
|
db $24,$47,$24,$47 ;half brick (???)
|
|
db $86,$8a,$87,$8b ;water pipe top
|
|
db $8e,$91,$8f,$92 ;water pipe bottom
|
|
db $24,$2f,$24,$3d ;flag ball (residual object)
|
|
|
|
Palette2_MTiles
|
|
db $24,$24,$24,$35 ;cloud left
|
|
db $36,$25,$37,$25 ;cloud middle
|
|
db $24,$38,$24,$24 ;cloud right
|
|
db $24,$24,$39,$24 ;cloud bottom left
|
|
db $3a,$24,$3b,$24 ;cloud bottom middle
|
|
db $3c,$24,$24,$24 ;cloud bottom right
|
|
db $41,$26,$41,$26 ;water/lava top
|
|
db $26,$26,$26,$26 ;water/lava
|
|
db $b0,$b1,$b2,$b3 ;cloud level terrain
|
|
db $77,$79,$77,$79 ;bowser's bridge
|
|
|
|
Palette3_MTiles
|
|
db $53,$55,$54,$56 ;question block (coin)
|
|
db $53,$55,$54,$56 ;question block (power-up)
|
|
db $a5,$a7,$a6,$a8 ;coin
|
|
db $c2,$c4,$c3,$c5 ;underwater coin
|
|
db $57,$59,$58,$5a ;empty block
|
|
db $7b,$7d,$7c,$7e ;axe
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;VRAM BUFFER DATA FOR LOCATIONS IN PRG-ROM
|
|
|
|
WaterPaletteData
|
|
db $3f,$00,$20
|
|
db $0f,$15,$12,$25
|
|
db $0f,$3a,$1a,$0f
|
|
db $0f,$30,$12,$0f
|
|
db $0f,$27,$12,$0f
|
|
db $22,$16,$27,$18
|
|
db $0f,$10,$30,$27
|
|
db $0f,$16,$30,$27
|
|
db $0f,$0f,$30,$10
|
|
db $00
|
|
|
|
GroundPaletteData
|
|
db $3f,$00,$20
|
|
db $0f,$29,$1a,$0f
|
|
db $0f,$36,$17,$0f
|
|
db $0f,$30,$21,$0f
|
|
db $0f,$27,$17,$0f
|
|
db $0f,$16,$27,$18
|
|
db $0f,$1a,$30,$27
|
|
db $0f,$16,$30,$27
|
|
db $0f,$0f,$36,$17
|
|
db $00
|
|
|
|
UndergroundPaletteData
|
|
db $3f,$00,$20
|
|
db $0f,$29,$1a,$09
|
|
db $0f,$3c,$1c,$0f
|
|
db $0f,$30,$21,$1c
|
|
db $0f,$27,$17,$1c
|
|
db $0f,$16,$27,$18
|
|
db $0f,$1c,$36,$17
|
|
db $0f,$16,$30,$27
|
|
db $0f,$0c,$3c,$1c
|
|
db $00
|
|
|
|
CastlePaletteData
|
|
db $3f,$00,$20
|
|
db $0f,$30,$10,$00
|
|
db $0f,$30,$10,$00
|
|
db $0f,$30,$16,$00
|
|
db $0f,$27,$17,$00
|
|
db $0f,$16,$27,$18
|
|
db $0f,$1c,$36,$17
|
|
db $0f,$16,$30,$27
|
|
db $0f,$00,$30,$10
|
|
db $00
|
|
|
|
DaySnowPaletteData
|
|
db $3f,$00,$04
|
|
db $22,$30,$00,$10
|
|
db $00
|
|
|
|
NightSnowPaletteData
|
|
db $3f,$00,$04
|
|
db $0f,$30,$00,$10
|
|
db $00
|
|
|
|
MushroomPaletteData
|
|
db $3f,$00,$04
|
|
db $22,$27,$16,$0f
|
|
db $00
|
|
|
|
BowserPaletteData
|
|
db $3f,$14,$04
|
|
db $0f,$1a,$30,$27
|
|
db $00
|
|
|
|
MarioThanksMessage
|
|
;"THANK YOU MARIO!"
|
|
db $25,$48,$10
|
|
db $1d,$11,$0a,$17,$14,$24
|
|
db $22,$18,$1e,$24
|
|
db $16,$0a,$1b,$12,$18,$2b
|
|
db $00
|
|
|
|
LuigiThanksMessage
|
|
;"THANK YOU LUIGI!"
|
|
db $25,$48,$10
|
|
db $1d,$11,$0a,$17,$14,$24
|
|
db $22,$18,$1e,$24
|
|
db $15,$1e,$12,$10,$12,$2b
|
|
db $00
|
|
|
|
MushroomRetainerSaved
|
|
;"BUT OUR PRINCESS IS IN"
|
|
db $25,$c5,$16
|
|
db $0b,$1e,$1d,$24,$18,$1e,$1b,$24
|
|
db $19,$1b,$12,$17,$0c,$0e,$1c,$1c,$24
|
|
db $12,$1c,$24,$12,$17
|
|
;"ANOTHER CASTLE!"
|
|
db $26,$05,$0f
|
|
db $0a,$17,$18,$1d,$11,$0e,$1b,$24
|
|
db $0c,$0a,$1c,$1d,$15,$0e,$2b,$00
|
|
|
|
PrincessSaved1
|
|
;"YOUR QUEST IS OVER."
|
|
db $25,$a7,$13
|
|
db $22,$18,$1e,$1b,$24
|
|
db $1a,$1e,$0e,$1c,$1d,$24
|
|
db $12,$1c,$24,$18,$1f,$0e,$1b,$af
|
|
db $00
|
|
|
|
PrincessSaved2
|
|
;"WE PRESENT YOU A NEW QUEST."
|
|
db $25,$e3,$1b
|
|
db $20,$0e,$24
|
|
db $19,$1b,$0e,$1c,$0e,$17,$1d,$24
|
|
db $22,$18,$1e,$24,$0a,$24,$17,$0e,$20,$24
|
|
db $1a,$1e,$0e,$1c,$1d,$af
|
|
db $00
|
|
|
|
WorldSelectMessage1
|
|
;"PUSH BUTTON B"
|
|
db $26,$4a,$0d
|
|
db $19,$1e,$1c,$11,$24
|
|
db $0b,$1e,$1d,$1d,$18,$17,$24,$0b
|
|
db $00
|
|
|
|
WorldSelectMessage2
|
|
;"TO SELECT A WORLD"
|
|
db $26,$88,$11
|
|
db $1d,$18,$24,$1c,$0e,$15,$0e,$0c,$1d,$24
|
|
db $0a,$24,$20,$18,$1b,$15,$0d
|
|
db $00
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$04 - address low to jump address
|
|
;$05 - address high to jump address
|
|
;$06 - jump address low
|
|
;$07 - jump address high
|
|
|
|
JumpEngine
|
|
asl ;shift bit from contents of A
|
|
tay
|
|
pla ;pull saved return address from stack
|
|
sta $04 ;save to indirect
|
|
pla
|
|
sta $05
|
|
iny
|
|
lda ($04),y ;load pointer from indirect
|
|
sta $06 ;note that if an RTS is performed in next routine
|
|
iny ;it will return to the execution before the sub
|
|
lda ($04),y ;that called this routine
|
|
sta $07
|
|
jmp ($06) ;jump to the address we loaded
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
InitializeNameTables
|
|
lda PPU_STATUS ;reset flip-flop
|
|
lda Mirror_PPU_CTRL_REG1 ;load mirror of ppu reg $2000
|
|
ora #%00010000 ;set sprites for first 4k and background for second 4k
|
|
and #%11110000 ;clear rest of lower nybble, leave higher alone
|
|
jsr WritePPUReg1
|
|
lda #$24 ;set vram address to start of name table 1
|
|
jsr WriteNTAddr
|
|
lda #$20 ;and then set it to name table 0
|
|
WriteNTAddr sta PPU_ADDRESS
|
|
lda #$00
|
|
sta PPU_ADDRESS
|
|
ldx #$04 ;clear name table with blank tile #24
|
|
ldy #$c0
|
|
lda #$24
|
|
InitNTLoop sta PPU_DATA ;count out exactly 768 tiles
|
|
dey
|
|
bne InitNTLoop
|
|
dex
|
|
bne InitNTLoop
|
|
ldy #64 ;now to clear the attribute table (with zero this time)
|
|
txa
|
|
sta VRAM_Buffer1_Offset ;init vram buffer 1 offset
|
|
sta VRAM_Buffer1 ;init vram buffer 1
|
|
InitATLoop sta PPU_DATA
|
|
dey
|
|
bne InitATLoop
|
|
sta HorizontalScroll ;reset scroll variables
|
|
sta VerticalScroll
|
|
jmp InitScroll ;initialize scroll registers to zero
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$00 - temp joypad bit
|
|
|
|
ReadJoypads
|
|
lda #$01 ;reset and clear strobe of joypad ports
|
|
sta JOYPAD_PORT
|
|
lsr
|
|
tax ;start with joypad 1's port
|
|
sta JOYPAD_PORT
|
|
jsr ReadPortBits
|
|
inx ;increment for joypad 2's port
|
|
ReadPortBits ldy #$08
|
|
PortLoop pha ;push previous bit onto stack
|
|
lda JOYPAD_PORT,x ;read current bit on joypad port
|
|
sta $00 ;check d1 and d0 of port output
|
|
lsr ;this is necessary on the old
|
|
ora $00 ;famicom systems in japan
|
|
lsr
|
|
pla ;read bits from stack
|
|
rol ;rotate bit from carry flag
|
|
dey
|
|
bne PortLoop ;count down bits left
|
|
sta SavedJoypadBits,x ;save controller status here always
|
|
pha
|
|
and #%00110000 ;check for select or start
|
|
and JoypadBitMask,x ;if neither saved state nor current state
|
|
beq Save8Bits ;have any of these two set, branch
|
|
pla
|
|
and #%11001111 ;otherwise store without select
|
|
sta SavedJoypadBits,x ;or start bits and leave
|
|
rts
|
|
Save8Bits pla
|
|
sta JoypadBitMask,x ;save with all bits in another place and leave
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$00 - vram buffer address table low
|
|
;$01 - vram buffer address table high
|
|
|
|
WriteBufferToScreen
|
|
sta PPU_ADDRESS ;store high byte of vram address
|
|
iny
|
|
lda ($00),y ;load next byte (second)
|
|
sta PPU_ADDRESS ;store low byte of vram address
|
|
iny
|
|
lda ($00),y ;load next byte (third)
|
|
asl ;shift to left and save in stack
|
|
pha
|
|
lda Mirror_PPU_CTRL_REG1 ;load mirror of $2000,
|
|
ora #%00000100 ;set ppu to increment by 32 by default
|
|
bcs SetupWrites ;if d7 of third byte was clear, ppu will
|
|
and #%11111011 ;only increment by 1
|
|
SetupWrites jsr WritePPUReg1 ;write to register
|
|
pla ;pull from stack and shift to left again
|
|
asl
|
|
bcc GetLength ;if d6 of third byte was clear, do not repeat byte
|
|
ora #%00000010 ;otherwise set d1 and increment Y
|
|
iny
|
|
GetLength lsr ;shift back to the right to get proper length
|
|
lsr ;note that d1 will now be in carry
|
|
tax
|
|
OutputToVRAM bcs RepeatByte ;if carry set, repeat loading the same byte
|
|
iny ;otherwise increment Y to load next byte
|
|
RepeatByte lda ($00),y ;load more data from buffer and write to vram
|
|
sta PPU_DATA
|
|
dex ;done writing?
|
|
bne OutputToVRAM
|
|
sec
|
|
tya
|
|
adc $00 ;add end length plus one to the indirect at $00
|
|
sta $00 ;to allow this routine to read another set of updates
|
|
lda #$00
|
|
adc $01
|
|
sta $01
|
|
lda #$3f ;sets vram address to $3f00
|
|
sta PPU_ADDRESS
|
|
lda #$00
|
|
sta PPU_ADDRESS
|
|
sta PPU_ADDRESS ;then reinitializes it for some reason
|
|
sta PPU_ADDRESS
|
|
UpdateScreen ldx PPU_STATUS ;reset flip-flop
|
|
ldy #$00 ;load first byte from indirect as a pointer
|
|
lda ($00),y
|
|
bne WriteBufferToScreen ;if byte is zero we have no further updates to make here
|
|
InitScroll sta PPU_SCROLL_REG ;store contents of A into scroll registers
|
|
sta PPU_SCROLL_REG ;and end whatever subroutine led us here
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
WritePPUReg1
|
|
sta PPU_CTRL_REG1 ;write contents of A to PPU register 1
|
|
sta Mirror_PPU_CTRL_REG1 ;and its mirror
|
|
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
|
|
StatusBarData
|
|
db $f0,$06 ; top score display on title screen
|
|
db $62,$06 ; player score
|
|
db $62,$06
|
|
db $6d,$02 ; coin tally
|
|
db $6d,$02
|
|
db $7a,$03 ; game timer
|
|
|
|
StatusBarOffset
|
|
db $06,$0c,$12,$18,$1e,$24
|
|
|
|
PrintStatusBarNumbers
|
|
sta $00 ;store player-specific offset
|
|
jsr OutputNumbers ;use first nybble to print the coin display
|
|
lda $00 ;move high nybble to low
|
|
lsr ;and print to score display
|
|
lsr
|
|
lsr
|
|
lsr
|
|
|
|
OutputNumbers
|
|
clc ;add 1 to low nybble
|
|
adc #$01
|
|
and #%00001111 ;mask out high nybble
|
|
cmp #$06
|
|
bcs ExitOutputN
|
|
pha ;save incremented value to stack for now and
|
|
asl ;shift to left and use as offset
|
|
tay
|
|
ldx VRAM_Buffer1_Offset ;get current buffer pointer
|
|
lda #$20 ;put at top of screen by default
|
|
cpy #$00 ;are we writing top score on title screen?
|
|
bne SetupNums
|
|
lda #$22 ;if so, put further down on the screen
|
|
SetupNums sta VRAM_Buffer1,x
|
|
lda StatusBarData,y ;write low vram address and length of thing
|
|
sta VRAM_Buffer1+1,x ;we're printing to the buffer
|
|
lda StatusBarData+1,y
|
|
sta VRAM_Buffer1+2,x
|
|
sta $03 ;save length byte in counter
|
|
stx $02 ;and buffer pointer elsewhere for now
|
|
pla ;pull original incremented value from stack
|
|
tax
|
|
lda StatusBarOffset,x ;load offset to value we want to write
|
|
sec
|
|
sbc StatusBarData+1,y ;subtract from length byte we read before
|
|
tay ;use value as offset to display digits
|
|
ldx $02
|
|
DigitPLoop lda DisplayDigits,y ;write digits to the buffer
|
|
sta VRAM_Buffer1+3,x
|
|
inx
|
|
iny
|
|
dec $03 ;do this until all the digits are written
|
|
bne DigitPLoop
|
|
lda #$00 ;put null terminator at end
|
|
sta VRAM_Buffer1+3,x
|
|
inx ;increment buffer pointer by 3
|
|
inx
|
|
inx
|
|
stx VRAM_Buffer1_Offset ;store it in case we want to use it again
|
|
ExitOutputN rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
DigitsMathRoutine
|
|
lda OperMode ;check mode of operation
|
|
cmp #TitleScreenModeValue
|
|
beq EraseDMods ;if in title screen mode, branch to lock score
|
|
ldx #$05
|
|
AddModLoop lda DigitModifier,x ;load digit amount to increment
|
|
clc
|
|
adc DisplayDigits,y ;add to current digit
|
|
bmi BorrowOne ;if result is a negative number, branch to subtract
|
|
cmp #10
|
|
bcs CarryOne ;if digit greater than $09, branch to add
|
|
StoreNewD sta DisplayDigits,y ;store as new score or game timer digit
|
|
dey ;move onto next digits in score or game timer
|
|
dex ;and digit amounts to increment
|
|
bpl AddModLoop ;loop back if we're not done yet
|
|
EraseDMods lda #$00 ;store zero here
|
|
ldx #$06 ;start with the last digit
|
|
EraseMLoop sta DigitModifier-1,x ;initialize the digit amounts to increment
|
|
dex
|
|
bpl EraseMLoop ;do this until they're all reset, then leave
|
|
rts
|
|
BorrowOne dec DigitModifier-1,x ;decrement the previous digit, then put $09 in
|
|
lda #$09 ;the game timer digit we're currently on to "borrow
|
|
bne StoreNewD ;the one", then do an unconditional branch back
|
|
CarryOne sec ;subtract ten from our digit to make it a
|
|
sbc #10 ;proper BCD number, then increment the digit
|
|
inc DigitModifier-1,x ;preceding current digit to "carry the one" properly
|
|
jmp StoreNewD ;go back to just after we branched here
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
UpdateTopScore
|
|
ldx #$05 ;start with mario's score
|
|
jsr TopScoreCheck
|
|
ldx #$0b ;now do luigi's score
|
|
|
|
TopScoreCheck
|
|
ldy #$05 ;start with the lowest digit
|
|
sec
|
|
GetScoreDiff lda PlayerScoreDisplay,x ;subtract each player digit from each high score digit
|
|
sbc TopScoreDisplay,y ;from lowest to highest, if any top score digit exceeds
|
|
dex ;any player digit, borrow will be set until a subsequent
|
|
dey ;subtraction clears it (player digit is higher than top)
|
|
bpl GetScoreDiff
|
|
bcc NoTopSc ;check to see if borrow is still set, if so, no new high score
|
|
inx ;increment X and Y once to the start of the score
|
|
iny
|
|
CopyScore lda PlayerScoreDisplay,x ;store player's score digits into high score memory area
|
|
sta TopScoreDisplay,y
|
|
inx
|
|
iny
|
|
cpy #$06 ;do this until we have stored them all
|
|
bcc CopyScore
|
|
NoTopSc rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
DefaultSprOffsets
|
|
db $04,$30,$48,$60,$78,$90,$a8,$c0
|
|
db $d8,$e8,$24,$f8,$fc,$28,$2c
|
|
|
|
Sprite0Data
|
|
db $18,$ff,$23,$58
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
InitializeGame
|
|
ldy #$6f ;clear all memory as in initialization procedure,
|
|
jsr InitializeMemory ;but this time, clear only as far as $076f
|
|
ldy #$1f
|
|
ClrSndLoop sta SoundMemory,y ;clear out memory used
|
|
dey ;by the sound engines
|
|
bpl ClrSndLoop
|
|
lda #$18 ;set demo timer
|
|
sta DemoTimer
|
|
jsr LoadAreaPointer
|
|
|
|
InitializeArea
|
|
ldy #$4b ;clear all memory again, only as far as $074b
|
|
jsr InitializeMemory ;this is only necessary if branching from
|
|
ldx #$21
|
|
lda #$00
|
|
ClrTimersLoop sta Timers,x ;clear out memory between
|
|
dex ;$0780 and $07a1
|
|
bpl ClrTimersLoop
|
|
lda HalfwayPage
|
|
ldy AltEntranceControl ;if AltEntranceControl not set, use halfway page, if any found
|
|
beq StartPage
|
|
lda EntrancePage ;otherwise use saved entry page number here
|
|
StartPage sta ScreenLeft_PageLoc ;set as value here
|
|
sta CurrentPageLoc ;also set as current page
|
|
sta BackloadingFlag ;set flag here if halfway page or saved entry page number found
|
|
jsr GetScreenPosition ;get pixel coordinates for screen borders
|
|
ldy #$20 ;if on odd numbered page, use $2480 as start of rendering
|
|
and #%00000001 ;otherwise use $2080, this address used later as name table
|
|
beq SetInitNTHigh ;address for rendering of game area
|
|
ldy #$24
|
|
SetInitNTHigh sty CurrentNTAddr_High ;store name table address
|
|
ldy #$80
|
|
sty CurrentNTAddr_Low
|
|
asl ;store LSB of page number in high nybble
|
|
asl ;of block buffer column position
|
|
asl
|
|
asl
|
|
sta BlockBufferColumnPos
|
|
dec AreaObjectLength ;set area object lengths for all empty
|
|
dec AreaObjectLength+1
|
|
dec AreaObjectLength+2
|
|
lda #$0b ;set value for renderer to update 12 column sets
|
|
sta ColumnSets ;12 column sets = 24 metatile columns = 1 1/2 screens
|
|
jsr GetAreaDataAddrs ;get enemy and level addresses and load header
|
|
lda PrimaryHardMode ;check to see if primary hard mode has been activated
|
|
bne SetSecHard ;if so, activate the secondary no matter where we're at
|
|
lda WorldNumber ;otherwise check world number
|
|
cmp #World5 ;if less than 5, do not activate secondary
|
|
bcc CheckHalfway
|
|
bne SetSecHard ;if not equal to, then world > 5, thus activate
|
|
lda LevelNumber ;otherwise, world 5, so check level number
|
|
cmp #Level3 ;if 1 or 2, do not set secondary hard mode flag
|
|
bcc CheckHalfway
|
|
SetSecHard inc SecondaryHardMode ;set secondary hard mode flag for areas 5-3 and beyond
|
|
CheckHalfway lda HalfwayPage
|
|
beq DoneInitArea
|
|
lda #$02 ;if halfway page set, overwrite start position from header
|
|
sta PlayerEntranceCtrl
|
|
DoneInitArea lda #Silence ;silence music
|
|
sta AreaMusicQueue
|
|
lda #$01 ;disable screen output
|
|
sta DisableScreenFlag
|
|
inc OperMode_Task ;increment one of the modes
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
PrimaryGameSetup
|
|
lda #$01
|
|
sta FetchNewGameTimerFlag ;set flag to load game timer from header
|
|
sta PlayerSize ;set player's size to small
|
|
lda #$02
|
|
sta NumberofLives ;give each player three lives
|
|
sta OffScr_NumberofLives
|
|
|
|
SecondaryGameSetup
|
|
lda #$00
|
|
sta DisableScreenFlag ;enable screen output
|
|
tay
|
|
ClearVRLoop sta VRAM_Buffer1-1,y ;clear buffer at $0300-$03ff
|
|
iny
|
|
bne ClearVRLoop
|
|
sta GameTimerExpiredFlag ;clear game timer exp flag
|
|
sta DisableIntermediate ;clear skip lives display flag
|
|
sta BackloadingFlag ;clear value here
|
|
lda #$ff
|
|
sta BalPlatformAlignment ;initialize balance platform assignment flag
|
|
lda ScreenLeft_PageLoc ;get left side page location
|
|
lsr Mirror_PPU_CTRL_REG1 ;shift LSB of ppu register #1 mirror out
|
|
and #$01 ;mask out all but LSB of page location
|
|
ror ;rotate LSB of page location into carry then onto mirror
|
|
rol Mirror_PPU_CTRL_REG1 ;this is to set the proper PPU name table
|
|
jsr GetAreaMusic ;load proper music into queue
|
|
lda #$38 ;load sprite shuffle amounts to be used later
|
|
sta SprShuffleAmt+2
|
|
lda #$48
|
|
sta SprShuffleAmt+1
|
|
lda #$58
|
|
sta SprShuffleAmt
|
|
ldx #$0e ;load default OAM offsets into $06e4-$06f2
|
|
ShufAmtLoop lda DefaultSprOffsets,x
|
|
sta SprDataOffset,x
|
|
dex ;do this until they're all set
|
|
bpl ShufAmtLoop
|
|
ldy #$03 ;set up sprite #0
|
|
ISpr0Loop lda Sprite0Data,y
|
|
sta Sprite_Data,y
|
|
dey
|
|
bpl ISpr0Loop
|
|
jsr DoNothing2 ;these jsrs doesn't do anything useful
|
|
jsr DoNothing1
|
|
inc Sprite0HitDetectFlag ;set sprite #0 check flag
|
|
inc OperMode_Task ;increment to next task
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
;$06 - RAM address low
|
|
;$07 - RAM address high
|
|
|
|
InitializeMemory
|
|
ldx #$07 ;set initial high byte to $0700-$07ff
|
|
lda #$00 ;set initial low byte to start of page (at $00 of page)
|
|
sta $06
|
|
InitPageLoop stx $07
|
|
InitByteLoop cpx #$01 ;check to see if we're on the stack ($0100-$01ff)
|
|
bne InitByte ;if not, go ahead anyway
|
|
cpy #$60 ;otherwise, check to see if we're at $0160-$01ff
|
|
bcs SkipByte ;if so, skip write
|
|
InitByte sta ($06),y ;otherwise, initialize byte with current low byte in Y
|
|
SkipByte dey
|
|
cpy #$ff ;do this until all bytes in page have been erased
|
|
bne InitByteLoop
|
|
dex ;go onto the next page
|
|
bpl InitPageLoop ;do this until all pages of memory have been erased
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
MusicSelectData
|
|
db WaterMusic, GroundMusic,
|
|
db CloudMusic, PipeIntroMusic
|
|
|
|
GetAreaMusic
|
|
lda OperMode ;if in title screen mode, leave
|
|
beq ExitGetM
|
|
lda AltEntranceControl ;check for specific alternate mode of entry
|
|
cmp #$02 ;if found, branch without checking starting position
|
|
beq ChkAreaType ;from area object data header
|
|
ldy #$05 ;select music for pipe intro scene by default
|
|
lda PlayerEntranceCtrl ;check value from level header for certain values
|
|
cmp #$06
|
|
beq StoreMusic ;load music for pipe intro scene if header
|
|
cmp #$07 ;start position either value $06 or $07
|
|
beq StoreMusic
|
|
ChkAreaType ldy AreaType ;load area type as offset for music bit
|
|
lda CloudTypeOverride
|
|
beq StoreMusic ;check for cloud type override
|
|
ldy #$04 ;select music for cloud type level if found
|
|
StoreMusic lda MusicSelectData,y ;otherwise select appropriate music for level type
|
|
sta AreaMusicQueue ;store in queue and leave
|
|
ExitGetM rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
PlayerStarting_X_Pos
|
|
db $28,$18
|
|
db $38,$28
|
|
|
|
AltYPosOffset
|
|
db $08,$00
|
|
|
|
PlayerStarting_Y_Pos
|
|
db $00,$20,$b0,$50,$00,$00,$b0,$b0
|
|
db $f0
|
|
|
|
PlayerBGPriorityData
|
|
db $00,$20,$00,$00,$00,$00,$00,$00
|
|
|
|
GameTimerData
|
|
db $20 ;dummy byte, used as part of bg priority data
|
|
db $04,$03,$02
|
|
|
|
Entrance_GameTimerSetup
|
|
lda ScreenLeft_PageLoc ;set current page for area objects
|
|
sta Player_PageLoc ;as page location for player
|
|
lda #$28 ;store value here
|
|
sta VerticalForceDown ;for fractional movement downwards if necessary
|
|
lda #$01 ;set high byte of player position and
|
|
sta PlayerFacingDir ;set facing direction so that player faces right
|
|
sta Player_Y_HighPos
|
|
lda #$00 ;set player state to on the ground by default
|
|
sta Player_State
|
|
dec Player_CollisionBits ;initialize player's collision bits
|
|
ldy #$00 ;initialize halfway page
|
|
sty HalfwayPage
|
|
lda AreaType ;check area type
|
|
bne ChkStPos ;if water type, set swimming flag, otherwise do not set
|
|
iny
|
|
ChkStPos sty SwimmingFlag
|
|
ldx PlayerEntranceCtrl ;get starting position loaded from header
|
|
ldy AltEntranceControl ;check alternate mode of entry flag for 0 or 1
|
|
beq SetStPos
|
|
cpy #$01
|
|
beq SetStPos
|
|
ldx AltYPosOffset-2,y ;if not 0 or 1, override $0710 with new offset in X
|
|
SetStPos lda PlayerStarting_X_Pos,y ;load appropriate horizontal position
|
|
sta Player_X_Position ;and vertical positions for the player, using
|
|
lda PlayerStarting_Y_Pos,x ;AltEntranceControl as offset for horizontal and either $0710
|
|
sta Player_Y_Position ;or value that overwrote $0710 as offset for vertical
|
|
lda PlayerBGPriorityData,x
|
|
sta Player_SprAttrib ;set player sprite attributes using offset in X
|
|
jsr GetPlayerColors ;get appropriate player palette
|
|
ldy GameTimerSetting ;get timer control value from header
|
|
beq ChkOverR ;if set to zero, branch (do not use dummy byte for this)
|
|
lda FetchNewGameTimerFlag ;do we need to set the game timer? if not, use
|
|
beq ChkOverR ;old game timer setting
|
|
lda GameTimerData,y ;if game timer is set and game timer flag is also set,
|
|
sta GameTimerDisplay ;use value of game timer control for first digit of game timer
|
|
lda #$01
|
|
sta GameTimerDisplay+2 ;set last digit of game timer to 1
|
|
lsr
|
|
sta GameTimerDisplay+1 ;set second digit of game timer
|
|
sta FetchNewGameTimerFlag ;clear flag for game timer reset
|
|
sta StarInvincibleTimer ;clear star mario timer
|
|
ChkOverR ldy JoypadOverride ;if controller bits not set, branch to skip this part
|
|
beq ChkSwimE
|
|
lda #$03 ;set player state to climbing
|
|
sta Player_State
|
|
ldx #$00 ;set offset for first slot, for block object
|
|
jsr InitBlock_XY_Pos
|
|
lda #$f0 ;set vertical coordinate for block object
|
|
sta Block_Y_Position
|
|
ldx #$05 ;set offset in X for last enemy object buffer slot
|
|
ldy #$00 ;set offset in Y for object coordinates used earlier
|
|
jsr Setup_Vine ;do a sub to grow vine
|
|
ChkSwimE ldy AreaType ;if level not water-type,
|
|
bne SetPESub ;skip this subroutine
|
|
jsr SetupBubble ;otherwise, execute sub to set up air bubbles
|
|
SetPESub lda #$07 ;set to run player entrance subroutine
|
|
sta GameEngineSubroutine ;on the next frame of game engine
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
;page numbers are in order from -1 to -4
|
|
HalfwayPageNybbles
|
|
db $56,$40
|
|
db $65,$70
|
|
db $66,$40
|
|
db $66,$40
|
|
db $66,$40
|
|
db $66,$60
|
|
db $65,$70
|
|
db $00,$00
|
|
|
|
PlayerLoseLife
|
|
inc DisableScreenFlag ;disable screen and sprite 0 check
|
|
lda #$00
|
|
sta Sprite0HitDetectFlag
|
|
lda #Silence ;silence music
|
|
sta EventMusicQueue
|
|
dec NumberofLives ;take one life from player
|
|
bpl StillInGame ;if player still has lives, branch
|
|
lda #$00
|
|
sta OperMode_Task ;initialize mode task,
|
|
lda #GameOverModeValue ;switch to game over mode
|
|
sta OperMode ;and leave
|
|
rts
|
|
StillInGame lda WorldNumber ;multiply world number by 2 and use
|
|
asl ;as offset
|
|
tax
|
|
lda LevelNumber ;if in area -3 or -4, increment
|
|
and #$02 ;offset by one byte, otherwise
|
|
beq GetHalfway ;leave offset alone
|
|
inx
|
|
GetHalfway ldy HalfwayPageNybbles,x ;get halfway page number with offset
|
|
lda LevelNumber ;check area number's LSB
|
|
lsr
|
|
tya ;if in area -2 or -4, use lower nybble
|
|
bcs MaskHPNyb
|
|
lsr ;move higher nybble to lower if area
|
|
lsr ;number is -1 or -3
|
|
lsr
|
|
lsr
|
|
MaskHPNyb and #%00001111 ;mask out all but lower nybble
|
|
cmp ScreenLeft_PageLoc
|
|
beq SetHalfway ;left side of screen must be at the halfway page,
|
|
bcc SetHalfway ;otherwise player must start at the
|
|
lda #$00 ;beginning of the level
|
|
SetHalfway sta HalfwayPage ;store as halfway page for player
|
|
jsr TransposePlayers ;switch players around if 2-player game
|
|
jmp ContinueGame ;continue the game
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
GameOverMode
|
|
lda OperMode_Task
|
|
jsr JumpEngine
|
|
|
|
dw SetupGameOver
|
|
dw ScreenRoutines
|
|
dw RunGameOver
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
SetupGameOver
|
|
lda #$00 ;reset screen routine task control for title screen, game,
|
|
sta ScreenRoutineTask ;and game over modes
|
|
sta Sprite0HitDetectFlag ;disable sprite 0 check
|
|
lda #GameOverMusic
|
|
sta EventMusicQueue ;put game over music in secondary queue
|
|
inc DisableScreenFlag ;disable screen output
|
|
inc OperMode_Task ;set secondary mode to 1
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
RunGameOver
|
|
lda #$00 ;reenable screen
|
|
sta DisableScreenFlag
|
|
lda SavedJoypad1Bits ;check controller for start pressed
|
|
and #Start_Button
|
|
bne TerminateGame
|
|
lda ScreenTimer ;if not pressed, wait for
|
|
bne GameIsOn ;screen timer to expire
|
|
TerminateGame
|
|
lda #Silence ;silence music
|
|
sta EventMusicQueue
|
|
jsr TransposePlayers ;check if other player can keep
|
|
bcc ContinueGame ;going, and do so if possible
|
|
lda WorldNumber ;otherwise put world number of current
|
|
sta ContinueWorld ;player into secret continue function variable
|
|
lda #$00
|
|
asl ;residual ASL instruction
|
|
sta OperMode_Task ;reset all modes to title screen and
|
|
sta ScreenTimer ;leave
|
|
sta OperMode
|
|
rts
|
|
|
|
ContinueGame
|
|
jsr LoadAreaPointer ;update level pointer with
|
|
lda #$01 ;actual world and area numbers, then
|
|
sta PlayerSize ;reset player's size, status, and
|
|
inc FetchNewGameTimerFlag ;set game timer flag to reload
|
|
lda #$00 ;game timer from header
|
|
sta TimerControl ;also set flag for timers to count again
|
|
sta PlayerStatus
|
|
sta GameEngineSubroutine ;reset task for game core
|
|
sta OperMode_Task ;set modes and leave
|
|
lda #$01 ;if in game over mode, switch back to
|
|
sta OperMode ;game mode, because game is still on
|
|
GameIsOn rts
|
|
|
|
TransposePlayers
|
|
sec ;set carry flag by default to end game
|
|
lda NumberOfPlayers ;if only a 1 player game, leave
|
|
beq ExTrans
|
|
lda OffScr_NumberofLives ;does offscreen player have any lives left?
|
|
bmi ExTrans ;branch if not
|
|
lda CurrentPlayer ;invert bit to update
|
|
eor #%00000001 ;which player is on the screen
|
|
sta CurrentPlayer
|
|
ldx #$06
|
|
TransLoop lda OnscreenPlayerInfo,x ;transpose the information
|
|
pha ;of the onscreen player
|
|
lda OffscreenPlayerInfo,x ;with that of the offscreen player
|
|
sta OnscreenPlayerInfo,x
|
|
pla
|
|
sta OffscreenPlayerInfo,x
|
|
dex
|
|
bpl TransLoop
|
|
clc ;clear carry flag to get game going
|
|
ExTrans rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
DoNothing1
|
|
lda #$ff ;this is residual code, this value is
|
|
sta $06c9 ;not used anywhere in the program
|
|
DoNothing2
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
AreaParserTaskHandler
|
|
ldy AreaParserTaskNum ;check number of tasks here
|
|
bne DoAPTasks ;if already set, go ahead
|
|
ldy #$08
|
|
sty AreaParserTaskNum ;otherwise, set eight by default
|
|
DoAPTasks dey
|
|
tya
|
|
jsr AreaParserTasks
|
|
dec AreaParserTaskNum ;if all tasks not complete do not
|
|
bne SkipATRender ;render attribute table yet
|
|
jsr RenderAttributeTables
|
|
SkipATRender rts
|
|
|
|
AreaParserTasks
|
|
jsr JumpEngine
|
|
|
|
dw IncrementColumnPos
|
|
dw RenderAreaGraphics
|
|
dw RenderAreaGraphics
|
|
dw AreaParserCore
|
|
dw IncrementColumnPos
|
|
dw RenderAreaGraphics
|
|
dw RenderAreaGraphics
|
|
dw AreaParserCore
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
IncrementColumnPos
|
|
inc CurrentColumnPos ;increment column where we're at
|
|
lda CurrentColumnPos
|
|
and #%00001111 ;mask out higher nybble
|
|
bne NoColWrap
|
|
sta CurrentColumnPos ;if no bits left set, wrap back to zero (0-f)
|
|
inc CurrentPageLoc ;and increment page number where we're at
|
|
NoColWrap inc BlockBufferColumnPos ;increment column offset where we're at
|
|
lda BlockBufferColumnPos
|
|
and #%00011111 ;mask out all but 5 LSB (0-1f)
|
|
sta BlockBufferColumnPos ;and save
|
|
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
|
|
db $00,$30,$60
|
|
|
|
BackSceneryData
|
|
db $93,$00,$00,$11,$12,$12,$13,$00 ;clouds
|
|
db $00,$51,$52,$53,$00,$00,$00,$00
|
|
db $00,$00,$01,$02,$02,$03,$00,$00
|
|
db $00,$00,$00,$00,$91,$92,$93,$00
|
|
db $00,$00,$00,$51,$52,$53,$41,$42
|
|
db $43,$00,$00,$00,$00,$00,$91,$92
|
|
|
|
db $97,$87,$88,$89,$99,$00,$00,$00 ;mountains and bushes
|
|
db $11,$12,$13,$a4,$a5,$a5,$a5,$a6
|
|
db $97,$98,$99,$01,$02,$03,$00,$a4
|
|
db $a5,$a6,$00,$11,$12,$12,$12,$13
|
|
db $00,$00,$00,$00,$01,$02,$02,$03
|
|
db $00,$a4,$a5,$a5,$a6,$00,$00,$00
|
|
|
|
db $11,$12,$12,$13,$00,$00,$00,$00 ;trees and fences
|
|
db $00,$00,$00,$9c,$00,$8b,$aa,$aa
|
|
db $aa,$aa,$11,$12,$13,$8b,$00,$9c
|
|
db $9c,$00,$00,$01,$02,$03,$11,$12
|
|
db $12,$13,$00,$00,$00,$00,$aa,$aa
|
|
db $9c,$aa,$00,$8b,$00,$01,$02,$03
|
|
|
|
BackSceneryMetatiles
|
|
db $80,$83,$00 ;cloud left
|
|
db $81,$84,$00 ;cloud middle
|
|
db $82,$85,$00 ;cloud right
|
|
db $02,$00,$00 ;bush left
|
|
db $03,$00,$00 ;bush middle
|
|
db $04,$00,$00 ;bush right
|
|
db $00,$05,$06 ;mountain left
|
|
db $07,$06,$0a ;mountain middle
|
|
db $00,$08,$09 ;mountain right
|
|
db $4d,$00,$00 ;fence
|
|
db $0d,$0f,$4e ;tall tree
|
|
db $0e,$4e,$4e ;short tree
|
|
|
|
FSceneDataOffsets
|
|
db $00,$0d,$1a
|
|
|
|
ForeSceneryData
|
|
db $86,$87,$87,$87,$87,$87,$87 ;in water
|
|
db $87,$87,$87,$87,$69,$69
|
|
|
|
db $00,$00,$00,$00,$00,$45,$47 ;wall
|
|
db $47,$47,$47,$47,$00,$00
|
|
|
|
db $00,$00,$00,$00,$00,$00,$00 ;over water
|
|
db $00,$00,$00,$00,$86,$87
|
|
|
|
TerrainMetatiles
|
|
db $69,$54,$52,$62
|
|
|
|
TerrainRenderBits
|
|
db %00000000,%00000000
|
|
db %00000000,%00011000
|
|
db %00000001,%00011000
|
|
db %00000111,%00011000
|
|
db %00001111,%00011000
|
|
db %11111111,%00011000
|
|
db %00000001,%00011111
|
|
db %00000111,%00011111
|
|
db %00001111,%00011111
|
|
db %10000001,%00011111
|
|
db %00000001,%00000000
|
|
db %10001111,%00011111
|
|
db %11110001,%00011111
|
|
db %11111001,%00011000
|
|
db %11110001,%00011000
|
|
db %11111111,%00011111
|
|
|
|
AreaParserCore
|
|
lda BackloadingFlag ;check to see if we are starting right of start
|
|
beq RenderSceneryTerrain ;if not, go ahead and render background, foreground and terrain
|
|
jsr ProcessAreaData ;otherwise skip ahead and load level data
|
|
|
|
RenderSceneryTerrain
|
|
ldx #$0c
|
|
lda #$00
|
|
ClrMTBuf sta MetatileBuffer,x ;clear out metatile buffer
|
|
dex
|
|
bpl ClrMTBuf
|
|
ldy BackgroundScenery ;do we need to render the background scenery?
|
|
beq RendFore ;if not, skip to check the foreground
|
|
lda CurrentPageLoc ;otherwise check for every third page
|
|
ThirdP cmp #$03
|
|
bmi RendBack ;if less than three we're there
|
|
sec
|
|
sbc #$03 ;if 3 or more, subtract 3 and
|
|
bpl ThirdP ;do an unconditional branch
|
|
RendBack asl ;move results to higher nybble
|
|
asl
|
|
asl
|
|
asl
|
|
adc BSceneDataOffsets-1,y ;add to it offset loaded from here
|
|
adc CurrentColumnPos ;add to the result our current column position
|
|
tax
|
|
lda BackSceneryData,x ;load data from sum of offsets
|
|
beq RendFore ;if zero, no scenery for that part
|
|
pha
|
|
and #$0f ;save to stack and clear high nybble
|
|
sec
|
|
sbc #$01 ;subtract one (because low nybble is $01-$0c)
|
|
sta $00 ;save low nybble
|
|
asl ;multiply by three (shift to left and add result to old one)
|
|
adc $00 ;note that since d7 was nulled, the carry flag is always clear
|
|
tax ;save as offset for background scenery metatile data
|
|
pla ;get high nybble from stack, move low
|
|
lsr
|
|
lsr
|
|
lsr
|
|
lsr
|
|
tay ;use as second offset (used to determine height)
|
|
lda #$03 ;use previously saved memory location for counter
|
|
sta $00
|
|
SceLoop1 lda BackSceneryMetatiles,x ;load metatile data from offset of (lsb - 1) * 3
|
|
sta MetatileBuffer,y ;store into buffer from offset of (msb / 16)
|
|
inx
|
|
iny
|
|
cpy #$0b ;if at this location, leave loop
|
|
beq RendFore
|
|
dec $00 ;decrement until counter expires, barring exception
|
|
bne SceLoop1
|
|
RendFore ldx ForegroundScenery ;check for foreground data needed or not
|
|
beq RendTerr ;if not, skip this part
|
|
ldy FSceneDataOffsets-1,x ;load offset from location offset by header value, then
|
|
ldx #$00 ;reinit X
|
|
SceLoop2 lda ForeSceneryData,y ;load data until counter expires
|
|
beq NoFore ;do not store if zero found
|
|
sta MetatileBuffer,x
|
|
NoFore iny
|
|
inx
|
|
cpx #$0d ;store up to end of metatile buffer
|
|
bne SceLoop2
|
|
RendTerr ldy AreaType ;check world type for water level
|
|
bne TerMTile ;if not water level, skip this part
|
|
lda WorldNumber ;check world number, if not world number eight
|
|
cmp #World8 ;then skip this part
|
|
bne TerMTile
|
|
lda #$62 ;if set as water level and world number eight,
|
|
jmp StoreMT ;use castle wall metatile as terrain type
|
|
TerMTile lda TerrainMetatiles,y ;otherwise get appropriate metatile for area type
|
|
ldy CloudTypeOverride ;check for cloud type override
|
|
beq StoreMT ;if not set, keep value otherwise
|
|
lda #$88 ;use cloud block terrain
|
|
StoreMT sta $07 ;store value here
|
|
ldx #$00 ;initialize X, use as metatile buffer offset
|
|
lda TerrainControl ;use yet another value from the header
|
|
asl ;multiply by 2 and use as yet another offset
|
|
tay
|
|
TerrLoop lda TerrainRenderBits,y ;get one of the terrain rendering bit data
|
|
sta $00
|
|
iny ;increment Y and use as offset next time around
|
|
sty $01
|
|
lda CloudTypeOverride ;skip if value here is zero
|
|
beq NoCloud2
|
|
cpx #$00 ;otherwise, check if we're doing the ceiling byte
|
|
beq NoCloud2
|
|
lda $00 ;if not, mask out all but d3
|
|
and #%00001000
|
|
sta $00
|
|
NoCloud2 ldy #$00 ;start at beginning of bitmasks
|
|
TerrBChk lda Bitmasks,y ;load bitmask, then perform AND on contents of first byte
|
|
bit $00
|
|
beq NextTBit ;if not set, skip this part (do not write terrain to buffer)
|
|
lda $07
|
|
sta MetatileBuffer,x ;load terrain type metatile number and store into buffer here
|
|
NextTBit inx ;continue until end of buffer
|
|
cpx #$0d
|
|
beq RendBBuf ;if we're at the end, break out of this loop
|
|
lda AreaType ;check world type for underground area
|
|
cmp #$02
|
|
bne EndUChk ;if not underground, skip this part
|
|
cpx #$0b
|
|
bne EndUChk ;if we're at the bottom of the screen, override
|
|
lda #$54 ;old terrain type with ground level terrain type
|
|
sta $07
|
|
EndUChk iny ;increment bitmasks offset in Y
|
|
cpy #$08
|
|
bne TerrBChk ;if not all bits checked, loop back
|
|
ldy $01
|
|
bne TerrLoop ;unconditional branch, use Y to load next byte
|
|
RendBBuf jsr ProcessAreaData ;do the area data loading routine now
|
|
lda BlockBufferColumnPos
|
|
jsr GetBlockBufferAddr ;get block buffer address from where we're at
|
|
ldx #$00
|
|
ldy #$00 ;init index regs and start at beginning of smaller buffer
|
|
ChkMTLow sty $00
|
|
lda MetatileBuffer,x ;load stored metatile number
|
|
and #%11000000 ;mask out all but 2 MSB
|
|
asl
|
|
rol ;make %xx000000 into %000000xx
|
|
rol
|
|
tay ;use as offset in Y
|
|
lda MetatileBuffer,x ;reload original unmasked value here
|
|
cmp BlockBuffLowBounds,y ;check for certain values depending on bits set
|
|
bcs StrBlock ;if equal or greater, branch
|
|
lda #$00 ;if less, init value before storing
|
|
StrBlock ldy $00 ;get offset for block buffer
|
|
sta ($06),y ;store value into block buffer
|
|
tya
|
|
clc ;add 16 (move down one row) to offset
|
|
adc #$10
|
|
tay
|
|
inx ;increment column value
|
|
cpx #$0d
|
|
bcc ChkMTLow ;continue until we pass last row, then leave
|
|
rts
|
|
|
|
;numbers lower than these with the same attribute bits
|
|
;will not be stored in the block buffer
|
|
BlockBuffLowBounds
|
|
db $10,$51,$88,$c0
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$00 - used to store area object identifier
|
|
;$07 - used as adder to find proper area object code
|
|
|
|
ProcessAreaData
|
|
ldx #$02 ;start at the end of area object buffer
|
|
ProcADLoop stx ObjectOffset
|
|
lda #$00 ;reset flag
|
|
sta BehindAreaParserFlag
|
|
ldy AreaDataOffset ;get offset of area data pointer
|
|
lda (AreaData),y ;get first byte of area object
|
|
cmp #$fd ;if end-of-area, skip all this crap
|
|
beq RdyDecode
|
|
lda AreaObjectLength,x ;check area object buffer flag
|
|
bpl RdyDecode ;if buffer not negative, branch, otherwise
|
|
iny
|
|
lda (AreaData),y ;get second byte of area object
|
|
asl ;check for page select bit (d7), branch if not set
|
|
bcc Chk1Row13
|
|
lda AreaObjectPageSel ;check page select
|
|
bne Chk1Row13
|
|
inc AreaObjectPageSel ;if not already set, set it now
|
|
inc AreaObjectPageLoc ;and increment page location
|
|
Chk1Row13 dey
|
|
lda (AreaData),y ;reread first byte of level object
|
|
and #$0f ;mask out high nybble
|
|
cmp #$0d ;row 13?
|
|
bne Chk1Row14
|
|
iny ;if so, reread second byte of level object
|
|
lda (AreaData),y
|
|
dey ;decrement to get ready to read first byte
|
|
and #%01000000 ;check for d6 set (if not, object is page control)
|
|
bne CheckRear
|
|
lda AreaObjectPageSel ;if page select is set, do not reread
|
|
bne CheckRear
|
|
iny ;if d6 not set, reread second byte
|
|
lda (AreaData),y
|
|
and #%00011111 ;mask out all but 5 LSB and store in page control
|
|
sta AreaObjectPageLoc
|
|
inc AreaObjectPageSel ;increment page select
|
|
jmp NextAObj
|
|
Chk1Row14 cmp #$0e ;row 14?
|
|
bne CheckRear
|
|
lda BackloadingFlag ;check flag for saved page number and branch if set
|
|
bne RdyDecode ;to render the object (otherwise bg might not look right)
|
|
CheckRear lda AreaObjectPageLoc ;check to see if current page of level object is
|
|
cmp CurrentPageLoc ;behind current page of renderer
|
|
bcc SetBehind ;if so branch
|
|
RdyDecode jsr DecodeAreaData ;do sub and do not turn on flag
|
|
jmp ChkLength
|
|
SetBehind inc BehindAreaParserFlag ;turn on flag if object is behind renderer
|
|
NextAObj jsr IncAreaObjOffset ;increment buffer offset and move on
|
|
ChkLength ldx ObjectOffset ;get buffer offset
|
|
lda AreaObjectLength,x ;check object length for anything stored here
|
|
bmi ProcLoopb ;if not, branch to handle loopback
|
|
dec AreaObjectLength,x ;otherwise decrement length or get rid of it
|
|
ProcLoopb dex ;decrement buffer offset
|
|
bpl ProcADLoop ;and loopback unless exceeded buffer
|
|
lda BehindAreaParserFlag ;check for flag set if objects were behind renderer
|
|
bne ProcessAreaData ;branch if true to load more level data, otherwise
|
|
lda BackloadingFlag ;check for flag set if starting right of page $00
|
|
bne ProcessAreaData ;branch if true to load more level data, otherwise leave
|
|
EndAParse rts
|
|
|
|
IncAreaObjOffset
|
|
inc AreaDataOffset ;increment offset of level pointer
|
|
inc AreaDataOffset
|
|
lda #$00 ;reset page select
|
|
sta AreaObjectPageSel
|
|
rts
|
|
|
|
DecodeAreaData
|
|
lda AreaObjectLength,x ;check current buffer flag
|
|
bmi Chk1stB
|
|
ldy AreaObjOffsetBuffer,x ;if not, get offset from buffer
|
|
Chk1stB ldx #$10 ;load offset of 16 for special row 15
|
|
lda (AreaData),y ;get first byte of level object again
|
|
cmp #$fd
|
|
beq EndAParse ;if end of level, leave this routine
|
|
and #$0f ;otherwise, mask out low nybble
|
|
cmp #$0f ;row 15?
|
|
beq ChkRow14 ;if so, keep the offset of 16
|
|
ldx #$08 ;otherwise load offset of 8 for special row 12
|
|
cmp #$0c ;row 12?
|
|
beq ChkRow14 ;if so, keep the offset value of 8
|
|
ldx #$00 ;otherwise nullify value by default
|
|
ChkRow14 stx $07 ;store whatever value we just loaded here
|
|
ldx ObjectOffset ;get object offset again
|
|
cmp #$0e ;row 14?
|
|
bne ChkRow13
|
|
lda #$00 ;if so, load offset with $00
|
|
sta $07
|
|
lda #$2e ;and load A with another value
|
|
bne NormObj ;unconditional branch
|
|
ChkRow13 cmp #$0d ;row 13?
|
|
bne ChkSRows
|
|
lda #$22 ;if so, load offset with 34
|
|
sta $07
|
|
iny ;get next byte
|
|
lda (AreaData),y
|
|
and #%01000000 ;mask out all but d6 (page control obj bit)
|
|
beq LeavePar ;if d6 clear, branch to leave (we handled this earlier)
|
|
lda (AreaData),y ;otherwise, get byte again
|
|
and #%01111111 ;mask out d7
|
|
cmp #$4b ;check for loop command in low nybble
|
|
bne Mask2MSB ;(plus d6 set for object other than page control)
|
|
inc LoopCommand ;if loop command, set loop command flag
|
|
Mask2MSB and #%00111111 ;mask out d7 and d6
|
|
jmp NormObj ;and jump
|
|
ChkSRows cmp #$0c ;row 12-15?
|
|
bcs SpecObj
|
|
iny ;if not, get second byte of level object
|
|
lda (AreaData),y
|
|
and #%01110000 ;mask out all but d6-d4
|
|
bne LrgObj ;if any bits set, branch to handle large object
|
|
lda #$16
|
|
sta $07 ;otherwise set offset of 24 for small object
|
|
lda (AreaData),y ;reload second byte of level object
|
|
and #%00001111 ;mask out higher nybble and jump
|
|
jmp NormObj
|
|
LrgObj sta $00 ;store value here (branch for large objects)
|
|
cmp #$70 ;check for vertical pipe object
|
|
bne NotWPipe
|
|
lda (AreaData),y ;if not, reload second byte
|
|
and #%00001000 ;mask out all but d3 (usage control bit)
|
|
beq NotWPipe ;if d3 clear, branch to get original value
|
|
lda #$00 ;otherwise, nullify value for warp pipe
|
|
sta $00
|
|
NotWPipe lda $00 ;get value and jump ahead
|
|
jmp MoveAOId
|
|
SpecObj iny ;branch here for rows 12-15
|
|
lda (AreaData),y
|
|
and #%01110000 ;get next byte and mask out all but d6-d4
|
|
MoveAOId lsr ;move d6-d4 to lower nybble
|
|
lsr
|
|
lsr
|
|
lsr
|
|
NormObj sta $00 ;store value here (branch for small objects and rows 13 and 14)
|
|
lda AreaObjectLength,x ;is there something stored here already?
|
|
bpl RunAObj ;if so, branch to do its particular sub
|
|
lda AreaObjectPageLoc ;otherwise check to see if the object we've loaded is on the
|
|
cmp CurrentPageLoc ;same page as the renderer, and if so, branch
|
|
beq InitRear
|
|
ldy AreaDataOffset ;if not, get old offset of level pointer
|
|
lda (AreaData),y ;and reload first byte
|
|
and #%00001111
|
|
cmp #$0e ;row 14?
|
|
bne LeavePar
|
|
lda BackloadingFlag ;if so, check backloading flag
|
|
bne StrAObj ;if set, branch to render object, else leave
|
|
LeavePar rts
|
|
InitRear lda BackloadingFlag ;check backloading flag to see if it's been initialized
|
|
beq BackColC ;branch to column-wise check
|
|
lda #$00 ;if not, initialize both backloading and
|
|
sta BackloadingFlag ;behind-renderer flags and leave
|
|
sta BehindAreaParserFlag
|
|
sta ObjectOffset
|
|
LoopCmdE rts
|
|
BackColC ldy AreaDataOffset ;get first byte again
|
|
lda (AreaData),y
|
|
and #%11110000 ;mask out low nybble and move high to low
|
|
lsr
|
|
lsr
|
|
lsr
|
|
lsr
|
|
cmp CurrentColumnPos ;is this where we're at?
|
|
bne LeavePar ;if not, branch to leave
|
|
StrAObj lda AreaDataOffset ;if so, load area obj offset and store in buffer
|
|
sta AreaObjOffsetBuffer,x
|
|
jsr IncAreaObjOffset ;do sub to increment to next object data
|
|
RunAObj lda $00 ;get stored value and add offset to it
|
|
clc ;then use the jump engine with current contents of A
|
|
adc $07
|
|
jsr JumpEngine
|
|
|
|
;large objects (rows $00-$0b or 00-11, d6-d4 set)
|
|
dw VerticalPipe ;used by warp pipes
|
|
dw AreaStyleObject
|
|
dw RowOfBricks
|
|
dw RowOfSolidBlocks
|
|
dw RowOfCoins
|
|
dw ColumnOfBricks
|
|
dw ColumnOfSolidBlocks
|
|
dw VerticalPipe ;used by decoration pipes
|
|
|
|
;objects for special row $0c or 12
|
|
dw Hole_Empty
|
|
dw PulleyRopeObject
|
|
dw Bridge_High
|
|
dw Bridge_Middle
|
|
dw Bridge_Low
|
|
dw Hole_Water
|
|
dw QuestionBlockRow_High
|
|
dw QuestionBlockRow_Low
|
|
|
|
;objects for special row $0f or 15
|
|
dw EndlessRope
|
|
dw BalancePlatRope
|
|
dw CastleObject
|
|
dw StaircaseObject
|
|
dw ExitPipe
|
|
dw FlagBalls_Residual
|
|
|
|
;small objects (rows $00-$0b or 00-11, d6-d4 all clear)
|
|
dw QuestionBlock ;power-up
|
|
dw QuestionBlock ;coin
|
|
dw QuestionBlock ;hidden, coin
|
|
dw Hidden1UpBlock ;hidden, 1-up
|
|
dw BrickWithItem ;brick, power-up
|
|
dw BrickWithItem ;brick, vine
|
|
dw BrickWithItem ;brick, star
|
|
dw BrickWithCoins ;brick, coins
|
|
dw BrickWithItem ;brick, 1-up
|
|
dw WaterPipe
|
|
dw EmptyBlock
|
|
dw Jumpspring
|
|
|
|
;objects for special row $0d or 13 (d6 set)
|
|
dw IntroPipe
|
|
dw FlagpoleObject
|
|
dw AxeObj
|
|
dw ChainObj
|
|
dw CastleBridgeObj
|
|
dw ScrollLockObject_Warp
|
|
dw ScrollLockObject
|
|
dw ScrollLockObject
|
|
dw AreaFrenzy ;flying cheep-cheeps
|
|
dw AreaFrenzy ;bullet bills or swimming cheep-cheeps
|
|
dw AreaFrenzy ;stop frenzy
|
|
dw LoopCmdE
|
|
|
|
;object for special row $0e or 14
|
|
dw 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
|
|
ldy AreaObjOffsetBuffer,x ;load offset for level object data saved in buffer
|
|
iny ;load second byte
|
|
lda (AreaData),y
|
|
pha ;save in stack for now
|
|
and #%01000000
|
|
bne Alter2 ;branch if d6 is set
|
|
pla
|
|
pha ;pull and push offset to copy to A
|
|
and #%00001111 ;mask out high nybble and store as
|
|
sta TerrainControl ;new terrain height type bits
|
|
pla
|
|
and #%00110000 ;pull and mask out all but d5 and d4
|
|
lsr ;move bits to lower nybble and store
|
|
lsr ;as new background scenery bits
|
|
lsr
|
|
lsr
|
|
sta BackgroundScenery ;then leave
|
|
rts
|
|
Alter2 pla
|
|
and #%00000111 ;mask out all but 3 LSB
|
|
cmp #$04 ;if four or greater, set color control bits
|
|
bcc SetFore ;and nullify foreground scenery bits
|
|
sta BackgroundColorCtrl
|
|
lda #$00
|
|
SetFore sta ForegroundScenery ;otherwise set new foreground scenery bits
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
ScrollLockObject_Warp
|
|
ldx #$04 ;load value of 4 for game text routine as default
|
|
lda WorldNumber ;warp zone (4-3-2), then check world number
|
|
beq WarpNum
|
|
inx ;if world number > 1, increment for next warp zone (5)
|
|
ldy AreaType ;check area type
|
|
dey
|
|
bne WarpNum ;if ground area type, increment for last warp zone
|
|
inx ;(8-7-6) and move on
|
|
WarpNum txa
|
|
sta WarpZoneControl ;store number here to be used by warp zone routine
|
|
jsr WriteGameText ;print text and warp zone numbers
|
|
lda #PiranhaPlant
|
|
jsr KillEnemies ;load identifier for piranha plants and do sub
|
|
|
|
ScrollLockObject
|
|
lda ScrollLock ;invert scroll lock to turn it on
|
|
eor #%00000001
|
|
sta ScrollLock
|
|
rts
|
|
|
|
;--------------------------------
|
|
;$00 - used to store enemy identifier in KillEnemies
|
|
|
|
KillEnemies
|
|
sta $00 ;store identifier here
|
|
lda #$00
|
|
ldx #$04 ;check for identifier in enemy object buffer
|
|
KillELoop ldy Enemy_ID,x
|
|
cpy $00 ;if not found, branch
|
|
bne NoKillE
|
|
sta Enemy_Flag,x ;if found, deactivate enemy object flag
|
|
NoKillE dex ;do this until all slots are checked
|
|
bpl KillELoop
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
FrenzyIDData
|
|
db FlyCheepCheepFrenzy, BBill_CCheep_Frenzy,
|
|
|
|
AreaFrenzy ldx $00 ;use area object identifier bit as offset
|
|
lda FrenzyIDData-8,x ;note that it starts at 8, thus weird address here
|
|
ldy #$05
|
|
FreCompLoop dey ;check regular slots of enemy object buffer
|
|
bmi ExitAFrenzy ;if all slots checked and enemy object not found, branch to store
|
|
cmp Enemy_ID,y ;check for enemy object in buffer versus frenzy object
|
|
bne FreCompLoop
|
|
lda #$00 ;if enemy object already present, nullify queue and leave
|
|
ExitAFrenzy sta EnemyFrenzyQueue ;store enemy into frenzy queue
|
|
rts
|
|
|
|
;--------------------------------
|
|
;$06 - used by MushroomLedge to store length
|
|
|
|
AreaStyleObject
|
|
lda AreaStyle ;load level object style and jump to the right sub
|
|
jsr JumpEngine
|
|
dw TreeLedge ;also used for cloud type levels
|
|
dw MushroomLedge
|
|
dw BulletBillCannon
|
|
|
|
TreeLedge
|
|
jsr GetLrgObjAttrib ;get row and length of green ledge
|
|
lda AreaObjectLength,x ;check length counter for expiration
|
|
beq EndTreeL
|
|
bpl MidTreeL
|
|
tya
|
|
sta AreaObjectLength,x ;store lower nybble into buffer flag as length of ledge
|
|
lda CurrentPageLoc
|
|
ora CurrentColumnPos ;are we at the start of the level?
|
|
beq MidTreeL
|
|
lda #$16 ;render start of tree ledge
|
|
jmp NoUnder
|
|
MidTreeL ldx $07
|
|
lda #$17 ;render middle of tree ledge
|
|
sta MetatileBuffer,x ;note that this is also used if ledge position is
|
|
lda #$4c ;at the start of level for continuous effect
|
|
jmp AllUnder ;now render the part underneath
|
|
EndTreeL lda #$18 ;render end of tree ledge
|
|
jmp NoUnder
|
|
|
|
MushroomLedge
|
|
jsr ChkLrgObjLength ;get shroom dimensions
|
|
sty $06 ;store length here for now
|
|
bcc EndMushL
|
|
lda AreaObjectLength,x ;divide length by 2 and store elsewhere
|
|
lsr
|
|
sta MushroomLedgeHalfLen,x
|
|
lda #$19 ;render start of mushroom
|
|
jmp NoUnder
|
|
EndMushL lda #$1b ;if at the end, render end of mushroom
|
|
ldy AreaObjectLength,x
|
|
beq NoUnder
|
|
lda MushroomLedgeHalfLen,x ;get divided length and store where length
|
|
sta $06 ;was stored originally
|
|
ldx $07
|
|
lda #$1a
|
|
sta MetatileBuffer,x ;render middle of mushroom
|
|
cpy $06 ;are we smack dab in the center?
|
|
bne MushLExit ;if not, branch to leave
|
|
inx
|
|
lda #$4f
|
|
sta MetatileBuffer,x ;render stem top of mushroom underneath the middle
|
|
lda #$50
|
|
AllUnder inx
|
|
ldy #$0f ;set $0f to render all way down
|
|
jmp RenderUnderPart ;now render the stem of mushroom
|
|
NoUnder ldx $07 ;load row of ledge
|
|
ldy #$00 ;set 0 for no bottom on this part
|
|
jmp RenderUnderPart
|
|
|
|
;--------------------------------
|
|
|
|
;tiles used by pulleys and rope object
|
|
PulleyRopeMetatiles
|
|
db $42,$41,$43
|
|
|
|
PulleyRopeObject
|
|
jsr ChkLrgObjLength ;get length of pulley/rope object
|
|
ldy #$00 ;initialize metatile offset
|
|
bcs RenderPul ;if starting, render left pulley
|
|
iny
|
|
lda AreaObjectLength,x ;if not at the end, render rope
|
|
bne RenderPul
|
|
iny ;otherwise render right pulley
|
|
RenderPul lda PulleyRopeMetatiles,y
|
|
sta MetatileBuffer ;render at the top of the screen
|
|
MushLExit rts ;and leave
|
|
|
|
;--------------------------------
|
|
;$06 - used to store upper limit of rows for CastleObject
|
|
|
|
CastleMetatiles
|
|
db $00,$45,$45,$45,$00
|
|
db $00,$48,$47,$46,$00
|
|
db $45,$49,$49,$49,$45
|
|
db $47,$47,$4a,$47,$47
|
|
db $47,$47,$4b,$47,$47
|
|
db $49,$49,$49,$49,$49
|
|
db $47,$4a,$47,$4a,$47
|
|
db $47,$4b,$47,$4b,$47
|
|
db $47,$47,$47,$47,$47
|
|
db $4a,$47,$4a,$47,$4a
|
|
db $4b,$47,$4b,$47,$4b
|
|
|
|
CastleObject
|
|
jsr GetLrgObjAttrib ;save lower nybble as starting row
|
|
sty $07 ;if starting row is above $0a, game will crash!!!
|
|
ldy #$04
|
|
jsr ChkLrgObjFixedLength ;load length of castle if not already loaded
|
|
txa
|
|
pha ;save obj buffer offset to stack
|
|
ldy AreaObjectLength,x ;use current length as offset for castle data
|
|
ldx $07 ;begin at starting row
|
|
lda #$0b
|
|
sta $06 ;load upper limit of number of rows to print
|
|
CRendLoop lda CastleMetatiles,y ;load current byte using offset
|
|
sta MetatileBuffer,x
|
|
inx ;store in buffer and increment buffer offset
|
|
lda $06
|
|
beq ChkCFloor ;have we reached upper limit yet?
|
|
iny ;if not, increment column-wise
|
|
iny ;to byte in next row
|
|
iny
|
|
iny
|
|
iny
|
|
dec $06 ;move closer to upper limit
|
|
ChkCFloor cpx #$0b ;have we reached the row just before floor?
|
|
bne CRendLoop ;if not, go back and do another row
|
|
pla
|
|
tax ;get obj buffer offset from before
|
|
lda CurrentPageLoc
|
|
beq ExitCastle ;if we're at page 0, we do not need to do anything else
|
|
lda AreaObjectLength,x ;check length
|
|
cmp #$01 ;if length almost about to expire, put brick at floor
|
|
beq PlayerStop
|
|
ldy $07 ;check starting row for tall castle ($00)
|
|
bne NotTall
|
|
cmp #$03 ;if found, then check to see if we're at the second column
|
|
beq PlayerStop
|
|
NotTall cmp #$02 ;if not tall castle, check to see if we're at the third column
|
|
bne ExitCastle ;if we aren't and the castle is tall, don't create flag yet
|
|
jsr GetAreaObjXPosition ;otherwise, obtain and save horizontal pixel coordinate
|
|
pha
|
|
jsr FindEmptyEnemySlot ;find an empty place on the enemy object buffer
|
|
pla
|
|
sta Enemy_X_Position,x ;then write horizontal coordinate for star flag
|
|
lda CurrentPageLoc
|
|
sta Enemy_PageLoc,x ;set page location for star flag
|
|
lda #$01
|
|
sta Enemy_Y_HighPos,x ;set vertical high byte
|
|
sta Enemy_Flag,x ;set flag for buffer
|
|
lda #$90
|
|
sta Enemy_Y_Position,x ;set vertical coordinate
|
|
lda #StarFlagObject ;set star flag value in buffer itself
|
|
sta Enemy_ID,x
|
|
rts
|
|
PlayerStop ldy #$52 ;put brick at floor to stop player at end of level
|
|
sty MetatileBuffer+10 ;this is only done if we're on the second column
|
|
ExitCastle rts
|
|
|
|
;--------------------------------
|
|
|
|
WaterPipe
|
|
jsr GetLrgObjAttrib ;get row and lower nybble
|
|
ldy AreaObjectLength,x ;get length (residual code, water pipe is 1 col thick)
|
|
ldx $07 ;get row
|
|
lda #$6b
|
|
sta MetatileBuffer,x ;draw something here and below it
|
|
lda #$6c
|
|
sta MetatileBuffer+1,x
|
|
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
|
|
|
|
IntroPipe
|
|
ldy #$03 ;check if length set, if not set, set it
|
|
jsr ChkLrgObjFixedLength
|
|
ldy #$0a ;set fixed value and render the sideways part
|
|
jsr RenderSidewaysPipe
|
|
bcs NoBlankP ;if carry flag set, not time to draw vertical pipe part
|
|
ldx #$06 ;blank everything above the vertical pipe part
|
|
VPipeSectLoop lda #$00 ;all the way to the top of the screen
|
|
sta MetatileBuffer,x ;because otherwise it will look like exit pipe
|
|
dex
|
|
bpl VPipeSectLoop
|
|
lda VerticalPipeData,y ;draw the end of the vertical pipe part
|
|
sta MetatileBuffer+7
|
|
NoBlankP rts
|
|
|
|
SidePipeShaftData
|
|
db $15,$14 ;used to control whether or not vertical pipe shaft
|
|
db $00,$00 ;is drawn, and if so, controls the metatile number
|
|
SidePipeTopPart
|
|
db $15,$1e ;top part of sideways part of pipe
|
|
db $1d,$1c
|
|
SidePipeBottomPart
|
|
db $15,$21 ;bottom part of sideways part of pipe
|
|
db $20,$1f
|
|
|
|
ExitPipe
|
|
ldy #$03 ;check if length set, if not set, set it
|
|
jsr ChkLrgObjFixedLength
|
|
jsr GetLrgObjAttrib ;get vertical length, then plow on through RenderSidewaysPipe
|
|
|
|
RenderSidewaysPipe
|
|
dey ;decrement twice to make room for shaft at bottom
|
|
dey ;and store here for now as vertical length
|
|
sty $05
|
|
ldy AreaObjectLength,x ;get length left over and store here
|
|
sty $06
|
|
ldx $05 ;get vertical length plus one, use as buffer offset
|
|
inx
|
|
lda SidePipeShaftData,y ;check for value $00 based on horizontal offset
|
|
cmp #$00
|
|
beq DrawSidePart ;if found, do not draw the vertical pipe shaft
|
|
ldx #$00
|
|
ldy $05 ;init buffer offset and get vertical length
|
|
jsr RenderUnderPart ;and render vertical shaft using tile number in A
|
|
clc ;clear carry flag to be used by IntroPipe
|
|
DrawSidePart ldy $06 ;render side pipe part at the bottom
|
|
lda SidePipeTopPart,y
|
|
sta MetatileBuffer,x ;note that the pipe parts are stored
|
|
lda SidePipeBottomPart,y ;backwards horizontally
|
|
sta MetatileBuffer+1,x
|
|
rts
|
|
|
|
VerticalPipeData
|
|
db $11,$10 ;used by pipes that lead somewhere
|
|
db $15,$14
|
|
db $13,$12 ;used by decoration pipes
|
|
db $15,$14
|
|
|
|
VerticalPipe
|
|
jsr GetPipeHeight
|
|
lda $00 ;check to see if value was nullified earlier
|
|
beq WarpPipe ;(if d3, the usage control bit of second byte, was set)
|
|
iny
|
|
iny
|
|
iny
|
|
iny ;add four if usage control bit was not set
|
|
WarpPipe tya ;save value in stack
|
|
pha
|
|
lda AreaNumber
|
|
ora WorldNumber ;if at world 1-1, do not add piranha plant ever
|
|
beq DrawPipe
|
|
ldy AreaObjectLength,x ;if on second column of pipe, branch
|
|
beq DrawPipe ;(because we only need to do this once)
|
|
jsr FindEmptyEnemySlot ;check for an empty moving data buffer space
|
|
bcs DrawPipe ;if not found, too many enemies, thus skip
|
|
jsr GetAreaObjXPosition ;get horizontal pixel coordinate
|
|
clc
|
|
adc #$08 ;add eight to put the piranha plant in the center
|
|
sta Enemy_X_Position,x ;store as enemy's horizontal coordinate
|
|
lda CurrentPageLoc ;add carry to current page number
|
|
adc #$00
|
|
sta Enemy_PageLoc,x ;store as enemy's page coordinate
|
|
lda #$01
|
|
sta Enemy_Y_HighPos,x
|
|
sta Enemy_Flag,x ;activate enemy flag
|
|
jsr GetAreaObjYPosition ;get piranha plant's vertical coordinate and store here
|
|
sta Enemy_Y_Position,x
|
|
lda #PiranhaPlant ;write piranha plant's value into buffer
|
|
sta Enemy_ID,x
|
|
jsr InitPiranhaPlant
|
|
DrawPipe pla ;get value saved earlier and use as Y
|
|
tay
|
|
ldx $07 ;get buffer offset
|
|
lda VerticalPipeData,y ;draw the appropriate pipe with the Y we loaded earlier
|
|
sta MetatileBuffer,x ;render the top of the pipe
|
|
inx
|
|
lda VerticalPipeData+2,y ;render the rest of the pipe
|
|
ldy $06 ;subtract one from length and render the part underneath
|
|
dey
|
|
jmp RenderUnderPart
|
|
|
|
GetPipeHeight
|
|
ldy #$01 ;check for length loaded, if not, load
|
|
jsr ChkLrgObjFixedLength ;pipe length of 2 (horizontal)
|
|
jsr GetLrgObjAttrib
|
|
tya ;get saved lower nybble as height
|
|
and #$07 ;save only the three lower bits as
|
|
sta $06 ;vertical length, then load Y with
|
|
ldy AreaObjectLength,x ;length left over
|
|
rts
|
|
|
|
FindEmptyEnemySlot
|
|
ldx #$00 ;start at first enemy slot
|
|
EmptyChkLoop clc ;clear carry flag by default
|
|
lda Enemy_Flag,x ;check enemy buffer for nonzero
|
|
beq ExitEmptyChk ;if zero, leave
|
|
inx
|
|
cpx #$05 ;if nonzero, check next value
|
|
bne EmptyChkLoop
|
|
ExitEmptyChk rts ;if all values nonzero, carry flag is set
|
|
|
|
;--------------------------------
|
|
|
|
Hole_Water
|
|
jsr ChkLrgObjLength ;get low nybble and save as length
|
|
lda #$86 ;render waves
|
|
sta MetatileBuffer+10
|
|
ldx #$0b
|
|
ldy #$01 ;now render the water underneath
|
|
lda #$87
|
|
jmp RenderUnderPart
|
|
|
|
;--------------------------------
|
|
|
|
QuestionBlockRow_High
|
|
lda #$03 ;start on the fourth row
|
|
db $2c ;BIT instruction opcode
|
|
|
|
QuestionBlockRow_Low
|
|
lda #$07 ;start on the eighth row
|
|
pha ;save whatever row to the stack for now
|
|
jsr ChkLrgObjLength ;get low nybble and save as length
|
|
pla
|
|
tax ;render question boxes with coins
|
|
lda #$c0
|
|
sta MetatileBuffer,x
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
Bridge_High
|
|
lda #$06 ;start on the seventh row from top of screen
|
|
db $2c ;BIT instruction opcode
|
|
|
|
Bridge_Middle
|
|
lda #$07 ;start on the eighth row
|
|
db $2c ;BIT instruction opcode
|
|
|
|
Bridge_Low
|
|
lda #$09 ;start on the tenth row
|
|
pha ;save whatever row to the stack for now
|
|
jsr ChkLrgObjLength ;get low nybble and save as length
|
|
pla
|
|
tax ;render bridge railing
|
|
lda #$0b
|
|
sta MetatileBuffer,x
|
|
inx
|
|
ldy #$00 ;now render the bridge itself
|
|
lda #$63
|
|
jmp RenderUnderPart
|
|
|
|
;--------------------------------
|
|
|
|
FlagBalls_Residual
|
|
jsr GetLrgObjAttrib ;get low nybble from object byte
|
|
ldx #$02 ;render flag balls on third row from top
|
|
lda #$6d ;of screen downwards based on low nybble
|
|
jmp RenderUnderPart
|
|
|
|
;--------------------------------
|
|
|
|
FlagpoleObject
|
|
lda #$24 ;render flagpole ball on top
|
|
sta MetatileBuffer
|
|
ldx #$01 ;now render the flagpole shaft
|
|
ldy #$08
|
|
lda #$25
|
|
jsr RenderUnderPart
|
|
lda #$61 ;render solid block at the bottom
|
|
sta MetatileBuffer+10
|
|
jsr GetAreaObjXPosition
|
|
sec ;get pixel coordinate of where the flagpole is,
|
|
sbc #$08 ;subtract eight pixels and use as horizontal
|
|
sta Enemy_X_Position+5 ;coordinate for the flag
|
|
lda CurrentPageLoc
|
|
sbc #$00 ;subtract borrow from page location and use as
|
|
sta Enemy_PageLoc+5 ;page location for the flag
|
|
lda #$30
|
|
sta Enemy_Y_Position+5 ;set vertical coordinate for flag
|
|
lda #$b0
|
|
sta FlagpoleFNum_Y_Pos ;set initial vertical coordinate for flagpole's floatey number
|
|
lda #FlagpoleFlagObject
|
|
sta Enemy_ID+5 ;set flag identifier, note that identifier and coordinates
|
|
inc Enemy_Flag+5 ;use last space in enemy object buffer
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
EndlessRope
|
|
ldx #$00 ;render rope from the top to the bottom of screen
|
|
ldy #$0f
|
|
jmp DrawRope
|
|
|
|
BalancePlatRope
|
|
txa ;save object buffer offset for now
|
|
pha
|
|
ldx #$01 ;blank out all from second row to the bottom
|
|
ldy #$0f ;with blank used for balance platform rope
|
|
lda #$44
|
|
jsr RenderUnderPart
|
|
pla ;get back object buffer offset
|
|
tax
|
|
jsr GetLrgObjAttrib ;get vertical length from lower nybble
|
|
ldx #$01
|
|
DrawRope lda #$40 ;render the actual rope
|
|
jmp RenderUnderPart
|
|
|
|
;--------------------------------
|
|
|
|
CoinMetatileData
|
|
db $c3,$c2,$c2,$c2
|
|
|
|
RowOfCoins
|
|
ldy AreaType ;get area type
|
|
lda CoinMetatileData,y ;load appropriate coin metatile
|
|
jmp GetRow
|
|
|
|
;--------------------------------
|
|
|
|
C_ObjectRow
|
|
db $06,$07,$08
|
|
|
|
C_ObjectMetatile
|
|
db $c5,$0c,$89
|
|
|
|
CastleBridgeObj
|
|
ldy #$0c ;load length of 13 columns
|
|
jsr ChkLrgObjFixedLength
|
|
jmp ChainObj
|
|
|
|
AxeObj
|
|
lda #$08 ;load bowser's palette into sprite portion of palette
|
|
sta VRAM_Buffer_AddrCtrl
|
|
|
|
ChainObj
|
|
ldy $00 ;get value loaded earlier from decoder
|
|
ldx C_ObjectRow-2,y ;get appropriate row and metatile for object
|
|
lda C_ObjectMetatile-2,y
|
|
jmp ColObj
|
|
|
|
EmptyBlock
|
|
jsr GetLrgObjAttrib ;get row location
|
|
ldx $07
|
|
lda #$c4
|
|
ColObj ldy #$00 ;column length of 1
|
|
jmp RenderUnderPart
|
|
|
|
;--------------------------------
|
|
|
|
SolidBlockMetatiles
|
|
db $69,$61,$61,$62
|
|
|
|
BrickMetatiles
|
|
db $22,$51,$52,$52
|
|
db $88 ;used only by row of bricks object
|
|
|
|
RowOfBricks
|
|
ldy AreaType ;load area type obtained from area offset pointer
|
|
lda CloudTypeOverride ;check for cloud type override
|
|
beq DrawBricks
|
|
ldy #$04 ;if cloud type, override area type
|
|
DrawBricks lda BrickMetatiles,y ;get appropriate metatile
|
|
jmp GetRow ;and go render it
|
|
|
|
RowOfSolidBlocks
|
|
ldy AreaType ;load area type obtained from area offset pointer
|
|
lda SolidBlockMetatiles,y ;get metatile
|
|
GetRow pha ;store metatile here
|
|
jsr ChkLrgObjLength ;get row number, load length
|
|
DrawRow ldx $07
|
|
ldy #$00 ;set vertical height of 1
|
|
pla
|
|
jmp RenderUnderPart ;render object
|
|
|
|
ColumnOfBricks
|
|
ldy AreaType ;load area type obtained from area offset
|
|
lda BrickMetatiles,y ;get metatile (no cloud override as for row)
|
|
jmp GetRow2
|
|
|
|
ColumnOfSolidBlocks
|
|
ldy AreaType ;load area type obtained from area offset
|
|
lda SolidBlockMetatiles,y ;get metatile
|
|
GetRow2 pha ;save metatile to stack for now
|
|
jsr GetLrgObjAttrib ;get length and row
|
|
pla ;restore metatile
|
|
ldx $07 ;get starting row
|
|
jmp RenderUnderPart ;now render the column
|
|
|
|
;--------------------------------
|
|
|
|
BulletBillCannon
|
|
jsr GetLrgObjAttrib ;get row and length of bullet bill cannon
|
|
ldx $07 ;start at first row
|
|
lda #$64 ;render bullet bill cannon
|
|
sta MetatileBuffer,x
|
|
inx
|
|
dey ;done yet?
|
|
bmi SetupCannon
|
|
lda #$65 ;if not, render middle part
|
|
sta MetatileBuffer,x
|
|
inx
|
|
dey ;done yet?
|
|
bmi SetupCannon
|
|
lda #$66 ;if not, render bottom until length expires
|
|
jsr RenderUnderPart
|
|
SetupCannon ldx Cannon_Offset ;get offset for data used by cannons and whirlpools
|
|
jsr GetAreaObjYPosition ;get proper vertical coordinate for cannon
|
|
sta Cannon_Y_Position,x ;and store it here
|
|
lda CurrentPageLoc
|
|
sta Cannon_PageLoc,x ;store page number for cannon here
|
|
jsr GetAreaObjXPosition ;get proper horizontal coordinate for cannon
|
|
sta Cannon_X_Position,x ;and store it here
|
|
inx
|
|
cpx #$06 ;increment and check offset
|
|
bcc StrCOffset ;if not yet reached sixth cannon, branch to save offset
|
|
ldx #$00 ;otherwise initialize it
|
|
StrCOffset stx Cannon_Offset ;save new offset and leave
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
StaircaseHeightData
|
|
db $07,$07,$06,$05,$04,$03,$02,$01,$00
|
|
|
|
StaircaseRowData
|
|
db $03,$03,$04,$05,$06,$07,$08,$09,$0a
|
|
|
|
StaircaseObject
|
|
jsr ChkLrgObjLength ;check and load length
|
|
bcc NextStair ;if length already loaded, skip init part
|
|
lda #$09 ;start past the end for the bottom
|
|
sta StaircaseControl ;of the staircase
|
|
NextStair dec StaircaseControl ;move onto next step (or first if starting)
|
|
ldy StaircaseControl
|
|
ldx StaircaseRowData,y ;get starting row and height to render
|
|
lda StaircaseHeightData,y
|
|
tay
|
|
lda #$61 ;now render solid block staircase
|
|
jmp RenderUnderPart
|
|
|
|
;--------------------------------
|
|
|
|
Jumpspring
|
|
jsr GetLrgObjAttrib
|
|
jsr FindEmptyEnemySlot ;find empty space in enemy object buffer
|
|
jsr GetAreaObjXPosition ;get horizontal coordinate for jumpspring
|
|
sta Enemy_X_Position,x ;and store
|
|
lda CurrentPageLoc ;store page location of jumpspring
|
|
sta Enemy_PageLoc,x
|
|
jsr GetAreaObjYPosition ;get vertical coordinate for jumpspring
|
|
sta Enemy_Y_Position,x ;and store
|
|
sta Jumpspring_FixedYPos,x ;store as permanent coordinate here
|
|
lda #JumpspringObject
|
|
sta Enemy_ID,x ;write jumpspring object to enemy object buffer
|
|
ldy #$01
|
|
sty Enemy_Y_HighPos,x ;store vertical high byte
|
|
inc Enemy_Flag,x ;set flag for enemy object buffer
|
|
ldx $07
|
|
lda #$67 ;draw metatiles in two rows where jumpspring is
|
|
sta MetatileBuffer,x
|
|
lda #$68
|
|
sta MetatileBuffer+1,x
|
|
rts
|
|
|
|
;--------------------------------
|
|
;$07 - used to save ID of brick object
|
|
|
|
Hidden1UpBlock
|
|
lda Hidden1UpFlag ;if flag not set, do not render object
|
|
beq ExitDecBlock
|
|
lda #$00 ;if set, init for the next one
|
|
sta Hidden1UpFlag
|
|
jmp BrickWithItem ;jump to code shared with unbreakable bricks
|
|
|
|
QuestionBlock
|
|
jsr GetAreaObjectID ;get value from level decoder routine
|
|
jmp DrawQBlk ;go to render it
|
|
|
|
BrickWithCoins
|
|
lda #$00 ;initialize multi-coin timer flag
|
|
sta BrickCoinTimerFlag
|
|
|
|
BrickWithItem
|
|
jsr GetAreaObjectID ;save area object ID
|
|
sty $07
|
|
lda #$00 ;load default adder for bricks with lines
|
|
ldy AreaType ;check level type for ground level
|
|
dey
|
|
beq BWithL ;if ground type, do not start with 5
|
|
lda #$05 ;otherwise use adder for bricks without lines
|
|
BWithL clc ;add object ID to adder
|
|
adc $07
|
|
tay ;use as offset for metatile
|
|
DrawQBlk lda BrickQBlockMetatiles,y ;get appropriate metatile for brick (question block
|
|
pha ;if branched to here from question block routine)
|
|
jsr GetLrgObjAttrib ;get row from location byte
|
|
jmp DrawRow ;now render the object
|
|
|
|
GetAreaObjectID
|
|
lda $00 ;get value saved from area parser routine
|
|
sec
|
|
sbc #$00 ;possibly residual code
|
|
tay ;save to Y
|
|
ExitDecBlock rts
|
|
|
|
;--------------------------------
|
|
|
|
HoleMetatiles
|
|
db $87,$00,$00,$00
|
|
|
|
Hole_Empty
|
|
jsr ChkLrgObjLength ;get lower nybble and save as length
|
|
bcc NoWhirlP ;skip this part if length already loaded
|
|
lda AreaType ;check for water type level
|
|
bne NoWhirlP ;if not water type, skip this part
|
|
ldx Whirlpool_Offset ;get offset for data used by cannons and whirlpools
|
|
jsr GetAreaObjXPosition ;get proper vertical coordinate of where we're at
|
|
sec
|
|
sbc #$10 ;subtract 16 pixels
|
|
sta Whirlpool_LeftExtent,x ;store as left extent of whirlpool
|
|
lda CurrentPageLoc ;get page location of where we're at
|
|
sbc #$00 ;subtract borrow
|
|
sta Whirlpool_PageLoc,x ;save as page location of whirlpool
|
|
iny
|
|
iny ;increment length by 2
|
|
tya
|
|
asl ;multiply by 16 to get size of whirlpool
|
|
asl ;note that whirlpool will always be
|
|
asl ;two blocks bigger than actual size of hole
|
|
asl ;and extend one block beyond each edge
|
|
sta Whirlpool_Length,x ;save size of whirlpool here
|
|
inx
|
|
cpx #$05 ;increment and check offset
|
|
bcc StrWOffset ;if not yet reached fifth whirlpool, branch to save offset
|
|
ldx #$00 ;otherwise initialize it
|
|
StrWOffset stx Whirlpool_Offset ;save new offset here
|
|
NoWhirlP ldx AreaType ;get appropriate metatile, then
|
|
lda HoleMetatiles,x ;render the hole proper
|
|
ldx #$08
|
|
ldy #$0f ;start at ninth row and go to bottom, run RenderUnderPart
|
|
|
|
;--------------------------------
|
|
|
|
RenderUnderPart
|
|
sty AreaObjectHeight ;store vertical length to render
|
|
ldy MetatileBuffer,x ;check current spot to see if there's something
|
|
beq DrawThisRow ;we need to keep, if nothing, go ahead
|
|
cpy #$17
|
|
beq WaitOneRow ;if middle part (tree ledge), wait until next row
|
|
cpy #$1a
|
|
beq WaitOneRow ;if middle part (mushroom ledge), wait until next row
|
|
cpy #$c0
|
|
beq DrawThisRow ;if question block w/ coin, overwrite
|
|
cpy #$c0
|
|
bcs WaitOneRow ;if any other metatile with palette 3, wait until next row
|
|
cpy #$54
|
|
bne DrawThisRow ;if cracked rock terrain, overwrite
|
|
cmp #$50
|
|
beq WaitOneRow ;if stem top of mushroom, wait until next row
|
|
DrawThisRow sta MetatileBuffer,x ;render contents of A from routine that called this
|
|
WaitOneRow inx
|
|
cpx #$0d ;stop rendering if we're at the bottom of the screen
|
|
bcs ExitUPartR
|
|
ldy AreaObjectHeight ;decrement, and stop rendering if there is no more length
|
|
dey
|
|
bpl RenderUnderPart
|
|
ExitUPartR rts
|
|
|
|
;--------------------------------
|
|
|
|
ChkLrgObjLength
|
|
jsr GetLrgObjAttrib ;get row location and size (length if branched to from here)
|
|
|
|
ChkLrgObjFixedLength
|
|
lda AreaObjectLength,x ;check for set length counter
|
|
clc ;clear carry flag for not just starting
|
|
bpl LenSet ;if counter not set, load it, otherwise leave alone
|
|
tya ;save length into length counter
|
|
sta AreaObjectLength,x
|
|
sec ;set carry flag if just starting
|
|
LenSet rts
|
|
|
|
|
|
GetLrgObjAttrib
|
|
ldy AreaObjOffsetBuffer,x ;get offset saved from area obj decoding routine
|
|
lda (AreaData),y ;get first byte of level object
|
|
and #%00001111
|
|
sta $07 ;save row location
|
|
iny
|
|
lda (AreaData),y ;get next byte, save lower nybble (length or height)
|
|
and #%00001111 ;as Y, then leave
|
|
tay
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
GetAreaObjXPosition
|
|
lda CurrentColumnPos ;multiply current offset where we're at by 16
|
|
asl ;to obtain horizontal pixel coordinate
|
|
asl
|
|
asl
|
|
asl
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
GetAreaObjYPosition
|
|
lda $07 ;multiply value by 16
|
|
asl
|
|
asl ;this will give us the proper vertical pixel coordinate
|
|
asl
|
|
asl
|
|
clc
|
|
adc #32 ;add 32 pixels for the status bar
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$06-$07 - used to store block buffer address used as indirect
|
|
|
|
BlockBufferAddr
|
|
db <Block_Buffer_1, <Block_Buffer_2
|
|
db >Block_Buffer_1, >Block_Buffer_2
|
|
|
|
GetBlockBufferAddr
|
|
pha ;take value of A, save
|
|
lsr ;move high nybble to low
|
|
lsr
|
|
lsr
|
|
lsr
|
|
tay ;use nybble as pointer to high byte
|
|
lda BlockBufferAddr+2,y ;of indirect here
|
|
sta $07
|
|
pla
|
|
and #%00001111 ;pull from stack, mask out high nybble
|
|
clc
|
|
adc BlockBufferAddr,y ;add to low byte
|
|
sta $06 ;store here and leave
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
;unused space
|
|
db $ff,$ff
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
AreaDataOfsLoopback
|
|
db $12,$36,$0e,$0e,$0e,$32,$32,$32,$0a,$26,$40
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
LoadAreaPointer
|
|
jsr FindAreaPointer ;find it and store it here
|
|
sta AreaPointer
|
|
GetAreaType and #%01100000 ;mask out all but d6 and d5
|
|
asl
|
|
rol
|
|
rol
|
|
rol ;make %0xx00000 into %000000xx
|
|
sta AreaType ;save 2 MSB as area type
|
|
rts
|
|
|
|
FindAreaPointer
|
|
ldy WorldNumber ;load offset from world variable
|
|
lda WorldAddrOffsets,y
|
|
clc ;add area number used to find data
|
|
adc AreaNumber
|
|
tay
|
|
lda AreaAddrOffsets,y ;from there we have our area pointer
|
|
rts
|
|
|
|
|
|
GetAreaDataAddrs
|
|
lda AreaPointer ;use 2 MSB for Y
|
|
jsr GetAreaType
|
|
tay
|
|
lda AreaPointer ;mask out all but 5 LSB
|
|
and #%00011111
|
|
sta AreaAddrsLOffset ;save as low offset
|
|
lda EnemyAddrHOffsets,y ;load base value with 2 altered MSB,
|
|
clc ;then add base value to 5 LSB, result
|
|
adc AreaAddrsLOffset ;becomes offset for level data
|
|
tay
|
|
lda EnemyDataAddrLow,y ;use offset to load pointer
|
|
sta EnemyDataLow
|
|
lda EnemyDataAddrHigh,y
|
|
sta EnemyDataHigh
|
|
ldy AreaType ;use area type as offset
|
|
lda AreaDataHOffsets,y ;do the same thing but with different base value
|
|
clc
|
|
adc AreaAddrsLOffset
|
|
tay
|
|
lda AreaDataAddrLow,y ;use this offset to load another pointer
|
|
sta AreaDataLow
|
|
lda AreaDataAddrHigh,y
|
|
sta AreaDataHigh
|
|
ldy #$00 ;load first byte of header
|
|
lda (AreaData),y
|
|
pha ;save it to the stack for now
|
|
and #%00000111 ;save 3 LSB for foreground scenery or bg color control
|
|
cmp #$04
|
|
bcc StoreFore
|
|
sta BackgroundColorCtrl ;if 4 or greater, save value here as bg color control
|
|
lda #$00
|
|
StoreFore sta ForegroundScenery ;if less, save value here as foreground scenery
|
|
pla ;pull byte from stack and push it back
|
|
pha
|
|
and #%00111000 ;save player entrance control bits
|
|
lsr ;shift bits over to LSBs
|
|
lsr
|
|
lsr
|
|
sta PlayerEntranceCtrl ;save value here as player entrance control
|
|
pla ;pull byte again but do not push it back
|
|
and #%11000000 ;save 2 MSB for game timer setting
|
|
clc
|
|
rol ;rotate bits over to LSBs
|
|
rol
|
|
rol
|
|
sta GameTimerSetting ;save value here as game timer setting
|
|
iny
|
|
lda (AreaData),y ;load second byte of header
|
|
pha ;save to stack
|
|
and #%00001111 ;mask out all but lower nybble
|
|
sta TerrainControl
|
|
pla ;pull and push byte to copy it to A
|
|
pha
|
|
and #%00110000 ;save 2 MSB for background scenery type
|
|
lsr
|
|
lsr ;shift bits to LSBs
|
|
lsr
|
|
lsr
|
|
sta BackgroundScenery ;save as background scenery
|
|
pla
|
|
and #%11000000
|
|
clc
|
|
rol ;rotate bits over to LSBs
|
|
rol
|
|
rol
|
|
cmp #%00000011 ;if set to 3, store here
|
|
bne StoreStyle ;and nullify other value
|
|
sta CloudTypeOverride ;otherwise store value in other place
|
|
lda #$00
|
|
StoreStyle sta AreaStyle
|
|
lda AreaDataLow ;increment area data address by 2 bytes
|
|
clc
|
|
adc #$02
|
|
sta AreaDataLow
|
|
lda AreaDataHigh
|
|
adc #$00
|
|
sta AreaDataHigh
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;GAME LEVELS DATA
|
|
|
|
WorldAddrOffsets
|
|
db World1Areas-AreaAddrOffsets, World2Areas-AreaAddrOffsets
|
|
db World3Areas-AreaAddrOffsets, World4Areas-AreaAddrOffsets
|
|
db World5Areas-AreaAddrOffsets, World6Areas-AreaAddrOffsets
|
|
db World7Areas-AreaAddrOffsets, World8Areas-AreaAddrOffsets
|
|
|
|
AreaAddrOffsets
|
|
World1Areas db $25,$29,$c0,$26,$60
|
|
World2Areas db $28,$29,$01,$27,$62
|
|
World3Areas db $24,$35,$20,$63
|
|
World4Areas db $22,$29,$41,$2c,$61
|
|
World5Areas db $2a,$31,$26,$62
|
|
World6Areas db $2e,$23,$2d,$60
|
|
World7Areas db $33,$29,$01,$27,$64
|
|
World8Areas db $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
|
|
db $1f,$06,$1c,$00
|
|
|
|
EnemyDataAddrLow
|
|
db <E_CastleArea1, <E_CastleArea2,
|
|
db <E_GroundArea1, <E_GroundArea2,
|
|
db <E_GroundArea7, <E_GroundArea8,
|
|
db <E_GroundArea13, <E_GroundArea14,
|
|
db <E_GroundArea19, <E_GroundArea20,
|
|
db <E_UndergroundArea2, <E_UndergroundArea3,
|
|
|
|
EnemyDataAddrHigh
|
|
db >E_CastleArea1, >E_CastleArea2,
|
|
db >E_GroundArea1, >E_GroundArea2,
|
|
db >E_GroundArea7, >E_GroundArea8,
|
|
db >E_GroundArea13, >E_GroundArea14,
|
|
db >E_GroundArea19, >E_GroundArea20,
|
|
db >E_UndergroundArea2, >E_UndergroundArea3,
|
|
|
|
AreaDataHOffsets
|
|
db $00,$03,$19,$1c
|
|
|
|
AreaDataAddrLow
|
|
db <L_WaterArea1, <L_WaterArea2,
|
|
db <L_GroundArea4, <L_GroundArea5,
|
|
db <L_GroundArea10, <L_GroundArea11,
|
|
db <L_GroundArea16, <L_GroundArea17,
|
|
db <L_GroundArea22, <L_UndergroundArea1,
|
|
db <L_CastleArea2, <L_CastleArea3,
|
|
|
|
AreaDataAddrHigh
|
|
db >L_WaterArea1, >L_WaterArea2,
|
|
db >L_GroundArea4, >L_GroundArea5,
|
|
db >L_GroundArea10, >L_GroundArea11,
|
|
db >L_GroundArea16, >L_GroundArea17,
|
|
db >L_GroundArea22, >L_UndergroundArea1,
|
|
db >L_CastleArea2, >L_CastleArea3,
|
|
|
|
;ENEMY OBJECT DATA
|
|
|
|
;level 1-4/6-4
|
|
E_CastleArea1
|
|
db $76,$dd,$bb,$4c,$ea,$1d,$1b,$cc,$56,$5d
|
|
db $16,$9d,$c6,$1d,$36,$9d,$c9,$1d,$04,$db
|
|
db $49,$1d,$84,$1b,$c9,$5d,$88,$95,$0f,$08
|
|
db $30,$4c,$78,$2d,$a6,$28,$90,$b5
|
|
db $ff
|
|
|
|
;level 4-4
|
|
E_CastleArea2
|
|
db $0f,$03,$56,$1b,$c9,$1b,$0f,$07,$36,$1b
|
|
db $aa,$1b,$48,$95,$0f,$0a,$2a,$1b,$5b,$0c
|
|
db $78,$2d,$90,$b5
|
|
db $ff
|
|
|
|
;level 2-4/5-4
|
|
E_CastleArea3
|
|
db $0b,$8c,$4b,$4c,$77,$5f,$eb,$0c,$bd,$db
|
|
db $19,$9d,$75,$1d,$7d,$5b,$d9,$1d,$3d,$dd
|
|
db $99,$1d,$26,$9d,$5a,$2b,$8a,$2c,$ca,$1b
|
|
db $20,$95,$7b,$5c,$db,$4c,$1b,$cc,$3b,$cc
|
|
db $78,$2d,$a6,$28,$90,$b5
|
|
db $ff
|
|
|
|
;level 3-4
|
|
E_CastleArea4
|
|
db $0b,$8c,$3b,$1d,$8b,$1d,$ab,$0c,$db,$1d
|
|
db $0f,$03,$65,$1d,$6b,$1b,$05,$9d,$0b,$1b
|
|
db $05,$9b,$0b,$1d,$8b,$0c,$1b,$8c,$70,$15
|
|
db $7b,$0c,$db,$0c,$0f,$08,$78,$2d,$a6,$28
|
|
db $90,$b5
|
|
db $ff
|
|
|
|
;level 7-4
|
|
E_CastleArea5
|
|
db $27,$a9,$4b,$0c,$68,$29,$0f,$06,$77,$1b
|
|
db $0f,$0b,$60,$15,$4b,$8c,$78,$2d,$90,$b5
|
|
db $ff
|
|
|
|
;level 8-4
|
|
E_CastleArea6
|
|
db $0f,$03,$8e,$65,$e1,$bb,$38,$6d,$a8,$3e,$e5,$e7
|
|
db $0f,$08,$0b,$02,$2b,$02,$5e,$65,$e1,$bb,$0e
|
|
db $db,$0e,$bb,$8e,$db,$0e,$fe,$65,$ec,$0f,$0d
|
|
db $4e,$65,$e1,$0f,$0e,$4e,$02,$e0,$0f,$10,$fe,$e5,$e1
|
|
db $1b,$85,$7b,$0c,$5b,$95,$78,$2d,$90,$b5
|
|
db $ff
|
|
|
|
;level 3-3
|
|
E_GroundArea1
|
|
db $a5,$86,$e4,$28,$18,$a8,$45,$83,$69,$03
|
|
db $c6,$29,$9b,$83,$16,$a4,$88,$24,$e9,$28
|
|
db $05,$a8,$7b,$28,$24,$8f,$c8,$03,$e8,$03
|
|
db $46,$a8,$85,$24,$c8,$24
|
|
db $ff
|
|
|
|
;level 8-3
|
|
E_GroundArea2
|
|
db $eb,$8e,$0f,$03,$fb,$05,$17,$85,$db,$8e
|
|
db $0f,$07,$57,$05,$7b,$05,$9b,$80,$2b,$85
|
|
db $fb,$05,$0f,$0b,$1b,$05,$9b,$05
|
|
db $ff
|
|
|
|
;level 4-1
|
|
E_GroundArea3
|
|
db $2e,$c2,$66,$e2,$11,$0f,$07,$02,$11,$0f,$0c
|
|
db $12,$11
|
|
db $ff
|
|
|
|
;level 6-2
|
|
E_GroundArea4
|
|
db $0e,$c2,$a8,$ab,$00,$bb,$8e,$6b,$82,$de,$00,$a0
|
|
db $33,$86,$43,$06,$3e,$b4,$a0,$cb,$02,$0f,$07
|
|
db $7e,$42,$a6,$83,$02,$0f,$0a,$3b,$02,$cb,$37
|
|
db $0f,$0c,$e3,$0e
|
|
db $ff
|
|
|
|
;level 3-1
|
|
E_GroundArea5
|
|
db $9b,$8e,$ca,$0e,$ee,$42,$44,$5b,$86,$80,$b8
|
|
db $1b,$80,$50,$ba,$10,$b7,$5b,$00,$17,$85
|
|
db $4b,$05,$fe,$34,$40,$b7,$86,$c6,$06,$5b,$80
|
|
db $83,$00,$d0,$38,$5b,$8e,$8a,$0e,$a6,$00
|
|
db $bb,$0e,$c5,$80,$f3,$00
|
|
db $ff
|
|
|
|
;level 1-1
|
|
E_GroundArea6
|
|
db $1e,$c2,$00,$6b,$06,$8b,$86,$63,$b7,$0f,$05
|
|
db $03,$06,$23,$06,$4b,$b7,$bb,$00,$5b,$b7
|
|
db $fb,$37,$3b,$b7,$0f,$0b,$1b,$37
|
|
db $ff
|
|
|
|
;level 1-3/5-3
|
|
E_GroundArea7
|
|
db $2b,$d7,$e3,$03,$c2,$86,$e2,$06,$76,$a5
|
|
db $a3,$8f,$03,$86,$2b,$57,$68,$28,$e9,$28
|
|
db $e5,$83,$24,$8f,$36,$a8,$5b,$03
|
|
db $ff
|
|
|
|
;level 2-3/7-3
|
|
E_GroundArea8
|
|
db $0f,$02,$78,$40,$48,$ce,$f8,$c3,$f8,$c3
|
|
db $0f,$07,$7b,$43,$c6,$d0,$0f,$8a,$c8,$50
|
|
db $ff
|
|
|
|
;level 2-1
|
|
E_GroundArea9
|
|
db $85,$86,$0b,$80,$1b,$00,$db,$37,$77,$80
|
|
db $eb,$37,$fe,$2b,$20,$2b,$80,$7b,$38,$ab,$b8
|
|
db $77,$86,$fe,$42,$20,$49,$86,$8b,$06,$9b,$80
|
|
db $7b,$8e,$5b,$b7,$9b,$0e,$bb,$0e,$9b,$80
|
|
;end of data terminator here is also used by pipe intro area
|
|
E_GroundArea10
|
|
db $ff
|
|
|
|
;level 5-1
|
|
E_GroundArea11
|
|
db $0b,$80,$60,$38,$10,$b8,$c0,$3b,$db,$8e
|
|
db $40,$b8,$f0,$38,$7b,$8e,$a0,$b8,$c0,$b8
|
|
db $fb,$00,$a0,$b8,$30,$bb,$ee,$42,$88,$0f,$0b
|
|
db $2b,$0e,$67,$0e
|
|
db $ff
|
|
|
|
;cloud level used in levels 2-1 and 5-2
|
|
E_GroundArea12
|
|
db $0a,$aa,$0e,$28,$2a,$0e,$31,$88
|
|
db $ff
|
|
|
|
;level 4-3
|
|
E_GroundArea13
|
|
db $c7,$83,$d7,$03,$42,$8f,$7a,$03,$05,$a4
|
|
db $78,$24,$a6,$25,$e4,$25,$4b,$83,$e3,$03
|
|
db $05,$a4,$89,$24,$b5,$24,$09,$a4,$65,$24
|
|
db $c9,$24,$0f,$08,$85,$25
|
|
db $ff
|
|
|
|
;level 6-3
|
|
E_GroundArea14
|
|
db $cd,$a5,$b5,$a8,$07,$a8,$76,$28,$cc,$25
|
|
db $65,$a4,$a9,$24,$e5,$24,$19,$a4,$0f,$07
|
|
db $95,$28,$e6,$24,$19,$a4,$d7,$29,$16,$a9
|
|
db $58,$29,$97,$29
|
|
db $ff
|
|
|
|
;level 6-1
|
|
E_GroundArea15
|
|
db $0f,$02,$02,$11,$0f,$07,$02,$11
|
|
db $ff
|
|
|
|
;warp zone area used in level 4-2
|
|
E_GroundArea16
|
|
db $ff
|
|
|
|
;level 8-1
|
|
E_GroundArea17
|
|
db $2b,$82,$ab,$38,$de,$42,$e2,$1b,$b8,$eb
|
|
db $3b,$db,$80,$8b,$b8,$1b,$82,$fb,$b8,$7b
|
|
db $80,$fb,$3c,$5b,$bc,$7b,$b8,$1b,$8e,$cb
|
|
db $0e,$1b,$8e,$0f,$0d,$2b,$3b,$bb,$b8,$eb,$82
|
|
db $4b,$b8,$bb,$38,$3b,$b7,$bb,$02,$0f,$13
|
|
db $1b,$00,$cb,$80,$6b,$bc
|
|
db $ff
|
|
|
|
;level 5-2
|
|
E_GroundArea18
|
|
db $7b,$80,$ae,$00,$80,$8b,$8e,$e8,$05,$f9,$86
|
|
db $17,$86,$16,$85,$4e,$2b,$80,$ab,$8e,$87,$85
|
|
db $c3,$05,$8b,$82,$9b,$02,$ab,$02,$bb,$86
|
|
db $cb,$06,$d3,$03,$3b,$8e,$6b,$0e,$a7,$8e
|
|
db $ff
|
|
|
|
;level 8-2
|
|
E_GroundArea19
|
|
db $29,$8e,$52,$11,$83,$0e,$0f,$03,$9b,$0e
|
|
db $2b,$8e,$5b,$0e,$cb,$8e,$fb,$0e,$fb,$82
|
|
db $9b,$82,$bb,$02,$fe,$42,$e8,$bb,$8e,$0f,$0a
|
|
db $ab,$0e,$cb,$0e,$f9,$0e,$88,$86,$a6,$06
|
|
db $db,$02,$b6,$8e
|
|
db $ff
|
|
|
|
;level 7-1
|
|
E_GroundArea20
|
|
db $ab,$ce,$de,$42,$c0,$cb,$ce,$5b,$8e,$1b,$ce
|
|
db $4b,$85,$67,$45,$0f,$07,$2b,$00,$7b,$85
|
|
db $97,$05,$0f,$0a,$92,$02
|
|
db $ff
|
|
|
|
;cloud level used in levels 3-1 and 6-2
|
|
E_GroundArea21
|
|
db $0a,$aa,$0e,$24,$4a,$1e,$23,$aa
|
|
db $ff
|
|
|
|
;level 3-2
|
|
E_GroundArea22
|
|
db $1b,$80,$bb,$38,$4b,$bc,$eb,$3b,$0f,$04
|
|
db $2b,$00,$ab,$38,$eb,$00,$cb,$8e,$fb,$80
|
|
db $ab,$b8,$6b,$80,$fb,$3c,$9b,$bb,$5b,$bc
|
|
db $fb,$00,$6b,$b8,$fb,$38
|
|
db $ff
|
|
|
|
;level 1-2
|
|
E_UndergroundArea1
|
|
db $0b,$86,$1a,$06,$db,$06,$de,$c2,$02,$f0,$3b
|
|
db $bb,$80,$eb,$06,$0b,$86,$93,$06,$f0,$39
|
|
db $0f,$06,$60,$b8,$1b,$86,$a0,$b9,$b7,$27
|
|
db $bd,$27,$2b,$83,$a1,$26,$a9,$26,$ee,$25,$0b
|
|
db $27,$b4
|
|
db $ff
|
|
|
|
;level 4-2
|
|
E_UndergroundArea2
|
|
db $0f,$02,$1e,$2f,$60,$e0,$3a,$a5,$a7,$db,$80
|
|
db $3b,$82,$8b,$02,$fe,$42,$68,$70,$bb,$25,$a7
|
|
db $2c,$27,$b2,$26,$b9,$26,$9b,$80,$a8,$82
|
|
db $b5,$27,$bc,$27,$b0,$bb,$3b,$82,$87,$34
|
|
db $ee,$25,$6b
|
|
db $ff
|
|
|
|
;underground bonus rooms area used in many levels
|
|
E_UndergroundArea3
|
|
db $1e,$a5,$0a,$2e,$28,$27,$2e,$33,$c7,$0f,$03,$1e,$40,$07
|
|
db $2e,$30,$e7,$0f,$05,$1e,$24,$44,$0f,$07,$1e,$22,$6a
|
|
db $2e,$23,$ab,$0f,$09,$1e,$41,$68,$1e,$2a,$8a,$2e,$23,$a2
|
|
db $2e,$32,$ea
|
|
db $ff
|
|
|
|
;water area used in levels 5-2 and 6-2
|
|
E_WaterArea1
|
|
db $3b,$87,$66,$27,$cc,$27,$ee,$31,$87,$ee,$23,$a7
|
|
db $3b,$87,$db,$07
|
|
db $ff
|
|
|
|
;level 2-2/7-2
|
|
E_WaterArea2
|
|
db $0f,$01,$2e,$25,$2b,$2e,$25,$4b,$4e,$25,$cb,$6b,$07
|
|
db $97,$47,$e9,$87,$47,$c7,$7a,$07,$d6,$c7
|
|
db $78,$07,$38,$87,$ab,$47,$e3,$07,$9b,$87
|
|
db $0f,$09,$68,$47,$db,$c7,$3b,$c7
|
|
db $ff
|
|
|
|
;water area used in level 8-4
|
|
E_WaterArea3
|
|
db $47,$9b,$cb,$07,$fa,$1d,$86,$9b,$3a,$87
|
|
db $56,$07,$88,$1b,$07,$9d,$2e,$65,$f0
|
|
db $ff
|
|
|
|
;AREA OBJECT DATA
|
|
|
|
;level 1-4/6-4
|
|
L_CastleArea1
|
|
db $9b,$07
|
|
db $05,$32,$06,$33,$07,$34,$ce,$03,$dc,$51
|
|
db $ee,$07,$73,$e0,$74,$0a,$7e,$06,$9e,$0a
|
|
db $ce,$06,$e4,$00,$e8,$0a,$fe,$0a,$2e,$89
|
|
db $4e,$0b,$54,$0a,$14,$8a,$c4,$0a,$34,$8a
|
|
db $7e,$06,$c7,$0a,$01,$e0,$02,$0a,$47,$0a
|
|
db $81,$60,$82,$0a,$c7,$0a,$0e,$87,$7e,$02
|
|
db $a7,$02,$b3,$02,$d7,$02,$e3,$02,$07,$82
|
|
db $13,$02,$3e,$06,$7e,$02,$ae,$07,$fe,$0a
|
|
db $0d,$c4,$cd,$43,$ce,$09,$de,$0b,$dd,$42
|
|
db $fe,$02,$5d,$c7
|
|
db $fd
|
|
|
|
;level 4-4
|
|
L_CastleArea2
|
|
db $5b,$07
|
|
db $05,$32,$06,$33,$07,$34,$5e,$0a,$68,$64
|
|
db $98,$64,$a8,$64,$ce,$06,$fe,$02,$0d,$01
|
|
db $1e,$0e,$7e,$02,$94,$63,$b4,$63,$d4,$63
|
|
db $f4,$63,$14,$e3,$2e,$0e,$5e,$02,$64,$35
|
|
db $88,$72,$be,$0e,$0d,$04,$ae,$02,$ce,$08
|
|
db $cd,$4b,$fe,$02,$0d,$05,$68,$31,$7e,$0a
|
|
db $96,$31,$a9,$63,$a8,$33,$d5,$30,$ee,$02
|
|
db $e6,$62,$f4,$61,$04,$b1,$08,$3f,$44,$33
|
|
db $94,$63,$a4,$31,$e4,$31,$04,$bf,$08,$3f
|
|
db $04,$bf,$08,$3f,$cd,$4b,$03,$e4,$0e,$03
|
|
db $2e,$01,$7e,$06,$be,$02,$de,$06,$fe,$0a
|
|
db $0d,$c4,$cd,$43,$ce,$09,$de,$0b,$dd,$42
|
|
db $fe,$02,$5d,$c7
|
|
db $fd
|
|
|
|
;level 2-4/5-4
|
|
L_CastleArea3
|
|
db $9b,$07
|
|
db $05,$32,$06,$33,$07,$34,$fe,$00,$27,$b1
|
|
db $65,$32,$75,$0a,$71,$00,$b7,$31,$08,$e4
|
|
db $18,$64,$1e,$04,$57,$3b,$bb,$0a,$17,$8a
|
|
db $27,$3a,$73,$0a,$7b,$0a,$d7,$0a,$e7,$3a
|
|
db $3b,$8a,$97,$0a,$fe,$08,$24,$8a,$2e,$00
|
|
db $3e,$40,$38,$64,$6f,$00,$9f,$00,$be,$43
|
|
db $c8,$0a,$c9,$63,$ce,$07,$fe,$07,$2e,$81
|
|
db $66,$42,$6a,$42,$79,$0a,$be,$00,$c8,$64
|
|
db $f8,$64,$08,$e4,$2e,$07,$7e,$03,$9e,$07
|
|
db $be,$03,$de,$07,$fe,$0a,$03,$a5,$0d,$44
|
|
db $cd,$43,$ce,$09,$dd,$42,$de,$0b,$fe,$02
|
|
db $5d,$c7
|
|
db $fd
|
|
|
|
;level 3-4
|
|
L_CastleArea4
|
|
db $9b,$07
|
|
db $05,$32,$06,$33,$07,$34,$fe,$06,$0c,$81
|
|
db $39,$0a,$5c,$01,$89,$0a,$ac,$01,$d9,$0a
|
|
db $fc,$01,$2e,$83,$a7,$01,$b7,$00,$c7,$01
|
|
db $de,$0a,$fe,$02,$4e,$83,$5a,$32,$63,$0a
|
|
db $69,$0a,$7e,$02,$ee,$03,$fa,$32,$03,$8a
|
|
db $09,$0a,$1e,$02,$ee,$03,$fa,$32,$03,$8a
|
|
db $09,$0a,$14,$42,$1e,$02,$7e,$0a,$9e,$07
|
|
db $fe,$0a,$2e,$86,$5e,$0a,$8e,$06,$be,$0a
|
|
db $ee,$07,$3e,$83,$5e,$07,$fe,$0a,$0d,$c4
|
|
db $41,$52,$51,$52,$cd,$43,$ce,$09,$de,$0b
|
|
db $dd,$42,$fe,$02,$5d,$c7
|
|
db $fd
|
|
|
|
;level 7-4
|
|
L_CastleArea5
|
|
db $5b,$07
|
|
db $05,$32,$06,$33,$07,$34,$fe,$0a,$ae,$86
|
|
db $be,$07,$fe,$02,$0d,$02,$27,$32,$46,$61
|
|
db $55,$62,$5e,$0e,$1e,$82,$68,$3c,$74,$3a
|
|
db $7d,$4b,$5e,$8e,$7d,$4b,$7e,$82,$84,$62
|
|
db $94,$61,$a4,$31,$bd,$4b,$ce,$06,$fe,$02
|
|
db $0d,$06,$34,$31,$3e,$0a,$64,$32,$75,$0a
|
|
db $7b,$61,$a4,$33,$ae,$02,$de,$0e,$3e,$82
|
|
db $64,$32,$78,$32,$b4,$36,$c8,$36,$dd,$4b
|
|
db $44,$b2,$58,$32,$94,$63,$a4,$3e,$ba,$30
|
|
db $c9,$61,$ce,$06,$dd,$4b,$ce,$86,$dd,$4b
|
|
db $fe,$02,$2e,$86,$5e,$02,$7e,$06,$fe,$02
|
|
db $1e,$86,$3e,$02,$5e,$06,$7e,$02,$9e,$06
|
|
db $fe,$0a,$0d,$c4,$cd,$43,$ce,$09,$de,$0b
|
|
db $dd,$42,$fe,$02,$5d,$c7
|
|
db $fd
|
|
|
|
;level 8-4
|
|
L_CastleArea6
|
|
db $5b,$06
|
|
db $05,$32,$06,$33,$07,$34,$5e,$0a,$ae,$02
|
|
db $0d,$01,$39,$73,$0d,$03,$39,$7b,$4d,$4b
|
|
db $de,$06,$1e,$8a,$ae,$06,$c4,$33,$16,$fe
|
|
db $a5,$77,$fe,$02,$fe,$82,$0d,$07,$39,$73
|
|
db $a8,$74,$ed,$4b,$49,$fb,$e8,$74,$fe,$0a
|
|
db $2e,$82,$67,$02,$84,$7a,$87,$31,$0d,$0b
|
|
db $fe,$02,$0d,$0c,$39,$73,$5e,$06,$c6,$76
|
|
db $45,$ff,$be,$0a,$dd,$48,$fe,$06,$3d,$cb
|
|
db $46,$7e,$ad,$4a,$fe,$82,$39,$f3,$a9,$7b
|
|
db $4e,$8a,$9e,$07,$fe,$0a,$0d,$c4,$cd,$43
|
|
db $ce,$09,$de,$0b,$dd,$42,$fe,$02,$5d,$c7
|
|
db $fd
|
|
|
|
;level 3-3
|
|
L_GroundArea1
|
|
db $94,$11
|
|
db $0f,$26,$fe,$10,$28,$94,$65,$15,$eb,$12
|
|
db $fa,$41,$4a,$96,$54,$40,$a4,$42,$b7,$13
|
|
db $e9,$19,$f5,$15,$11,$80,$47,$42,$71,$13
|
|
db $80,$41,$15,$92,$1b,$1f,$24,$40,$55,$12
|
|
db $64,$40,$95,$12,$a4,$40,$d2,$12,$e1,$40
|
|
db $13,$c0,$2c,$17,$2f,$12,$49,$13,$83,$40
|
|
db $9f,$14,$a3,$40,$17,$92,$83,$13,$92,$41
|
|
db $b9,$14,$c5,$12,$c8,$40,$d4,$40,$4b,$92
|
|
db $78,$1b,$9c,$94,$9f,$11,$df,$14,$fe,$11
|
|
db $7d,$c1,$9e,$42,$cf,$20
|
|
db $fd
|
|
|
|
;level 8-3
|
|
L_GroundArea2
|
|
db $90,$b1
|
|
db $0f,$26,$29,$91,$7e,$42,$fe,$40,$28,$92
|
|
db $4e,$42,$2e,$c0,$57,$73,$c3,$25,$c7,$27
|
|
db $23,$84,$33,$20,$5c,$01,$77,$63,$88,$62
|
|
db $99,$61,$aa,$60,$bc,$01,$ee,$42,$4e,$c0
|
|
db $69,$11,$7e,$42,$de,$40,$f8,$62,$0e,$c2
|
|
db $ae,$40,$d7,$63,$e7,$63,$33,$a7,$37,$27
|
|
db $43,$04,$cc,$01,$e7,$73,$0c,$81,$3e,$42
|
|
db $0d,$0a,$5e,$40,$88,$72,$be,$42,$e7,$87
|
|
db $fe,$40,$39,$e1,$4e,$00,$69,$60,$87,$60
|
|
db $a5,$60,$c3,$31,$fe,$31,$6d,$c1,$be,$42
|
|
db $ef,$20
|
|
db $fd
|
|
|
|
;level 4-1
|
|
L_GroundArea3
|
|
db $52,$21
|
|
db $0f,$20,$6e,$40,$58,$f2,$93,$01,$97,$00
|
|
db $0c,$81,$97,$40,$a6,$41,$c7,$40,$0d,$04
|
|
db $03,$01,$07,$01,$23,$01,$27,$01,$ec,$03
|
|
db $ac,$f3,$c3,$03,$78,$e2,$94,$43,$47,$f3
|
|
db $74,$43,$47,$fb,$74,$43,$2c,$f1,$4c,$63
|
|
db $47,$00,$57,$21,$5c,$01,$7c,$72,$39,$f1
|
|
db $ec,$02,$4c,$81,$d8,$62,$ec,$01,$0d,$0d
|
|
db $0f,$38,$c7,$07,$ed,$4a,$1d,$c1,$5f,$26
|
|
db $fd
|
|
|
|
;level 6-2
|
|
L_GroundArea4
|
|
db $54,$21
|
|
db $0f,$26,$a7,$22,$37,$fb,$73,$20,$83,$07
|
|
db $87,$02,$93,$20,$c7,$73,$04,$f1,$06,$31
|
|
db $39,$71,$59,$71,$e7,$73,$37,$a0,$47,$04
|
|
db $86,$7c,$e5,$71,$e7,$31,$33,$a4,$39,$71
|
|
db $a9,$71,$d3,$23,$08,$f2,$13,$05,$27,$02
|
|
db $49,$71,$75,$75,$e8,$72,$67,$f3,$99,$71
|
|
db $e7,$20,$f4,$72,$f7,$31,$17,$a0,$33,$20
|
|
db $39,$71,$73,$28,$bc,$05,$39,$f1,$79,$71
|
|
db $a6,$21,$c3,$06,$d3,$20,$dc,$00,$fc,$00
|
|
db $07,$a2,$13,$21,$5f,$32,$8c,$00,$98,$7a
|
|
db $c7,$63,$d9,$61,$03,$a2,$07,$22,$74,$72
|
|
db $77,$31,$e7,$73,$39,$f1,$58,$72,$77,$73
|
|
db $d8,$72,$7f,$b1,$97,$73,$b6,$64,$c5,$65
|
|
db $d4,$66,$e3,$67,$f3,$67,$8d,$c1,$cf,$26
|
|
db $fd
|
|
|
|
;level 3-1
|
|
L_GroundArea5
|
|
db $52,$31
|
|
db $0f,$20,$6e,$66,$07,$81,$36,$01,$66,$00
|
|
db $a7,$22,$08,$f2,$67,$7b,$dc,$02,$98,$f2
|
|
db $d7,$20,$39,$f1,$9f,$33,$dc,$27,$dc,$57
|
|
db $23,$83,$57,$63,$6c,$51,$87,$63,$99,$61
|
|
db $a3,$06,$b3,$21,$77,$f3,$f3,$21,$f7,$2a
|
|
db $13,$81,$23,$22,$53,$00,$63,$22,$e9,$0b
|
|
db $0c,$83,$13,$21,$16,$22,$33,$05,$8f,$35
|
|
db $ec,$01,$63,$a0,$67,$20,$73,$01,$77,$01
|
|
db $83,$20,$87,$20,$b3,$20,$b7,$20,$c3,$01
|
|
db $c7,$00,$d3,$20,$d7,$20,$67,$a0,$77,$07
|
|
db $87,$22,$e8,$62,$f5,$65,$1c,$82,$7f,$38
|
|
db $8d,$c1,$cf,$26
|
|
db $fd
|
|
|
|
;level 1-1
|
|
L_GroundArea6
|
|
db $50,$21
|
|
db $07,$81,$47,$24,$57,$00,$63,$01,$77,$01
|
|
db $c9,$71,$68,$f2,$e7,$73,$97,$fb,$06,$83
|
|
db $5c,$01,$d7,$22,$e7,$00,$03,$a7,$6c,$02
|
|
db $b3,$22,$e3,$01,$e7,$07,$47,$a0,$57,$06
|
|
db $a7,$01,$d3,$00,$d7,$01,$07,$81,$67,$20
|
|
db $93,$22,$03,$a3,$1c,$61,$17,$21,$6f,$33
|
|
db $c7,$63,$d8,$62,$e9,$61,$fa,$60,$4f,$b3
|
|
db $87,$63,$9c,$01,$b7,$63,$c8,$62,$d9,$61
|
|
db $ea,$60,$39,$f1,$87,$21,$a7,$01,$b7,$20
|
|
db $39,$f1,$5f,$38,$6d,$c1,$af,$26
|
|
db $fd
|
|
|
|
;level 1-3/5-3
|
|
L_GroundArea7
|
|
db $90,$11
|
|
db $0f,$26,$fe,$10,$2a,$93,$87,$17,$a3,$14
|
|
db $b2,$42,$0a,$92,$19,$40,$36,$14,$50,$41
|
|
db $82,$16,$2b,$93,$24,$41,$bb,$14,$b8,$00
|
|
db $c2,$43,$c3,$13,$1b,$94,$67,$12,$c4,$15
|
|
db $53,$c1,$d2,$41,$12,$c1,$29,$13,$85,$17
|
|
db $1b,$92,$1a,$42,$47,$13,$83,$41,$a7,$13
|
|
db $0e,$91,$a7,$63,$b7,$63,$c5,$65,$d5,$65
|
|
db $dd,$4a,$e3,$67,$f3,$67,$8d,$c1,$ae,$42
|
|
db $df,$20
|
|
db $fd
|
|
|
|
;level 2-3/7-3
|
|
L_GroundArea8
|
|
db $90,$11
|
|
db $0f,$26,$6e,$10,$8b,$17,$af,$32,$d8,$62
|
|
db $e8,$62,$fc,$3f,$ad,$c8,$f8,$64,$0c,$be
|
|
db $43,$43,$f8,$64,$0c,$bf,$73,$40,$84,$40
|
|
db $93,$40,$a4,$40,$b3,$40,$f8,$64,$48,$e4
|
|
db $5c,$39,$83,$40,$92,$41,$b3,$40,$f8,$64
|
|
db $48,$e4,$5c,$39,$f8,$64,$13,$c2,$37,$65
|
|
db $4c,$24,$63,$00,$97,$65,$c3,$42,$0b,$97
|
|
db $ac,$32,$f8,$64,$0c,$be,$53,$45,$9d,$48
|
|
db $f8,$64,$2a,$e2,$3c,$47,$56,$43,$ba,$62
|
|
db $f8,$64,$0c,$b7,$88,$64,$bc,$31,$d4,$45
|
|
db $fc,$31,$3c,$b1,$78,$64,$8c,$38,$0b,$9c
|
|
db $1a,$33,$18,$61,$28,$61,$39,$60,$5d,$4a
|
|
db $ee,$11,$0f,$b8,$1d,$c1,$3e,$42,$6f,$20
|
|
db $fd
|
|
|
|
;level 2-1
|
|
L_GroundArea9
|
|
db $52,$31
|
|
db $0f,$20,$6e,$40,$f7,$20,$07,$84,$17,$20
|
|
db $4f,$34,$c3,$03,$c7,$02,$d3,$22,$27,$e3
|
|
db $39,$61,$e7,$73,$5c,$e4,$57,$00,$6c,$73
|
|
db $47,$a0,$53,$06,$63,$22,$a7,$73,$fc,$73
|
|
db $13,$a1,$33,$05,$43,$21,$5c,$72,$c3,$23
|
|
db $cc,$03,$77,$fb,$ac,$02,$39,$f1,$a7,$73
|
|
db $d3,$04,$e8,$72,$e3,$22,$26,$f4,$bc,$02
|
|
db $8c,$81,$a8,$62,$17,$87,$43,$24,$a7,$01
|
|
db $c3,$04,$08,$f2,$97,$21,$a3,$02,$c9,$0b
|
|
db $e1,$69,$f1,$69,$8d,$c1,$cf,$26
|
|
db $fd
|
|
|
|
;pipe intro area
|
|
L_GroundArea10
|
|
db $38,$11
|
|
db $0f,$26,$ad,$40,$3d,$c7
|
|
db $fd
|
|
|
|
;level 5-1
|
|
L_GroundArea11
|
|
db $95,$b1
|
|
db $0f,$26,$0d,$02,$c8,$72,$1c,$81,$38,$72
|
|
db $0d,$05,$97,$34,$98,$62,$a3,$20,$b3,$06
|
|
db $c3,$20,$cc,$03,$f9,$91,$2c,$81,$48,$62
|
|
db $0d,$09,$37,$63,$47,$03,$57,$21,$8c,$02
|
|
db $c5,$79,$c7,$31,$f9,$11,$39,$f1,$a9,$11
|
|
db $6f,$b4,$d3,$65,$e3,$65,$7d,$c1,$bf,$26
|
|
db $fd
|
|
|
|
;cloud level used in levels 2-1 and 5-2
|
|
L_GroundArea12
|
|
db $00,$c1
|
|
db $4c,$00,$f4,$4f,$0d,$02,$02,$42,$43,$4f
|
|
db $52,$c2,$de,$00,$5a,$c2,$4d,$c7
|
|
db $fd
|
|
|
|
;level 4-3
|
|
L_GroundArea13
|
|
db $90,$51
|
|
db $0f,$26,$ee,$10,$0b,$94,$33,$14,$42,$42
|
|
db $77,$16,$86,$44,$02,$92,$4a,$16,$69,$42
|
|
db $73,$14,$b0,$00,$c7,$12,$05,$c0,$1c,$17
|
|
db $1f,$11,$36,$12,$8f,$14,$91,$40,$1b,$94
|
|
db $35,$12,$34,$42,$60,$42,$61,$12,$87,$12
|
|
db $96,$40,$a3,$14,$1c,$98,$1f,$11,$47,$12
|
|
db $9f,$15,$cc,$15,$cf,$11,$05,$c0,$1f,$15
|
|
db $39,$12,$7c,$16,$7f,$11,$82,$40,$98,$12
|
|
db $df,$15,$16,$c4,$17,$14,$54,$12,$9b,$16
|
|
db $28,$94,$ce,$01,$3d,$c1,$5e,$42,$8f,$20
|
|
db $fd
|
|
|
|
;level 6-3
|
|
L_GroundArea14
|
|
db $97,$11
|
|
db $0f,$26,$fe,$10,$2b,$92,$57,$12,$8b,$12
|
|
db $c0,$41,$f7,$13,$5b,$92,$69,$0b,$bb,$12
|
|
db $b2,$46,$19,$93,$71,$00,$17,$94,$7c,$14
|
|
db $7f,$11,$93,$41,$bf,$15,$fc,$13,$ff,$11
|
|
db $2f,$95,$50,$42,$51,$12,$58,$14,$a6,$12
|
|
db $db,$12,$1b,$93,$46,$43,$7b,$12,$8d,$49
|
|
db $b7,$14,$1b,$94,$49,$0b,$bb,$12,$fc,$13
|
|
db $ff,$12,$03,$c1,$2f,$15,$43,$12,$4b,$13
|
|
db $77,$13,$9d,$4a,$15,$c1,$a1,$41,$c3,$12
|
|
db $fe,$01,$7d,$c1,$9e,$42,$cf,$20
|
|
db $fd
|
|
|
|
;level 6-1
|
|
L_GroundArea15
|
|
db $52,$21
|
|
db $0f,$20,$6e,$44,$0c,$f1,$4c,$01,$aa,$35
|
|
db $d9,$34,$ee,$20,$08,$b3,$37,$32,$43,$04
|
|
db $4e,$21,$53,$20,$7c,$01,$97,$21,$b7,$07
|
|
db $9c,$81,$e7,$42,$5f,$b3,$97,$63,$ac,$02
|
|
db $c5,$41,$49,$e0,$58,$61,$76,$64,$85,$65
|
|
db $94,$66,$a4,$22,$a6,$03,$c8,$22,$dc,$02
|
|
db $68,$f2,$96,$42,$13,$82,$17,$02,$af,$34
|
|
db $f6,$21,$fc,$06,$26,$80,$2a,$24,$36,$01
|
|
db $8c,$00,$ff,$35,$4e,$a0,$55,$21,$77,$20
|
|
db $87,$07,$89,$22,$ae,$21,$4c,$82,$9f,$34
|
|
db $ec,$01,$03,$e7,$13,$67,$8d,$4a,$ad,$41
|
|
db $0f,$a6
|
|
db $fd
|
|
|
|
;warp zone area used in level 4-2
|
|
L_GroundArea16
|
|
db $10,$51
|
|
db $4c,$00,$c7,$12,$c6,$42,$03,$92,$02,$42
|
|
db $29,$12,$63,$12,$62,$42,$69,$14,$a5,$12
|
|
db $a4,$42,$e2,$14,$e1,$44,$f8,$16,$37,$c1
|
|
db $8f,$38,$02,$bb,$28,$7a,$68,$7a,$a8,$7a
|
|
db $e0,$6a,$f0,$6a,$6d,$c5
|
|
db $fd
|
|
|
|
;level 8-1
|
|
L_GroundArea17
|
|
db $92,$31
|
|
db $0f,$20,$6e,$40,$0d,$02,$37,$73,$ec,$00
|
|
db $0c,$80,$3c,$00,$6c,$00,$9c,$00,$06,$c0
|
|
db $c7,$73,$06,$83,$28,$72,$96,$40,$e7,$73
|
|
db $26,$c0,$87,$7b,$d2,$41,$39,$f1,$c8,$f2
|
|
db $97,$e3,$a3,$23,$e7,$02,$e3,$07,$f3,$22
|
|
db $37,$e3,$9c,$00,$bc,$00,$ec,$00,$0c,$80
|
|
db $3c,$00,$86,$21,$a6,$06,$b6,$24,$5c,$80
|
|
db $7c,$00,$9c,$00,$29,$e1,$dc,$05,$f6,$41
|
|
db $dc,$80,$e8,$72,$0c,$81,$27,$73,$4c,$01
|
|
db $66,$74,$0d,$11,$3f,$35,$b6,$41,$2c,$82
|
|
db $36,$40,$7c,$02,$86,$40,$f9,$61,$39,$e1
|
|
db $ac,$04,$c6,$41,$0c,$83,$16,$41,$88,$f2
|
|
db $39,$f1,$7c,$00,$89,$61,$9c,$00,$a7,$63
|
|
db $bc,$00,$c5,$65,$dc,$00,$e3,$67,$f3,$67
|
|
db $8d,$c1,$cf,$26
|
|
db $fd
|
|
|
|
;level 5-2
|
|
L_GroundArea18
|
|
db $55,$b1
|
|
db $0f,$26,$cf,$33,$07,$b2,$15,$11,$52,$42
|
|
db $99,$0b,$ac,$02,$d3,$24,$d6,$42,$d7,$25
|
|
db $23,$84,$cf,$33,$07,$e3,$19,$61,$78,$7a
|
|
db $ef,$33,$2c,$81,$46,$64,$55,$65,$65,$65
|
|
db $ec,$74,$47,$82,$53,$05,$63,$21,$62,$41
|
|
db $96,$22,$9a,$41,$cc,$03,$b9,$91,$39,$f1
|
|
db $63,$26,$67,$27,$d3,$06,$fc,$01,$18,$e2
|
|
db $d9,$07,$e9,$04,$0c,$86,$37,$22,$93,$24
|
|
db $87,$84,$ac,$02,$c2,$41,$c3,$23,$d9,$71
|
|
db $fc,$01,$7f,$b1,$9c,$00,$a7,$63,$b6,$64
|
|
db $cc,$00,$d4,$66,$e3,$67,$f3,$67,$8d,$c1
|
|
db $cf,$26
|
|
db $fd
|
|
|
|
;level 8-2
|
|
L_GroundArea19
|
|
db $50,$b1
|
|
db $0f,$26,$fc,$00,$1f,$b3,$5c,$00,$65,$65
|
|
db $74,$66,$83,$67,$93,$67,$dc,$73,$4c,$80
|
|
db $b3,$20,$c9,$0b,$c3,$08,$d3,$2f,$dc,$00
|
|
db $2c,$80,$4c,$00,$8c,$00,$d3,$2e,$ed,$4a
|
|
db $fc,$00,$d7,$a1,$ec,$01,$4c,$80,$59,$11
|
|
db $d8,$11,$da,$10,$37,$a0,$47,$04,$99,$11
|
|
db $e7,$21,$3a,$90,$67,$20,$76,$10,$77,$60
|
|
db $87,$07,$d8,$12,$39,$f1,$ac,$00,$e9,$71
|
|
db $0c,$80,$2c,$00,$4c,$05,$c7,$7b,$39,$f1
|
|
db $ec,$00,$f9,$11,$0c,$82,$6f,$34,$f8,$11
|
|
db $fa,$10,$7f,$b2,$ac,$00,$b6,$64,$cc,$01
|
|
db $e3,$67,$f3,$67,$8d,$c1,$cf,$26
|
|
db $fd
|
|
|
|
;level 7-1
|
|
L_GroundArea20
|
|
db $52,$b1
|
|
db $0f,$20,$6e,$45,$39,$91,$b3,$04,$c3,$21
|
|
db $c8,$11,$ca,$10,$49,$91,$7c,$73,$e8,$12
|
|
db $88,$91,$8a,$10,$e7,$21,$05,$91,$07,$30
|
|
db $17,$07,$27,$20,$49,$11,$9c,$01,$c8,$72
|
|
db $23,$a6,$27,$26,$d3,$03,$d8,$7a,$89,$91
|
|
db $d8,$72,$39,$f1,$a9,$11,$09,$f1,$63,$24
|
|
db $67,$24,$d8,$62,$28,$91,$2a,$10,$56,$21
|
|
db $70,$04,$79,$0b,$8c,$00,$94,$21,$9f,$35
|
|
db $2f,$b8,$3d,$c1,$7f,$26
|
|
db $fd
|
|
|
|
;cloud level used in levels 3-1 and 6-2
|
|
L_GroundArea21
|
|
db $06,$c1
|
|
db $4c,$00,$f4,$4f,$0d,$02,$06,$20,$24,$4f
|
|
db $35,$a0,$36,$20,$53,$46,$d5,$20,$d6,$20
|
|
db $34,$a1,$73,$49,$74,$20,$94,$20,$b4,$20
|
|
db $d4,$20,$f4,$20,$2e,$80,$59,$42,$4d,$c7
|
|
db $fd
|
|
|
|
;level 3-2
|
|
L_GroundArea22
|
|
db $96,$31
|
|
db $0f,$26,$0d,$03,$1a,$60,$77,$42,$c4,$00
|
|
db $c8,$62,$b9,$e1,$d3,$06,$d7,$07,$f9,$61
|
|
db $0c,$81,$4e,$b1,$8e,$b1,$bc,$01,$e4,$50
|
|
db $e9,$61,$0c,$81,$0d,$0a,$84,$43,$98,$72
|
|
db $0d,$0c,$0f,$38,$1d,$c1,$5f,$26
|
|
db $fd
|
|
|
|
;level 1-2
|
|
L_UndergroundArea1
|
|
db $48,$0f
|
|
db $0e,$01,$5e,$02,$a7,$00,$bc,$73,$1a,$e0
|
|
db $39,$61,$58,$62,$77,$63,$97,$63,$b8,$62
|
|
db $d6,$07,$f8,$62,$19,$e1,$75,$52,$86,$40
|
|
db $87,$50,$95,$52,$93,$43,$a5,$21,$c5,$52
|
|
db $d6,$40,$d7,$20,$e5,$06,$e6,$51,$3e,$8d
|
|
db $5e,$03,$67,$52,$77,$52,$7e,$02,$9e,$03
|
|
db $a6,$43,$a7,$23,$de,$05,$fe,$02,$1e,$83
|
|
db $33,$54,$46,$40,$47,$21,$56,$04,$5e,$02
|
|
db $83,$54,$93,$52,$96,$07,$97,$50,$be,$03
|
|
db $c7,$23,$fe,$02,$0c,$82,$43,$45,$45,$24
|
|
db $46,$24,$90,$08,$95,$51,$78,$fa,$d7,$73
|
|
db $39,$f1,$8c,$01,$a8,$52,$b8,$52,$cc,$01
|
|
db $5f,$b3,$97,$63,$9e,$00,$0e,$81,$16,$24
|
|
db $66,$04,$8e,$00,$fe,$01,$08,$d2,$0e,$06
|
|
db $6f,$47,$9e,$0f,$0e,$82,$2d,$47,$28,$7a
|
|
db $68,$7a,$a8,$7a,$ae,$01,$de,$0f,$6d,$c5
|
|
db $fd
|
|
|
|
;level 4-2
|
|
L_UndergroundArea2
|
|
db $48,$0f
|
|
db $0e,$01,$5e,$02,$bc,$01,$fc,$01,$2c,$82
|
|
db $41,$52,$4e,$04,$67,$25,$68,$24,$69,$24
|
|
db $ba,$42,$c7,$04,$de,$0b,$b2,$87,$fe,$02
|
|
db $2c,$e1,$2c,$71,$67,$01,$77,$00,$87,$01
|
|
db $8e,$00,$ee,$01,$f6,$02,$03,$85,$05,$02
|
|
db $13,$21,$16,$02,$27,$02,$2e,$02,$88,$72
|
|
db $c7,$20,$d7,$07,$e4,$76,$07,$a0,$17,$06
|
|
db $48,$7a,$76,$20,$98,$72,$79,$e1,$88,$62
|
|
db $9c,$01,$b7,$73,$dc,$01,$f8,$62,$fe,$01
|
|
db $08,$e2,$0e,$00,$6e,$02,$73,$20,$77,$23
|
|
db $83,$04,$93,$20,$ae,$00,$fe,$0a,$0e,$82
|
|
db $39,$71,$a8,$72,$e7,$73,$0c,$81,$8f,$32
|
|
db $ae,$00,$fe,$04,$04,$d1,$17,$04,$26,$49
|
|
db $27,$29,$df,$33,$fe,$02,$44,$f6,$7c,$01
|
|
db $8e,$06,$bf,$47,$ee,$0f,$4d,$c7,$0e,$82
|
|
db $68,$7a,$ae,$01,$de,$0f,$6d,$c5
|
|
db $fd
|
|
|
|
;underground bonus rooms area used in many levels
|
|
L_UndergroundArea3
|
|
db $48,$01
|
|
db $0e,$01,$00,$5a,$3e,$06,$45,$46,$47,$46
|
|
db $53,$44,$ae,$01,$df,$4a,$4d,$c7,$0e,$81
|
|
db $00,$5a,$2e,$04,$37,$28,$3a,$48,$46,$47
|
|
db $c7,$07,$ce,$0f,$df,$4a,$4d,$c7,$0e,$81
|
|
db $00,$5a,$33,$53,$43,$51,$46,$40,$47,$50
|
|
db $53,$04,$55,$40,$56,$50,$62,$43,$64,$40
|
|
db $65,$50,$71,$41,$73,$51,$83,$51,$94,$40
|
|
db $95,$50,$a3,$50,$a5,$40,$a6,$50,$b3,$51
|
|
db $b6,$40,$b7,$50,$c3,$53,$df,$4a,$4d,$c7
|
|
db $0e,$81,$00,$5a,$2e,$02,$36,$47,$37,$52
|
|
db $3a,$49,$47,$25,$a7,$52,$d7,$04,$df,$4a
|
|
db $4d,$c7,$0e,$81,$00,$5a,$3e,$02,$44,$51
|
|
db $53,$44,$54,$44,$55,$24,$a1,$54,$ae,$01
|
|
db $b4,$21,$df,$4a,$e5,$07,$4d,$c7
|
|
db $fd
|
|
|
|
;water area used in levels 5-2 and 6-2
|
|
L_WaterArea1
|
|
db $41,$01
|
|
db $b4,$34,$c8,$52,$f2,$51,$47,$d3,$6c,$03
|
|
db $65,$49,$9e,$07,$be,$01,$cc,$03,$fe,$07
|
|
db $0d,$c9,$1e,$01,$6c,$01,$62,$35,$63,$53
|
|
db $8a,$41,$ac,$01,$b3,$53,$e9,$51,$26,$c3
|
|
db $27,$33,$63,$43,$64,$33,$ba,$60,$c9,$61
|
|
db $ce,$0b,$e5,$09,$ee,$0f,$7d,$ca,$7d,$47
|
|
db $fd
|
|
|
|
;level 2-2/7-2
|
|
L_WaterArea2
|
|
db $41,$01
|
|
db $b8,$52,$ea,$41,$27,$b2,$b3,$42,$16,$d4
|
|
db $4a,$42,$a5,$51,$a7,$31,$27,$d3,$08,$e2
|
|
db $16,$64,$2c,$04,$38,$42,$76,$64,$88,$62
|
|
db $de,$07,$fe,$01,$0d,$c9,$23,$32,$31,$51
|
|
db $98,$52,$0d,$c9,$59,$42,$63,$53,$67,$31
|
|
db $14,$c2,$36,$31,$87,$53,$17,$e3,$29,$61
|
|
db $30,$62,$3c,$08,$42,$37,$59,$40,$6a,$42
|
|
db $99,$40,$c9,$61,$d7,$63,$39,$d1,$58,$52
|
|
db $c3,$67,$d3,$31,$dc,$06,$f7,$42,$fa,$42
|
|
db $23,$b1,$43,$67,$c3,$34,$c7,$34,$d1,$51
|
|
db $43,$b3,$47,$33,$9a,$30,$a9,$61,$b8,$62
|
|
db $be,$0b,$d5,$09,$de,$0f,$0d,$ca,$7d,$47
|
|
db $fd
|
|
|
|
;water area used in level 8-4
|
|
L_WaterArea3
|
|
db $49,$0f
|
|
db $1e,$01,$39,$73,$5e,$07,$ae,$0b,$1e,$82
|
|
db $6e,$88,$9e,$02,$0d,$04,$2e,$0b,$45,$09
|
|
db $4e,$0f,$ed,$47
|
|
db $fd
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
;unused space
|
|
db $ff
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
;indirect jump routine called when
|
|
;$0770 is set to 1
|
|
GameMode
|
|
lda OperMode_Task
|
|
jsr JumpEngine
|
|
|
|
dw InitializeArea
|
|
dw ScreenRoutines
|
|
dw SecondaryGameSetup
|
|
dw GameCoreRoutine
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
GameCoreRoutine
|
|
ldx CurrentPlayer ;get which player is on the screen
|
|
lda SavedJoypadBits,x ;use appropriate player's controller bits
|
|
sta SavedJoypadBits ;as the master controller bits
|
|
jsr GameRoutines ;execute one of many possible subs
|
|
lda OperMode_Task ;check major task of operating mode
|
|
cmp #$03 ;if we are supposed to be here,
|
|
bcs GameEngine ;branch to the game engine itself
|
|
rts
|
|
|
|
GameEngine
|
|
jsr ProcFireball_Bubble ;process fireballs and air bubbles
|
|
ldx #$00
|
|
ProcELoop stx ObjectOffset ;put incremented offset in X as enemy object offset
|
|
jsr EnemiesAndLoopsCore ;process enemy objects
|
|
jsr FloateyNumbersRoutine ;process floatey numbers
|
|
inx
|
|
cpx #$06 ;do these two subroutines until the whole buffer is done
|
|
bne ProcELoop
|
|
jsr GetPlayerOffscreenBits ;get offscreen bits for player object
|
|
jsr RelativePlayerPosition ;get relative coordinates for player object
|
|
jsr PlayerGfxHandler ;draw the player
|
|
jsr BlockObjMT_Updater ;replace block objects with metatiles if necessary
|
|
ldx #$01
|
|
stx ObjectOffset ;set offset for second
|
|
jsr BlockObjectsCore ;process second block object
|
|
dex
|
|
stx ObjectOffset ;set offset for first
|
|
jsr BlockObjectsCore ;process first block object
|
|
jsr MiscObjectsCore ;process misc objects (hammer, jumping coins)
|
|
jsr ProcessCannons ;process bullet bill cannons
|
|
jsr ProcessWhirlpools ;process whirlpools
|
|
jsr FlagpoleRoutine ;process the flagpole
|
|
jsr RunGameTimer ;count down the game timer
|
|
jsr ColorRotation ;cycle one of the background colors
|
|
lda Player_Y_HighPos
|
|
cmp #$02 ;if player is below the screen, don't bother with the music
|
|
bpl NoChgMus
|
|
lda StarInvincibleTimer ;if star mario invincibility timer at zero,
|
|
beq ClrPlrPal ;skip this part
|
|
cmp #$04
|
|
bne NoChgMus ;if not yet at a certain point, continue
|
|
lda IntervalTimerControl ;if interval timer not yet expired,
|
|
bne NoChgMus ;branch ahead, don't bother with the music
|
|
jsr GetAreaMusic ;to re-attain appropriate level music
|
|
NoChgMus ldy StarInvincibleTimer ;get invincibility timer
|
|
lda FrameCounter ;get frame counter
|
|
cpy #$08 ;if timer still above certain point,
|
|
bcs CycleTwo ;branch to cycle player's palette quickly
|
|
lsr ;otherwise, divide by 8 to cycle every eighth frame
|
|
lsr
|
|
CycleTwo lsr ;if branched here, divide by 2 to cycle every other frame
|
|
jsr CyclePlayerPalette ;do sub to cycle the palette (note shares fire flower code)
|
|
jmp SaveAB ;then skip this sub to finish up the game engine
|
|
ClrPlrPal jsr ResetPalStar ;do sub to clear player's palette bits in attributes
|
|
SaveAB lda A_B_Buttons ;save current A and B button
|
|
sta PreviousA_B_Buttons ;into temp variable to be used on next frame
|
|
lda #$00
|
|
sta Left_Right_Buttons ;nullify left and right buttons temp variable
|
|
UpdScrollVar lda VRAM_Buffer_AddrCtrl
|
|
cmp #$06 ;if vram address controller set to 6 (one of two $0341s)
|
|
beq ExitEng ;then branch to leave
|
|
lda AreaParserTaskNum ;otherwise check number of tasks
|
|
bne RunParser
|
|
lda ScrollThirtyTwo ;get horizontal scroll in 0-31 or $00-$20 range
|
|
cmp #$20 ;check to see if exceeded $21
|
|
bmi ExitEng ;branch to leave if not
|
|
lda ScrollThirtyTwo
|
|
sbc #$20 ;otherwise subtract $20 to set appropriately
|
|
sta ScrollThirtyTwo ;and store
|
|
lda #$00 ;reset vram buffer offset used in conjunction with
|
|
sta VRAM_Buffer2_Offset ;level graphics buffer at $0341-$035f
|
|
RunParser jsr AreaParserTaskHandler ;update the name table with more level graphics
|
|
ExitEng rts ;and after all that, we're finally done!
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
ScrollHandler
|
|
lda Player_X_Scroll ;load value saved here
|
|
clc
|
|
adc Platform_X_Scroll ;add value used by left/right platforms
|
|
sta Player_X_Scroll ;save as new value here to impose force on scroll
|
|
lda ScrollLock ;check scroll lock flag
|
|
bne InitScrlAmt ;skip a bunch of code here if set
|
|
lda Player_Pos_ForScroll
|
|
cmp #$50 ;check player's horizontal screen position
|
|
bcc InitScrlAmt ;if less than 80 pixels to the right, branch
|
|
lda SideCollisionTimer ;if timer related to player's side collision
|
|
bne InitScrlAmt ;not expired, branch
|
|
ldy Player_X_Scroll ;get value and decrement by one
|
|
dey ;if value originally set to zero or otherwise
|
|
bmi InitScrlAmt ;negative for left movement, branch
|
|
iny
|
|
cpy #$02 ;if value $01, branch and do not decrement
|
|
bcc ChkNearMid
|
|
dey ;otherwise decrement by one
|
|
ChkNearMid lda Player_Pos_ForScroll
|
|
cmp #$70 ;check player's horizontal screen position
|
|
bcc ScrollScreen ;if less than 112 pixels to the right, branch
|
|
ldy Player_X_Scroll ;otherwise get original value undecremented
|
|
|
|
ScrollScreen
|
|
tya
|
|
sta ScrollAmount ;save value here
|
|
clc
|
|
adc ScrollThirtyTwo ;add to value already set here
|
|
sta ScrollThirtyTwo ;save as new value here
|
|
tya
|
|
clc
|
|
adc ScreenLeft_X_Pos ;add to left side coordinate
|
|
sta ScreenLeft_X_Pos ;save as new left side coordinate
|
|
sta HorizontalScroll ;save here also
|
|
lda ScreenLeft_PageLoc
|
|
adc #$00 ;add carry to page location for left
|
|
sta ScreenLeft_PageLoc ;side of the screen
|
|
and #$01 ;get LSB of page location
|
|
sta $00 ;save as temp variable for PPU register 1 mirror
|
|
lda Mirror_PPU_CTRL_REG1 ;get PPU register 1 mirror
|
|
and #%11111110 ;save all bits except d0
|
|
ora $00 ;get saved bit here and save in PPU register 1
|
|
sta Mirror_PPU_CTRL_REG1 ;mirror to be used to set name table later
|
|
jsr GetScreenPosition ;figure out where the right side is
|
|
lda #$08
|
|
sta ScrollIntervalTimer ;set scroll timer (residual, not used elsewhere)
|
|
jmp ChkPOffscr ;skip this part
|
|
InitScrlAmt lda #$00
|
|
sta ScrollAmount ;initialize value here
|
|
ChkPOffscr ldx #$00 ;set X for player offset
|
|
jsr GetXOffscreenBits ;get horizontal offscreen bits for player
|
|
sta $00 ;save them here
|
|
ldy #$00 ;load default offset (left side)
|
|
asl ;if d7 of offscreen bits are set,
|
|
bcs KeepOnscr ;branch with default offset
|
|
iny ;otherwise use different offset (right side)
|
|
lda $00
|
|
and #%00100000 ;check offscreen bits for d5 set
|
|
beq InitPlatScrl ;if not set, branch ahead of this part
|
|
KeepOnscr lda ScreenEdge_X_Pos,y ;get left or right side coordinate based on offset
|
|
sec
|
|
sbc X_SubtracterData,y ;subtract amount based on offset
|
|
sta Player_X_Position ;store as player position to prevent movement further
|
|
lda ScreenEdge_PageLoc,y ;get left or right page location based on offset
|
|
sbc #$00 ;subtract borrow
|
|
sta Player_PageLoc ;save as player's page location
|
|
lda Left_Right_Buttons ;check saved controller bits
|
|
cmp OffscrJoypadBitsData,y ;against bits based on offset
|
|
beq InitPlatScrl ;if not equal, branch
|
|
lda #$00
|
|
sta Player_X_Speed ;otherwise nullify horizontal speed of player
|
|
InitPlatScrl lda #$00 ;nullify platform force imposed on scroll
|
|
sta Platform_X_Scroll
|
|
rts
|
|
|
|
X_SubtracterData
|
|
db $00,$10
|
|
|
|
OffscrJoypadBitsData
|
|
db $01,$02
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
GetScreenPosition
|
|
lda ScreenLeft_X_Pos ;get coordinate of screen's left boundary
|
|
clc
|
|
adc #$ff ;add 255 pixels
|
|
sta ScreenRight_X_Pos ;store as coordinate of screen's right boundary
|
|
lda ScreenLeft_PageLoc ;get page number where left boundary is
|
|
adc #$00 ;add carry from before
|
|
sta ScreenRight_PageLoc ;store as page number where right boundary is
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
GameRoutines
|
|
lda GameEngineSubroutine ;run routine based on number (a few of these routines are
|
|
jsr JumpEngine ;merely placeholders as conditions for other routines)
|
|
|
|
dw Entrance_GameTimerSetup
|
|
dw Vine_AutoClimb
|
|
dw SideExitPipeEntry
|
|
dw VerticalPipeEntry
|
|
dw FlagpoleSlide
|
|
dw PlayerEndLevel
|
|
dw PlayerLoseLife
|
|
dw PlayerEntrance
|
|
dw PlayerCtrlRoutine
|
|
dw PlayerChangeSize
|
|
dw PlayerInjuryBlink
|
|
dw PlayerDeath
|
|
dw PlayerFireFlower
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
PlayerEntrance
|
|
lda AltEntranceControl ;check for mode of alternate entry
|
|
cmp #$02
|
|
beq EntrMode2 ;if found, branch to enter from pipe or with vine
|
|
lda #$00
|
|
ldy Player_Y_Position ;if vertical position above a certain
|
|
cpy #$30 ;point, nullify controller bits and continue
|
|
bcc AutoControlPlayer ;with player movement code, do not return
|
|
lda PlayerEntranceCtrl ;check player entry bits from header
|
|
cmp #$06
|
|
beq ChkBehPipe ;if set to 6 or 7, execute pipe intro code
|
|
cmp #$07 ;otherwise branch to normal entry
|
|
bne PlayerRdy
|
|
ChkBehPipe lda Player_SprAttrib ;check for sprite attributes
|
|
bne IntroEntr ;branch if found
|
|
lda #$01
|
|
jmp AutoControlPlayer ;force player to walk to the right
|
|
IntroEntr jsr EnterSidePipe ;execute sub to move player to the right
|
|
dec ChangeAreaTimer ;decrement timer for change of area
|
|
bne ExitEntr ;branch to exit if not yet expired
|
|
inc DisableIntermediate ;set flag to skip world and lives display
|
|
jmp NextArea ;jump to increment to next area and set modes
|
|
EntrMode2 lda JoypadOverride ;if controller override bits set here,
|
|
bne VineEntr ;branch to enter with vine
|
|
lda #$ff ;otherwise, set value here then execute sub
|
|
jsr MovePlayerYAxis ;to move player upwards (note $ff = -1)
|
|
lda Player_Y_Position ;check to see if player is at a specific coordinate
|
|
cmp #$91 ;if player risen to a certain point (this requires pipes
|
|
bcc PlayerRdy ;to be at specific height to look/function right) branch
|
|
rts ;to the last part, otherwise leave
|
|
VineEntr lda VineHeight
|
|
cmp #$60 ;check vine height
|
|
bne ExitEntr ;if vine not yet reached maximum height, branch to leave
|
|
lda Player_Y_Position ;get player's vertical coordinate
|
|
cmp #$99 ;check player's vertical coordinate against preset value
|
|
ldy #$00 ;load default values to be written to
|
|
lda #$01 ;this value moves player to the right off the vine
|
|
bcc OffVine ;if vertical coordinate < preset value, use defaults
|
|
lda #$03
|
|
sta Player_State ;otherwise set player state to climbing
|
|
iny ;increment value in Y
|
|
lda #$08 ;set block in block buffer to cover hole, then
|
|
sta Block_Buffer_1+$b4 ;use same value to force player to climb
|
|
OffVine sty DisableCollisionDet ;set collision detection disable flag
|
|
jsr AutoControlPlayer ;use contents of A to move player up or right, execute sub
|
|
lda Player_X_Position
|
|
cmp #$48 ;check player's horizontal position
|
|
bcc ExitEntr ;if not far enough to the right, branch to leave
|
|
PlayerRdy lda #$08 ;set routine to be executed by game engine next frame
|
|
sta GameEngineSubroutine
|
|
lda #$01 ;set to face player to the right
|
|
sta PlayerFacingDir
|
|
lsr ;init A
|
|
sta AltEntranceControl ;init mode of entry
|
|
sta DisableCollisionDet ;init collision detection disable flag
|
|
sta JoypadOverride ;nullify controller override bits
|
|
ExitEntr rts ;leave!
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$07 - used to hold upper limit of high byte when player falls down hole
|
|
|
|
AutoControlPlayer
|
|
sta SavedJoypadBits ;override controller bits with contents of A if executing here
|
|
|
|
PlayerCtrlRoutine
|
|
lda GameEngineSubroutine ;check task here
|
|
cmp #$0b ;if certain value is set, branch to skip controller bit loading
|
|
beq SizeChk
|
|
lda AreaType ;are we in a water type area?
|
|
bne SaveJoyp ;if not, branch
|
|
ldy Player_Y_HighPos
|
|
dey ;if not in vertical area between
|
|
bne DisJoyp ;status bar and bottom, branch
|
|
lda Player_Y_Position
|
|
cmp #$d0 ;if nearing the bottom of the screen or
|
|
bcc SaveJoyp ;not in the vertical area between status bar or bottom,
|
|
DisJoyp lda #$00 ;disable controller bits
|
|
sta SavedJoypadBits
|
|
SaveJoyp lda SavedJoypadBits ;otherwise store A and B buttons in $0a
|
|
and #%11000000
|
|
sta A_B_Buttons
|
|
lda SavedJoypadBits ;store left and right buttons in $0c
|
|
and #%00000011
|
|
sta Left_Right_Buttons
|
|
lda SavedJoypadBits ;store up and down buttons in $0b
|
|
and #%00001100
|
|
sta Up_Down_Buttons
|
|
and #%00000100 ;check for pressing down
|
|
beq SizeChk ;if not, branch
|
|
lda Player_State ;check player's state
|
|
bne SizeChk ;if not on the ground, branch
|
|
ldy Left_Right_Buttons ;check left and right
|
|
beq SizeChk ;if neither pressed, branch
|
|
lda #$00
|
|
sta Left_Right_Buttons ;if pressing down while on the ground,
|
|
sta Up_Down_Buttons ;nullify directional bits
|
|
SizeChk jsr PlayerMovementSubs ;run movement subroutines
|
|
ldy #$01 ;is player small?
|
|
lda PlayerSize
|
|
bne ChkMoveDir
|
|
ldy #$00 ;check for if crouching
|
|
lda CrouchingFlag
|
|
beq ChkMoveDir ;if not, branch ahead
|
|
ldy #$02 ;if big and crouching, load y with 2
|
|
ChkMoveDir sty Player_BoundBoxCtrl ;set contents of Y as player's bounding box size control
|
|
lda #$01 ;set moving direction to right by default
|
|
ldy Player_X_Speed ;check player's horizontal speed
|
|
beq PlayerSubs ;if not moving at all horizontally, skip this part
|
|
bpl SetMoveDir ;if moving to the right, use default moving direction
|
|
asl ;otherwise change to move to the left
|
|
SetMoveDir sta Player_MovingDir ;set moving direction
|
|
PlayerSubs jsr ScrollHandler ;move the screen if necessary
|
|
jsr GetPlayerOffscreenBits ;get player's offscreen bits
|
|
jsr RelativePlayerPosition ;get coordinates relative to the screen
|
|
ldx #$00 ;set offset for player object
|
|
jsr BoundingBoxCore ;get player's bounding box coordinates
|
|
jsr PlayerBGCollision ;do collision detection and process
|
|
lda Player_Y_Position
|
|
cmp #$40 ;check to see if player is higher than 64th pixel
|
|
bcc PlayerHole ;if so, branch ahead
|
|
lda GameEngineSubroutine
|
|
cmp #$05 ;if running end-of-level routine, branch ahead
|
|
beq PlayerHole
|
|
cmp #$07 ;if running player entrance routine, branch ahead
|
|
beq PlayerHole
|
|
cmp #$04 ;if running routines $00-$03, branch ahead
|
|
bcc PlayerHole
|
|
lda Player_SprAttrib
|
|
and #%11011111 ;otherwise nullify player's
|
|
sta Player_SprAttrib ;background priority flag
|
|
PlayerHole lda Player_Y_HighPos ;check player's vertical high byte
|
|
cmp #$02 ;for below the screen
|
|
bmi ExitCtrl ;branch to leave if not that far down
|
|
ldx #$01
|
|
stx ScrollLock ;set scroll lock
|
|
ldy #$04
|
|
sty $07 ;set value here
|
|
ldx #$00 ;use X as flag, and clear for cloud level
|
|
ldy GameTimerExpiredFlag ;check game timer expiration flag
|
|
bne HoleDie ;if set, branch
|
|
ldy CloudTypeOverride ;check for cloud type override
|
|
bne ChkHoleX ;skip to last part if found
|
|
HoleDie inx ;set flag in X for player death
|
|
ldy GameEngineSubroutine
|
|
cpy #$0b ;check for some other routine running
|
|
beq ChkHoleX ;if so, branch ahead
|
|
ldy DeathMusicLoaded ;check value here
|
|
bne HoleBottom ;if already set, branch to next part
|
|
iny
|
|
sty EventMusicQueue ;otherwise play death music
|
|
sty DeathMusicLoaded ;and set value here
|
|
HoleBottom ldy #$06
|
|
sty $07 ;change value here
|
|
ChkHoleX cmp $07 ;compare vertical high byte with value set here
|
|
bmi ExitCtrl ;if less, branch to leave
|
|
dex ;otherwise decrement flag in X
|
|
bmi CloudExit ;if flag was clear, branch to set modes and other values
|
|
ldy EventMusicBuffer ;check to see if music is still playing
|
|
bne ExitCtrl ;branch to leave if so
|
|
lda #$06 ;otherwise set to run lose life routine
|
|
sta GameEngineSubroutine ;on next frame
|
|
ExitCtrl rts ;leave
|
|
|
|
CloudExit
|
|
lda #$00
|
|
sta JoypadOverride ;clear controller override bits if any are set
|
|
jsr SetEntr ;do sub to set secondary mode
|
|
inc AltEntranceControl ;set mode of entry to 3
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
Vine_AutoClimb
|
|
lda Player_Y_HighPos ;check to see whether player reached position
|
|
bne AutoClimb ;above the status bar yet and if so, set modes
|
|
lda Player_Y_Position
|
|
cmp #$e4
|
|
bcc SetEntr
|
|
AutoClimb lda #%00001000 ;set controller bits override to up
|
|
sta JoypadOverride
|
|
ldy #$03 ;set player state to climbing
|
|
sty Player_State
|
|
jmp AutoControlPlayer
|
|
SetEntr lda #$02 ;set starting position to override
|
|
sta AltEntranceControl
|
|
jmp ChgAreaMode ;set modes
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
VerticalPipeEntry
|
|
lda #$01 ;set 1 as movement amount
|
|
jsr MovePlayerYAxis ;do sub to move player downwards
|
|
jsr ScrollHandler ;do sub to scroll screen with saved force if necessary
|
|
ldy #$00 ;load default mode of entry
|
|
lda WarpZoneControl ;check warp zone control variable/flag
|
|
bne ChgAreaPipe ;if set, branch to use mode 0
|
|
iny
|
|
lda AreaType ;check for castle level type
|
|
cmp #$03
|
|
bne ChgAreaPipe ;if not castle type level, use mode 1
|
|
iny
|
|
jmp ChgAreaPipe ;otherwise use mode 2
|
|
|
|
MovePlayerYAxis
|
|
clc
|
|
adc Player_Y_Position ;add contents of A to player position
|
|
sta Player_Y_Position
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
SideExitPipeEntry
|
|
jsr EnterSidePipe ;execute sub to move player to the right
|
|
ldy #$02
|
|
ChgAreaPipe dec ChangeAreaTimer ;decrement timer for change of area
|
|
bne ExitCAPipe
|
|
sty AltEntranceControl ;when timer expires set mode of alternate entry
|
|
ChgAreaMode inc DisableScreenFlag ;set flag to disable screen output
|
|
lda #$00
|
|
sta OperMode_Task ;set secondary mode of operation
|
|
sta Sprite0HitDetectFlag ;disable sprite 0 check
|
|
ExitCAPipe rts ;leave
|
|
|
|
EnterSidePipe
|
|
lda #$08 ;set player's horizontal speed
|
|
sta Player_X_Speed
|
|
ldy #$01 ;set controller right button by default
|
|
lda Player_X_Position ;mask out higher nybble of player's
|
|
and #%00001111 ;horizontal position
|
|
bne RightPipe
|
|
sta Player_X_Speed ;if lower nybble = 0, set as horizontal speed
|
|
tay ;and nullify controller bit override here
|
|
RightPipe tya ;use contents of Y to
|
|
jsr AutoControlPlayer ;execute player control routine with ctrl bits nulled
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
PlayerChangeSize
|
|
lda TimerControl ;check master timer control
|
|
cmp #$f8 ;for specific moment in time
|
|
bne EndChgSize ;branch if before or after that point
|
|
jmp InitChangeSize ;otherwise run code to get growing/shrinking going
|
|
EndChgSize cmp #$c4 ;check again for another specific moment
|
|
bne ExitChgSize ;and branch to leave if before or after that point
|
|
jsr DonePlayerTask ;otherwise do sub to init timer control and set routine
|
|
ExitChgSize rts ;and then leave
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
PlayerInjuryBlink
|
|
lda TimerControl ;check master timer control
|
|
cmp #$f0 ;for specific moment in time
|
|
bcs ExitBlink ;branch if before that point
|
|
cmp #$c8 ;check again for another specific point
|
|
beq DonePlayerTask ;branch if at that point, and not before or after
|
|
jmp PlayerCtrlRoutine ;otherwise run player control routine
|
|
ExitBlink bne ExitBoth ;do unconditional branch to leave
|
|
|
|
InitChangeSize
|
|
ldy PlayerChangeSizeFlag ;if growing/shrinking flag already set
|
|
bne ExitBoth ;then branch to leave
|
|
sty PlayerAnimCtrl ;otherwise initialize player's animation frame control
|
|
inc PlayerChangeSizeFlag ;set growing/shrinking flag
|
|
lda PlayerSize
|
|
eor #$01 ;invert player's size
|
|
sta PlayerSize
|
|
ExitBoth rts ;leave
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$00 - used in CyclePlayerPalette to store current palette to cycle
|
|
|
|
PlayerDeath
|
|
lda TimerControl ;check master timer control
|
|
cmp #$f0 ;for specific moment in time
|
|
bcs ExitDeath ;branch to leave if before that point
|
|
jmp PlayerCtrlRoutine ;otherwise run player control routine
|
|
|
|
DonePlayerTask
|
|
lda #$00
|
|
sta TimerControl ;initialize master timer control to continue timers
|
|
lda #$08
|
|
sta GameEngineSubroutine ;set player control routine to run next frame
|
|
rts ;leave
|
|
|
|
PlayerFireFlower
|
|
lda TimerControl ;check master timer control
|
|
cmp #$c0 ;for specific moment in time
|
|
beq ResetPalFireFlower ;branch if at moment, not before or after
|
|
lda FrameCounter ;get frame counter
|
|
lsr
|
|
lsr ;divide by four to change every four frames
|
|
|
|
CyclePlayerPalette
|
|
and #$03 ;mask out all but d1-d0 (previously d3-d2)
|
|
sta $00 ;store result here to use as palette bits
|
|
lda Player_SprAttrib ;get player attributes
|
|
and #%11111100 ;save any other bits but palette bits
|
|
ora $00 ;add palette bits
|
|
sta Player_SprAttrib ;store as new player attributes
|
|
rts ;and leave
|
|
|
|
ResetPalFireFlower
|
|
jsr DonePlayerTask ;do sub to init timer control and run player control routine
|
|
|
|
ResetPalStar
|
|
lda Player_SprAttrib ;get player attributes
|
|
and #%11111100 ;mask out palette bits to force palette 0
|
|
sta Player_SprAttrib ;store as new player attributes
|
|
rts ;and leave
|
|
|
|
ExitDeath
|
|
rts ;leave from death routine
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
FlagpoleSlide
|
|
lda Enemy_ID+5 ;check special use enemy slot
|
|
cmp #FlagpoleFlagObject ;for flagpole flag object
|
|
bne NoFPObj ;if not found, branch to something residual
|
|
lda FlagpoleSoundQueue ;load flagpole sound
|
|
sta Square1SoundQueue ;into square 1's sfx queue
|
|
lda #$00
|
|
sta FlagpoleSoundQueue ;init flagpole sound queue
|
|
ldy Player_Y_Position
|
|
cpy #$9e ;check to see if player has slid down
|
|
bcs SlidePlayer ;far enough, and if so, branch with no controller bits set
|
|
lda #$04 ;otherwise force player to climb down (to slide)
|
|
SlidePlayer jmp AutoControlPlayer ;jump to player control routine
|
|
NoFPObj inc GameEngineSubroutine ;increment to next routine (this may
|
|
rts ;be residual code)
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
Hidden1UpCoinAmts
|
|
db $15,$23,$16,$1b,$17,$18,$23,$63
|
|
|
|
PlayerEndLevel
|
|
lda #$01 ;force player to walk to the right
|
|
jsr AutoControlPlayer
|
|
lda Player_Y_Position ;check player's vertical position
|
|
cmp #$ae
|
|
bcc ChkStop ;if player is not yet off the flagpole, skip this part
|
|
lda ScrollLock ;if scroll lock not set, branch ahead to next part
|
|
beq ChkStop ;because we only need to do this part once
|
|
lda #EndOfLevelMusic
|
|
sta EventMusicQueue ;load win level music in event music queue
|
|
lda #$00
|
|
sta ScrollLock ;turn off scroll lock to skip this part later
|
|
ChkStop lda Player_CollisionBits ;get player collision bits
|
|
lsr ;check for d0 set
|
|
bcs RdyNextA ;if d0 set, skip to next part
|
|
lda StarFlagTaskControl ;if star flag task control already set,
|
|
bne InCastle ;go ahead with the rest of the code
|
|
inc StarFlagTaskControl ;otherwise set task control now (this gets ball rolling!)
|
|
InCastle lda #%00100000 ;set player's background priority bit to
|
|
sta Player_SprAttrib ;give illusion of being inside the castle
|
|
RdyNextA lda StarFlagTaskControl
|
|
cmp #$05 ;if star flag task control not yet set
|
|
bne ExitNA ;beyond last valid task number, branch to leave
|
|
inc LevelNumber ;increment level number used for game logic
|
|
lda LevelNumber
|
|
cmp #$03 ;check to see if we have yet reached level -4
|
|
bne NextArea ;and skip this last part here if not
|
|
ldy WorldNumber ;get world number as offset
|
|
lda CoinTallyFor1Ups ;check third area coin tally for bonus 1-ups
|
|
cmp Hidden1UpCoinAmts,y ;against minimum value, if player has not collected
|
|
bcc NextArea ;at least this number of coins, leave flag clear
|
|
inc Hidden1UpFlag ;otherwise set hidden 1-up box control flag
|
|
NextArea inc AreaNumber ;increment area number used for address loader
|
|
jsr LoadAreaPointer ;get new level pointer
|
|
inc FetchNewGameTimerFlag ;set flag to load new game timer
|
|
jsr ChgAreaMode ;do sub to set secondary mode, disable screen and sprite 0
|
|
sta HalfwayPage ;reset halfway page to 0 (beginning)
|
|
lda #Silence
|
|
sta EventMusicQueue ;silence music and leave
|
|
ExitNA rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
PlayerMovementSubs
|
|
lda #$00 ;set A to init crouch flag by default
|
|
ldy PlayerSize ;is player small?
|
|
bne SetCrouch ;if so, branch
|
|
lda Player_State ;check state of player
|
|
bne ProcMove ;if not on the ground, branch
|
|
lda Up_Down_Buttons ;load controller bits for up and down
|
|
and #%00000100 ;single out bit for down button
|
|
SetCrouch sta CrouchingFlag ;store value in crouch flag
|
|
ProcMove jsr PlayerPhysicsSub ;run sub related to jumping and swimming
|
|
lda PlayerChangeSizeFlag ;if growing/shrinking flag set,
|
|
bne NoMoveSub ;branch to leave
|
|
lda Player_State
|
|
cmp #$03 ;get player state
|
|
beq MoveSubs ;if climbing, branch ahead, leave timer unset
|
|
ldy #$18
|
|
sty ClimbSideTimer ;otherwise reset timer now
|
|
MoveSubs jsr JumpEngine
|
|
|
|
dw OnGroundStateSub
|
|
dw JumpSwimSub
|
|
dw FallingSub
|
|
dw ClimbingSub
|
|
|
|
NoMoveSub rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$00 - used by ClimbingSub to store high vertical adder
|
|
|
|
OnGroundStateSub
|
|
jsr GetPlayerAnimSpeed ;do a sub to set animation frame timing
|
|
lda Left_Right_Buttons
|
|
beq GndMove ;if left/right controller bits not set, skip instruction
|
|
sta PlayerFacingDir ;otherwise set new facing direction
|
|
GndMove jsr ImposeFriction ;do a sub to impose friction on player's walk/run
|
|
jsr MovePlayerHorizontally ;do another sub to move player horizontally
|
|
sta Player_X_Scroll ;set returned value as player's movement speed for scroll
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
FallingSub
|
|
lda VerticalForceDown
|
|
sta VerticalForce ;dump vertical movement force for falling into main one
|
|
jmp LRAir ;movement force, then skip ahead to process left/right movement
|
|
|
|
;--------------------------------
|
|
|
|
JumpSwimSub
|
|
ldy Player_Y_Speed ;if player's vertical speed zero
|
|
bpl DumpFall ;or moving downwards, branch to falling
|
|
lda A_B_Buttons
|
|
and #A_Button ;check to see if A button is being pressed
|
|
and PreviousA_B_Buttons ;and was pressed in previous frame
|
|
bne ProcSwim ;if so, branch elsewhere
|
|
lda JumpOrigin_Y_Position ;get vertical position player jumped from
|
|
sec
|
|
sbc Player_Y_Position ;subtract current from original vertical coordinate
|
|
cmp DiffToHaltJump ;compare to value set here to see if player is in mid-jump
|
|
bcc ProcSwim ;or just starting to jump, if just starting, skip ahead
|
|
DumpFall lda VerticalForceDown ;otherwise dump falling into main fractional
|
|
sta VerticalForce
|
|
ProcSwim lda SwimmingFlag ;if swimming flag not set,
|
|
beq LRAir ;branch ahead to last part
|
|
jsr GetPlayerAnimSpeed ;do a sub to get animation frame timing
|
|
lda Player_Y_Position
|
|
cmp #$14 ;check vertical position against preset value
|
|
bcs LRWater ;if not yet reached a certain position, branch ahead
|
|
lda #$18
|
|
sta VerticalForce ;otherwise set fractional
|
|
LRWater lda Left_Right_Buttons ;check left/right controller bits (check for swimming)
|
|
beq LRAir ;if not pressing any, skip
|
|
sta PlayerFacingDir ;otherwise set facing direction accordingly
|
|
LRAir lda Left_Right_Buttons ;check left/right controller bits (check for jumping/falling)
|
|
beq JSMove ;if not pressing any, skip
|
|
jsr ImposeFriction ;otherwise process horizontal movement
|
|
JSMove jsr MovePlayerHorizontally ;do a sub to move player horizontally
|
|
sta Player_X_Scroll ;set player's speed here, to be used for scroll later
|
|
lda GameEngineSubroutine
|
|
cmp #$0b ;check for specific routine selected
|
|
bne ExitMov1 ;branch if not set to run
|
|
lda #$28
|
|
sta VerticalForce ;otherwise set fractional
|
|
ExitMov1 jmp MovePlayerVertically ;jump to move player vertically, then leave
|
|
|
|
;--------------------------------
|
|
|
|
ClimbAdderLow
|
|
db $0e,$04,$fc,$f2
|
|
ClimbAdderHigh
|
|
db $00,$00,$ff,$ff
|
|
|
|
ClimbingSub
|
|
lda Player_YMF_Dummy
|
|
clc ;add movement force to dummy variable
|
|
adc Player_Y_MoveForce ;save with carry
|
|
sta Player_YMF_Dummy
|
|
ldy #$00 ;set default adder here
|
|
lda Player_Y_Speed ;get player's vertical speed
|
|
bpl MoveOnVine ;if not moving upwards, branch
|
|
dey ;otherwise set adder to $ff
|
|
MoveOnVine sty $00 ;store adder here
|
|
adc Player_Y_Position ;add carry to player's vertical position
|
|
sta Player_Y_Position ;and store to move player up or down
|
|
lda Player_Y_HighPos
|
|
adc $00 ;add carry to player's page location
|
|
sta Player_Y_HighPos ;and store
|
|
lda Left_Right_Buttons ;compare left/right controller bits
|
|
and Player_CollisionBits ;to collision flag
|
|
beq InitCSTimer ;if not set, skip to end
|
|
ldy ClimbSideTimer ;otherwise check timer
|
|
bne ExitCSub ;if timer not expired, branch to leave
|
|
ldy #$18
|
|
sty ClimbSideTimer ;otherwise set timer now
|
|
ldx #$00 ;set default offset here
|
|
ldy PlayerFacingDir ;get facing direction
|
|
lsr ;move right button controller bit to carry
|
|
bcs ClimbFD ;if controller right pressed, branch ahead
|
|
inx
|
|
inx ;otherwise increment offset by 2 bytes
|
|
ClimbFD dey ;check to see if facing right
|
|
beq CSetFDir ;if so, branch, do not increment
|
|
inx ;otherwise increment by 1 byte
|
|
CSetFDir lda Player_X_Position
|
|
clc ;add or subtract from player's horizontal position
|
|
adc ClimbAdderLow,x ;using value here as adder and X as offset
|
|
sta Player_X_Position
|
|
lda Player_PageLoc ;add or subtract carry or borrow using value here
|
|
adc ClimbAdderHigh,x ;from the player's page location
|
|
sta Player_PageLoc
|
|
lda Left_Right_Buttons ;get left/right controller bits again
|
|
eor #%00000011 ;invert them and store them while player
|
|
sta PlayerFacingDir ;is on vine to face player in opposite direction
|
|
ExitCSub rts ;then leave
|
|
InitCSTimer sta ClimbSideTimer ;initialize timer here
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$00 - used to store offset to friction data
|
|
|
|
JumpMForceData
|
|
db $20,$20,$1e,$28,$28,$0d,$04
|
|
|
|
FallMForceData
|
|
db $70,$70,$60,$90,$90,$0a,$09
|
|
|
|
PlayerYSpdData
|
|
db $fc,$fc,$fc,$fb,$fb,$fe,$ff
|
|
|
|
InitMForceData
|
|
db $00,$00,$00,$00,$00,$80,$00
|
|
|
|
MaxLeftXSpdData
|
|
db $d8,$e8,$f0
|
|
|
|
MaxRightXSpdData
|
|
db $28,$18,$10
|
|
db $0c ;used for pipe intros
|
|
|
|
FrictionData
|
|
db $e4,$98,$d0
|
|
|
|
Climb_Y_SpeedData
|
|
db $00,$ff,$01
|
|
|
|
Climb_Y_MForceData
|
|
db $00,$20,$ff
|
|
|
|
PlayerPhysicsSub
|
|
lda Player_State ;check player state
|
|
cmp #$03
|
|
bne CheckForJumping ;if not climbing, branch
|
|
ldy #$00
|
|
lda Up_Down_Buttons ;get controller bits for up/down
|
|
and Player_CollisionBits ;check against player's collision detection bits
|
|
beq ProcClimb ;if not pressing up or down, branch
|
|
iny
|
|
and #%00001000 ;check for pressing up
|
|
bne ProcClimb
|
|
iny
|
|
ProcClimb ldx Climb_Y_MForceData,y ;load value here
|
|
stx Player_Y_MoveForce ;store as vertical movement force
|
|
lda #$08 ;load default animation timing
|
|
ldx Climb_Y_SpeedData,y ;load some other value here
|
|
stx Player_Y_Speed ;store as vertical speed
|
|
bmi SetCAnim ;if climbing down, use default animation timing value
|
|
lsr ;otherwise divide timer setting by 2
|
|
SetCAnim sta PlayerAnimTimerSet ;store animation timer setting and leave
|
|
rts
|
|
|
|
CheckForJumping
|
|
lda JumpspringAnimCtrl ;if jumpspring animating,
|
|
bne NoJump ;skip ahead to something else
|
|
lda A_B_Buttons ;check for A button press
|
|
and #A_Button
|
|
beq NoJump ;if not, branch to something else
|
|
and PreviousA_B_Buttons ;if button not pressed in previous frame, branch
|
|
beq ProcJumping
|
|
NoJump jmp X_Physics ;otherwise, jump to something else
|
|
|
|
ProcJumping
|
|
lda Player_State ;check player state
|
|
beq InitJS ;if on the ground, branch
|
|
lda SwimmingFlag ;if swimming flag not set, jump to do something else
|
|
beq NoJump ;to prevent midair jumping, otherwise continue
|
|
lda JumpSwimTimer ;if jump/swim timer nonzero, branch
|
|
bne InitJS
|
|
lda Player_Y_Speed ;check player's vertical speed
|
|
bpl InitJS ;if player's vertical speed motionless or down, branch
|
|
jmp X_Physics ;if timer at zero and player still rising, do not swim
|
|
InitJS lda #$20 ;set jump/swim timer
|
|
sta JumpSwimTimer
|
|
ldy #$00 ;initialize vertical force and dummy variable
|
|
sty Player_YMF_Dummy
|
|
sty Player_Y_MoveForce
|
|
lda Player_Y_HighPos ;get vertical high and low bytes of jump origin
|
|
sta JumpOrigin_Y_HighPos ;and store them next to each other here
|
|
lda Player_Y_Position
|
|
sta JumpOrigin_Y_Position
|
|
lda #$01 ;set player state to jumping/swimming
|
|
sta Player_State
|
|
lda Player_XSpeedAbsolute ;check value related to walking/running speed
|
|
cmp #$09
|
|
bcc ChkWtr ;branch if below certain values, increment Y
|
|
iny ;for each amount equal or exceeded
|
|
cmp #$10
|
|
bcc ChkWtr
|
|
iny
|
|
cmp #$19
|
|
bcc ChkWtr
|
|
iny
|
|
cmp #$1c
|
|
bcc ChkWtr ;note that for jumping, range is 0-4 for Y
|
|
iny
|
|
ChkWtr lda #$01 ;set value here (apparently always set to 1)
|
|
sta DiffToHaltJump
|
|
lda SwimmingFlag ;if swimming flag disabled, branch
|
|
beq GetYPhy
|
|
ldy #$05 ;otherwise set Y to 5, range is 5-6
|
|
lda Whirlpool_Flag ;if whirlpool flag not set, branch
|
|
beq GetYPhy
|
|
iny ;otherwise increment to 6
|
|
GetYPhy lda JumpMForceData,y ;store appropriate jump/swim
|
|
sta VerticalForce ;data here
|
|
lda FallMForceData,y
|
|
sta VerticalForceDown
|
|
lda InitMForceData,y
|
|
sta Player_Y_MoveForce
|
|
lda PlayerYSpdData,y
|
|
sta Player_Y_Speed
|
|
lda SwimmingFlag ;if swimming flag disabled, branch
|
|
beq PJumpSnd
|
|
lda #Sfx_EnemyStomp ;load swim/goomba stomp sound into
|
|
sta Square1SoundQueue ;square 1's sfx queue
|
|
lda Player_Y_Position
|
|
cmp #$14 ;check vertical low byte of player position
|
|
bcs X_Physics ;if below a certain point, branch
|
|
lda #$00 ;otherwise reset player's vertical speed
|
|
sta Player_Y_Speed ;and jump to something else to keep player
|
|
jmp X_Physics ;from swimming above water level
|
|
PJumpSnd lda #Sfx_BigJump ;load big mario's jump sound by default
|
|
ldy PlayerSize ;is mario big?
|
|
beq SJumpSnd
|
|
lda #Sfx_SmallJump ;if not, load small mario's jump sound
|
|
SJumpSnd sta Square1SoundQueue ;store appropriate jump sound in square 1 sfx queue
|
|
X_Physics ldy #$00
|
|
sty $00 ;init value here
|
|
lda Player_State ;if mario is on the ground, branch
|
|
beq ProcPRun
|
|
lda Player_XSpeedAbsolute ;check something that seems to be related
|
|
cmp #$19 ;to mario's speed
|
|
bcs GetXPhy ;if =>$19 branch here
|
|
bcc ChkRFast ;if not branch elsewhere
|
|
ProcPRun iny ;if mario on the ground, increment Y
|
|
lda AreaType ;check area type
|
|
beq ChkRFast ;if water type, branch
|
|
dey ;decrement Y by default for non-water type area
|
|
lda Left_Right_Buttons ;get left/right controller bits
|
|
cmp Player_MovingDir ;check against moving direction
|
|
bne ChkRFast ;if controller bits <> moving direction, skip this part
|
|
lda A_B_Buttons ;check for b button pressed
|
|
and #B_Button
|
|
bne SetRTmr ;if pressed, skip ahead to set timer
|
|
lda RunningTimer ;check for running timer set
|
|
bne GetXPhy ;if set, branch
|
|
ChkRFast iny ;if running timer not set or level type is water,
|
|
inc $00 ;increment Y again and temp variable in memory
|
|
lda RunningSpeed
|
|
bne FastXSp ;if running speed set here, branch
|
|
lda Player_XSpeedAbsolute
|
|
cmp #$21 ;otherwise check player's walking/running speed
|
|
bcc GetXPhy ;if less than a certain amount, branch ahead
|
|
FastXSp inc $00 ;if running speed set or speed => $21 increment $00
|
|
jmp GetXPhy ;and jump ahead
|
|
SetRTmr lda #$0a ;if b button pressed, set running timer
|
|
sta RunningTimer
|
|
GetXPhy lda MaxLeftXSpdData,y ;get maximum speed to the left
|
|
sta MaximumLeftSpeed
|
|
lda GameEngineSubroutine ;check for specific routine running
|
|
cmp #$07 ;(player entrance)
|
|
bne GetXPhy2 ;if not running, skip and use old value of Y
|
|
ldy #$03 ;otherwise set Y to 3
|
|
GetXPhy2 lda MaxRightXSpdData,y ;get maximum speed to the right
|
|
sta MaximumRightSpeed
|
|
ldy $00 ;get other value in memory
|
|
lda FrictionData,y ;get value using value in memory as offset
|
|
sta FrictionAdderLow
|
|
lda #$00
|
|
sta FrictionAdderHigh ;init something here
|
|
lda PlayerFacingDir
|
|
cmp Player_MovingDir ;check facing direction against moving direction
|
|
beq ExitPhy ;if the same, branch to leave
|
|
asl FrictionAdderLow ;otherwise shift d7 of friction adder low into carry
|
|
rol FrictionAdderHigh ;then rotate carry onto d0 of friction adder high
|
|
ExitPhy rts ;and then leave
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
PlayerAnimTmrData
|
|
db $02,$04,$07
|
|
|
|
GetPlayerAnimSpeed
|
|
ldy #$00 ;initialize offset in Y
|
|
lda Player_XSpeedAbsolute ;check player's walking/running speed
|
|
cmp #$1c ;against preset amount
|
|
bcs SetRunSpd ;if greater than a certain amount, branch ahead
|
|
iny ;otherwise increment Y
|
|
cmp #$0e ;compare against lower amount
|
|
bcs ChkSkid ;if greater than this but not greater than first, skip increment
|
|
iny ;otherwise increment Y again
|
|
ChkSkid lda SavedJoypadBits ;get controller bits
|
|
and #%01111111 ;mask out A button
|
|
beq SetAnimSpd ;if no other buttons pressed, branch ahead of all this
|
|
and #$03 ;mask out all others except left and right
|
|
cmp Player_MovingDir ;check against moving direction
|
|
bne ProcSkid ;if left/right controller bits <> moving direction, branch
|
|
lda #$00 ;otherwise set zero value here
|
|
SetRunSpd sta RunningSpeed ;store zero or running speed here
|
|
jmp SetAnimSpd
|
|
ProcSkid lda Player_XSpeedAbsolute ;check player's walking/running speed
|
|
cmp #$0b ;against one last amount
|
|
bcs SetAnimSpd ;if greater than this amount, branch
|
|
lda PlayerFacingDir
|
|
sta Player_MovingDir ;otherwise use facing direction to set moving direction
|
|
lda #$00
|
|
sta Player_X_Speed ;nullify player's horizontal speed
|
|
sta Player_X_MoveForce ;and dummy variable for player
|
|
SetAnimSpd lda PlayerAnimTmrData,y ;get animation timer setting using Y as offset
|
|
sta PlayerAnimTimerSet
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
ImposeFriction
|
|
and Player_CollisionBits ;perform AND between left/right controller bits and collision flag
|
|
cmp #$00 ;then compare to zero (this instruction is redundant)
|
|
bne JoypFrict ;if any bits set, branch to next part
|
|
lda Player_X_Speed
|
|
beq SetAbsSpd ;if player has no horizontal speed, branch ahead to last part
|
|
bpl RghtFrict ;if player moving to the right, branch to slow
|
|
bmi LeftFrict ;otherwise logic dictates player moving left, branch to slow
|
|
JoypFrict lsr ;put right controller bit into carry
|
|
bcc RghtFrict ;if left button pressed, carry = 0, thus branch
|
|
LeftFrict lda Player_X_MoveForce ;load value set here
|
|
clc
|
|
adc FrictionAdderLow ;add to it another value set here
|
|
sta Player_X_MoveForce ;store here
|
|
lda Player_X_Speed
|
|
adc FrictionAdderHigh ;add value plus carry to horizontal speed
|
|
sta Player_X_Speed ;set as new horizontal speed
|
|
cmp MaximumRightSpeed ;compare against maximum value for right movement
|
|
bmi XSpdSign ;if horizontal speed greater negatively, branch
|
|
lda MaximumRightSpeed ;otherwise set preset value as horizontal speed
|
|
sta Player_X_Speed ;thus slowing the player's left movement down
|
|
jmp SetAbsSpd ;skip to the end
|
|
RghtFrict lda Player_X_MoveForce ;load value set here
|
|
sec
|
|
sbc FrictionAdderLow ;subtract from it another value set here
|
|
sta Player_X_MoveForce ;store here
|
|
lda Player_X_Speed
|
|
sbc FrictionAdderHigh ;subtract value plus borrow from horizontal speed
|
|
sta Player_X_Speed ;set as new horizontal speed
|
|
cmp MaximumLeftSpeed ;compare against maximum value for left movement
|
|
bpl XSpdSign ;if horizontal speed greater positively, branch
|
|
lda MaximumLeftSpeed ;otherwise set preset value as horizontal speed
|
|
sta Player_X_Speed ;thus slowing the player's right movement down
|
|
XSpdSign cmp #$00 ;if player not moving or moving to the right,
|
|
bpl SetAbsSpd ;branch and leave horizontal speed value unmodified
|
|
eor #$ff
|
|
clc ;otherwise get two's compliment to get absolute
|
|
adc #$01 ;unsigned walking/running speed
|
|
SetAbsSpd sta Player_XSpeedAbsolute ;store walking/running speed here and leave
|
|
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
|
|
lda PlayerStatus ;check player's status
|
|
cmp #$02
|
|
bcc ProcAirBubbles ;if not fiery, branch
|
|
lda A_B_Buttons
|
|
and #B_Button ;check for b button pressed
|
|
beq ProcFireballs ;branch if not pressed
|
|
and PreviousA_B_Buttons
|
|
bne ProcFireballs ;if button pressed in previous frame, branch
|
|
lda FireballCounter ;load fireball counter
|
|
and #%00000001 ;get LSB and use as offset for buffer
|
|
tax
|
|
lda Fireball_State,x ;load fireball state
|
|
bne ProcFireballs ;if not inactive, branch
|
|
ldy Player_Y_HighPos ;if player too high or too low, branch
|
|
dey
|
|
bne ProcFireballs
|
|
lda CrouchingFlag ;if player crouching, branch
|
|
bne ProcFireballs
|
|
lda Player_State ;if player's state = climbing, branch
|
|
cmp #$03
|
|
beq ProcFireballs
|
|
lda #Sfx_Fireball ;play fireball sound effect
|
|
sta Square1SoundQueue
|
|
lda #$02 ;load state
|
|
sta Fireball_State,x
|
|
ldy PlayerAnimTimerSet ;copy animation frame timer setting
|
|
sty FireballThrowingTimer ;into fireball throwing timer
|
|
dey
|
|
sty PlayerAnimTimer ;decrement and store in player's animation timer
|
|
inc FireballCounter ;increment fireball counter
|
|
|
|
ProcFireballs
|
|
ldx #$00
|
|
jsr FireballObjCore ;process first fireball object
|
|
ldx #$01
|
|
jsr FireballObjCore ;process second fireball object, then do air bubbles
|
|
|
|
ProcAirBubbles
|
|
lda AreaType ;if not water type level, skip the rest of this
|
|
bne BublExit
|
|
ldx #$02 ;otherwise load counter and use as offset
|
|
BublLoop stx ObjectOffset ;store offset
|
|
jsr BubbleCheck ;check timers and coordinates, create air bubble
|
|
jsr RelativeBubblePosition ;get relative coordinates
|
|
jsr GetBubbleOffscreenBits ;get offscreen information
|
|
jsr DrawBubble ;draw the air bubble
|
|
dex
|
|
bpl BublLoop ;do this until all three are handled
|
|
BublExit rts ;then leave
|
|
|
|
FireballXSpdData
|
|
db $40,$c0
|
|
|
|
FireballObjCore
|
|
stx ObjectOffset ;store offset as current object
|
|
lda Fireball_State,x ;check for d7 = 1
|
|
asl
|
|
bcs FireballExplosion ;if so, branch to get relative coordinates and draw explosion
|
|
ldy Fireball_State,x ;if fireball inactive, branch to leave
|
|
beq NoFBall
|
|
dey ;if fireball state set to 1, skip this part and just run it
|
|
beq RunFB
|
|
lda Player_X_Position ;get player's horizontal position
|
|
adc #$04 ;add four pixels and store as fireball's horizontal position
|
|
sta Fireball_X_Position,x
|
|
lda Player_PageLoc ;get player's page location
|
|
adc #$00 ;add carry and store as fireball's page location
|
|
sta Fireball_PageLoc,x
|
|
lda Player_Y_Position ;get player's vertical position and store
|
|
sta Fireball_Y_Position,x
|
|
lda #$01 ;set high byte of vertical position
|
|
sta Fireball_Y_HighPos,x
|
|
ldy PlayerFacingDir ;get player's facing direction
|
|
dey ;decrement to use as offset here
|
|
lda FireballXSpdData,y ;set horizontal speed of fireball accordingly
|
|
sta Fireball_X_Speed,x
|
|
lda #$04 ;set vertical speed of fireball
|
|
sta Fireball_Y_Speed,x
|
|
lda #$07
|
|
sta Fireball_BoundBoxCtrl,x ;set bounding box size control for fireball
|
|
dec Fireball_State,x ;decrement state to 1 to skip this part from now on
|
|
RunFB txa ;add 7 to offset to use
|
|
clc ;as fireball offset for next routines
|
|
adc #$07
|
|
tax
|
|
lda #$50 ;set downward movement force here
|
|
sta $00
|
|
lda #$03 ;set maximum speed here
|
|
sta $02
|
|
lda #$00
|
|
jsr ImposeGravity ;do sub here to impose gravity on fireball and move vertically
|
|
jsr MoveObjectHorizontally ;do another sub to move it horizontally
|
|
ldx ObjectOffset ;return fireball offset to X
|
|
jsr RelativeFireballPosition ;get relative coordinates
|
|
jsr GetFireballOffscreenBits ;get offscreen information
|
|
jsr GetFireballBoundBox ;get bounding box coordinates
|
|
jsr FireballBGCollision ;do fireball to background collision detection
|
|
lda FBall_OffscreenBits ;get fireball offscreen bits
|
|
and #%11001100 ;mask out certain bits
|
|
bne EraseFB ;if any bits still set, branch to kill fireball
|
|
jsr FireballEnemyCollision ;do fireball to enemy collision detection and deal with collisions
|
|
jmp DrawFireball ;draw fireball appropriately and leave
|
|
EraseFB lda #$00 ;erase fireball state
|
|
sta Fireball_State,x
|
|
NoFBall rts ;leave
|
|
|
|
FireballExplosion
|
|
jsr RelativeFireballPosition
|
|
jmp DrawExplosion_Fireball
|
|
|
|
BubbleCheck
|
|
lda PseudoRandomBitReg+1,x ;get part of LSFR
|
|
and #$01
|
|
sta $07 ;store pseudorandom bit here
|
|
lda Bubble_Y_Position,x ;get vertical coordinate for air bubble
|
|
cmp #$f8 ;if offscreen coordinate not set,
|
|
bne MoveBubl ;branch to move air bubble
|
|
lda AirBubbleTimer ;if air bubble timer not expired,
|
|
bne ExitBubl ;branch to leave, otherwise create new air bubble
|
|
|
|
SetupBubble
|
|
ldy #$00 ;load default value here
|
|
lda PlayerFacingDir ;get player's facing direction
|
|
lsr ;move d0 to carry
|
|
bcc PosBubl ;branch to use default value if facing left
|
|
ldy #$08 ;otherwise load alternate value here
|
|
PosBubl tya ;use value loaded as adder
|
|
adc Player_X_Position ;add to player's horizontal position
|
|
sta Bubble_X_Position,x ;save as horizontal position for airbubble
|
|
lda Player_PageLoc
|
|
adc #$00 ;add carry to player's page location
|
|
sta Bubble_PageLoc,x ;save as page location for airbubble
|
|
lda Player_Y_Position
|
|
clc ;add eight pixels to player's vertical position
|
|
adc #$08
|
|
sta Bubble_Y_Position,x ;save as vertical position for air bubble
|
|
lda #$01
|
|
sta Bubble_Y_HighPos,x ;set vertical high byte for air bubble
|
|
ldy $07 ;get pseudorandom bit, use as offset
|
|
lda BubbleTimerData,y ;get data for air bubble timer
|
|
sta AirBubbleTimer ;set air bubble timer
|
|
MoveBubl ldy $07 ;get pseudorandom bit again, use as offset
|
|
lda Bubble_YMF_Dummy,x
|
|
sec ;subtract pseudorandom amount from dummy variable
|
|
sbc Bubble_MForceData,y
|
|
sta Bubble_YMF_Dummy,x ;save dummy variable
|
|
lda Bubble_Y_Position,x
|
|
sbc #$00 ;subtract borrow from airbubble's vertical coordinate
|
|
cmp #$20 ;if below the status bar,
|
|
bcs Y_Bubl ;branch to go ahead and use to move air bubble upwards
|
|
lda #$f8 ;otherwise set offscreen coordinate
|
|
Y_Bubl sta Bubble_Y_Position,x ;store as new vertical coordinate for air bubble
|
|
ExitBubl rts ;leave
|
|
|
|
Bubble_MForceData
|
|
db $ff,$50
|
|
|
|
BubbleTimerData
|
|
db $40,$20
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
RunGameTimer
|
|
lda OperMode ;get primary mode of operation
|
|
beq ExGTimer ;branch to leave if in title screen mode
|
|
lda GameEngineSubroutine
|
|
cmp #$08 ;if routine number less than eight running,
|
|
bcc ExGTimer ;branch to leave
|
|
cmp #$0b ;if running death routine,
|
|
beq ExGTimer ;branch to leave
|
|
lda Player_Y_HighPos
|
|
cmp #$02 ;if player below the screen,
|
|
bcs ExGTimer ;branch to leave regardless of level type
|
|
lda GameTimerCtrlTimer ;if game timer control not yet expired,
|
|
bne ExGTimer ;branch to leave
|
|
lda GameTimerDisplay
|
|
ora GameTimerDisplay+1 ;otherwise check game timer digits
|
|
ora GameTimerDisplay+2
|
|
beq TimeUpOn ;if game timer digits at 000, branch to time-up code
|
|
ldy GameTimerDisplay ;otherwise check first digit
|
|
dey ;if first digit not on 1,
|
|
bne ResGTCtrl ;branch to reset game timer control
|
|
lda GameTimerDisplay+1 ;otherwise check second and third digits
|
|
ora GameTimerDisplay+2
|
|
bne ResGTCtrl ;if timer not at 100, branch to reset game timer control
|
|
lda #TimeRunningOutMusic
|
|
sta EventMusicQueue ;otherwise load time running out music
|
|
ResGTCtrl lda #$18 ;reset game timer control
|
|
sta GameTimerCtrlTimer
|
|
ldy #$23 ;set offset for last digit
|
|
lda #$ff ;set value to decrement game timer digit
|
|
sta DigitModifier+5
|
|
jsr DigitsMathRoutine ;do sub to decrement game timer slowly
|
|
lda #$a4 ;set status nybbles to update game timer display
|
|
jmp PrintStatusBarNumbers ;do sub to update the display
|
|
TimeUpOn sta PlayerStatus ;init player status (note A will always be zero here)
|
|
jsr ForceInjury ;do sub to kill the player (note player is small here)
|
|
inc GameTimerExpiredFlag ;set game timer expiration flag
|
|
ExGTimer rts ;leave
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
WarpZoneObject
|
|
lda ScrollLock ;check for scroll lock flag
|
|
beq ExGTimer ;branch if not set to leave
|
|
lda Player_Y_Position ;check to see if player's vertical coordinate has
|
|
and Player_Y_HighPos ;same bits set as in vertical high byte (why?)
|
|
bne ExGTimer ;if so, branch to leave
|
|
sta ScrollLock ;otherwise nullify scroll lock flag
|
|
inc WarpZoneControl ;increment warp zone flag to make warp pipes for warp zone
|
|
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
|
|
lda AreaType ;check for water type level
|
|
bne ExitWh ;branch to leave if not found
|
|
sta Whirlpool_Flag ;otherwise initialize whirlpool flag
|
|
lda TimerControl ;if master timer control set,
|
|
bne ExitWh ;branch to leave
|
|
ldy #$04 ;otherwise start with last whirlpool data
|
|
WhLoop lda Whirlpool_LeftExtent,y ;get left extent of whirlpool
|
|
clc
|
|
adc Whirlpool_Length,y ;add length of whirlpool
|
|
sta $02 ;store result as right extent here
|
|
lda Whirlpool_PageLoc,y ;get page location
|
|
beq NextWh ;if none or page 0, branch to get next data
|
|
adc #$00 ;add carry
|
|
sta $01 ;store result as page location of right extent here
|
|
lda Player_X_Position ;get player's horizontal position
|
|
sec
|
|
sbc Whirlpool_LeftExtent,y ;subtract left extent
|
|
lda Player_PageLoc ;get player's page location
|
|
sbc Whirlpool_PageLoc,y ;subtract borrow
|
|
bmi NextWh ;if player too far left, branch to get next data
|
|
lda $02 ;otherwise get right extent
|
|
sec
|
|
sbc Player_X_Position ;subtract player's horizontal coordinate
|
|
lda $01 ;get right extent's page location
|
|
sbc Player_PageLoc ;subtract borrow
|
|
bpl WhirlpoolActivate ;if player within right extent, branch to whirlpool code
|
|
NextWh dey ;move onto next whirlpool data
|
|
bpl WhLoop ;do this until all whirlpools are checked
|
|
ExitWh rts ;leave
|
|
|
|
WhirlpoolActivate
|
|
lda Whirlpool_Length,y ;get length of whirlpool
|
|
lsr ;divide by 2
|
|
sta $00 ;save here
|
|
lda Whirlpool_LeftExtent,y ;get left extent of whirlpool
|
|
clc
|
|
adc $00 ;add length divided by 2
|
|
sta $01 ;save as center of whirlpool
|
|
lda Whirlpool_PageLoc,y ;get page location
|
|
adc #$00 ;add carry
|
|
sta $00 ;save as page location of whirlpool center
|
|
lda FrameCounter ;get frame counter
|
|
lsr ;shift d0 into carry (to run on every other frame)
|
|
bcc WhPull ;if d0 not set, branch to last part of code
|
|
lda $01 ;get center
|
|
sec
|
|
sbc Player_X_Position ;subtract player's horizontal coordinate
|
|
lda $00 ;get page location of center
|
|
sbc Player_PageLoc ;subtract borrow
|
|
bpl LeftWh ;if player to the left of center, branch
|
|
lda Player_X_Position ;otherwise slowly pull player left, towards the center
|
|
sec
|
|
sbc #$01 ;subtract one pixel
|
|
sta Player_X_Position ;set player's new horizontal coordinate
|
|
lda Player_PageLoc
|
|
sbc #$00 ;subtract borrow
|
|
jmp SetPWh ;jump to set player's new page location
|
|
LeftWh lda Player_CollisionBits ;get player's collision bits
|
|
lsr ;shift d0 into carry
|
|
bcc WhPull ;if d0 not set, branch
|
|
lda Player_X_Position ;otherwise slowly pull player right, towards the center
|
|
clc
|
|
adc #$01 ;add one pixel
|
|
sta Player_X_Position ;set player's new horizontal coordinate
|
|
lda Player_PageLoc
|
|
adc #$00 ;add carry
|
|
SetPWh sta Player_PageLoc ;set player's new page location
|
|
WhPull lda #$10
|
|
sta $00 ;set vertical movement force
|
|
lda #$01
|
|
sta Whirlpool_Flag ;set whirlpool flag to be used later
|
|
sta $02 ;also set maximum vertical speed
|
|
lsr
|
|
tax ;set X for player offset
|
|
jmp ImposeGravity ;jump to put whirlpool effect on player vertically, do not return
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
FlagpoleScoreMods
|
|
db $05,$02,$08,$04,$01
|
|
|
|
FlagpoleScoreDigits
|
|
db $03,$03,$04,$04,$04
|
|
|
|
FlagpoleRoutine
|
|
ldx #$05 ;set enemy object offset
|
|
stx ObjectOffset ;to special use slot
|
|
lda Enemy_ID,x
|
|
cmp #FlagpoleFlagObject ;if flagpole flag not found,
|
|
bne ExitFlagP ;branch to leave
|
|
lda GameEngineSubroutine
|
|
cmp #$04 ;if flagpole slide routine not running,
|
|
bne SkipScore ;branch to near the end of code
|
|
lda Player_State
|
|
cmp #$03 ;if player state not climbing,
|
|
bne SkipScore ;branch to near the end of code
|
|
lda Enemy_Y_Position,x ;check flagpole flag's vertical coordinate
|
|
cmp #$aa ;if flagpole flag down to a certain point,
|
|
bcs GiveFPScr ;branch to end the level
|
|
lda Player_Y_Position ;check player's vertical coordinate
|
|
cmp #$a2 ;if player down to a certain point,
|
|
bcs GiveFPScr ;branch to end the level
|
|
lda Enemy_YMF_Dummy,x
|
|
adc #$ff ;add movement amount to dummy variable
|
|
sta Enemy_YMF_Dummy,x ;save dummy variable
|
|
lda Enemy_Y_Position,x ;get flag's vertical coordinate
|
|
adc #$01 ;add 1 plus carry to move flag, and
|
|
sta Enemy_Y_Position,x ;store vertical coordinate
|
|
lda FlagpoleFNum_YMFDummy
|
|
sec ;subtract movement amount from dummy variable
|
|
sbc #$ff
|
|
sta FlagpoleFNum_YMFDummy ;save dummy variable
|
|
lda FlagpoleFNum_Y_Pos
|
|
sbc #$01 ;subtract one plus borrow to move floatey number,
|
|
sta FlagpoleFNum_Y_Pos ;and store vertical coordinate here
|
|
SkipScore jmp FPGfx ;jump to skip ahead and draw flag and floatey number
|
|
GiveFPScr ldy FlagpoleScore ;get score offset from earlier (when player touched flagpole)
|
|
lda FlagpoleScoreMods,y ;get amount to award player points
|
|
ldx FlagpoleScoreDigits,y ;get digit with which to award points
|
|
sta DigitModifier,x ;store in digit modifier
|
|
jsr AddToScore ;do sub to award player points depending on height of collision
|
|
lda #$05
|
|
sta GameEngineSubroutine ;set to run end-of-level subroutine on next frame
|
|
FPGfx jsr GetEnemyOffscreenBits ;get offscreen information
|
|
jsr RelativeEnemyPosition ;get relative coordinates
|
|
jsr FlagpoleGfxHandler ;draw flagpole flag and floatey number
|
|
ExitFlagP rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
Jumpspring_Y_PosData
|
|
db $08,$10,$08,$00
|
|
|
|
JumpspringHandler
|
|
jsr GetEnemyOffscreenBits ;get offscreen information
|
|
lda TimerControl ;check master timer control
|
|
bne DrawJSpr ;branch to last section if set
|
|
lda JumpspringAnimCtrl ;check jumpspring frame control
|
|
beq DrawJSpr ;branch to last section if not set
|
|
tay
|
|
dey ;subtract one from frame control,
|
|
tya ;the only way a poor nmos 6502 can
|
|
and #%00000010 ;mask out all but d1, original value still in Y
|
|
bne DownJSpr ;if set, branch to move player up
|
|
inc Player_Y_Position
|
|
inc Player_Y_Position ;move player's vertical position down two pixels
|
|
jmp PosJSpr ;skip to next part
|
|
DownJSpr dec Player_Y_Position ;move player's vertical position up two pixels
|
|
dec Player_Y_Position
|
|
PosJSpr lda Jumpspring_FixedYPos,x ;get permanent vertical position
|
|
clc
|
|
adc Jumpspring_Y_PosData,y ;add value using frame control as offset
|
|
sta Enemy_Y_Position,x ;store as new vertical position
|
|
cpy #$01 ;check frame control offset (second frame is $00)
|
|
bcc BounceJS ;if offset not yet at third frame ($01), skip to next part
|
|
lda A_B_Buttons
|
|
and #A_Button ;check saved controller bits for A button press
|
|
beq BounceJS ;skip to next part if A not pressed
|
|
and PreviousA_B_Buttons ;check for A button pressed in previous frame
|
|
bne BounceJS ;skip to next part if so
|
|
lda #$f4
|
|
sta JumpspringForce ;otherwise write new jumpspring force here
|
|
BounceJS cpy #$03 ;check frame control offset again
|
|
bne DrawJSpr ;skip to last part if not yet at fifth frame ($03)
|
|
lda JumpspringForce
|
|
sta Player_Y_Speed ;store jumpspring force as player's new vertical speed
|
|
lda #$00
|
|
sta JumpspringAnimCtrl ;initialize jumpspring frame control
|
|
DrawJSpr jsr RelativeEnemyPosition ;get jumpspring's relative coordinates
|
|
jsr EnemyGfxHandler ;draw jumpspring
|
|
jsr OffscreenBoundsCheck ;check to see if we need to kill it
|
|
lda JumpspringAnimCtrl ;if frame control at zero, don't bother
|
|
beq ExJSpring ;trying to animate it, just leave
|
|
lda JumpspringTimer
|
|
bne ExJSpring ;if jumpspring timer not expired yet, leave
|
|
lda #$04
|
|
sta JumpspringTimer ;otherwise initialize jumpspring timer
|
|
inc JumpspringAnimCtrl ;increment frame control to animate jumpspring
|
|
ExJSpring rts ;leave
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
Setup_Vine
|
|
lda #VineObject ;load identifier for vine object
|
|
sta Enemy_ID,x ;store in buffer
|
|
lda #$01
|
|
sta Enemy_Flag,x ;set flag for enemy object buffer
|
|
lda Block_PageLoc,y
|
|
sta Enemy_PageLoc,x ;copy page location from previous object
|
|
lda Block_X_Position,y
|
|
sta Enemy_X_Position,x ;copy horizontal coordinate from previous object
|
|
lda Block_Y_Position,y
|
|
sta Enemy_Y_Position,x ;copy vertical coordinate from previous object
|
|
ldy VineFlagOffset ;load vine flag/offset to next available vine slot
|
|
bne NextVO ;if set at all, don't bother to store vertical
|
|
sta VineStart_Y_Position ;otherwise store vertical coordinate here
|
|
NextVO txa ;store object offset to next available vine slot
|
|
sta VineObjOffset,y ;using vine flag as offset
|
|
inc VineFlagOffset ;increment vine flag offset
|
|
lda #Sfx_GrowVine
|
|
sta Square2SoundQueue ;load vine grow sound
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$06-$07 - used as address to block buffer data
|
|
;$02 - used as vertical high nybble of block buffer offset
|
|
|
|
VineHeightData
|
|
db $30,$60
|
|
|
|
VineObjectHandler
|
|
cpx #$05 ;check enemy offset for special use slot
|
|
bne ExitVH ;if not in last slot, branch to leave
|
|
ldy VineFlagOffset
|
|
dey ;decrement vine flag in Y, use as offset
|
|
lda VineHeight
|
|
cmp VineHeightData,y ;if vine has reached certain height,
|
|
beq RunVSubs ;branch ahead to skip this part
|
|
lda FrameCounter ;get frame counter
|
|
lsr ;shift d1 into carry
|
|
lsr
|
|
bcc RunVSubs ;if d1 not set (2 frames every 4) skip this part
|
|
lda Enemy_Y_Position+5
|
|
sbc #$01 ;subtract vertical position of vine
|
|
sta Enemy_Y_Position+5 ;one pixel every frame it's time
|
|
inc VineHeight ;increment vine height
|
|
RunVSubs lda VineHeight ;if vine still very small,
|
|
cmp #$08 ;branch to leave
|
|
bcc ExitVH
|
|
jsr RelativeEnemyPosition ;get relative coordinates of vine,
|
|
jsr GetEnemyOffscreenBits ;and any offscreen bits
|
|
ldy #$00 ;initialize offset used in draw vine sub
|
|
VDrawLoop jsr DrawVine ;draw vine
|
|
iny ;increment offset
|
|
cpy VineFlagOffset ;if offset in Y and offset here
|
|
bne VDrawLoop ;do not yet match, loop back to draw more vine
|
|
lda Enemy_OffscreenBits
|
|
and #%00001100 ;mask offscreen bits
|
|
beq WrCMTile ;if none of the saved offscreen bits set, skip ahead
|
|
dey ;otherwise decrement Y to get proper offset again
|
|
KillVine ldx VineObjOffset,y ;get enemy object offset for this vine object
|
|
jsr EraseEnemyObject ;kill this vine object
|
|
dey ;decrement Y
|
|
bpl KillVine ;if any vine objects left, loop back to kill it
|
|
sta VineFlagOffset ;initialize vine flag/offset
|
|
sta VineHeight ;initialize vine height
|
|
WrCMTile lda VineHeight ;check vine height
|
|
cmp #$20 ;if vine small (less than 32 pixels tall)
|
|
bcc ExitVH ;then branch ahead to leave
|
|
ldx #$06 ;set offset in X to last enemy slot
|
|
lda #$01 ;set A to obtain horizontal in $04, but we don't care
|
|
ldy #$1b ;set Y to offset to get block at ($04,$10) of coordinates
|
|
jsr BlockBufferCollision ;do a sub to get block buffer address set, return contents
|
|
ldy $02
|
|
cpy #$d0 ;if vertical high nybble offset beyond extent of
|
|
bcs ExitVH ;current block buffer, branch to leave, do not write
|
|
lda ($06),y ;otherwise check contents of block buffer at
|
|
bne ExitVH ;current offset, if not empty, branch to leave
|
|
lda #$26
|
|
sta ($06),y ;otherwise, write climbing metatile to block buffer
|
|
ExitVH ldx ObjectOffset ;get enemy object offset and leave
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
CannonBitmasks
|
|
db %00001111,%00000111
|
|
|
|
ProcessCannons
|
|
lda AreaType ;get area type
|
|
beq ExCannon ;if water type area, branch to leave
|
|
ldx #$02
|
|
ThreeSChk stx ObjectOffset ;start at third enemy slot
|
|
lda Enemy_Flag,x ;check enemy buffer flag
|
|
bne Chk_BB ;if set, branch to check enemy
|
|
lda PseudoRandomBitReg+1,x ;otherwise get part of LSFR
|
|
ldy SecondaryHardMode ;get secondary hard mode flag, use as offset
|
|
and CannonBitmasks,y ;mask out bits of LSFR as decided by flag
|
|
cmp #$06 ;check to see if lower nybble is above certain value
|
|
bcs Chk_BB ;if so, branch to check enemy
|
|
tay ;transfer masked contents of LSFR to Y as pseudorandom offset
|
|
lda Cannon_PageLoc,y ;get page location
|
|
beq Chk_BB ;if not set or on page 0, branch to check enemy
|
|
lda Cannon_Timer,y ;get cannon timer
|
|
beq FireCannon ;if expired, branch to fire cannon
|
|
sbc #$00 ;otherwise subtract borrow (note carry will always be clear here)
|
|
sta Cannon_Timer,y ;to count timer down
|
|
jmp Chk_BB ;then jump ahead to check enemy
|
|
|
|
FireCannon
|
|
lda TimerControl ;if master timer control set,
|
|
bne Chk_BB ;branch to check enemy
|
|
lda #$0e ;otherwise we start creating one
|
|
sta Cannon_Timer,y ;first, reset cannon timer
|
|
lda Cannon_PageLoc,y ;get page location of cannon
|
|
sta Enemy_PageLoc,x ;save as page location of bullet bill
|
|
lda Cannon_X_Position,y ;get horizontal coordinate of cannon
|
|
sta Enemy_X_Position,x ;save as horizontal coordinate of bullet bill
|
|
lda Cannon_Y_Position,y ;get vertical coordinate of cannon
|
|
sec
|
|
sbc #$08 ;subtract eight pixels (because enemies are 24 pixels tall)
|
|
sta Enemy_Y_Position,x ;save as vertical coordinate of bullet bill
|
|
lda #$01
|
|
sta Enemy_Y_HighPos,x ;set vertical high byte of bullet bill
|
|
sta Enemy_Flag,x ;set buffer flag
|
|
lsr ;shift right once to init A
|
|
sta Enemy_State,x ;then initialize enemy's state
|
|
lda #$09
|
|
sta Enemy_BoundBoxCtrl,x ;set bounding box size control for bullet bill
|
|
lda #BulletBill_CannonVar
|
|
sta Enemy_ID,x ;load identifier for bullet bill (cannon variant)
|
|
jmp Next3Slt ;move onto next slot
|
|
Chk_BB lda Enemy_ID,x ;check enemy identifier for bullet bill (cannon variant)
|
|
cmp #BulletBill_CannonVar
|
|
bne Next3Slt ;if not found, branch to get next slot
|
|
jsr OffscreenBoundsCheck ;otherwise, check to see if it went offscreen
|
|
lda Enemy_Flag,x ;check enemy buffer flag
|
|
beq Next3Slt ;if not set, branch to get next slot
|
|
jsr GetEnemyOffscreenBits ;otherwise, get offscreen information
|
|
jsr BulletBillHandler ;then do sub to handle bullet bill
|
|
Next3Slt dex ;move onto next slot
|
|
bpl ThreeSChk ;do this until first three slots are checked
|
|
ExCannon rts ;then leave
|
|
|
|
;--------------------------------
|
|
|
|
BulletBillXSpdData
|
|
db $18,$e8
|
|
|
|
BulletBillHandler
|
|
lda TimerControl ;if master timer control set,
|
|
bne RunBBSubs ;branch to run subroutines except movement sub
|
|
lda Enemy_State,x
|
|
bne ChkDSte ;if bullet bill's state set, branch to check defeated state
|
|
lda Enemy_OffscreenBits ;otherwise load offscreen bits
|
|
and #%00001100 ;mask out bits
|
|
cmp #%00001100 ;check to see if all bits are set
|
|
beq KillBB ;if so, branch to kill this object
|
|
ldy #$01 ;set to move right by default
|
|
jsr PlayerEnemyDiff ;get horizontal difference between player and bullet bill
|
|
bmi SetupBB ;if enemy to the left of player, branch
|
|
iny ;otherwise increment to move left
|
|
SetupBB sty Enemy_MovingDir,x ;set bullet bill's moving direction
|
|
dey ;decrement to use as offset
|
|
lda BulletBillXSpdData,y ;get horizontal speed based on moving direction
|
|
sta Enemy_X_Speed,x ;and store it
|
|
lda $00 ;get horizontal difference
|
|
adc #$28 ;add 40 pixels
|
|
cmp #$50 ;if less than a certain amount, player is too close
|
|
bcc KillBB ;to cannon either on left or right side, thus branch
|
|
lda #$01
|
|
sta Enemy_State,x ;otherwise set bullet bill's state
|
|
lda #$0a
|
|
sta EnemyFrameTimer,x ;set enemy frame timer
|
|
lda #Sfx_Blast
|
|
sta Square2SoundQueue ;play fireworks/gunfire sound
|
|
ChkDSte lda Enemy_State,x ;check enemy state for d5 set
|
|
and #%00100000
|
|
beq BBFly ;if not set, skip to move horizontally
|
|
jsr MoveD_EnemyVertically ;otherwise do sub to move bullet bill vertically
|
|
BBFly jsr MoveEnemyHorizontally ;do sub to move bullet bill horizontally
|
|
RunBBSubs jsr GetEnemyOffscreenBits ;get offscreen information
|
|
jsr RelativeEnemyPosition ;get relative coordinates
|
|
jsr GetEnemyBoundBox ;get bounding box coordinates
|
|
jsr PlayerEnemyCollision ;handle player to enemy collisions
|
|
jmp EnemyGfxHandler ;draw the bullet bill and leave
|
|
KillBB jsr EraseEnemyObject ;kill bullet bill and leave
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
HammerEnemyOfsData
|
|
db $04,$04,$04,$05,$05,$05
|
|
db $06,$06,$06
|
|
|
|
HammerXSpdData
|
|
db $10,$f0
|
|
|
|
SpawnHammerObj
|
|
lda PseudoRandomBitReg+1 ;get pseudorandom bits from
|
|
and #%00000111 ;second part of LSFR
|
|
bne SetMOfs ;if any bits are set, branch and use as offset
|
|
lda PseudoRandomBitReg+1
|
|
and #%00001000 ;get d3 from same part of LSFR
|
|
SetMOfs tay ;use either d3 or d2-d0 for offset here
|
|
lda Misc_State,y ;if any values loaded in
|
|
bne NoHammer ;$2a-$32 where offset is then leave with carry clear
|
|
ldx HammerEnemyOfsData,y ;get offset of enemy slot to check using Y as offset
|
|
lda Enemy_Flag,x ;check enemy buffer flag at offset
|
|
bne NoHammer ;if buffer flag set, branch to leave with carry clear
|
|
ldx ObjectOffset ;get original enemy object offset
|
|
txa
|
|
sta HammerEnemyOffset,y ;save here
|
|
lda #$90
|
|
sta Misc_State,y ;save hammer's state here
|
|
lda #$07
|
|
sta Misc_BoundBoxCtrl,y ;set something else entirely, here
|
|
sec ;return with carry set
|
|
rts
|
|
NoHammer ldx ObjectOffset ;get original enemy object offset
|
|
clc ;return with carry clear
|
|
rts
|
|
|
|
;--------------------------------
|
|
;$00 - used to set downward force
|
|
;$01 - used to set upward force (residual)
|
|
;$02 - used to set maximum speed
|
|
|
|
ProcHammerObj
|
|
lda TimerControl ;if master timer control set
|
|
bne RunHSubs ;skip all of this code and go to last subs at the end
|
|
lda Misc_State,x ;otherwise get hammer's state
|
|
and #%01111111 ;mask out d7
|
|
ldy HammerEnemyOffset,x ;get enemy object offset that spawned this hammer
|
|
cmp #$02 ;check hammer's state
|
|
beq SetHSpd ;if currently at 2, branch
|
|
bcs SetHPos ;if greater than 2, branch elsewhere
|
|
txa
|
|
clc ;add 13 bytes to use
|
|
adc #$0d ;proper misc object
|
|
tax ;return offset to X
|
|
lda #$10
|
|
sta $00 ;set downward movement force
|
|
lda #$0f
|
|
sta $01 ;set upward movement force (not used)
|
|
lda #$04
|
|
sta $02 ;set maximum vertical speed
|
|
lda #$00 ;set A to impose gravity on hammer
|
|
jsr ImposeGravity ;do sub to impose gravity on hammer and move vertically
|
|
jsr MoveObjectHorizontally ;do sub to move it horizontally
|
|
ldx ObjectOffset ;get original misc object offset
|
|
jmp RunAllH ;branch to essential subroutines
|
|
SetHSpd lda #$fe
|
|
sta Misc_Y_Speed,x ;set hammer's vertical speed
|
|
lda Enemy_State,y ;get enemy object state
|
|
and #%11110111 ;mask out d3
|
|
sta Enemy_State,y ;store new state
|
|
ldx Enemy_MovingDir,y ;get enemy's moving direction
|
|
dex ;decrement to use as offset
|
|
lda HammerXSpdData,x ;get proper speed to use based on moving direction
|
|
ldx ObjectOffset ;reobtain hammer's buffer offset
|
|
sta Misc_X_Speed,x ;set hammer's horizontal speed
|
|
SetHPos dec Misc_State,x ;decrement hammer's state
|
|
lda Enemy_X_Position,y ;get enemy's horizontal position
|
|
clc
|
|
adc #$02 ;set position 2 pixels to the right
|
|
sta Misc_X_Position,x ;store as hammer's horizontal position
|
|
lda Enemy_PageLoc,y ;get enemy's page location
|
|
adc #$00 ;add carry
|
|
sta Misc_PageLoc,x ;store as hammer's page location
|
|
lda Enemy_Y_Position,y ;get enemy's vertical position
|
|
sec
|
|
sbc #$0a ;move position 10 pixels upward
|
|
sta Misc_Y_Position,x ;store as hammer's vertical position
|
|
lda #$01
|
|
sta Misc_Y_HighPos,x ;set hammer's vertical high byte
|
|
bne RunHSubs ;unconditional branch to skip first routine
|
|
RunAllH jsr PlayerHammerCollision ;handle collisions
|
|
RunHSubs jsr GetMiscOffscreenBits ;get offscreen information
|
|
jsr RelativeMiscPosition ;get relative coordinates
|
|
jsr GetMiscBoundBox ;get bounding box coordinates
|
|
jsr DrawHammer ;draw the hammer
|
|
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
|
|
|
|
CoinBlock
|
|
jsr FindEmptyMiscSlot ;set offset for empty or last misc object buffer slot
|
|
lda Block_PageLoc,x ;get page location of block object
|
|
sta Misc_PageLoc,y ;store as page location of misc object
|
|
lda Block_X_Position,x ;get horizontal coordinate of block object
|
|
ora #$05 ;add 5 pixels
|
|
sta Misc_X_Position,y ;store as horizontal coordinate of misc object
|
|
lda Block_Y_Position,x ;get vertical coordinate of block object
|
|
sbc #$10 ;subtract 16 pixels
|
|
sta Misc_Y_Position,y ;store as vertical coordinate of misc object
|
|
jmp JCoinC ;jump to rest of code as applies to this misc object
|
|
|
|
SetupJumpCoin
|
|
jsr FindEmptyMiscSlot ;set offset for empty or last misc object buffer slot
|
|
lda Block_PageLoc2,x ;get page location saved earlier
|
|
sta Misc_PageLoc,y ;and save as page location for misc object
|
|
lda $06 ;get low byte of block buffer offset
|
|
asl
|
|
asl ;multiply by 16 to use lower nybble
|
|
asl
|
|
asl
|
|
ora #$05 ;add five pixels
|
|
sta Misc_X_Position,y ;save as horizontal coordinate for misc object
|
|
lda $02 ;get vertical high nybble offset from earlier
|
|
adc #$20 ;add 32 pixels for the status bar
|
|
sta Misc_Y_Position,y ;store as vertical coordinate
|
|
JCoinC lda #$fb
|
|
sta Misc_Y_Speed,y ;set vertical speed
|
|
lda #$01
|
|
sta Misc_Y_HighPos,y ;set vertical high byte
|
|
sta Misc_State,y ;set state for misc object
|
|
sta Square2SoundQueue ;load coin grab sound
|
|
stx ObjectOffset ;store current control bit as misc object offset
|
|
jsr GiveOneCoin ;update coin tally on the screen and coin amount variable
|
|
inc CoinTallyFor1Ups ;increment coin tally used to activate 1-up block flag
|
|
rts
|
|
|
|
FindEmptyMiscSlot
|
|
ldy #$08 ;start at end of misc objects buffer
|
|
FMiscLoop lda Misc_State,y ;get misc object state
|
|
beq UseMiscS ;branch if none found to use current offset
|
|
dey ;decrement offset
|
|
cpy #$05 ;do this for three slots
|
|
bne FMiscLoop ;do this until all slots are checked
|
|
ldy #$08 ;if no empty slots found, use last slot
|
|
UseMiscS sty JumpCoinMiscOffset ;store offset of misc object buffer here (residual)
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
MiscObjectsCore
|
|
ldx #$08 ;set at end of misc object buffer
|
|
MiscLoop stx ObjectOffset ;store misc object offset here
|
|
lda Misc_State,x ;check misc object state
|
|
beq MiscLoopBack ;branch to check next slot
|
|
asl ;otherwise shift d7 into carry
|
|
bcc ProcJumpCoin ;if d7 not set, jumping coin, thus skip to rest of code here
|
|
jsr ProcHammerObj ;otherwise go to process hammer,
|
|
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
|
|
|
|
ProcJumpCoin
|
|
ldy Misc_State,x ;check misc object state
|
|
dey ;decrement to see if it's set to 1
|
|
beq JCoinRun ;if so, branch to handle jumping coin
|
|
inc Misc_State,x ;otherwise increment state to either start off or as timer
|
|
lda Misc_X_Position,x ;get horizontal coordinate for misc object
|
|
clc ;whether its jumping coin (state 0 only) or floatey number
|
|
adc ScrollAmount ;add current scroll speed
|
|
sta Misc_X_Position,x ;store as new horizontal coordinate
|
|
lda Misc_PageLoc,x ;get page location
|
|
adc #$00 ;add carry
|
|
sta Misc_PageLoc,x ;store as new page location
|
|
lda Misc_State,x
|
|
cmp #$30 ;check state of object for preset value
|
|
bne RunJCSubs ;if not yet reached, branch to subroutines
|
|
lda #$00
|
|
sta Misc_State,x ;otherwise nullify object state
|
|
jmp MiscLoopBack ;and move onto next slot
|
|
JCoinRun txa
|
|
clc ;add 13 bytes to offset for next subroutine
|
|
adc #$0d
|
|
tax
|
|
lda #$50 ;set downward movement amount
|
|
sta $00
|
|
lda #$06 ;set maximum vertical speed
|
|
sta $02
|
|
lsr ;divide by 2 and set
|
|
sta $01 ;as upward movement amount (apparently residual)
|
|
lda #$00 ;set A to impose gravity on jumping coin
|
|
jsr ImposeGravity ;do sub to move coin vertically and impose gravity on it
|
|
ldx ObjectOffset ;get original misc object offset
|
|
lda Misc_Y_Speed,x ;check vertical speed
|
|
cmp #$05
|
|
bne RunJCSubs ;if not moving downward fast enough, keep state as-is
|
|
inc Misc_State,x ;otherwise increment state to change to floatey number
|
|
RunJCSubs jsr RelativeMiscPosition ;get relative coordinates
|
|
jsr GetMiscOffscreenBits ;get offscreen information
|
|
jsr GetMiscBoundBox ;get bounding box coordinates (why?)
|
|
jsr JCoinGfxHandler ;draw the coin or floatey number
|
|
|
|
MiscLoopBack
|
|
dex ;decrement misc object offset
|
|
bpl MiscLoop ;loop back until all misc objects handled
|
|
rts ;then leave
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
CoinTallyOffsets
|
|
db $17,$1d
|
|
|
|
ScoreOffsets
|
|
db $0b,$11
|
|
|
|
StatusBarNybbles
|
|
db $02,$13
|
|
|
|
GiveOneCoin
|
|
lda #$01 ;set digit modifier to add 1 coin
|
|
sta DigitModifier+5 ;to the current player's coin tally
|
|
ldx CurrentPlayer ;get current player on the screen
|
|
ldy CoinTallyOffsets,x ;get offset for player's coin tally
|
|
jsr DigitsMathRoutine ;update the coin tally
|
|
inc CoinTally ;increment onscreen player's coin amount
|
|
lda CoinTally
|
|
cmp #100 ;does player have 100 coins yet?
|
|
bne CoinPoints ;if not, skip all of this
|
|
lda #$00
|
|
sta CoinTally ;otherwise, reinitialize coin amount
|
|
inc NumberofLives ;give the player an extra life
|
|
lda #Sfx_ExtraLife
|
|
sta Square2SoundQueue ;play 1-up sound
|
|
|
|
CoinPoints
|
|
lda #$02 ;set digit modifier to award
|
|
sta DigitModifier+4 ;200 points to the player
|
|
|
|
AddToScore
|
|
ldx CurrentPlayer ;get current player
|
|
ldy ScoreOffsets,x ;get offset for player's score
|
|
jsr DigitsMathRoutine ;update the score internally with value in digit modifier
|
|
|
|
GetSBNybbles
|
|
ldy CurrentPlayer ;get current player
|
|
lda StatusBarNybbles,y ;get nybbles based on player, use to update score and coins
|
|
|
|
UpdateNumber
|
|
jsr PrintStatusBarNumbers ;print status bar numbers based on nybbles, whatever they be
|
|
ldy VRAM_Buffer1_Offset
|
|
lda VRAM_Buffer1-6,y ;check highest digit of score
|
|
bne NoZSup ;if zero, overwrite with space tile for zero suppression
|
|
lda #$24
|
|
sta VRAM_Buffer1-6,y
|
|
NoZSup ldx ObjectOffset ;get enemy object buffer offset
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
SetupPowerUp
|
|
lda #PowerUpObject ;load power-up identifier into
|
|
sta Enemy_ID+5 ;special use slot of enemy object buffer
|
|
lda Block_PageLoc,x ;store page location of block object
|
|
sta Enemy_PageLoc+5 ;as page location of power-up object
|
|
lda Block_X_Position,x ;store horizontal coordinate of block object
|
|
sta Enemy_X_Position+5 ;as horizontal coordinate of power-up object
|
|
lda #$01
|
|
sta Enemy_Y_HighPos+5 ;set vertical high byte of power-up object
|
|
lda Block_Y_Position,x ;get vertical coordinate of block object
|
|
sec
|
|
sbc #$08 ;subtract 8 pixels
|
|
sta Enemy_Y_Position+5 ;and use as vertical coordinate of power-up object
|
|
PwrUpJmp lda #$01 ;this is a residual jump point in enemy object jump table
|
|
sta Enemy_State+5 ;set power-up object's state
|
|
sta Enemy_Flag+5 ;set buffer flag
|
|
lda #$03
|
|
sta Enemy_BoundBoxCtrl+5 ;set bounding box size control for power-up object
|
|
lda PowerUpType
|
|
cmp #$02 ;check currently loaded power-up type
|
|
bcs PutBehind ;if star or 1-up, branch ahead
|
|
lda PlayerStatus ;otherwise check player's current status
|
|
cmp #$02
|
|
bcc StrType ;if player not fiery, use status as power-up type
|
|
lsr ;otherwise shift right to force fire flower type
|
|
StrType sta PowerUpType ;store type here
|
|
PutBehind lda #%00100000
|
|
sta Enemy_SprAttrib+5 ;set background priority bit
|
|
lda #Sfx_GrowPowerUp
|
|
sta Square2SoundQueue ;load power-up reveal sound and leave
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
PowerUpObjHandler
|
|
ldx #$05 ;set object offset for last slot in enemy object buffer
|
|
stx ObjectOffset
|
|
lda Enemy_State+5 ;check power-up object's state
|
|
beq ExitPUp ;if not set, branch to leave
|
|
asl ;shift to check if d7 was set in object state
|
|
bcc GrowThePowerUp ;if not set, branch ahead to skip this part
|
|
lda TimerControl ;if master timer control set,
|
|
bne RunPUSubs ;branch ahead to enemy object routines
|
|
lda PowerUpType ;check power-up type
|
|
beq ShroomM ;if normal mushroom, branch ahead to move it
|
|
cmp #$03
|
|
beq ShroomM ;if 1-up mushroom, branch ahead to move it
|
|
cmp #$02
|
|
bne RunPUSubs ;if not star, branch elsewhere to skip movement
|
|
jsr MoveJumpingEnemy ;otherwise impose gravity on star power-up and make it jump
|
|
jsr EnemyJump ;note that green paratroopa shares the same code here
|
|
jmp RunPUSubs ;then jump to other power-up subroutines
|
|
ShroomM jsr MoveNormalEnemy ;do sub to make mushrooms move
|
|
jsr EnemyToBGCollisionDet ;deal with collisions
|
|
jmp RunPUSubs ;run the other subroutines
|
|
|
|
GrowThePowerUp
|
|
lda FrameCounter ;get frame counter
|
|
and #$03 ;mask out all but 2 LSB
|
|
bne ChkPUSte ;if any bits set here, branch
|
|
dec Enemy_Y_Position+5 ;otherwise decrement vertical coordinate slowly
|
|
lda Enemy_State+5 ;load power-up object state
|
|
inc Enemy_State+5 ;increment state for next frame (to make power-up rise)
|
|
cmp #$11 ;if power-up object state not yet past 16th pixel,
|
|
bcc ChkPUSte ;branch ahead to last part here
|
|
lda #$10
|
|
sta Enemy_X_Speed,x ;otherwise set horizontal speed
|
|
lda #%10000000
|
|
sta Enemy_State+5 ;and then set d7 in power-up object's state
|
|
asl ;shift once to init A
|
|
sta Enemy_SprAttrib+5 ;initialize background priority bit set here
|
|
rol ;rotate A to set right moving direction
|
|
sta Enemy_MovingDir,x ;set moving direction
|
|
ChkPUSte lda Enemy_State+5 ;check power-up object's state
|
|
cmp #$06 ;for if power-up has risen enough
|
|
bcc ExitPUp ;if not, don't even bother running these routines
|
|
RunPUSubs jsr RelativeEnemyPosition ;get coordinates relative to screen
|
|
jsr GetEnemyOffscreenBits ;get offscreen bits
|
|
jsr GetEnemyBoundBox ;get bounding box coordinates
|
|
jsr DrawPowerUp ;draw the power-up object
|
|
jsr PlayerEnemyCollision ;check for collision with player
|
|
jsr OffscreenBoundsCheck ;check to see if it went offscreen
|
|
ExitPUp rts ;and we're done
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;These apply to all routines in this section unless otherwise noted
|
|
;$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
|
|
db $04,$12
|
|
|
|
PlayerHeadCollision
|
|
pha ;store metatile number to stack
|
|
lda #$11 ;load unbreakable block object state by default
|
|
ldx SprDataOffset_Ctrl ;load offset control bit here
|
|
ldy PlayerSize ;check player's size
|
|
bne DBlockSte ;if small, branch
|
|
lda #$12 ;otherwise load breakable block object state
|
|
DBlockSte sta Block_State,x ;store into block object buffer
|
|
jsr DestroyBlockMetatile ;store blank metatile in vram buffer to write to name table
|
|
ldx SprDataOffset_Ctrl ;load offset control bit
|
|
lda $02 ;get vertical high nybble offset used in block buffer routine
|
|
sta Block_Orig_YPos,x ;set as vertical coordinate for block object
|
|
tay
|
|
lda $06 ;get low byte of block buffer address used in same routine
|
|
sta Block_BBuf_Low,x ;save as offset here to be used later
|
|
lda ($06),y ;get contents of block buffer at old address at $06,$07
|
|
jsr BlockBumpedChk ;do a sub to check which block player bumped head on
|
|
sta $00 ;store metatile here
|
|
ldy PlayerSize ;check player's size
|
|
bne ChkBrick ;if small, use metatile itself as contents of A
|
|
tya ;otherwise init A (note big = 0)
|
|
ChkBrick bcc PutMTileB ;if no match was found in previous sub, skip ahead
|
|
ldy #$11 ;otherwise load unbreakable state into block object buffer
|
|
sty Block_State,x ;note this applies to both player sizes
|
|
lda #$c4 ;load empty block metatile into A for now
|
|
ldy $00 ;get metatile from before
|
|
cpy #$58 ;is it brick with coins (with line)?
|
|
beq StartBTmr ;if so, branch
|
|
cpy #$5d ;is it brick with coins (without line)?
|
|
bne PutMTileB ;if not, branch ahead to store empty block metatile
|
|
StartBTmr lda BrickCoinTimerFlag ;check brick coin timer flag
|
|
bne ContBTmr ;if set, timer expired or counting down, thus branch
|
|
lda #$0b
|
|
sta BrickCoinTimer ;if not set, set brick coin timer
|
|
inc BrickCoinTimerFlag ;and set flag linked to it
|
|
ContBTmr lda BrickCoinTimer ;check brick coin timer
|
|
bne PutOldMT ;if not yet expired, branch to use current metatile
|
|
ldy #$c4 ;otherwise use empty block metatile
|
|
PutOldMT tya ;put metatile into A
|
|
PutMTileB sta Block_Metatile,x ;store whatever metatile be appropriate here
|
|
jsr InitBlock_XY_Pos ;get block object horizontal coordinates saved
|
|
ldy $02 ;get vertical high nybble offset
|
|
lda #$23
|
|
sta ($06),y ;write blank metatile $23 to block buffer
|
|
lda #$10
|
|
sta BlockBounceTimer ;set block bounce timer
|
|
pla ;pull original metatile from stack
|
|
sta $05 ;and save here
|
|
ldy #$00 ;set default offset
|
|
lda CrouchingFlag ;is player crouching?
|
|
bne SmallBP ;if so, branch to increment offset
|
|
lda PlayerSize ;is player big?
|
|
beq BigBP ;if so, branch to use default offset
|
|
SmallBP iny ;increment for small or big and crouching
|
|
BigBP lda Player_Y_Position ;get player's vertical coordinate
|
|
clc
|
|
adc BlockYPosAdderData,y ;add value determined by size
|
|
and #$f0 ;mask out low nybble to get 16-pixel correspondence
|
|
sta Block_Y_Position,x ;save as vertical coordinate for block object
|
|
ldy Block_State,x ;get block object state
|
|
cpy #$11
|
|
beq Unbreak ;if set to value loaded for unbreakable, branch
|
|
jsr BrickShatter ;execute code for breakable brick
|
|
jmp InvOBit ;skip subroutine to do last part of code here
|
|
Unbreak jsr BumpBlock ;execute code for unbreakable brick or question block
|
|
InvOBit lda SprDataOffset_Ctrl ;invert control bit used by block objects
|
|
eor #$01 ;and floatey numbers
|
|
sta SprDataOffset_Ctrl
|
|
rts ;leave!
|
|
|
|
;--------------------------------
|
|
|
|
InitBlock_XY_Pos
|
|
lda Player_X_Position ;get player's horizontal coordinate
|
|
clc
|
|
adc #$08 ;add eight pixels
|
|
and #$f0 ;mask out low nybble to give 16-pixel correspondence
|
|
sta Block_X_Position,x ;save as horizontal coordinate for block object
|
|
lda Player_PageLoc
|
|
adc #$00 ;add carry to page location of player
|
|
sta Block_PageLoc,x ;save as page location of block object
|
|
sta Block_PageLoc2,x ;save elsewhere to be used later
|
|
lda Player_Y_HighPos
|
|
sta Block_Y_HighPos,x ;save vertical high byte of player into
|
|
rts ;vertical high byte of block object and leave
|
|
|
|
;--------------------------------
|
|
|
|
BumpBlock
|
|
jsr CheckTopOfBlock ;check to see if there's a coin directly above this block
|
|
lda #Sfx_Bump
|
|
sta Square1SoundQueue ;play bump sound
|
|
lda #$00
|
|
sta Block_X_Speed,x ;initialize horizontal speed for block object
|
|
sta Block_Y_MoveForce,x ;init fractional movement force
|
|
sta Player_Y_Speed ;init player's vertical speed
|
|
lda #$fe
|
|
sta Block_Y_Speed,x ;set vertical speed for block object
|
|
lda $05 ;get original metatile from stack
|
|
jsr BlockBumpedChk ;do a sub to check which block player bumped head on
|
|
bcc ExitBlockChk ;if no match was found, branch to leave
|
|
tya ;move block number to A
|
|
cmp #$09 ;if block number was within 0-8 range,
|
|
bcc BlockCode ;branch to use current number
|
|
sbc #$05 ;otherwise subtract 5 for second set to get proper number
|
|
BlockCode jsr JumpEngine ;run appropriate subroutine depending on block number
|
|
|
|
dw MushFlowerBlock
|
|
dw CoinBlock
|
|
dw CoinBlock
|
|
dw ExtraLifeMushBlock
|
|
dw MushFlowerBlock
|
|
dw VineBlock
|
|
dw StarBlock
|
|
dw CoinBlock
|
|
dw ExtraLifeMushBlock
|
|
|
|
;--------------------------------
|
|
|
|
MushFlowerBlock
|
|
lda #$00 ;load mushroom/fire flower into power-up type
|
|
db $2c ;BIT instruction opcode
|
|
|
|
StarBlock
|
|
lda #$02 ;load star into power-up type
|
|
db $2c ;BIT instruction opcode
|
|
|
|
ExtraLifeMushBlock
|
|
lda #$03 ;load 1-up mushroom into power-up type
|
|
sta $39 ;store correct power-up type
|
|
jmp SetupPowerUp
|
|
|
|
VineBlock
|
|
ldx #$05 ;load last slot for enemy object buffer
|
|
ldy SprDataOffset_Ctrl ;get control bit
|
|
jsr Setup_Vine ;set up vine object
|
|
|
|
ExitBlockChk
|
|
rts ;leave
|
|
|
|
;--------------------------------
|
|
|
|
BrickQBlockMetatiles
|
|
db $c1,$c0,$5f,$60 ;used by question blocks
|
|
|
|
;these two sets are functionally identical, but look different
|
|
db $55,$56,$57,$58,$59 ;used by ground level types
|
|
db $5a,$5b,$5c,$5d,$5e ;used by other level types
|
|
|
|
BlockBumpedChk
|
|
ldy #$0d ;start at end of metatile data
|
|
BumpChkLoop cmp BrickQBlockMetatiles,y ;check to see if current metatile matches
|
|
beq MatchBump ;metatile found in block buffer, branch if so
|
|
dey ;otherwise move onto next metatile
|
|
bpl BumpChkLoop ;do this until all metatiles are checked
|
|
clc ;if none match, return with carry clear
|
|
MatchBump rts ;note carry is set if found match
|
|
|
|
;--------------------------------
|
|
|
|
BrickShatter
|
|
jsr CheckTopOfBlock ;check to see if there's a coin directly above this block
|
|
lda #Sfx_BrickShatter
|
|
sta Block_RepFlag,x ;set flag for block object to immediately replace metatile
|
|
sta NoiseSoundQueue ;load brick shatter sound
|
|
jsr SpawnBrickChunks ;create brick chunk objects
|
|
lda #$fe
|
|
sta Player_Y_Speed ;set vertical speed for player
|
|
lda #$05
|
|
sta DigitModifier+5 ;set digit modifier to give player 50 points
|
|
jsr AddToScore ;do sub to update the score
|
|
ldx SprDataOffset_Ctrl ;load control bit and leave
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
CheckTopOfBlock
|
|
ldx SprDataOffset_Ctrl ;load control bit
|
|
ldy $02 ;get vertical high nybble offset used in block buffer
|
|
beq TopEx ;branch to leave if set to zero, because we're at the top
|
|
tya ;otherwise set to A
|
|
sec
|
|
sbc #$10 ;subtract $10 to move up one row in the block buffer
|
|
sta $02 ;store as new vertical high nybble offset
|
|
tay
|
|
lda ($06),y ;get contents of block buffer in same column, one row up
|
|
cmp #$c2 ;is it a coin? (not underwater)
|
|
bne TopEx ;if not, branch to leave
|
|
lda #$00
|
|
sta ($06),y ;otherwise put blank metatile where coin was
|
|
jsr RemoveCoin_Axe ;write blank metatile to vram buffer
|
|
ldx SprDataOffset_Ctrl ;get control bit
|
|
jsr SetupJumpCoin ;create jumping coin object and update coin variables
|
|
TopEx rts ;leave!
|
|
|
|
;--------------------------------
|
|
|
|
SpawnBrickChunks
|
|
lda Block_X_Position,x ;set horizontal coordinate of block object
|
|
sta Block_Orig_XPos,x ;as original horizontal coordinate here
|
|
lda #$f0
|
|
sta Block_X_Speed,x ;set horizontal speed for brick chunk objects
|
|
sta Block_X_Speed+2,x
|
|
lda #$fa
|
|
sta Block_Y_Speed,x ;set vertical speed for one
|
|
lda #$fc
|
|
sta Block_Y_Speed+2,x ;set lower vertical speed for the other
|
|
lda #$00
|
|
sta Block_Y_MoveForce,x ;init fractional movement force for both
|
|
sta Block_Y_MoveForce+2,x
|
|
lda Block_PageLoc,x
|
|
sta Block_PageLoc+2,x ;copy page location
|
|
lda Block_X_Position,x
|
|
sta Block_X_Position+2,x ;copy horizontal coordinate
|
|
lda Block_Y_Position,x
|
|
clc ;add 8 pixels to vertical coordinate
|
|
adc #$08 ;and save as vertical coordinate for one of them
|
|
sta Block_Y_Position+2,x
|
|
lda #$fa
|
|
sta Block_Y_Speed,x ;set vertical speed...again??? (redundant)
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
BlockObjectsCore
|
|
lda Block_State,x ;get state of block object
|
|
beq UpdSte ;if not set, branch to leave
|
|
and #$0f ;mask out high nybble
|
|
pha ;push to stack
|
|
tay ;put in Y for now
|
|
txa
|
|
clc
|
|
adc #$09 ;add 9 bytes to offset (note two block objects are created
|
|
tax ;when using brick chunks, but only one offset for both)
|
|
dey ;decrement Y to check for solid block state
|
|
beq BouncingBlockHandler ;branch if found, otherwise continue for brick chunks
|
|
jsr ImposeGravityBlock ;do sub to impose gravity on one block object object
|
|
jsr MoveObjectHorizontally ;do another sub to move horizontally
|
|
txa
|
|
clc ;move onto next block object
|
|
adc #$02
|
|
tax
|
|
jsr ImposeGravityBlock ;do sub to impose gravity on other block object
|
|
jsr MoveObjectHorizontally ;do another sub to move horizontally
|
|
ldx ObjectOffset ;get block object offset used for both
|
|
jsr RelativeBlockPosition ;get relative coordinates
|
|
jsr GetBlockOffscreenBits ;get offscreen information
|
|
jsr DrawBrickChunks ;draw the brick chunks
|
|
pla ;get lower nybble of saved state
|
|
ldy Block_Y_HighPos,x ;check vertical high byte of block object
|
|
beq UpdSte ;if above the screen, branch to kill it
|
|
pha ;otherwise save state back into stack
|
|
lda #$f0
|
|
cmp Block_Y_Position+2,x ;check to see if bottom block object went
|
|
bcs ChkTop ;to the bottom of the screen, and branch if not
|
|
sta Block_Y_Position+2,x ;otherwise set offscreen coordinate
|
|
ChkTop lda Block_Y_Position,x ;get top block object's vertical coordinate
|
|
cmp #$f0 ;see if it went to the bottom of the screen
|
|
pla ;pull block object state from stack
|
|
bcc UpdSte ;if not, branch to save state
|
|
bcs KillBlock ;otherwise do unconditional branch to kill it
|
|
|
|
BouncingBlockHandler
|
|
jsr ImposeGravityBlock ;do sub to impose gravity on block object
|
|
ldx ObjectOffset ;get block object offset
|
|
jsr RelativeBlockPosition ;get relative coordinates
|
|
jsr GetBlockOffscreenBits ;get offscreen information
|
|
jsr DrawBlock ;draw the block
|
|
lda Block_Y_Position,x ;get vertical coordinate
|
|
and #$0f ;mask out high nybble
|
|
cmp #$05 ;check to see if low nybble wrapped around
|
|
pla ;pull state from stack
|
|
bcs UpdSte ;if still above amount, not time to kill block yet, thus branch
|
|
lda #$01
|
|
sta Block_RepFlag,x ;otherwise set flag to replace metatile
|
|
KillBlock lda #$00 ;if branched here, nullify object state
|
|
UpdSte sta Block_State,x ;store contents of A in block object state
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$02 - used to store offset to block buffer
|
|
;$06-$07 - used to store block buffer address
|
|
|
|
BlockObjMT_Updater
|
|
ldx #$01 ;set offset to start with second block object
|
|
UpdateLoop stx ObjectOffset ;set offset here
|
|
lda VRAM_Buffer1 ;if vram buffer already being used here,
|
|
bne NextBUpd ;branch to move onto next block object
|
|
lda Block_RepFlag,x ;if flag for block object already clear,
|
|
beq NextBUpd ;branch to move onto next block object
|
|
lda Block_BBuf_Low,x ;get low byte of block buffer
|
|
sta $06 ;store into block buffer address
|
|
lda #$05
|
|
sta $07 ;set high byte of block buffer address
|
|
lda Block_Orig_YPos,x ;get original vertical coordinate of block object
|
|
sta $02 ;store here and use as offset to block buffer
|
|
tay
|
|
lda Block_Metatile,x ;get metatile to be written
|
|
sta ($06),y ;write it to the block buffer
|
|
jsr ReplaceBlockMetatile ;do sub to replace metatile where block object is
|
|
lda #$00
|
|
sta Block_RepFlag,x ;clear block object flag
|
|
NextBUpd dex ;decrement block object offset
|
|
bpl UpdateLoop ;do this until both block objects are dealt with
|
|
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
|
|
inx ;increment offset for enemy offset
|
|
jsr MoveObjectHorizontally ;position object horizontally according to
|
|
ldx ObjectOffset ;counters, return with saved value in A,
|
|
rts ;put enemy offset back in X and leave
|
|
|
|
MovePlayerHorizontally
|
|
lda JumpspringAnimCtrl ;if jumpspring currently animating,
|
|
bne ExXMove ;branch to leave
|
|
tax ;otherwise set zero for offset to use player's stuff
|
|
|
|
MoveObjectHorizontally
|
|
lda SprObject_X_Speed,x ;get currently saved value (horizontal
|
|
asl ;speed, secondary counter, whatever)
|
|
asl ;and move low nybble to high
|
|
asl
|
|
asl
|
|
sta $01 ;store result here
|
|
lda SprObject_X_Speed,x ;get saved value again
|
|
lsr ;move high nybble to low
|
|
lsr
|
|
lsr
|
|
lsr
|
|
cmp #$08 ;if < 8, branch, do not change
|
|
bcc SaveXSpd
|
|
ora #%11110000 ;otherwise alter high nybble
|
|
SaveXSpd sta $00 ;save result here
|
|
ldy #$00 ;load default Y value here
|
|
cmp #$00 ;if result positive, leave Y alone
|
|
bpl UseAdder
|
|
dey ;otherwise decrement Y
|
|
UseAdder sty $02 ;save Y here
|
|
lda SprObject_X_MoveForce,x ;get whatever number's here
|
|
clc
|
|
adc $01 ;add low nybble moved to high
|
|
sta SprObject_X_MoveForce,x ;store result here
|
|
lda #$00 ;init A
|
|
rol ;rotate carry into d0
|
|
pha ;push onto stack
|
|
ror ;rotate d0 back onto carry
|
|
lda SprObject_X_Position,x
|
|
adc $00 ;add carry plus saved value (high nybble moved to low
|
|
sta SprObject_X_Position,x ;plus $f0 if necessary) to object's horizontal position
|
|
lda SprObject_PageLoc,x
|
|
adc $02 ;add carry plus other saved value to the
|
|
sta SprObject_PageLoc,x ;object's page location and save
|
|
pla
|
|
clc ;pull old carry from stack and add
|
|
adc $00 ;to high nybble moved to low
|
|
ExXMove rts ;and leave
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$00 - used for downward force
|
|
;$01 - used for upward force
|
|
;$02 - used for maximum vertical speed
|
|
|
|
MovePlayerVertically
|
|
ldx #$00 ;set X for player offset
|
|
lda TimerControl
|
|
bne NoJSChk ;if master timer control set, branch ahead
|
|
lda JumpspringAnimCtrl ;otherwise check to see if jumpspring is animating
|
|
bne ExXMove ;branch to leave if so
|
|
NoJSChk lda VerticalForce ;dump vertical force
|
|
sta $00
|
|
lda #$04 ;set maximum vertical speed here
|
|
jmp ImposeGravitySprObj ;then jump to move player vertically
|
|
|
|
;--------------------------------
|
|
|
|
MoveD_EnemyVertically
|
|
ldy #$3d ;set quick movement amount downwards
|
|
lda Enemy_State,x ;then check enemy state
|
|
cmp #$05 ;if not set to unique state for spiny's egg, go ahead
|
|
bne ContVMove ;and use, otherwise set different movement amount, continue on
|
|
|
|
MoveFallingPlatform
|
|
ldy #$20 ;set movement amount
|
|
ContVMove jmp SetHiMax ;jump to skip the rest of this
|
|
|
|
;--------------------------------
|
|
|
|
MoveRedPTroopaDown
|
|
ldy #$00 ;set Y to move downwards
|
|
jmp MoveRedPTroopa ;skip to movement routine
|
|
|
|
MoveRedPTroopaUp
|
|
ldy #$01 ;set Y to move upwards
|
|
|
|
MoveRedPTroopa
|
|
inx ;increment X for enemy offset
|
|
lda #$03
|
|
sta $00 ;set downward movement amount here
|
|
lda #$06
|
|
sta $01 ;set upward movement amount here
|
|
lda #$02
|
|
sta $02 ;set maximum speed here
|
|
tya ;set movement direction in A, and
|
|
jmp RedPTroopaGrav ;jump to move this thing
|
|
|
|
;--------------------------------
|
|
|
|
MoveDropPlatform
|
|
ldy #$7f ;set movement amount for drop platform
|
|
bne SetMdMax ;skip ahead of other value set here
|
|
|
|
MoveEnemySlowVert
|
|
ldy #$0f ;set movement amount for bowser/other objects
|
|
SetMdMax lda #$02 ;set maximum speed in A
|
|
bne SetXMoveAmt ;unconditional branch
|
|
|
|
;--------------------------------
|
|
|
|
MoveJ_EnemyVertically
|
|
ldy #$1c ;set movement amount for podoboo/other objects
|
|
SetHiMax lda #$03 ;set maximum speed in A
|
|
SetXMoveAmt sty $00 ;set movement amount here
|
|
inx ;increment X for enemy offset
|
|
jsr ImposeGravitySprObj ;do a sub to move enemy object downwards
|
|
ldx ObjectOffset ;get enemy object buffer offset and leave
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
MaxSpdBlockData
|
|
db $06,$08
|
|
|
|
ResidualGravityCode
|
|
ldy #$00 ;this part appears to be residual,
|
|
db $2c ;no code branches or jumps to it...
|
|
|
|
ImposeGravityBlock
|
|
ldy #$01 ;set offset for maximum speed
|
|
lda #$50 ;set movement amount here
|
|
sta $00
|
|
lda MaxSpdBlockData,y ;get maximum speed
|
|
|
|
ImposeGravitySprObj
|
|
sta $02 ;set maximum speed here
|
|
lda #$00 ;set value to move downwards
|
|
jmp ImposeGravity ;jump to the code that actually moves it
|
|
|
|
;--------------------------------
|
|
|
|
MovePlatformDown
|
|
lda #$00 ;save value to stack (if branching here, execute next
|
|
db $2c ;part as BIT instruction)
|
|
|
|
MovePlatformUp
|
|
lda #$01 ;save value to stack
|
|
pha
|
|
ldy Enemy_ID,x ;get enemy object identifier
|
|
inx ;increment offset for enemy object
|
|
lda #$05 ;load default value here
|
|
cpy #$29 ;residual comparison, object #29 never executes
|
|
bne SetDplSpd ;this code, thus unconditional branch here
|
|
lda #$09 ;residual code
|
|
SetDplSpd sta $00 ;save downward movement amount here
|
|
lda #$0a ;save upward movement amount here
|
|
sta $01
|
|
lda #$03 ;save maximum vertical speed here
|
|
sta $02
|
|
pla ;get value from stack
|
|
tay ;use as Y, then move onto code shared by red koopa
|
|
|
|
RedPTroopaGrav
|
|
jsr ImposeGravity ;do a sub to move object gradually
|
|
ldx ObjectOffset ;get enemy object offset and leave
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$00 - used for downward force
|
|
;$01 - used for upward force
|
|
;$07 - used as adder for vertical position
|
|
|
|
ImposeGravity
|
|
pha ;push value to stack
|
|
lda SprObject_YMF_Dummy,x
|
|
clc ;add value in movement force to contents of dummy variable
|
|
adc SprObject_Y_MoveForce,x
|
|
sta SprObject_YMF_Dummy,x
|
|
ldy #$00 ;set Y to zero by default
|
|
lda SprObject_Y_Speed,x ;get current vertical speed
|
|
bpl AlterYP ;if currently moving downwards, do not decrement Y
|
|
dey ;otherwise decrement Y
|
|
AlterYP sty $07 ;store Y here
|
|
adc SprObject_Y_Position,x ;add vertical position to vertical speed plus carry
|
|
sta SprObject_Y_Position,x ;store as new vertical position
|
|
lda SprObject_Y_HighPos,x
|
|
adc $07 ;add carry plus contents of $07 to vertical high byte
|
|
sta SprObject_Y_HighPos,x ;store as new vertical high byte
|
|
lda SprObject_Y_MoveForce,x
|
|
clc
|
|
adc $00 ;add downward movement amount to contents of $0433
|
|
sta SprObject_Y_MoveForce,x
|
|
lda SprObject_Y_Speed,x ;add carry to vertical speed and store
|
|
adc #$00
|
|
sta SprObject_Y_Speed,x
|
|
cmp $02 ;compare to maximum speed
|
|
bmi ChkUpM ;if less than preset value, skip this part
|
|
lda SprObject_Y_MoveForce,x
|
|
cmp #$80 ;if less positively than preset maximum, skip this part
|
|
bcc ChkUpM
|
|
lda $02
|
|
sta SprObject_Y_Speed,x ;keep vertical speed within maximum value
|
|
lda #$00
|
|
sta SprObject_Y_MoveForce,x ;clear fractional
|
|
ChkUpM pla ;get value from stack
|
|
beq ExVMove ;if set to zero, branch to leave
|
|
lda $02
|
|
eor #%11111111 ;otherwise get two's compliment of maximum speed
|
|
tay
|
|
iny
|
|
sty $07 ;store two's compliment here
|
|
lda SprObject_Y_MoveForce,x
|
|
sec ;subtract upward movement amount from contents
|
|
sbc $01 ;of movement force, note that $01 is twice as large as $00,
|
|
sta SprObject_Y_MoveForce,x ;thus it effectively undoes add we did earlier
|
|
lda SprObject_Y_Speed,x
|
|
sbc #$00 ;subtract borrow from vertical speed and store
|
|
sta SprObject_Y_Speed,x
|
|
cmp $07 ;compare vertical speed to two's compliment
|
|
bpl ExVMove ;if less negatively than preset maximum, skip this part
|
|
lda SprObject_Y_MoveForce,x
|
|
cmp #$80 ;check if fractional part is above certain amount,
|
|
bcs ExVMove ;and if so, branch to leave
|
|
lda $07
|
|
sta SprObject_Y_Speed,x ;keep vertical speed within maximum value
|
|
lda #$ff
|
|
sta SprObject_Y_MoveForce,x ;clear fractional
|
|
ExVMove rts ;leave!
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
EnemiesAndLoopsCore
|
|
lda Enemy_Flag,x ;check data here for MSB set
|
|
pha ;save in stack
|
|
asl
|
|
bcs ChkBowserF ;if MSB set in enemy flag, branch ahead of jumps
|
|
pla ;get from stack
|
|
beq ChkAreaTsk ;if data zero, branch
|
|
jmp RunEnemyObjectsCore ;otherwise, jump to run enemy subroutines
|
|
ChkAreaTsk lda AreaParserTaskNum ;check number of tasks to perform
|
|
and #$07
|
|
cmp #$07 ;if at a specific task, jump and leave
|
|
beq ExitELCore
|
|
jmp ProcLoopCommand ;otherwise, jump to process loop command/load enemies
|
|
ChkBowserF pla ;get data from stack
|
|
and #%00001111 ;mask out high nybble
|
|
tay
|
|
lda Enemy_Flag,y ;use as pointer and load same place with different offset
|
|
bne ExitELCore
|
|
sta Enemy_Flag,x ;if second enemy flag not set, also clear first one
|
|
ExitELCore rts
|
|
|
|
;--------------------------------
|
|
|
|
;loop command data
|
|
LoopCmdWorldNumber
|
|
db $03,$03,$06,$06,$06,$06,$06,$06,$07,$07,$07
|
|
|
|
LoopCmdPageNumber
|
|
db $05,$09,$04,$05,$06,$08,$09,$0a,$06,$0b,$10
|
|
|
|
LoopCmdYPosition
|
|
db $40,$b0,$b0,$80,$40,$40,$80,$40,$f0,$f0,$f0
|
|
|
|
ExecGameLoopback
|
|
lda Player_PageLoc ;send player back four pages
|
|
sec
|
|
sbc #$04
|
|
sta Player_PageLoc
|
|
lda CurrentPageLoc ;send current page back four pages
|
|
sec
|
|
sbc #$04
|
|
sta CurrentPageLoc
|
|
lda ScreenLeft_PageLoc ;subtract four from page location
|
|
sec ;of screen's left border
|
|
sbc #$04
|
|
sta ScreenLeft_PageLoc
|
|
lda ScreenRight_PageLoc ;do the same for the page location
|
|
sec ;of screen's right border
|
|
sbc #$04
|
|
sta ScreenRight_PageLoc
|
|
lda AreaObjectPageLoc ;subtract four from page control
|
|
sec ;for area objects
|
|
sbc #$04
|
|
sta AreaObjectPageLoc
|
|
lda #$00 ;initialize page select for both
|
|
sta EnemyObjectPageSel ;area and enemy objects
|
|
sta AreaObjectPageSel
|
|
sta EnemyDataOffset ;initialize enemy object data offset
|
|
sta EnemyObjectPageLoc ;and enemy object page control
|
|
lda AreaDataOfsLoopback,y ;adjust area object offset based on
|
|
sta AreaDataOffset ;which loop command we encountered
|
|
rts
|
|
|
|
ProcLoopCommand
|
|
lda LoopCommand ;check if loop command was found
|
|
beq ChkEnemyFrenzy
|
|
lda CurrentColumnPos ;check to see if we're still on the first page
|
|
bne ChkEnemyFrenzy ;if not, do not loop yet
|
|
ldy #$0b ;start at the end of each set of loop data
|
|
FindLoop dey
|
|
bmi ChkEnemyFrenzy ;if all data is checked and not match, do not loop
|
|
lda WorldNumber ;check to see if one of the world numbers
|
|
cmp LoopCmdWorldNumber,y ;matches our current world number
|
|
bne FindLoop
|
|
lda CurrentPageLoc ;check to see if one of the page numbers
|
|
cmp LoopCmdPageNumber,y ;matches the page we're currently on
|
|
bne FindLoop
|
|
lda Player_Y_Position ;check to see if the player is at the correct position
|
|
cmp LoopCmdYPosition,y ;if not, branch to check for world 7
|
|
bne WrongChk
|
|
lda Player_State ;check to see if the player is
|
|
cmp #$00 ;on solid ground (i.e. not jumping or falling)
|
|
bne WrongChk ;if not, player fails to pass loop, and loopback
|
|
lda WorldNumber ;are we in world 7? (check performed on correct
|
|
cmp #World7 ;vertical position and on solid ground)
|
|
bne InitMLp ;if not, initialize flags used there, otherwise
|
|
inc MultiLoopCorrectCntr ;increment counter for correct progression
|
|
IncMLoop inc MultiLoopPassCntr ;increment master multi-part counter
|
|
lda MultiLoopPassCntr ;have we done all three parts?
|
|
cmp #$03
|
|
bne InitLCmd ;if not, skip this part
|
|
lda MultiLoopCorrectCntr ;if so, have we done them all correctly?
|
|
cmp #$03
|
|
beq InitMLp ;if so, branch past unnecessary check here
|
|
bne DoLpBack ;unconditional branch if previous branch fails
|
|
WrongChk lda WorldNumber ;are we in world 7? (check performed on
|
|
cmp #World7 ;incorrect vertical position or not on solid ground)
|
|
beq IncMLoop
|
|
DoLpBack jsr ExecGameLoopback ;if player is not in right place, loop back
|
|
jsr KillAllEnemies
|
|
InitMLp lda #$00 ;initialize counters used for multi-part loop commands
|
|
sta MultiLoopPassCntr
|
|
sta MultiLoopCorrectCntr
|
|
InitLCmd lda #$00 ;initialize loop command flag
|
|
sta LoopCommand
|
|
|
|
;--------------------------------
|
|
|
|
ChkEnemyFrenzy
|
|
lda EnemyFrenzyQueue ;check for enemy object in frenzy queue
|
|
beq ProcessEnemyData ;if not, skip this part
|
|
sta Enemy_ID,x ;store as enemy object identifier here
|
|
lda #$01
|
|
sta Enemy_Flag,x ;activate enemy object flag
|
|
lda #$00
|
|
sta Enemy_State,x ;initialize state and frenzy queue
|
|
sta EnemyFrenzyQueue
|
|
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
|
|
ldy EnemyDataOffset ;get offset of enemy object data
|
|
lda (EnemyData),y ;load first byte
|
|
cmp #$ff ;check for EOD terminator
|
|
bne CheckEndofBuffer
|
|
jmp CheckFrenzyBuffer ;if found, jump to check frenzy buffer, otherwise
|
|
|
|
CheckEndofBuffer
|
|
and #%00001111 ;check for special row $0e
|
|
cmp #$0e
|
|
beq CheckRightBounds ;if found, branch, otherwise
|
|
cpx #$05 ;check for end of buffer
|
|
bcc CheckRightBounds ;if not at end of buffer, branch
|
|
iny
|
|
lda (EnemyData),y ;check for specific value here
|
|
and #%00111111 ;not sure what this was intended for, exactly
|
|
cmp #$2e ;this part is quite possibly residual code
|
|
beq CheckRightBounds ;but it has the effect of keeping enemies out of
|
|
rts ;the sixth slot
|
|
|
|
CheckRightBounds
|
|
lda ScreenRight_X_Pos ;add 48 to pixel coordinate of right boundary
|
|
clc
|
|
adc #$30
|
|
and #%11110000 ;store high nybble
|
|
sta $07
|
|
lda ScreenRight_PageLoc ;add carry to page location of right boundary
|
|
adc #$00
|
|
sta $06 ;store page location + carry
|
|
ldy EnemyDataOffset
|
|
iny
|
|
lda (EnemyData),y ;if MSB of enemy object is clear, branch to check for row $0f
|
|
asl
|
|
bcc CheckPageCtrlRow
|
|
lda EnemyObjectPageSel ;if page select already set, do not set again
|
|
bne CheckPageCtrlRow
|
|
inc EnemyObjectPageSel ;otherwise, if MSB is set, set page select
|
|
inc EnemyObjectPageLoc ;and increment page control
|
|
|
|
CheckPageCtrlRow
|
|
dey
|
|
lda (EnemyData),y ;reread first byte
|
|
and #$0f
|
|
cmp #$0f ;check for special row $0f
|
|
bne PositionEnemyObj ;if not found, branch to position enemy object
|
|
lda EnemyObjectPageSel ;if page select set,
|
|
bne PositionEnemyObj ;branch without reading second byte
|
|
iny
|
|
lda (EnemyData),y ;otherwise, get second byte, mask out 2 MSB
|
|
and #%00111111
|
|
sta EnemyObjectPageLoc ;store as page control for enemy object data
|
|
inc EnemyDataOffset ;increment enemy object data offset 2 bytes
|
|
inc EnemyDataOffset
|
|
inc EnemyObjectPageSel ;set page select for enemy object data and
|
|
jmp ProcLoopCommand ;jump back to process loop commands again
|
|
|
|
PositionEnemyObj
|
|
lda EnemyObjectPageLoc ;store page control as page location
|
|
sta Enemy_PageLoc,x ;for enemy object
|
|
lda (EnemyData),y ;get first byte of enemy object
|
|
and #%11110000
|
|
sta Enemy_X_Position,x ;store column position
|
|
cmp ScreenRight_X_Pos ;check column position against right boundary
|
|
lda Enemy_PageLoc,x ;without subtracting, then subtract borrow
|
|
sbc ScreenRight_PageLoc ;from page location
|
|
bcs CheckRightExtBounds ;if enemy object beyond or at boundary, branch
|
|
lda (EnemyData),y
|
|
and #%00001111 ;check for special row $0e
|
|
cmp #$0e ;if found, jump elsewhere
|
|
beq ParseRow0e
|
|
jmp CheckThreeBytes ;if not found, unconditional jump
|
|
|
|
CheckRightExtBounds
|
|
lda $07 ;check right boundary + 48 against
|
|
cmp Enemy_X_Position,x ;column position without subtracting,
|
|
lda $06 ;then subtract borrow from page control temp
|
|
sbc Enemy_PageLoc,x ;plus carry
|
|
bcc CheckFrenzyBuffer ;if enemy object beyond extended boundary, branch
|
|
lda #$01 ;store value in vertical high byte
|
|
sta Enemy_Y_HighPos,x
|
|
lda (EnemyData),y ;get first byte again
|
|
asl ;multiply by four to get the vertical
|
|
asl ;coordinate
|
|
asl
|
|
asl
|
|
sta Enemy_Y_Position,x
|
|
cmp #$e0 ;do one last check for special row $0e
|
|
beq ParseRow0e ;(necessary if branched to $c1cb)
|
|
iny
|
|
lda (EnemyData),y ;get second byte of object
|
|
and #%01000000 ;check to see if hard mode bit is set
|
|
beq CheckForEnemyGroup ;if not, branch to check for group enemy objects
|
|
lda SecondaryHardMode ;if set, check to see if secondary hard mode flag
|
|
beq Inc2B ;is on, and if not, branch to skip this object completely
|
|
|
|
CheckForEnemyGroup
|
|
lda (EnemyData),y ;get second byte and mask out 2 MSB
|
|
and #%00111111
|
|
cmp #$37 ;check for value below $37
|
|
bcc BuzzyBeetleMutate
|
|
cmp #$3f ;if $37 or greater, check for value
|
|
bcc DoGroup ;below $3f, branch if below $3f
|
|
|
|
BuzzyBeetleMutate
|
|
cmp #Goomba ;if below $37, check for goomba
|
|
bne StrID ;value ($3f or more always fails)
|
|
ldy PrimaryHardMode ;check if primary hard mode flag is set
|
|
beq StrID ;and if so, change goomba to buzzy beetle
|
|
lda #BuzzyBeetle
|
|
StrID sta Enemy_ID,x ;store enemy object number into buffer
|
|
lda #$01
|
|
sta Enemy_Flag,x ;set flag for enemy in buffer
|
|
jsr InitEnemyObject
|
|
lda Enemy_Flag,x ;check to see if flag is set
|
|
bne Inc2B ;if not, leave, otherwise branch
|
|
rts
|
|
|
|
CheckFrenzyBuffer
|
|
lda EnemyFrenzyBuffer ;if enemy object stored in frenzy buffer
|
|
bne StrFre ;then branch ahead to store in enemy object buffer
|
|
lda VineFlagOffset ;otherwise check vine flag offset
|
|
cmp #$01
|
|
bne ExEPar ;if other value <> 1, leave
|
|
lda #VineObject ;otherwise put vine in enemy identifier
|
|
StrFre sta Enemy_ID,x ;store contents of frenzy buffer into enemy identifier value
|
|
|
|
InitEnemyObject
|
|
lda #$00 ;initialize enemy state
|
|
sta Enemy_State,x
|
|
jsr CheckpointEnemyID ;jump ahead to run jump engine and subroutines
|
|
ExEPar rts ;then leave
|
|
|
|
DoGroup
|
|
jmp HandleGroupEnemies ;handle enemy group objects
|
|
|
|
ParseRow0e
|
|
iny ;increment Y to load third byte of object
|
|
iny
|
|
lda (EnemyData),y
|
|
lsr ;move 3 MSB to the bottom, effectively
|
|
lsr ;making %xxx00000 into %00000xxx
|
|
lsr
|
|
lsr
|
|
lsr
|
|
cmp WorldNumber ;is it the same world number as we're on?
|
|
bne NotUse ;if not, do not use (this allows multiple uses
|
|
dey ;of the same area, like the underground bonus areas)
|
|
lda (EnemyData),y ;otherwise, get second byte and use as offset
|
|
sta AreaPointer ;to addresses for level and enemy object data
|
|
iny
|
|
lda (EnemyData),y ;get third byte again, and this time mask out
|
|
and #%00011111 ;the 3 MSB from before, save as page number to be
|
|
sta EntrancePage ;used upon entry to area, if area is entered
|
|
NotUse jmp Inc3B
|
|
|
|
CheckThreeBytes
|
|
ldy EnemyDataOffset ;load current offset for enemy object data
|
|
lda (EnemyData),y ;get first byte
|
|
and #%00001111 ;check for special row $0e
|
|
cmp #$0e
|
|
bne Inc2B
|
|
Inc3B inc EnemyDataOffset ;if row = $0e, increment three bytes
|
|
Inc2B inc EnemyDataOffset ;otherwise increment two bytes
|
|
inc EnemyDataOffset
|
|
lda #$00 ;init page select for enemy objects
|
|
sta EnemyObjectPageSel
|
|
ldx ObjectOffset ;reload current offset in enemy buffers
|
|
rts ;and leave
|
|
|
|
CheckpointEnemyID
|
|
lda Enemy_ID,x
|
|
cmp #$15 ;check enemy object identifier for $15 or greater
|
|
bcs InitEnemyRoutines ;and branch straight to the jump engine if found
|
|
tay ;save identifier in Y register for now
|
|
lda Enemy_Y_Position,x
|
|
adc #$08 ;add eight pixels to what will eventually be the
|
|
sta Enemy_Y_Position,x ;enemy object's vertical coordinate ($00-$14 only)
|
|
lda #$01
|
|
sta EnemyOffscrBitsMasked,x ;set offscreen masked bit
|
|
tya ;get identifier back and use as offset for jump engine
|
|
|
|
InitEnemyRoutines
|
|
jsr JumpEngine
|
|
|
|
;jump engine table for newly loaded enemy objects
|
|
|
|
dw InitNormalEnemy ;for objects $00-$0f
|
|
dw InitNormalEnemy
|
|
dw InitNormalEnemy
|
|
dw InitRedKoopa
|
|
dw NoInitCode
|
|
dw InitHammerBro
|
|
dw InitGoomba
|
|
dw InitBloober
|
|
dw InitBulletBill
|
|
dw NoInitCode
|
|
dw InitCheepCheep
|
|
dw InitCheepCheep
|
|
dw InitPodoboo
|
|
dw InitPiranhaPlant
|
|
dw InitJumpGPTroopa
|
|
dw InitRedPTroopa
|
|
|
|
dw InitHorizFlySwimEnemy ;for objects $10-$1f
|
|
dw InitLakitu
|
|
dw InitEnemyFrenzy
|
|
dw NoInitCode
|
|
dw InitEnemyFrenzy
|
|
dw InitEnemyFrenzy
|
|
dw InitEnemyFrenzy
|
|
dw InitEnemyFrenzy
|
|
dw EndFrenzy
|
|
dw NoInitCode
|
|
dw NoInitCode
|
|
dw InitShortFirebar
|
|
dw InitShortFirebar
|
|
dw InitShortFirebar
|
|
dw InitShortFirebar
|
|
dw InitLongFirebar
|
|
|
|
dw NoInitCode ;for objects $20-$2f
|
|
dw NoInitCode
|
|
dw NoInitCode
|
|
dw NoInitCode
|
|
dw InitBalPlatform
|
|
dw InitVertPlatform
|
|
dw LargeLiftUp
|
|
dw LargeLiftDown
|
|
dw InitHoriPlatform
|
|
dw InitDropPlatform
|
|
dw InitHoriPlatform
|
|
dw PlatLiftUp
|
|
dw PlatLiftDown
|
|
dw InitBowser
|
|
dw PwrUpJmp ;possibly dummy value
|
|
dw Setup_Vine
|
|
|
|
dw NoInitCode ;for objects $30-$36
|
|
dw NoInitCode
|
|
dw NoInitCode
|
|
dw NoInitCode
|
|
dw NoInitCode
|
|
dw InitRetainerObj
|
|
dw EndOfEnemyInitCode
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
NoInitCode
|
|
rts ;this executed when enemy object has no init code
|
|
|
|
;--------------------------------
|
|
|
|
InitGoomba
|
|
jsr InitNormalEnemy ;set appropriate horizontal speed
|
|
jmp SmallBBox ;set $09 as bounding box control, set other values
|
|
|
|
;--------------------------------
|
|
|
|
InitPodoboo
|
|
lda #$02 ;set enemy position to below
|
|
sta Enemy_Y_HighPos,x ;the bottom of the screen
|
|
sta Enemy_Y_Position,x
|
|
lsr
|
|
sta EnemyIntervalTimer,x ;set timer for enemy
|
|
lsr
|
|
sta Enemy_State,x ;initialize enemy state, then jump to use
|
|
jmp SmallBBox ;$09 as bounding box size and set other things
|
|
|
|
;--------------------------------
|
|
|
|
InitRetainerObj
|
|
lda #$b8 ;set fixed vertical position for
|
|
sta Enemy_Y_Position,x ;princess/mushroom retainer object
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
NormalXSpdData
|
|
db $f8,$f4
|
|
|
|
InitNormalEnemy
|
|
ldy #$01 ;load offset of 1 by default
|
|
lda PrimaryHardMode ;check for primary hard mode flag set
|
|
bne GetESpd
|
|
dey ;if not set, decrement offset
|
|
GetESpd lda NormalXSpdData,y ;get appropriate horizontal speed
|
|
SetESpd sta Enemy_X_Speed,x ;store as speed for enemy object
|
|
jmp TallBBox ;branch to set bounding box control and other data
|
|
|
|
;--------------------------------
|
|
|
|
InitRedKoopa
|
|
jsr InitNormalEnemy ;load appropriate horizontal speed
|
|
lda #$01 ;set enemy state for red koopa troopa $03
|
|
sta Enemy_State,x
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
HBroWalkingTimerData
|
|
db $80,$50
|
|
|
|
InitHammerBro
|
|
lda #$00 ;init horizontal speed and timer used by hammer bro
|
|
sta HammerThrowingTimer,x ;apparently to time hammer throwing
|
|
sta Enemy_X_Speed,x
|
|
ldy SecondaryHardMode ;get secondary hard mode flag
|
|
lda HBroWalkingTimerData,y
|
|
sta EnemyIntervalTimer,x ;set value as delay for hammer bro to walk left
|
|
lda #$0b ;set specific value for bounding box size control
|
|
jmp SetBBox
|
|
|
|
;--------------------------------
|
|
|
|
InitHorizFlySwimEnemy
|
|
lda #$00 ;initialize horizontal speed
|
|
jmp SetESpd
|
|
|
|
;--------------------------------
|
|
|
|
InitBloober
|
|
lda #$00 ;initialize horizontal speed
|
|
sta BlooperMoveSpeed,x
|
|
SmallBBox lda #$09 ;set specific bounding box size control
|
|
bne SetBBox ;unconditional branch
|
|
|
|
;--------------------------------
|
|
|
|
InitRedPTroopa
|
|
ldy #$30 ;load central position adder for 48 pixels down
|
|
lda Enemy_Y_Position,x ;set vertical coordinate into location to
|
|
sta RedPTroopaOrigXPos,x ;be used as original vertical coordinate
|
|
bpl GetCent ;if vertical coordinate < $80
|
|
ldy #$e0 ;if => $80, load position adder for 32 pixels up
|
|
GetCent tya ;send central position adder to A
|
|
adc Enemy_Y_Position,x ;add to current vertical coordinate
|
|
sta RedPTroopaCenterYPos,x ;store as central vertical coordinate
|
|
TallBBox lda #$03 ;set specific bounding box size control
|
|
SetBBox sta Enemy_BoundBoxCtrl,x ;set bounding box control here
|
|
lda #$02 ;set moving direction for left
|
|
sta Enemy_MovingDir,x
|
|
InitVStf lda #$00 ;initialize vertical speed
|
|
sta Enemy_Y_Speed,x ;and movement force
|
|
sta Enemy_Y_MoveForce,x
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
InitBulletBill
|
|
lda #$02 ;set moving direction for left
|
|
sta Enemy_MovingDir,x
|
|
lda #$09 ;set bounding box control for $09
|
|
sta Enemy_BoundBoxCtrl,x
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
InitCheepCheep
|
|
jsr SmallBBox ;set vertical bounding box, speed, init others
|
|
lda PseudoRandomBitReg,x ;check one portion of LSFR
|
|
and #%00010000 ;get d4 from it
|
|
sta CheepCheepMoveMFlag,x ;save as movement flag of some sort
|
|
lda Enemy_Y_Position,x
|
|
sta CheepCheepOrigYPos,x ;save original vertical coordinate here
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
InitLakitu
|
|
lda EnemyFrenzyBuffer ;check to see if an enemy is already in
|
|
bne KillLakitu ;the frenzy buffer, and branch to kill lakitu if so
|
|
|
|
SetupLakitu
|
|
lda #$00 ;erase counter for lakitu's reappearance
|
|
sta LakituReappearTimer
|
|
jsr InitHorizFlySwimEnemy ;set $03 as bounding box, set other attributes
|
|
jmp TallBBox2 ;set $03 as bounding box again (not necessary) and leave
|
|
|
|
KillLakitu
|
|
jmp EraseEnemyObject
|
|
|
|
;--------------------------------
|
|
;$01-$03 - used to hold pseudorandom difference adjusters
|
|
|
|
PRDiffAdjustData
|
|
db $26,$2c,$32,$38
|
|
db $20,$22,$24,$26
|
|
db $13,$14,$15,$16
|
|
|
|
LakituAndSpinyHandler
|
|
lda FrenzyEnemyTimer ;if timer here not expired, leave
|
|
bne ExLSHand
|
|
cpx #$05 ;if we are on the special use slot, leave
|
|
bcs ExLSHand
|
|
lda #$80 ;set timer
|
|
sta FrenzyEnemyTimer
|
|
ldy #$04 ;start with the last enemy slot
|
|
ChkLak lda Enemy_ID,y ;check all enemy slots to see
|
|
cmp #Lakitu ;if lakitu is on one of them
|
|
beq CreateSpiny ;if so, branch out of this loop
|
|
dey ;otherwise check another slot
|
|
bpl ChkLak ;loop until all slots are checked
|
|
inc LakituReappearTimer ;increment reappearance timer
|
|
lda LakituReappearTimer
|
|
cmp #$07 ;check to see if we're up to a certain value yet
|
|
bcc ExLSHand ;if not, leave
|
|
ldx #$04 ;start with the last enemy slot again
|
|
ChkNoEn lda Enemy_Flag,x ;check enemy buffer flag for non-active enemy slot
|
|
beq CreateL ;branch out of loop if found
|
|
dex ;otherwise check next slot
|
|
bpl ChkNoEn ;branch until all slots are checked
|
|
bmi RetEOfs ;if no empty slots were found, branch to leave
|
|
CreateL lda #$00 ;initialize enemy state
|
|
sta Enemy_State,x
|
|
lda #Lakitu ;create lakitu enemy object
|
|
sta Enemy_ID,x
|
|
jsr SetupLakitu ;do a sub to set up lakitu
|
|
lda #$20
|
|
jsr PutAtRightExtent ;finish setting up lakitu
|
|
RetEOfs ldx ObjectOffset ;get enemy object buffer offset again and leave
|
|
ExLSHand rts
|
|
|
|
;--------------------------------
|
|
|
|
CreateSpiny
|
|
lda Player_Y_Position ;if player above a certain point, branch to leave
|
|
cmp #$2c
|
|
bcc ExLSHand
|
|
lda Enemy_State,y ;if lakitu is not in normal state, branch to leave
|
|
bne ExLSHand
|
|
lda Enemy_PageLoc,y ;store horizontal coordinates (high and low) of lakitu
|
|
sta Enemy_PageLoc,x ;into the coordinates of the spiny we're going to create
|
|
lda Enemy_X_Position,y
|
|
sta Enemy_X_Position,x
|
|
lda #$01 ;put spiny within vertical screen unit
|
|
sta Enemy_Y_HighPos,x
|
|
lda Enemy_Y_Position,y ;put spiny eight pixels above where lakitu is
|
|
sec
|
|
sbc #$08
|
|
sta Enemy_Y_Position,x
|
|
lda PseudoRandomBitReg,x ;get 2 LSB of LSFR and save to Y
|
|
and #%00000011
|
|
tay
|
|
ldx #$02
|
|
DifLoop lda PRDiffAdjustData,y ;get three values and save them
|
|
sta $01,x ;to $01-$03
|
|
iny
|
|
iny ;increment Y four bytes for each value
|
|
iny
|
|
iny
|
|
dex ;decrement X for each one
|
|
bpl DifLoop ;loop until all three are written
|
|
ldx ObjectOffset ;get enemy object buffer offset
|
|
jsr PlayerLakituDiff ;move enemy, change direction, get value - difference
|
|
ldy Player_X_Speed ;check player's horizontal speed
|
|
cpy #$08
|
|
bcs SetSpSpd ;if moving faster than a certain amount, branch elsewhere
|
|
tay ;otherwise save value in A to Y for now
|
|
lda PseudoRandomBitReg+1,x
|
|
and #%00000011 ;get one of the LSFR parts and save the 2 LSB
|
|
beq UsePosv ;branch if neither bits are set
|
|
tya
|
|
eor #%11111111 ;otherwise get two's compliment of Y
|
|
tay
|
|
iny
|
|
UsePosv tya ;put value from A in Y back to A (they will be lost anyway)
|
|
SetSpSpd jsr SmallBBox ;set bounding box control, init attributes, lose contents of A
|
|
ldy #$02
|
|
sta Enemy_X_Speed,x ;set horizontal speed to zero because previous contents
|
|
cmp #$00 ;of A were lost...branch here will never be taken for
|
|
bmi SpinyRte ;the same reason
|
|
dey
|
|
SpinyRte sty Enemy_MovingDir,x ;set moving direction to the right
|
|
lda #$fd
|
|
sta Enemy_Y_Speed,x ;set vertical speed to move upwards
|
|
lda #$01
|
|
sta Enemy_Flag,x ;enable enemy object by setting flag
|
|
lda #$05
|
|
sta Enemy_State,x ;put spiny in egg state and leave
|
|
ChpChpEx rts
|
|
|
|
;--------------------------------
|
|
|
|
FirebarSpinSpdData
|
|
db $28,$38,$28,$38,$28
|
|
|
|
FirebarSpinDirData
|
|
db $00,$00,$10,$10,$00
|
|
|
|
InitLongFirebar
|
|
jsr DuplicateEnemyObj ;create enemy object for long firebar
|
|
|
|
InitShortFirebar
|
|
lda #$00 ;initialize low byte of spin state
|
|
sta FirebarSpinState_Low,x
|
|
lda Enemy_ID,x ;subtract $1b from enemy identifier
|
|
sec ;to get proper offset for firebar data
|
|
sbc #$1b
|
|
tay
|
|
lda FirebarSpinSpdData,y ;get spinning speed of firebar
|
|
sta FirebarSpinSpeed,x
|
|
lda FirebarSpinDirData,y ;get spinning direction of firebar
|
|
sta FirebarSpinDirection,x
|
|
lda Enemy_Y_Position,x
|
|
clc ;add four pixels to vertical coordinate
|
|
adc #$04
|
|
sta Enemy_Y_Position,x
|
|
lda Enemy_X_Position,x
|
|
clc ;add four pixels to horizontal coordinate
|
|
adc #$04
|
|
sta Enemy_X_Position,x
|
|
lda Enemy_PageLoc,x
|
|
adc #$00 ;add carry to page location
|
|
sta Enemy_PageLoc,x
|
|
jmp TallBBox2 ;set bounding box control (not used) and leave
|
|
|
|
;--------------------------------
|
|
;$00-$01 - used to hold pseudorandom bits
|
|
|
|
FlyCCXPositionData
|
|
db $80,$30,$40,$80
|
|
db $30,$50,$50,$70
|
|
db $20,$40,$80,$a0
|
|
db $70,$40,$90,$68
|
|
|
|
FlyCCXSpeedData
|
|
db $0e,$05,$06,$0e
|
|
db $1c,$20,$10,$0c
|
|
db $1e,$22,$18,$14
|
|
|
|
FlyCCTimerData
|
|
db $10,$60,$20,$48
|
|
|
|
InitFlyingCheepCheep
|
|
lda FrenzyEnemyTimer ;if timer here not expired yet, branch to leave
|
|
bne ChpChpEx
|
|
jsr SmallBBox ;jump to set bounding box size $09 and init other values
|
|
lda PseudoRandomBitReg+1,x
|
|
and #%00000011 ;set pseudorandom offset here
|
|
tay
|
|
lda FlyCCTimerData,y ;load timer with pseudorandom offset
|
|
sta FrenzyEnemyTimer
|
|
ldy #$03 ;load Y with default value
|
|
lda SecondaryHardMode
|
|
beq MaxCC ;if secondary hard mode flag not set, do not increment Y
|
|
iny ;otherwise, increment Y to allow as many as four onscreen
|
|
MaxCC sty $00 ;store whatever pseudorandom bits are in Y
|
|
cpx $00 ;compare enemy object buffer offset with Y
|
|
bcs ChpChpEx ;if X => Y, branch to leave
|
|
lda PseudoRandomBitReg,x
|
|
and #%00000011 ;get last two bits of LSFR, first part
|
|
sta $00 ;and store in two places
|
|
sta $01
|
|
lda #$fb ;set vertical speed for cheep-cheep
|
|
sta Enemy_Y_Speed,x
|
|
lda #$00 ;load default value
|
|
ldy Player_X_Speed ;check player's horizontal speed
|
|
beq GSeed ;if player not moving left or right, skip this part
|
|
lda #$04
|
|
cpy #$19 ;if moving to the right but not very quickly,
|
|
bcc GSeed ;do not change A
|
|
asl ;otherwise, multiply A by 2
|
|
GSeed pha ;save to stack
|
|
clc
|
|
adc $00 ;add to last two bits of LSFR we saved earlier
|
|
sta $00 ;save it there
|
|
lda PseudoRandomBitReg+1,x
|
|
and #%00000011 ;if neither of the last two bits of second LSFR set,
|
|
beq RSeed ;skip this part and save contents of $00
|
|
lda PseudoRandomBitReg+2,x
|
|
and #%00001111 ;otherwise overwrite with lower nybble of
|
|
sta $00 ;third LSFR part
|
|
RSeed pla ;get value from stack we saved earlier
|
|
clc
|
|
adc $01 ;add to last two bits of LSFR we saved in other place
|
|
tay ;use as pseudorandom offset here
|
|
lda FlyCCXSpeedData,y ;get horizontal speed using pseudorandom offset
|
|
sta Enemy_X_Speed,x
|
|
lda #$01 ;set to move towards the right
|
|
sta Enemy_MovingDir,x
|
|
lda Player_X_Speed ;if player moving left or right, branch ahead of this part
|
|
bne D2XPos1
|
|
ldy $00 ;get first LSFR or third LSFR lower nybble
|
|
tya ;and check for d1 set
|
|
and #%00000010
|
|
beq D2XPos1 ;if d1 not set, branch
|
|
lda Enemy_X_Speed,x
|
|
eor #$ff ;if d1 set, change horizontal speed
|
|
clc ;into two's compliment, thus moving in the opposite
|
|
adc #$01 ;direction
|
|
sta Enemy_X_Speed,x
|
|
inc Enemy_MovingDir,x ;increment to move towards the left
|
|
D2XPos1 tya ;get first LSFR or third LSFR lower nybble again
|
|
and #%00000010
|
|
beq D2XPos2 ;check for d1 set again, branch again if not set
|
|
lda Player_X_Position ;get player's horizontal position
|
|
clc
|
|
adc FlyCCXPositionData,y ;if d1 set, add value obtained from pseudorandom offset
|
|
sta Enemy_X_Position,x ;and save as enemy's horizontal position
|
|
lda Player_PageLoc ;get player's page location
|
|
adc #$00 ;add carry and jump past this part
|
|
jmp FinCCSt
|
|
D2XPos2 lda Player_X_Position ;get player's horizontal position
|
|
sec
|
|
sbc FlyCCXPositionData,y ;if d1 not set, subtract value obtained from pseudorandom
|
|
sta Enemy_X_Position,x ;offset and save as enemy's horizontal position
|
|
lda Player_PageLoc ;get player's page location
|
|
sbc #$00 ;subtract borrow
|
|
FinCCSt sta Enemy_PageLoc,x ;save as enemy's page location
|
|
lda #$01
|
|
sta Enemy_Flag,x ;set enemy's buffer flag
|
|
sta Enemy_Y_HighPos,x ;set enemy's high vertical byte
|
|
lda #$f8
|
|
sta Enemy_Y_Position,x ;put enemy below the screen, and we are done
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
InitBowser
|
|
jsr DuplicateEnemyObj ;jump to create another bowser object
|
|
stx BowserFront_Offset ;save offset of first here
|
|
lda #$00
|
|
sta BowserBodyControls ;initialize bowser's body controls
|
|
sta BridgeCollapseOffset ;and bridge collapse offset
|
|
lda Enemy_X_Position,x
|
|
sta BowserOrigXPos ;store original horizontal position here
|
|
lda #$df
|
|
sta BowserFireBreathTimer ;store something here
|
|
sta Enemy_MovingDir,x ;and in moving direction
|
|
lda #$20
|
|
sta BowserFeetCounter ;set bowser's feet timer and in enemy timer
|
|
sta EnemyFrameTimer,x
|
|
lda #$05
|
|
sta BowserHitPoints ;give bowser 5 hit points
|
|
lsr
|
|
sta BowserMovementSpeed ;set default movement speed here
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
DuplicateEnemyObj
|
|
ldy #$ff ;start at beginning of enemy slots
|
|
FSLoop iny ;increment one slot
|
|
lda Enemy_Flag,y ;check enemy buffer flag for empty slot
|
|
bne FSLoop ;if set, branch and keep checking
|
|
sty DuplicateObj_Offset ;otherwise set offset here
|
|
txa ;transfer original enemy buffer offset
|
|
ora #%10000000 ;store with d7 set as flag in new enemy
|
|
sta Enemy_Flag,y ;slot as well as enemy offset
|
|
lda Enemy_PageLoc,x
|
|
sta Enemy_PageLoc,y ;copy page location and horizontal coordinates
|
|
lda Enemy_X_Position,x ;from original enemy to new enemy
|
|
sta Enemy_X_Position,y
|
|
lda #$01
|
|
sta Enemy_Flag,x ;set flag as normal for original enemy
|
|
sta Enemy_Y_HighPos,y ;set high vertical byte for new enemy
|
|
lda Enemy_Y_Position,x
|
|
sta Enemy_Y_Position,y ;copy vertical coordinate from original to new
|
|
FlmEx rts ;and then leave
|
|
|
|
;--------------------------------
|
|
|
|
FlameYPosData
|
|
db $90,$80,$70,$90
|
|
|
|
FlameYMFAdderData
|
|
db $ff,$01
|
|
|
|
InitBowserFlame
|
|
lda FrenzyEnemyTimer ;if timer not expired yet, branch to leave
|
|
bne FlmEx
|
|
sta Enemy_Y_MoveForce,x ;reset something here
|
|
lda NoiseSoundQueue
|
|
ora #Sfx_BowserFlame ;load bowser's flame sound into queue
|
|
sta NoiseSoundQueue
|
|
ldy BowserFront_Offset ;get bowser's buffer offset
|
|
lda Enemy_ID,y ;check for bowser
|
|
cmp #Bowser
|
|
beq SpawnFromMouth ;branch if found
|
|
jsr SetFlameTimer ;get timer data based on flame counter
|
|
clc
|
|
adc #$20 ;add 32 frames by default
|
|
ldy SecondaryHardMode
|
|
beq SetFrT ;if secondary mode flag not set, use as timer setting
|
|
sec
|
|
sbc #$10 ;otherwise subtract 16 frames for secondary hard mode
|
|
SetFrT sta FrenzyEnemyTimer ;set timer accordingly
|
|
lda PseudoRandomBitReg,x
|
|
and #%00000011 ;get 2 LSB from first part of LSFR
|
|
sta BowserFlamePRandomOfs,x ;set here
|
|
tay ;use as offset
|
|
lda FlameYPosData,y ;load vertical position based on pseudorandom offset
|
|
|
|
PutAtRightExtent
|
|
sta Enemy_Y_Position,x ;set vertical position
|
|
lda ScreenRight_X_Pos
|
|
clc
|
|
adc #$20 ;place enemy 32 pixels beyond right side of screen
|
|
sta Enemy_X_Position,x
|
|
lda ScreenRight_PageLoc
|
|
adc #$00 ;add carry
|
|
sta Enemy_PageLoc,x
|
|
jmp FinishFlame ;skip this part to finish setting values
|
|
|
|
SpawnFromMouth
|
|
lda Enemy_X_Position,y ;get bowser's horizontal position
|
|
sec
|
|
sbc #$0e ;subtract 14 pixels
|
|
sta Enemy_X_Position,x ;save as flame's horizontal position
|
|
lda Enemy_PageLoc,y
|
|
sta Enemy_PageLoc,x ;copy page location from bowser to flame
|
|
lda Enemy_Y_Position,y
|
|
clc ;add 8 pixels to bowser's vertical position
|
|
adc #$08
|
|
sta Enemy_Y_Position,x ;save as flame's vertical position
|
|
lda PseudoRandomBitReg,x
|
|
and #%00000011 ;get 2 LSB from first part of LSFR
|
|
sta Enemy_YMF_Dummy,x ;save here
|
|
tay ;use as offset
|
|
lda FlameYPosData,y ;get value here using bits as offset
|
|
ldy #$00 ;load default offset
|
|
cmp Enemy_Y_Position,x ;compare value to flame's current vertical position
|
|
bcc SetMF ;if less, do not increment offset
|
|
iny ;otherwise increment now
|
|
SetMF lda FlameYMFAdderData,y ;get value here and save
|
|
sta Enemy_Y_MoveForce,x ;to vertical movement force
|
|
lda #$00
|
|
sta EnemyFrenzyBuffer ;clear enemy frenzy buffer
|
|
|
|
FinishFlame
|
|
lda #$08 ;set $08 for bounding box control
|
|
sta Enemy_BoundBoxCtrl,x
|
|
lda #$01 ;set high byte of vertical and
|
|
sta Enemy_Y_HighPos,x ;enemy buffer flag
|
|
sta Enemy_Flag,x
|
|
lsr
|
|
sta Enemy_X_MoveForce,x ;initialize horizontal movement force, and
|
|
sta Enemy_State,x ;enemy state
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
FireworksXPosData
|
|
db $00,$30,$60,$60,$00,$20
|
|
|
|
FireworksYPosData
|
|
db $60,$40,$70,$40,$60,$30
|
|
|
|
InitFireworks
|
|
lda FrenzyEnemyTimer ;if timer not expired yet, branch to leave
|
|
bne ExitFWk
|
|
lda #$20 ;otherwise reset timer
|
|
sta FrenzyEnemyTimer
|
|
dec FireworksCounter ;decrement for each explosion
|
|
ldy #$06 ;start at last slot
|
|
StarFChk dey
|
|
lda Enemy_ID,y ;check for presence of star flag object
|
|
cmp #StarFlagObject ;if there isn't a star flag object,
|
|
bne StarFChk ;routine goes into infinite loop = crash
|
|
lda Enemy_X_Position,y
|
|
sec ;get horizontal coordinate of star flag object, then
|
|
sbc #$30 ;subtract 48 pixels from it and save to
|
|
pha ;the stack
|
|
lda Enemy_PageLoc,y
|
|
sbc #$00 ;subtract the carry from the page location
|
|
sta $00 ;of the star flag object
|
|
lda FireworksCounter ;get fireworks counter
|
|
clc
|
|
adc Enemy_State,y ;add state of star flag object (possibly not necessary)
|
|
tay ;use as offset
|
|
pla ;get saved horizontal coordinate of star flag - 48 pixels
|
|
clc
|
|
adc FireworksXPosData,y ;add number based on offset of fireworks counter
|
|
sta Enemy_X_Position,x ;store as the fireworks object horizontal coordinate
|
|
lda $00
|
|
adc #$00 ;add carry and store as page location for
|
|
sta Enemy_PageLoc,x ;the fireworks object
|
|
lda FireworksYPosData,y ;get vertical position using same offset
|
|
sta Enemy_Y_Position,x ;and store as vertical coordinate for fireworks object
|
|
lda #$01
|
|
sta Enemy_Y_HighPos,x ;store in vertical high byte
|
|
sta Enemy_Flag,x ;and activate enemy buffer flag
|
|
lsr
|
|
sta ExplosionGfxCounter,x ;initialize explosion counter
|
|
lda #$08
|
|
sta ExplosionTimerCounter,x ;set explosion timing counter
|
|
ExitFWk rts
|
|
|
|
;--------------------------------
|
|
|
|
Bitmasks
|
|
db %00000001, %00000010,
|
|
|
|
Enemy17YPosData
|
|
db $40,$30,$90,$50,$20,$60,$a0,$70
|
|
|
|
SwimCC_IDData
|
|
db $0a,$0b
|
|
|
|
BulletBillCheepCheep
|
|
lda FrenzyEnemyTimer ;if timer not expired yet, branch to leave
|
|
bne ExF17
|
|
lda AreaType ;are we in a water-type level?
|
|
bne DoBulletBills ;if not, branch elsewhere
|
|
cpx #$03 ;are we past third enemy slot?
|
|
bcs ExF17 ;if so, branch to leave
|
|
ldy #$00 ;load default offset
|
|
lda PseudoRandomBitReg,x
|
|
cmp #$aa ;check first part of LSFR against preset value
|
|
bcc ChkW2 ;if less than preset, do not increment offset
|
|
iny ;otherwise increment
|
|
ChkW2 lda WorldNumber ;check world number
|
|
cmp #World2
|
|
beq Get17ID ;if we're on world 2, do not increment offset
|
|
iny ;otherwise increment
|
|
Get17ID tya
|
|
and #%00000001 ;mask out all but last bit of offset
|
|
tay
|
|
lda SwimCC_IDData,y ;load identifier for cheep-cheeps
|
|
Set17ID sta Enemy_ID,x ;store whatever's in A as enemy identifier
|
|
lda BitMFilter
|
|
cmp #$ff ;if not all bits set, skip init part and compare bits
|
|
bne GetRBit
|
|
lda #$00 ;initialize vertical position filter
|
|
sta BitMFilter
|
|
GetRBit lda PseudoRandomBitReg,x ;get first part of LSFR
|
|
and #%00000111 ;mask out all but 3 LSB
|
|
ChkRBit tay ;use as offset
|
|
lda Bitmasks,y ;load bitmask
|
|
bit BitMFilter ;perform AND on filter without changing it
|
|
beq AddFBit
|
|
iny ;increment offset
|
|
tya
|
|
and #%00000111 ;mask out all but 3 LSB thus keeping it 0-7
|
|
jmp ChkRBit ;do another check
|
|
AddFBit ora BitMFilter ;add bit to already set bits in filter
|
|
sta BitMFilter ;and store
|
|
lda Enemy17YPosData,y ;load vertical position using offset
|
|
jsr PutAtRightExtent ;set vertical position and other values
|
|
sta Enemy_YMF_Dummy,x ;initialize dummy variable
|
|
lda #$20 ;set timer
|
|
sta FrenzyEnemyTimer
|
|
jmp CheckpointEnemyID ;process our new enemy object
|
|
|
|
DoBulletBills
|
|
ldy #$ff ;start at beginning of enemy slots
|
|
BB_SLoop iny ;move onto the next slot
|
|
cpy #$05 ;branch to play sound if we've done all slots
|
|
bcs FireBulletBill
|
|
lda Enemy_Flag,y ;if enemy buffer flag not set,
|
|
beq BB_SLoop ;loop back and check another slot
|
|
lda Enemy_ID,y
|
|
cmp #BulletBill_FrenzyVar ;check enemy identifier for
|
|
bne BB_SLoop ;bullet bill object (frenzy variant)
|
|
ExF17 rts ;if found, leave
|
|
|
|
FireBulletBill
|
|
lda Square2SoundQueue
|
|
ora #Sfx_Blast ;play fireworks/gunfire sound
|
|
sta Square2SoundQueue
|
|
lda #BulletBill_FrenzyVar ;load identifier for bullet bill object
|
|
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
|
|
ldy #$00 ;load value for green koopa troopa
|
|
sec
|
|
sbc #$37 ;subtract $37 from second byte read
|
|
pha ;save result in stack for now
|
|
cmp #$04 ;was byte in $3b-$3e range?
|
|
bcs SnglID ;if so, branch
|
|
pha ;save another copy to stack
|
|
ldy #Goomba ;load value for goomba enemy
|
|
lda PrimaryHardMode ;if primary hard mode flag not set,
|
|
beq PullID ;branch, otherwise change to value
|
|
ldy #BuzzyBeetle ;for buzzy beetle
|
|
PullID pla ;get second copy from stack
|
|
SnglID sty $01 ;save enemy id here
|
|
ldy #$b0 ;load default y coordinate
|
|
and #$02 ;check to see if d1 was set
|
|
beq SetYGp ;if so, move y coordinate up,
|
|
ldy #$70 ;otherwise branch and use default
|
|
SetYGp sty $00 ;save y coordinate here
|
|
lda ScreenRight_PageLoc ;get page number of right edge of screen
|
|
sta $02 ;save here
|
|
lda ScreenRight_X_Pos ;get pixel coordinate of right edge
|
|
sta $03 ;save here
|
|
ldy #$02 ;load two enemies by default
|
|
pla ;get first copy from stack
|
|
lsr ;check to see if d0 was set
|
|
bcc CntGrp ;if not, use default value
|
|
iny ;otherwise increment to three enemies
|
|
CntGrp sty NumberofGroupEnemies ;save number of enemies here
|
|
GrLoop ldx #$ff ;start at beginning of enemy buffers
|
|
GSltLp inx ;increment and branch if past
|
|
cpx #$05 ;end of buffers
|
|
bcs NextED
|
|
lda Enemy_Flag,x ;check to see if enemy is already
|
|
bne GSltLp ;stored in buffer, and branch if so
|
|
lda $01
|
|
sta Enemy_ID,x ;store enemy object identifier
|
|
lda $02
|
|
sta Enemy_PageLoc,x ;store page location for enemy object
|
|
lda $03
|
|
sta Enemy_X_Position,x ;store x coordinate for enemy object
|
|
clc
|
|
adc #$18 ;add 24 pixels for next enemy
|
|
sta $03
|
|
lda $02 ;add carry to page location for
|
|
adc #$00 ;next enemy
|
|
sta $02
|
|
lda $00 ;store y coordinate for enemy object
|
|
sta Enemy_Y_Position,x
|
|
lda #$01 ;activate flag for buffer, and
|
|
sta Enemy_Y_HighPos,x ;put enemy within the screen vertically
|
|
sta Enemy_Flag,x
|
|
jsr CheckpointEnemyID ;process each enemy object separately
|
|
dec NumberofGroupEnemies ;do this until we run out of enemy objects
|
|
bne GrLoop
|
|
NextED jmp Inc2B ;jump to increment data offset and leave
|
|
|
|
;--------------------------------
|
|
|
|
InitPiranhaPlant
|
|
lda #$01 ;set initial speed
|
|
sta PiranhaPlant_Y_Speed,x
|
|
lsr
|
|
sta Enemy_State,x ;initialize enemy state and what would normally
|
|
sta PiranhaPlant_MoveFlag,x ;be used as vertical speed, but not in this case
|
|
lda Enemy_Y_Position,x
|
|
sta PiranhaPlantDownYPos,x ;save original vertical coordinate here
|
|
sec
|
|
sbc #$18
|
|
sta PiranhaPlantUpYPos,x ;save original vertical coordinate - 24 pixels here
|
|
lda #$09
|
|
jmp SetBBox2 ;set specific value for bounding box control
|
|
|
|
;--------------------------------
|
|
|
|
InitEnemyFrenzy
|
|
lda Enemy_ID,x ;load enemy identifier
|
|
sta EnemyFrenzyBuffer ;save in enemy frenzy buffer
|
|
sec
|
|
sbc #$12 ;subtract 12 and use as offset for jump engine
|
|
jsr JumpEngine
|
|
|
|
;frenzy object jump table
|
|
dw LakituAndSpinyHandler
|
|
dw NoFrenzyCode
|
|
dw InitFlyingCheepCheep
|
|
dw InitBowserFlame
|
|
dw InitFireworks
|
|
dw BulletBillCheepCheep
|
|
|
|
;--------------------------------
|
|
|
|
NoFrenzyCode
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
EndFrenzy
|
|
ldy #$05 ;start at last slot
|
|
LakituChk lda Enemy_ID,y ;check enemy identifiers
|
|
cmp #Lakitu ;for lakitu
|
|
bne NextFSlot
|
|
lda #$01 ;if found, set state
|
|
sta Enemy_State,y
|
|
NextFSlot dey ;move onto the next slot
|
|
bpl LakituChk ;do this until all slots are checked
|
|
lda #$00
|
|
sta EnemyFrenzyBuffer ;empty enemy frenzy buffer
|
|
sta Enemy_Flag,x ;disable enemy buffer flag for this object
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
InitJumpGPTroopa
|
|
lda #$02 ;set for movement to the left
|
|
sta Enemy_MovingDir,x
|
|
lda #$f8 ;set horizontal speed
|
|
sta Enemy_X_Speed,x
|
|
TallBBox2 lda #$03 ;set specific value for bounding box control
|
|
SetBBox2 sta Enemy_BoundBoxCtrl,x ;set bounding box control then leave
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
InitBalPlatform
|
|
dec Enemy_Y_Position,x ;raise vertical position by two pixels
|
|
dec Enemy_Y_Position,x
|
|
ldy SecondaryHardMode ;if secondary hard mode flag not set,
|
|
bne AlignP ;branch ahead
|
|
ldy #$02 ;otherwise set value here
|
|
jsr PosPlatform ;do a sub to add or subtract pixels
|
|
AlignP ldy #$ff ;set default value here for now
|
|
lda BalPlatformAlignment ;get current balance platform alignment
|
|
sta Enemy_State,x ;set platform alignment to object state here
|
|
bpl SetBPA ;if old alignment $ff, put $ff as alignment for negative
|
|
txa ;if old contents already $ff, put
|
|
tay ;object offset as alignment to make next positive
|
|
SetBPA sty BalPlatformAlignment ;store whatever value's in Y here
|
|
lda #$00
|
|
sta Enemy_MovingDir,x ;init moving direction
|
|
tay ;init Y
|
|
jsr PosPlatform ;do a sub to add 8 pixels, then run shared code here
|
|
|
|
;--------------------------------
|
|
|
|
InitDropPlatform
|
|
lda #$ff
|
|
sta PlatformCollisionFlag,x ;set some value here
|
|
jmp CommonPlatCode ;then jump ahead to execute more code
|
|
|
|
;--------------------------------
|
|
|
|
InitHoriPlatform
|
|
lda #$00
|
|
sta XMoveSecondaryCounter,x ;init one of the moving counters
|
|
jmp CommonPlatCode ;jump ahead to execute more code
|
|
|
|
;--------------------------------
|
|
|
|
InitVertPlatform
|
|
ldy #$40 ;set default value here
|
|
lda Enemy_Y_Position,x ;check vertical position
|
|
bpl SetYO ;if above a certain point, skip this part
|
|
eor #$ff
|
|
clc ;otherwise get two's compliment
|
|
adc #$01
|
|
ldy #$c0 ;get alternate value to add to vertical position
|
|
SetYO sta YPlatformTopYPos,x ;save as top vertical position
|
|
tya
|
|
clc ;load value from earlier, add number of pixels
|
|
adc Enemy_Y_Position,x ;to vertical position
|
|
sta YPlatformCenterYPos,x ;save result as central vertical position
|
|
|
|
;--------------------------------
|
|
|
|
CommonPlatCode
|
|
jsr InitVStf ;do a sub to init certain other values
|
|
SPBBox lda #$05 ;set default bounding box size control
|
|
ldy AreaType
|
|
cpy #$03 ;check for castle-type level
|
|
beq CasPBB ;use default value if found
|
|
ldy SecondaryHardMode ;otherwise check for secondary hard mode flag
|
|
bne CasPBB ;if set, use default value
|
|
lda #$06 ;use alternate value if not castle or secondary not set
|
|
CasPBB sta Enemy_BoundBoxCtrl,x ;set bounding box size control here and leave
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
LargeLiftUp
|
|
jsr PlatLiftUp ;execute code for platforms going up
|
|
jmp LargeLiftBBox ;overwrite bounding box for large platforms
|
|
|
|
LargeLiftDown
|
|
jsr PlatLiftDown ;execute code for platforms going down
|
|
|
|
LargeLiftBBox
|
|
jmp SPBBox ;jump to overwrite bounding box size control
|
|
|
|
;--------------------------------
|
|
|
|
PlatLiftUp
|
|
lda #$10 ;set movement amount here
|
|
sta Enemy_Y_MoveForce,x
|
|
lda #$ff ;set moving speed for platforms going up
|
|
sta Enemy_Y_Speed,x
|
|
jmp CommonSmallLift ;skip ahead to part we should be executing
|
|
|
|
;--------------------------------
|
|
|
|
PlatLiftDown
|
|
lda #$f0 ;set movement amount here
|
|
sta Enemy_Y_MoveForce,x
|
|
lda #$00 ;set moving speed for platforms going down
|
|
sta Enemy_Y_Speed,x
|
|
|
|
;--------------------------------
|
|
|
|
CommonSmallLift
|
|
ldy #$01
|
|
jsr PosPlatform ;do a sub to add 12 pixels due to preset value
|
|
lda #$04
|
|
sta Enemy_BoundBoxCtrl,x ;set bounding box control for small platforms
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
PlatPosDataLow
|
|
db $08,$0c,$f8
|
|
|
|
PlatPosDataHigh
|
|
db $00,$00,$ff
|
|
|
|
PosPlatform
|
|
lda Enemy_X_Position,x ;get horizontal coordinate
|
|
clc
|
|
adc PlatPosDataLow,y ;add or subtract pixels depending on offset
|
|
sta Enemy_X_Position,x ;store as new horizontal coordinate
|
|
lda Enemy_PageLoc,x
|
|
adc PlatPosDataHigh,y ;add or subtract page location depending on offset
|
|
sta Enemy_PageLoc,x ;store as new page location
|
|
rts ;and go back
|
|
|
|
;--------------------------------
|
|
|
|
EndOfEnemyInitCode
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
RunEnemyObjectsCore
|
|
ldx ObjectOffset ;get offset for enemy object buffer
|
|
lda #$00 ;load value 0 for jump engine by default
|
|
ldy Enemy_ID,x
|
|
cpy #$15 ;if enemy object < $15, use default value
|
|
bcc JmpEO
|
|
tya ;otherwise subtract $14 from the value and use
|
|
sbc #$14 ;as value for jump engine
|
|
JmpEO jsr JumpEngine
|
|
|
|
dw RunNormalEnemies ;for objects $00-$14
|
|
|
|
dw RunBowserFlame ;for objects $15-$1f
|
|
dw RunFireworks
|
|
dw NoRunCode
|
|
dw NoRunCode
|
|
dw NoRunCode
|
|
dw NoRunCode
|
|
dw RunFirebarObj
|
|
dw RunFirebarObj
|
|
dw RunFirebarObj
|
|
dw RunFirebarObj
|
|
dw RunFirebarObj
|
|
|
|
dw RunFirebarObj ;for objects $20-$2f
|
|
dw RunFirebarObj
|
|
dw RunFirebarObj
|
|
dw NoRunCode
|
|
dw RunLargePlatform
|
|
dw RunLargePlatform
|
|
dw RunLargePlatform
|
|
dw RunLargePlatform
|
|
dw RunLargePlatform
|
|
dw RunLargePlatform
|
|
dw RunLargePlatform
|
|
dw RunSmallPlatform
|
|
dw RunSmallPlatform
|
|
dw RunBowser
|
|
dw PowerUpObjHandler
|
|
dw VineObjectHandler
|
|
|
|
dw NoRunCode ;for objects $30-$35
|
|
dw RunStarFlagObj
|
|
dw JumpspringHandler
|
|
dw NoRunCode
|
|
dw WarpZoneObject
|
|
dw RunRetainerObj
|
|
|
|
;--------------------------------
|
|
|
|
NoRunCode
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
RunRetainerObj
|
|
jsr GetEnemyOffscreenBits
|
|
jsr RelativeEnemyPosition
|
|
jmp EnemyGfxHandler
|
|
|
|
;--------------------------------
|
|
|
|
RunNormalEnemies
|
|
lda #$00 ;init sprite attributes
|
|
sta Enemy_SprAttrib,x
|
|
jsr GetEnemyOffscreenBits
|
|
jsr RelativeEnemyPosition
|
|
jsr EnemyGfxHandler
|
|
jsr GetEnemyBoundBox
|
|
jsr EnemyToBGCollisionDet
|
|
jsr EnemiesCollision
|
|
jsr PlayerEnemyCollision
|
|
ldy TimerControl ;if master timer control set, skip to last routine
|
|
bne SkipMove
|
|
jsr EnemyMovementSubs
|
|
SkipMove jmp OffscreenBoundsCheck
|
|
|
|
EnemyMovementSubs
|
|
lda Enemy_ID,x
|
|
jsr JumpEngine
|
|
|
|
dw MoveNormalEnemy ;only objects $00-$14 use this table
|
|
dw MoveNormalEnemy
|
|
dw MoveNormalEnemy
|
|
dw MoveNormalEnemy
|
|
dw MoveNormalEnemy
|
|
dw ProcHammerBro
|
|
dw MoveNormalEnemy
|
|
dw MoveBloober
|
|
dw MoveBulletBill
|
|
dw NoMoveCode
|
|
dw MoveSwimmingCheepCheep
|
|
dw MoveSwimmingCheepCheep
|
|
dw MovePodoboo
|
|
dw MovePiranhaPlant
|
|
dw MoveJumpingEnemy
|
|
dw ProcMoveRedPTroopa
|
|
dw MoveFlyGreenPTroopa
|
|
dw MoveLakitu
|
|
dw MoveNormalEnemy
|
|
dw NoMoveCode ;dummy
|
|
dw MoveFlyingCheepCheep
|
|
|
|
;--------------------------------
|
|
|
|
NoMoveCode
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
RunBowserFlame
|
|
jsr ProcBowserFlame
|
|
jsr GetEnemyOffscreenBits
|
|
jsr RelativeEnemyPosition
|
|
jsr GetEnemyBoundBox
|
|
jsr PlayerEnemyCollision
|
|
jmp OffscreenBoundsCheck
|
|
|
|
;--------------------------------
|
|
|
|
RunFirebarObj
|
|
jsr ProcFirebar
|
|
jmp OffscreenBoundsCheck
|
|
|
|
;--------------------------------
|
|
|
|
RunSmallPlatform
|
|
jsr GetEnemyOffscreenBits
|
|
jsr RelativeEnemyPosition
|
|
jsr SmallPlatformBoundBox
|
|
jsr SmallPlatformCollision
|
|
jsr RelativeEnemyPosition
|
|
jsr DrawSmallPlatform
|
|
jsr MoveSmallPlatform
|
|
jmp OffscreenBoundsCheck
|
|
|
|
;--------------------------------
|
|
|
|
RunLargePlatform
|
|
jsr GetEnemyOffscreenBits
|
|
jsr RelativeEnemyPosition
|
|
jsr LargePlatformBoundBox
|
|
jsr LargePlatformCollision
|
|
lda TimerControl ;if master timer control set,
|
|
bne SkipPT ;skip subroutine tree
|
|
jsr LargePlatformSubroutines
|
|
SkipPT jsr RelativeEnemyPosition
|
|
jsr DrawLargePlatform
|
|
jmp OffscreenBoundsCheck
|
|
|
|
;--------------------------------
|
|
|
|
LargePlatformSubroutines
|
|
lda Enemy_ID,x ;subtract $24 to get proper offset for jump table
|
|
sec
|
|
sbc #$24
|
|
jsr JumpEngine
|
|
|
|
dw BalancePlatform ;table used by objects $24-$2a
|
|
dw YMovingPlatform
|
|
dw MoveLargeLiftPlat
|
|
dw MoveLargeLiftPlat
|
|
dw XMovingPlatform
|
|
dw DropPlatform
|
|
dw RightPlatform
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
EraseEnemyObject
|
|
lda #$00 ;clear all enemy object variables
|
|
sta Enemy_Flag,x
|
|
sta Enemy_ID,x
|
|
sta Enemy_State,x
|
|
sta FloateyNum_Control,x
|
|
sta EnemyIntervalTimer,x
|
|
sta ShellChainCounter,x
|
|
sta Enemy_SprAttrib,x
|
|
sta EnemyFrameTimer,x
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
MovePodoboo
|
|
lda EnemyIntervalTimer,x ;check enemy timer
|
|
bne PdbM ;branch to move enemy if not expired
|
|
jsr InitPodoboo ;otherwise set up podoboo again
|
|
lda PseudoRandomBitReg+1,x ;get part of LSFR
|
|
ora #%10000000 ;set d7
|
|
sta Enemy_Y_MoveForce,x ;store as movement force
|
|
and #%00001111 ;mask out high nybble
|
|
ora #$06 ;set for at least six intervals
|
|
sta EnemyIntervalTimer,x ;store as new enemy timer
|
|
lda #$f9
|
|
sta Enemy_Y_Speed,x ;set vertical speed to move podoboo upwards
|
|
PdbM jmp MoveJ_EnemyVertically ;branch to impose gravity on podoboo
|
|
|
|
;--------------------------------
|
|
;$00 - used in HammerBroJumpCode as bitmask
|
|
|
|
HammerThrowTmrData
|
|
db $30,$1c
|
|
|
|
XSpeedAdderData
|
|
db $00,$e8,$00,$18
|
|
|
|
RevivedXSpeed
|
|
db $08,$f8,$0c,$f4
|
|
|
|
ProcHammerBro
|
|
lda Enemy_State,x ;check hammer bro's enemy state for d5 set
|
|
and #%00100000
|
|
beq ChkJH ;if not set, go ahead with code
|
|
jmp MoveDefeatedEnemy ;otherwise jump to something else
|
|
ChkJH lda HammerBroJumpTimer,x ;check jump timer
|
|
beq HammerBroJumpCode ;if expired, branch to jump
|
|
dec HammerBroJumpTimer,x ;otherwise decrement jump timer
|
|
lda Enemy_OffscreenBits
|
|
and #%00001100 ;check offscreen bits
|
|
bne MoveHammerBroXDir ;if hammer bro a little offscreen, skip to movement code
|
|
lda HammerThrowingTimer,x ;check hammer throwing timer
|
|
bne DecHT ;if not expired, skip ahead, do not throw hammer
|
|
ldy SecondaryHardMode ;otherwise get secondary hard mode flag
|
|
lda HammerThrowTmrData,y ;get timer data using flag as offset
|
|
sta HammerThrowingTimer,x ;set as new timer
|
|
jsr SpawnHammerObj ;do a sub here to spawn hammer object
|
|
bcc DecHT ;if carry clear, hammer not spawned, skip to decrement timer
|
|
lda Enemy_State,x
|
|
ora #%00001000 ;set d3 in enemy state for hammer throw
|
|
sta Enemy_State,x
|
|
jmp MoveHammerBroXDir ;jump to move hammer bro
|
|
DecHT dec HammerThrowingTimer,x ;decrement timer
|
|
jmp MoveHammerBroXDir ;jump to move hammer bro
|
|
|
|
HammerBroJumpLData
|
|
db $20,$37
|
|
|
|
HammerBroJumpCode
|
|
lda Enemy_State,x ;get hammer bro's enemy state
|
|
and #%00000111 ;mask out all but 3 LSB
|
|
cmp #$01 ;check for d0 set (for jumping)
|
|
beq MoveHammerBroXDir ;if set, branch ahead to moving code
|
|
lda #$00 ;load default value here
|
|
sta $00 ;save into temp variable for now
|
|
ldy #$fa ;set default vertical speed
|
|
lda Enemy_Y_Position,x ;check hammer bro's vertical coordinate
|
|
bmi SetHJ ;if on the bottom half of the screen, use current speed
|
|
ldy #$fd ;otherwise set alternate vertical speed
|
|
cmp #$70 ;check to see if hammer bro is above the middle of screen
|
|
inc $00 ;increment preset value to $01
|
|
bcc SetHJ ;if above the middle of the screen, use current speed and $01
|
|
dec $00 ;otherwise return value to $00
|
|
lda PseudoRandomBitReg+1,x ;get part of LSFR, mask out all but LSB
|
|
and #$01
|
|
bne SetHJ ;if d0 of LSFR set, branch and use current speed and $00
|
|
ldy #$fa ;otherwise reset to default vertical speed
|
|
SetHJ sty Enemy_Y_Speed,x ;set vertical speed for jumping
|
|
lda Enemy_State,x ;set d0 in enemy state for jumping
|
|
ora #$01
|
|
sta Enemy_State,x
|
|
lda $00 ;load preset value here to use as bitmask
|
|
and PseudoRandomBitReg+2,x ;and do bit-wise comparison with part of LSFR
|
|
tay ;then use as offset
|
|
lda SecondaryHardMode ;check secondary hard mode flag
|
|
bne HJump
|
|
tay ;if secondary hard mode flag clear, set offset to 0
|
|
HJump lda HammerBroJumpLData,y ;get jump length timer data using offset from before
|
|
sta EnemyFrameTimer,x ;save in enemy timer
|
|
lda PseudoRandomBitReg+1,x
|
|
ora #%11000000 ;get contents of part of LSFR, set d7 and d6, then
|
|
sta HammerBroJumpTimer,x ;store in jump timer
|
|
|
|
MoveHammerBroXDir
|
|
ldy #$fc ;move hammer bro a little to the left
|
|
lda FrameCounter
|
|
and #%01000000 ;change hammer bro's direction every 64 frames
|
|
bne Shimmy
|
|
ldy #$04 ;if d6 set in counter, move him a little to the right
|
|
Shimmy sty Enemy_X_Speed,x ;store horizontal speed
|
|
ldy #$01 ;set to face right by default
|
|
jsr PlayerEnemyDiff ;get horizontal difference between player and hammer bro
|
|
bmi SetShim ;if enemy to the left of player, skip this part
|
|
iny ;set to face left
|
|
lda EnemyIntervalTimer,x ;check walking timer
|
|
bne SetShim ;if not yet expired, skip to set moving direction
|
|
lda #$f8
|
|
sta Enemy_X_Speed,x ;otherwise, make the hammer bro walk left towards player
|
|
SetShim sty Enemy_MovingDir,x ;set moving direction
|
|
|
|
MoveNormalEnemy
|
|
ldy #$00 ;init Y to leave horizontal movement as-is
|
|
lda Enemy_State,x
|
|
and #%01000000 ;check enemy state for d6 set, if set skip
|
|
bne FallE ;to move enemy vertically, then horizontally if necessary
|
|
lda Enemy_State,x
|
|
asl ;check enemy state for d7 set
|
|
bcs SteadM ;if set, branch to move enemy horizontally
|
|
lda Enemy_State,x
|
|
and #%00100000 ;check enemy state for d5 set
|
|
bne MoveDefeatedEnemy ;if set, branch to move defeated enemy object
|
|
lda Enemy_State,x
|
|
and #%00000111 ;check d2-d0 of enemy state for any set bits
|
|
beq SteadM ;if enemy in normal state, branch to move enemy horizontally
|
|
cmp #$05
|
|
beq FallE ;if enemy in state used by spiny's egg, go ahead here
|
|
cmp #$03
|
|
bcs ReviveStunned ;if enemy in states $03 or $04, skip ahead to yet another part
|
|
FallE jsr MoveD_EnemyVertically ;do a sub here to move enemy downwards
|
|
ldy #$00
|
|
lda Enemy_State,x ;check for enemy state $02
|
|
cmp #$02
|
|
beq MEHor ;if found, branch to move enemy horizontally
|
|
and #%01000000 ;check for d6 set
|
|
beq SteadM ;if not set, branch to something else
|
|
lda Enemy_ID,x
|
|
cmp #PowerUpObject ;check for power-up object
|
|
beq SteadM
|
|
bne SlowM ;if any other object where d6 set, jump to set Y
|
|
MEHor jmp MoveEnemyHorizontally ;jump here to move enemy horizontally for <> $2e and d6 set
|
|
|
|
SlowM ldy #$01 ;if branched here, increment Y to slow horizontal movement
|
|
SteadM lda Enemy_X_Speed,x ;get current horizontal speed
|
|
pha ;save to stack
|
|
bpl AddHS ;if not moving or moving right, skip, leave Y alone
|
|
iny
|
|
iny ;otherwise increment Y to next data
|
|
AddHS clc
|
|
adc XSpeedAdderData,y ;add value here to slow enemy down if necessary
|
|
sta Enemy_X_Speed,x ;save as horizontal speed temporarily
|
|
jsr MoveEnemyHorizontally ;then do a sub to move horizontally
|
|
pla
|
|
sta Enemy_X_Speed,x ;get old horizontal speed from stack and return to
|
|
rts ;original memory location, then leave
|
|
|
|
ReviveStunned
|
|
lda EnemyIntervalTimer,x ;if enemy timer not expired yet,
|
|
bne ChkKillGoomba ;skip ahead to something else
|
|
sta Enemy_State,x ;otherwise initialize enemy state to normal
|
|
lda FrameCounter
|
|
and #$01 ;get d0 of frame counter
|
|
tay ;use as Y and increment for movement direction
|
|
iny
|
|
sty Enemy_MovingDir,x ;store as pseudorandom movement direction
|
|
dey ;decrement for use as pointer
|
|
lda PrimaryHardMode ;check primary hard mode flag
|
|
beq SetRSpd ;if not set, use pointer as-is
|
|
iny
|
|
iny ;otherwise increment 2 bytes to next data
|
|
SetRSpd lda RevivedXSpeed,y ;load and store new horizontal speed
|
|
sta Enemy_X_Speed,x ;and leave
|
|
rts
|
|
|
|
MoveDefeatedEnemy
|
|
jsr MoveD_EnemyVertically ;execute sub to move defeated enemy downwards
|
|
jmp MoveEnemyHorizontally ;now move defeated enemy horizontally
|
|
|
|
ChkKillGoomba
|
|
cmp #$0e ;check to see if enemy timer has reached
|
|
bne NKGmba ;a certain point, and branch to leave if not
|
|
lda Enemy_ID,x
|
|
cmp #Goomba ;check for goomba object
|
|
bne NKGmba ;branch if not found
|
|
jsr EraseEnemyObject ;otherwise, kill this goomba object
|
|
NKGmba rts ;leave!
|
|
|
|
;--------------------------------
|
|
|
|
MoveJumpingEnemy
|
|
jsr MoveJ_EnemyVertically ;do a sub to impose gravity on green paratroopa
|
|
jmp MoveEnemyHorizontally ;jump to move enemy horizontally
|
|
|
|
;--------------------------------
|
|
|
|
ProcMoveRedPTroopa
|
|
lda Enemy_Y_Speed,x
|
|
ora Enemy_Y_MoveForce,x ;check for any vertical force or speed
|
|
bne MoveRedPTUpOrDown ;branch if any found
|
|
sta Enemy_YMF_Dummy,x ;initialize something here
|
|
lda Enemy_Y_Position,x ;check current vs. original vertical coordinate
|
|
cmp RedPTroopaOrigXPos,x
|
|
bcs MoveRedPTUpOrDown ;if current => original, skip ahead to more code
|
|
lda FrameCounter ;get frame counter
|
|
and #%00000111 ;mask out all but 3 LSB
|
|
bne NoIncPT ;if any bits set, branch to leave
|
|
inc Enemy_Y_Position,x ;otherwise increment red paratroopa's vertical position
|
|
NoIncPT rts ;leave
|
|
|
|
MoveRedPTUpOrDown
|
|
lda Enemy_Y_Position,x ;check current vs. central vertical coordinate
|
|
cmp RedPTroopaCenterYPos,x
|
|
bcc MovPTDwn ;if current < central, jump to move downwards
|
|
jmp MoveRedPTroopaUp ;otherwise jump to move upwards
|
|
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
|
|
jsr XMoveCntr_GreenPTroopa ;do sub to increment primary and secondary counters
|
|
jsr MoveWithXMCntrs ;do sub to move green paratroopa accordingly, and horizontally
|
|
ldy #$01 ;set Y to move green paratroopa down
|
|
lda FrameCounter
|
|
and #%00000011 ;check frame counter 2 LSB for any bits set
|
|
bne NoMGPT ;branch to leave if set to move up/down every fourth frame
|
|
lda FrameCounter
|
|
and #%01000000 ;check frame counter for d6 set
|
|
bne YSway ;branch to move green paratroopa down if set
|
|
ldy #$ff ;otherwise set Y to move green paratroopa up
|
|
YSway sty $00 ;store adder here
|
|
lda Enemy_Y_Position,x
|
|
clc ;add or subtract from vertical position
|
|
adc $00 ;to give green paratroopa a wavy flight
|
|
sta Enemy_Y_Position,x
|
|
NoMGPT rts ;leave!
|
|
|
|
XMoveCntr_GreenPTroopa
|
|
lda #$13 ;load preset maximum value for secondary counter
|
|
|
|
XMoveCntr_Platform
|
|
sta $01 ;store value here
|
|
lda FrameCounter
|
|
and #%00000011 ;branch to leave if not on
|
|
bne NoIncXM ;every fourth frame
|
|
ldy XMoveSecondaryCounter,x ;get secondary counter
|
|
lda XMovePrimaryCounter,x ;get primary counter
|
|
lsr
|
|
bcs DecSeXM ;if d0 of primary counter set, branch elsewhere
|
|
cpy $01 ;compare secondary counter to preset maximum value
|
|
beq IncPXM ;if equal, branch ahead of this part
|
|
inc XMoveSecondaryCounter,x ;increment secondary counter and leave
|
|
NoIncXM rts
|
|
IncPXM inc XMovePrimaryCounter,x ;increment primary counter and leave
|
|
rts
|
|
DecSeXM tya ;put secondary counter in A
|
|
beq IncPXM ;if secondary counter at zero, branch back
|
|
dec XMoveSecondaryCounter,x ;otherwise decrement secondary counter and leave
|
|
rts
|
|
|
|
MoveWithXMCntrs
|
|
lda XMoveSecondaryCounter,x ;save secondary counter to stack
|
|
pha
|
|
ldy #$01 ;set value here by default
|
|
lda XMovePrimaryCounter,x
|
|
and #%00000010 ;if d1 of primary counter is
|
|
bne XMRight ;set, branch ahead of this part here
|
|
lda XMoveSecondaryCounter,x
|
|
eor #$ff ;otherwise change secondary
|
|
clc ;counter to two's compliment
|
|
adc #$01
|
|
sta XMoveSecondaryCounter,x
|
|
ldy #$02 ;load alternate value here
|
|
XMRight sty Enemy_MovingDir,x ;store as moving direction
|
|
jsr MoveEnemyHorizontally
|
|
sta $00 ;save value obtained from sub here
|
|
pla ;get secondary counter from stack
|
|
sta XMoveSecondaryCounter,x ;and return to original place
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
BlooberBitmasks
|
|
db %00111111,%00000011
|
|
|
|
MoveBloober
|
|
lda Enemy_State,x
|
|
and #%00100000 ;check enemy state for d5 set
|
|
bne MoveDefeatedBloober ;branch if set to move defeated bloober
|
|
ldy SecondaryHardMode ;use secondary hard mode flag as offset
|
|
lda PseudoRandomBitReg+1,x ;get LSFR
|
|
and BlooberBitmasks,y ;mask out bits in LSFR using bitmask loaded with offset
|
|
bne BlooberSwim ;if any bits set, skip ahead to make swim
|
|
txa
|
|
lsr ;check to see if on second or fourth slot (1 or 3)
|
|
bcc FBLeft ;if not, branch to figure out moving direction
|
|
ldy Player_MovingDir ;otherwise, load player's moving direction and
|
|
bcs SBMDir ;do an unconditional branch to set
|
|
FBLeft ldy #$02 ;set left moving direction by default
|
|
jsr PlayerEnemyDiff ;get horizontal difference between player and bloober
|
|
bpl SBMDir ;if enemy to the right of player, keep left
|
|
dey ;otherwise decrement to set right moving direction
|
|
SBMDir sty Enemy_MovingDir,x ;set moving direction of bloober, then continue on here
|
|
|
|
BlooberSwim
|
|
jsr ProcSwimmingB ;execute sub to make bloober swim characteristically
|
|
lda Enemy_Y_Position,x ;get vertical coordinate
|
|
sec
|
|
sbc Enemy_Y_MoveForce,x ;subtract movement force
|
|
cmp #$20 ;check to see if position is above edge of status bar
|
|
bcc SwimX ;if so, don't do it
|
|
sta Enemy_Y_Position,x ;otherwise, set new vertical position, make bloober swim
|
|
SwimX ldy Enemy_MovingDir,x ;check moving direction
|
|
dey
|
|
bne LeftSwim ;if moving to the left, branch to second part
|
|
lda Enemy_X_Position,x
|
|
clc ;add movement speed to horizontal coordinate
|
|
adc BlooperMoveSpeed,x
|
|
sta Enemy_X_Position,x ;store result as new horizontal coordinate
|
|
lda Enemy_PageLoc,x
|
|
adc #$00 ;add carry to page location
|
|
sta Enemy_PageLoc,x ;store as new page location and leave
|
|
rts
|
|
|
|
LeftSwim
|
|
lda Enemy_X_Position,x
|
|
sec ;subtract movement speed from horizontal coordinate
|
|
sbc BlooperMoveSpeed,x
|
|
sta Enemy_X_Position,x ;store result as new horizontal coordinate
|
|
lda Enemy_PageLoc,x
|
|
sbc #$00 ;subtract borrow from page location
|
|
sta Enemy_PageLoc,x ;store as new page location and leave
|
|
rts
|
|
|
|
MoveDefeatedBloober
|
|
jmp MoveEnemySlowVert ;jump to move defeated bloober downwards
|
|
|
|
ProcSwimmingB
|
|
lda BlooperMoveCounter,x ;get enemy's movement counter
|
|
and #%00000010 ;check for d1 set
|
|
bne ChkForFloatdown ;branch if set
|
|
lda FrameCounter
|
|
and #%00000111 ;get 3 LSB of frame counter
|
|
pha ;and save it to the stack
|
|
lda BlooperMoveCounter,x ;get enemy's movement counter
|
|
lsr ;check for d0 set
|
|
bcs SlowSwim ;branch if set
|
|
pla ;pull 3 LSB of frame counter from the stack
|
|
bne BSwimE ;branch to leave, execute code only every eighth frame
|
|
lda Enemy_Y_MoveForce,x
|
|
clc ;add to movement force to speed up swim
|
|
adc #$01
|
|
sta Enemy_Y_MoveForce,x ;set movement force
|
|
sta BlooperMoveSpeed,x ;set as movement speed
|
|
cmp #$02
|
|
bne BSwimE ;if certain horizontal speed, branch to leave
|
|
inc BlooperMoveCounter,x ;otherwise increment movement counter
|
|
BSwimE rts
|
|
|
|
SlowSwim
|
|
pla ;pull 3 LSB of frame counter from the stack
|
|
bne NoSSw ;branch to leave, execute code only every eighth frame
|
|
lda Enemy_Y_MoveForce,x
|
|
sec ;subtract from movement force to slow swim
|
|
sbc #$01
|
|
sta Enemy_Y_MoveForce,x ;set movement force
|
|
sta BlooperMoveSpeed,x ;set as movement speed
|
|
bne NoSSw ;if any speed, branch to leave
|
|
inc BlooperMoveCounter,x ;otherwise increment movement counter
|
|
lda #$02
|
|
sta EnemyIntervalTimer,x ;set enemy's timer
|
|
NoSSw rts ;leave
|
|
|
|
ChkForFloatdown
|
|
lda EnemyIntervalTimer,x ;get enemy timer
|
|
beq ChkNearPlayer ;branch if expired
|
|
|
|
Floatdown
|
|
lda FrameCounter ;get frame counter
|
|
lsr ;check for d0 set
|
|
bcs NoFD ;branch to leave on every other frame
|
|
inc Enemy_Y_Position,x ;otherwise increment vertical coordinate
|
|
NoFD rts ;leave
|
|
|
|
ChkNearPlayer
|
|
lda Enemy_Y_Position,x ;get vertical coordinate
|
|
adc #$10 ;add sixteen pixels
|
|
cmp Player_Y_Position ;compare result with player's vertical coordinate
|
|
bcc Floatdown ;if modified vertical less than player's, branch
|
|
lda #$00
|
|
sta BlooperMoveCounter,x ;otherwise nullify movement counter
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
MoveBulletBill
|
|
lda Enemy_State,x ;check bullet bill's enemy object state for d5 set
|
|
and #%00100000
|
|
beq NotDefB ;if not set, continue with movement code
|
|
jmp MoveJ_EnemyVertically ;otherwise jump to move defeated bullet bill downwards
|
|
NotDefB lda #$e8 ;set bullet bill's horizontal speed
|
|
sta Enemy_X_Speed,x ;and move it accordingly (note this bullet bill
|
|
jmp MoveEnemyHorizontally ;object occurs in frenzy object $17, not from cannons)
|
|
|
|
;--------------------------------
|
|
;$02 - used to hold preset values
|
|
;$03 - used to hold enemy state
|
|
|
|
SwimCCXMoveData
|
|
db $40,$80
|
|
db $04,$04 ;residual data, not used
|
|
|
|
MoveSwimmingCheepCheep
|
|
lda Enemy_State,x ;check cheep-cheep's enemy object state
|
|
and #%00100000 ;for d5 set
|
|
beq CCSwim ;if not set, continue with movement code
|
|
jmp MoveEnemySlowVert ;otherwise jump to move defeated cheep-cheep downwards
|
|
CCSwim sta $03 ;save enemy state in $03
|
|
lda Enemy_ID,x ;get enemy identifier
|
|
sec
|
|
sbc #$0a ;subtract ten for cheep-cheep identifiers
|
|
tay ;use as offset
|
|
lda SwimCCXMoveData,y ;load value here
|
|
sta $02
|
|
lda Enemy_X_MoveForce,x ;load horizontal force
|
|
sec
|
|
sbc $02 ;subtract preset value from horizontal force
|
|
sta Enemy_X_MoveForce,x ;store as new horizontal force
|
|
lda Enemy_X_Position,x ;get horizontal coordinate
|
|
sbc #$00 ;subtract borrow (thus moving it slowly)
|
|
sta Enemy_X_Position,x ;and save as new horizontal coordinate
|
|
lda Enemy_PageLoc,x
|
|
sbc #$00 ;subtract borrow again, this time from the
|
|
sta Enemy_PageLoc,x ;page location, then save
|
|
lda #$20
|
|
sta $02 ;save new value here
|
|
cpx #$02 ;check enemy object offset
|
|
bcc ExSwCC ;if in first or second slot, branch to leave
|
|
lda CheepCheepMoveMFlag,x ;check movement flag
|
|
cmp #$10 ;if movement speed set to $00,
|
|
bcc CCSwimUpwards ;branch to move upwards
|
|
lda Enemy_YMF_Dummy,x
|
|
clc
|
|
adc $02 ;add preset value to dummy variable to get carry
|
|
sta Enemy_YMF_Dummy,x ;and save dummy
|
|
lda Enemy_Y_Position,x ;get vertical coordinate
|
|
adc $03 ;add carry to it plus enemy state to slowly move it downwards
|
|
sta Enemy_Y_Position,x ;save as new vertical coordinate
|
|
lda Enemy_Y_HighPos,x
|
|
adc #$00 ;add carry to page location and
|
|
jmp ChkSwimYPos ;jump to end of movement code
|
|
|
|
CCSwimUpwards
|
|
lda Enemy_YMF_Dummy,x
|
|
sec
|
|
sbc $02 ;subtract preset value to dummy variable to get borrow
|
|
sta Enemy_YMF_Dummy,x ;and save dummy
|
|
lda Enemy_Y_Position,x ;get vertical coordinate
|
|
sbc $03 ;subtract borrow to it plus enemy state to slowly move it upwards
|
|
sta Enemy_Y_Position,x ;save as new vertical coordinate
|
|
lda Enemy_Y_HighPos,x
|
|
sbc #$00 ;subtract borrow from page location
|
|
|
|
ChkSwimYPos
|
|
sta Enemy_Y_HighPos,x ;save new page location here
|
|
ldy #$00 ;load movement speed to upwards by default
|
|
lda Enemy_Y_Position,x ;get vertical coordinate
|
|
sec
|
|
sbc CheepCheepOrigYPos,x ;subtract original coordinate from current
|
|
bpl YPDiff ;if result positive, skip to next part
|
|
ldy #$10 ;otherwise load movement speed to downwards
|
|
eor #$ff
|
|
clc ;get two's compliment of result
|
|
adc #$01 ;to obtain total difference of original vs. current
|
|
YPDiff cmp #$0f ;if difference between original vs. current vertical
|
|
bcc ExSwCC ;coordinates < 15 pixels, leave movement speed alone
|
|
tya
|
|
sta CheepCheepMoveMFlag,x ;otherwise change movement speed
|
|
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
|
|
db $00,$01,$03,$04,$05,$06,$07,$07,$08
|
|
db $00,$03,$06,$09,$0b,$0d,$0e,$0f,$10
|
|
db $00,$04,$09,$0d,$10,$13,$16,$17,$18
|
|
db $00,$06,$0c,$12,$16,$1a,$1d,$1f,$20
|
|
db $00,$07,$0f,$16,$1c,$21,$25,$27,$28
|
|
db $00,$09,$12,$1b,$21,$27,$2c,$2f,$30
|
|
db $00,$0b,$15,$1f,$27,$2e,$33,$37,$38
|
|
db $00,$0c,$18,$24,$2d,$35,$3b,$3e,$40
|
|
db $00,$0e,$1b,$28,$32,$3b,$42,$46,$48
|
|
db $00,$0f,$1f,$2d,$38,$42,$4a,$4e,$50
|
|
db $00,$11,$22,$31,$3e,$49,$51,$56,$58
|
|
|
|
FirebarMirrorData
|
|
db $01,$03,$02,$00
|
|
|
|
FirebarTblOffsets
|
|
db $00,$09,$12,$1b,$24,$2d
|
|
db $36,$3f,$48,$51,$5a,$63
|
|
|
|
FirebarYPos
|
|
db $0c,$18
|
|
|
|
ProcFirebar
|
|
jsr GetEnemyOffscreenBits ;get offscreen information
|
|
lda Enemy_OffscreenBits ;check for d3 set
|
|
and #%00001000 ;if so, branch to leave
|
|
bne SkipFBar
|
|
lda TimerControl ;if master timer control set, branch
|
|
bne SusFbar ;ahead of this part
|
|
lda FirebarSpinSpeed,x ;load spinning speed of firebar
|
|
jsr FirebarSpin ;modify current spinstate
|
|
and #%00011111 ;mask out all but 5 LSB
|
|
sta FirebarSpinState_High,x ;and store as new high byte of spinstate
|
|
SusFbar lda FirebarSpinState_High,x ;get high byte of spinstate
|
|
ldy Enemy_ID,x ;check enemy identifier
|
|
cpy #$1f
|
|
bcc SetupGFB ;if < $1f (long firebar), branch
|
|
cmp #$08 ;check high byte of spinstate
|
|
beq SkpFSte ;if eight, branch to change
|
|
cmp #$18
|
|
bne SetupGFB ;if not at twenty-four branch to not change
|
|
SkpFSte clc
|
|
adc #$01 ;add one to spinning thing to avoid horizontal state
|
|
sta FirebarSpinState_High,x
|
|
SetupGFB sta $ef ;save high byte of spinning thing, modified or otherwise
|
|
jsr RelativeEnemyPosition ;get relative coordinates to screen
|
|
jsr GetFirebarPosition ;do a sub here (residual, too early to be used now)
|
|
ldy Enemy_SprDataOffset,x ;get OAM data offset
|
|
lda Enemy_Rel_YPos ;get relative vertical coordinate
|
|
sta Sprite_Y_Position,y ;store as Y in OAM data
|
|
sta $07 ;also save here
|
|
lda Enemy_Rel_XPos ;get relative horizontal coordinate
|
|
sta Sprite_X_Position,y ;store as X in OAM data
|
|
sta $06 ;also save here
|
|
lda #$01
|
|
sta $00 ;set $01 value here (not necessary)
|
|
jsr FirebarCollision ;draw fireball part and do collision detection
|
|
ldy #$05 ;load value for short firebars by default
|
|
lda Enemy_ID,x
|
|
cmp #$1f ;are we doing a long firebar?
|
|
bcc SetMFbar ;no, branch then
|
|
ldy #$0b ;otherwise load value for long firebars
|
|
SetMFbar sty $ed ;store maximum value for length of firebars
|
|
lda #$00
|
|
sta $00 ;initialize counter here
|
|
DrawFbar lda $ef ;load high byte of spinstate
|
|
jsr GetFirebarPosition ;get fireball position data depending on firebar part
|
|
jsr DrawFirebar_Collision ;position it properly, draw it and do collision detection
|
|
lda $00 ;check which firebar part
|
|
cmp #$04
|
|
bne NextFbar
|
|
ldy DuplicateObj_Offset ;if we arrive at fifth firebar part,
|
|
lda Enemy_SprDataOffset,y ;get offset from long firebar and load OAM data offset
|
|
sta $06 ;using long firebar offset, then store as new one here
|
|
NextFbar inc $00 ;move onto the next firebar part
|
|
lda $00
|
|
cmp $ed ;if we end up at the maximum part, go on and leave
|
|
bcc DrawFbar ;otherwise go back and do another
|
|
SkipFBar rts
|
|
|
|
DrawFirebar_Collision
|
|
lda $03 ;store mirror data elsewhere
|
|
sta $05
|
|
ldy $06 ;load OAM data offset for firebar
|
|
lda $01 ;load horizontal adder we got from position loader
|
|
lsr $05 ;shift LSB of mirror data
|
|
bcs AddHA ;if carry was set, skip this part
|
|
eor #$ff
|
|
adc #$01 ;otherwise get two's compliment of horizontal adder
|
|
AddHA clc ;add horizontal coordinate relative to screen to
|
|
adc Enemy_Rel_XPos ;horizontal adder, modified or otherwise
|
|
sta Sprite_X_Position,y ;store as X coordinate here
|
|
sta $06 ;store here for now, note offset is saved in Y still
|
|
cmp Enemy_Rel_XPos ;compare X coordinate of sprite to original X of firebar
|
|
bcs SubtR1 ;if sprite coordinate => original coordinate, branch
|
|
lda Enemy_Rel_XPos
|
|
sec ;otherwise subtract sprite X from the
|
|
sbc $06 ;original one and skip this part
|
|
jmp ChkFOfs
|
|
SubtR1 sec ;subtract original X from the
|
|
sbc Enemy_Rel_XPos ;current sprite X
|
|
ChkFOfs cmp #$59 ;if difference of coordinates within a certain range,
|
|
bcc VAHandl ;continue by handling vertical adder
|
|
lda #$f8 ;otherwise, load offscreen Y coordinate
|
|
bne SetVFbr ;and unconditionally branch to move sprite offscreen
|
|
VAHandl lda Enemy_Rel_YPos ;if vertical relative coordinate offscreen,
|
|
cmp #$f8 ;skip ahead of this part and write into sprite Y coordinate
|
|
beq SetVFbr
|
|
lda $02 ;load vertical adder we got from position loader
|
|
lsr $05 ;shift LSB of mirror data one more time
|
|
bcs AddVA ;if carry was set, skip this part
|
|
eor #$ff
|
|
adc #$01 ;otherwise get two's compliment of second part
|
|
AddVA clc ;add vertical coordinate relative to screen to
|
|
adc Enemy_Rel_YPos ;the second data, modified or otherwise
|
|
SetVFbr sta Sprite_Y_Position,y ;store as Y coordinate here
|
|
sta $07 ;also store here for now
|
|
|
|
FirebarCollision
|
|
jsr DrawFirebar ;run sub here to draw current tile of firebar
|
|
tya ;return OAM data offset and save
|
|
pha ;to the stack for now
|
|
lda StarInvincibleTimer ;if star mario invincibility timer
|
|
ora TimerControl ;or master timer controls set
|
|
bne NoColFB ;then skip all of this
|
|
sta $05 ;otherwise initialize counter
|
|
ldy Player_Y_HighPos
|
|
dey ;if player's vertical high byte offscreen,
|
|
bne NoColFB ;skip all of this
|
|
ldy Player_Y_Position ;get player's vertical position
|
|
lda PlayerSize ;get player's size
|
|
bne AdjSm ;if player small, branch to alter variables
|
|
lda CrouchingFlag
|
|
beq BigJp ;if player big and not crouching, jump ahead
|
|
AdjSm inc $05 ;if small or big but crouching, execute this part
|
|
inc $05 ;first increment our counter twice (setting $02 as flag)
|
|
tya
|
|
clc ;then add 24 pixels to the player's
|
|
adc #$18 ;vertical coordinate
|
|
tay
|
|
BigJp tya ;get vertical coordinate, altered or otherwise, from Y
|
|
FBCLoop sec ;subtract vertical position of firebar
|
|
sbc $07 ;from the vertical coordinate of the player
|
|
bpl ChkVFBD ;if player lower on the screen than firebar,
|
|
eor #$ff ;skip two's compliment part
|
|
clc ;otherwise get two's compliment
|
|
adc #$01
|
|
ChkVFBD cmp #$08 ;if difference => 8 pixels, skip ahead of this part
|
|
bcs Chk2Ofs
|
|
lda $06 ;if firebar on far right on the screen, skip this,
|
|
cmp #$f0 ;because, really, what's the point?
|
|
bcs Chk2Ofs
|
|
lda Sprite_X_Position+4 ;get OAM X coordinate for sprite #1
|
|
clc
|
|
adc #$04 ;add four pixels
|
|
sta $04 ;store here
|
|
sec ;subtract horizontal coordinate of firebar
|
|
sbc $06 ;from the X coordinate of player's sprite 1
|
|
bpl ChkFBCl ;if modded X coordinate to the right of firebar
|
|
eor #$ff ;skip two's compliment part
|
|
clc ;otherwise get two's compliment
|
|
adc #$01
|
|
ChkFBCl cmp #$08 ;if difference < 8 pixels, collision, thus branch
|
|
bcc ChgSDir ;to process
|
|
Chk2Ofs lda $05 ;if value of $02 was set earlier for whatever reason,
|
|
cmp #$02 ;branch to increment OAM offset and leave, no collision
|
|
beq NoColFB
|
|
ldy $05 ;otherwise get temp here and use as offset
|
|
lda Player_Y_Position
|
|
clc
|
|
adc FirebarYPos,y ;add value loaded with offset to player's vertical coordinate
|
|
inc $05 ;then increment temp and jump back
|
|
jmp FBCLoop
|
|
ChgSDir ldx #$01 ;set movement direction by default
|
|
lda $04 ;if OAM X coordinate of player's sprite 1
|
|
cmp $06 ;is greater than horizontal coordinate of firebar
|
|
bcs SetSDir ;then do not alter movement direction
|
|
inx ;otherwise increment it
|
|
SetSDir stx Enemy_MovingDir ;store movement direction here
|
|
ldx #$00
|
|
lda $00 ;save value written to $00 to stack
|
|
pha
|
|
jsr InjurePlayer ;perform sub to hurt or kill player
|
|
pla
|
|
sta $00 ;get value of $00 from stack
|
|
NoColFB pla ;get OAM data offset
|
|
clc ;add four to it and save
|
|
adc #$04
|
|
sta $06
|
|
ldx ObjectOffset ;get enemy object buffer offset and leave
|
|
rts
|
|
|
|
GetFirebarPosition
|
|
pha ;save high byte of spinstate to the stack
|
|
and #%00001111 ;mask out low nybble
|
|
cmp #$09
|
|
bcc GetHAdder ;if lower than $09, branch ahead
|
|
eor #%00001111 ;otherwise get two's compliment to oscillate
|
|
clc
|
|
adc #$01
|
|
GetHAdder sta $01 ;store result, modified or not, here
|
|
ldy $00 ;load number of firebar ball where we're at
|
|
lda FirebarTblOffsets,y ;load offset to firebar position data
|
|
clc
|
|
adc $01 ;add oscillated high byte of spinstate
|
|
tay ;to offset here and use as new offset
|
|
lda FirebarPosLookupTbl,y ;get data here and store as horizontal adder
|
|
sta $01
|
|
pla ;pull whatever was in A from the stack
|
|
pha ;save it again because we still need it
|
|
clc
|
|
adc #$08 ;add eight this time, to get vertical adder
|
|
and #%00001111 ;mask out high nybble
|
|
cmp #$09 ;if lower than $09, branch ahead
|
|
bcc GetVAdder
|
|
eor #%00001111 ;otherwise get two's compliment
|
|
clc
|
|
adc #$01
|
|
GetVAdder sta $02 ;store result here
|
|
ldy $00
|
|
lda FirebarTblOffsets,y ;load offset to firebar position data again
|
|
clc
|
|
adc $02 ;this time add value in $02 to offset here and use as offset
|
|
tay
|
|
lda FirebarPosLookupTbl,y ;get data here and store as vertica adder
|
|
sta $02
|
|
pla ;pull out whatever was in A one last time
|
|
lsr ;divide by eight or shift three to the right
|
|
lsr
|
|
lsr
|
|
tay ;use as offset
|
|
lda FirebarMirrorData,y ;load mirroring data here
|
|
sta $03 ;store
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
PRandomSubtracter
|
|
db $f8,$a0,$70,$bd,$00
|
|
|
|
FlyCCBPriority
|
|
db $20,$20,$20,$00,$00
|
|
|
|
MoveFlyingCheepCheep
|
|
lda Enemy_State,x ;check cheep-cheep's enemy state
|
|
and #%00100000 ;for d5 set
|
|
beq FlyCC ;branch to continue code if not set
|
|
lda #$00
|
|
sta Enemy_SprAttrib,x ;otherwise clear sprite attributes
|
|
jmp MoveJ_EnemyVertically ;and jump to move defeated cheep-cheep downwards
|
|
FlyCC jsr MoveEnemyHorizontally ;move cheep-cheep horizontally based on speed and force
|
|
ldy #$0d ;set vertical movement amount
|
|
lda #$05 ;set maximum speed
|
|
jsr SetXMoveAmt ;branch to impose gravity on flying cheep-cheep
|
|
lda Enemy_Y_MoveForce,x
|
|
lsr ;get vertical movement force and
|
|
lsr ;move high nybble to low
|
|
lsr
|
|
lsr
|
|
tay ;save as offset (note this tends to go into reach of code)
|
|
lda Enemy_Y_Position,x ;get vertical position
|
|
sec ;subtract pseudorandom value based on offset from position
|
|
sbc PRandomSubtracter,y
|
|
bpl AddCCF ;if result within top half of screen, skip this part
|
|
eor #$ff
|
|
clc ;otherwise get two's compliment
|
|
adc #$01
|
|
AddCCF cmp #$08 ;if result or two's compliment greater than eight,
|
|
bcs BPGet ;skip to the end without changing movement force
|
|
lda Enemy_Y_MoveForce,x
|
|
clc
|
|
adc #$10 ;otherwise add to it
|
|
sta Enemy_Y_MoveForce,x
|
|
lsr ;move high nybble to low again
|
|
lsr
|
|
lsr
|
|
lsr
|
|
tay
|
|
BPGet lda FlyCCBPriority,y ;load bg priority data and store (this is very likely
|
|
sta Enemy_SprAttrib,x ;broken or residual code, value is overwritten before
|
|
rts ;drawing it next frame), then leave
|
|
|
|
;--------------------------------
|
|
;$00 - used to hold horizontal difference
|
|
;$01-$03 - used to hold difference adjusters
|
|
|
|
LakituDiffAdj
|
|
db $15,$30,$40
|
|
|
|
MoveLakitu
|
|
lda Enemy_State,x ;check lakitu's enemy state
|
|
and #%00100000 ;for d5 set
|
|
beq ChkLS ;if not set, continue with code
|
|
jmp MoveD_EnemyVertically ;otherwise jump to move defeated lakitu downwards
|
|
ChkLS lda Enemy_State,x ;if lakitu's enemy state not set at all,
|
|
beq Fr12S ;go ahead and continue with code
|
|
lda #$00
|
|
sta LakituMoveDirection,x ;otherwise initialize moving direction to move to left
|
|
sta EnemyFrenzyBuffer ;initialize frenzy buffer
|
|
lda #$10
|
|
bne SetLSpd ;load horizontal speed and do unconditional branch
|
|
Fr12S lda #Spiny
|
|
sta EnemyFrenzyBuffer ;set spiny identifier in frenzy buffer
|
|
ldy #$02
|
|
LdLDa lda LakituDiffAdj,y ;load values
|
|
sta $0001,y ;store in zero page
|
|
dey
|
|
bpl LdLDa ;do this until all values are stired
|
|
jsr PlayerLakituDiff ;execute sub to set speed and create spinys
|
|
SetLSpd sta LakituMoveSpeed,x ;set movement speed returned from sub
|
|
ldy #$01 ;set moving direction to right by default
|
|
lda LakituMoveDirection,x
|
|
and #$01 ;get LSB of moving direction
|
|
bne SetLMov ;if set, branch to the end to use moving direction
|
|
lda LakituMoveSpeed,x
|
|
eor #$ff ;get two's compliment of moving speed
|
|
clc
|
|
adc #$01
|
|
sta LakituMoveSpeed,x ;store as new moving speed
|
|
iny ;increment moving direction to left
|
|
SetLMov sty Enemy_MovingDir,x ;store moving direction
|
|
jmp MoveEnemyHorizontally ;move lakitu horizontally
|
|
|
|
PlayerLakituDiff
|
|
ldy #$00 ;set Y for default value
|
|
jsr PlayerEnemyDiff ;get horizontal difference between enemy and player
|
|
bpl ChkLakDif ;branch if enemy is to the right of the player
|
|
iny ;increment Y for left of player
|
|
lda $00
|
|
eor #$ff ;get two's compliment of low byte of horizontal difference
|
|
clc
|
|
adc #$01 ;store two's compliment as horizontal difference
|
|
sta $00
|
|
ChkLakDif lda $00 ;get low byte of horizontal difference
|
|
cmp #$3c ;if within a certain distance of player, branch
|
|
bcc ChkPSpeed
|
|
lda #$3c ;otherwise set maximum distance
|
|
sta $00
|
|
lda Enemy_ID,x ;check if lakitu is in our current enemy slot
|
|
cmp #Lakitu
|
|
bne ChkPSpeed ;if not, branch elsewhere
|
|
tya ;compare contents of Y, now in A
|
|
cmp LakituMoveDirection,x ;to what is being used as horizontal movement direction
|
|
beq ChkPSpeed ;if moving toward the player, branch, do not alter
|
|
lda LakituMoveDirection,x ;if moving to the left beyond maximum distance,
|
|
beq SetLMovD ;branch and alter without delay
|
|
dec LakituMoveSpeed,x ;decrement horizontal speed
|
|
lda LakituMoveSpeed,x ;if horizontal speed not yet at zero, branch to leave
|
|
bne ExMoveLak
|
|
SetLMovD tya ;set horizontal direction depending on horizontal
|
|
sta LakituMoveDirection,x ;difference between enemy and player if necessary
|
|
ChkPSpeed lda $00
|
|
and #%00111100 ;mask out all but four bits in the middle
|
|
lsr ;divide masked difference by four
|
|
lsr
|
|
sta $00 ;store as new value
|
|
ldy #$00 ;init offset
|
|
lda Player_X_Speed
|
|
beq SubDifAdj ;if player not moving horizontally, branch
|
|
lda ScrollAmount
|
|
beq SubDifAdj ;if scroll speed not set, branch to same place
|
|
iny ;otherwise increment offset
|
|
lda Player_X_Speed
|
|
cmp #$19 ;if player not running, branch
|
|
bcc ChkSpinyO
|
|
lda ScrollAmount
|
|
cmp #$02 ;if scroll speed below a certain amount, branch
|
|
bcc ChkSpinyO ;to same place
|
|
iny ;otherwise increment once more
|
|
ChkSpinyO lda Enemy_ID,x ;check for spiny object
|
|
cmp #Spiny
|
|
bne ChkEmySpd ;branch if not found
|
|
lda Player_X_Speed ;if player not moving, skip this part
|
|
bne SubDifAdj
|
|
ChkEmySpd lda Enemy_Y_Speed,x ;check vertical speed
|
|
bne SubDifAdj ;branch if nonzero
|
|
ldy #$00 ;otherwise reinit offset
|
|
SubDifAdj lda $0001,y ;get one of three saved values from earlier
|
|
ldy $00 ;get saved horizontal difference
|
|
SPixelLak sec ;subtract one for each pixel of horizontal difference
|
|
sbc #$01 ;from one of three saved values
|
|
dey
|
|
bpl SPixelLak ;branch until all pixels are subtracted, to adjust difference
|
|
ExMoveLak rts ;leave!!!
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$04-$05 - used to store name table address in little endian order
|
|
|
|
BridgeCollapseData
|
|
db $1a ;axe
|
|
db $58 ;chain
|
|
db $98,$96,$94,$92,$90,$8e,$8c ;bridge
|
|
db $8a,$88,$86,$84,$82,$80
|
|
|
|
BridgeCollapse
|
|
ldx BowserFront_Offset ;get enemy offset for bowser
|
|
lda Enemy_ID,x ;check enemy object identifier for bowser
|
|
cmp #Bowser ;if not found, branch ahead,
|
|
bne SetM2 ;metatile removal not necessary
|
|
stx ObjectOffset ;store as enemy offset here
|
|
lda Enemy_State,x ;if bowser in normal state, skip all of this
|
|
beq RemoveBridge
|
|
and #%01000000 ;if bowser's state has d6 clear, skip to silence music
|
|
beq SetM2
|
|
lda Enemy_Y_Position,x ;check bowser's vertical coordinate
|
|
cmp #$e0 ;if bowser not yet low enough, skip this part ahead
|
|
bcc MoveD_Bowser
|
|
SetM2 lda #Silence ;silence music
|
|
sta EventMusicQueue
|
|
inc OperMode_Task ;move onto next secondary mode in autoctrl mode
|
|
jmp KillAllEnemies ;jump to empty all enemy slots and then leave
|
|
|
|
MoveD_Bowser
|
|
jsr MoveEnemySlowVert ;do a sub to move bowser downwards
|
|
jmp BowserGfxHandler ;jump to draw bowser's front and rear, then leave
|
|
|
|
RemoveBridge
|
|
dec BowserFeetCounter ;decrement timer to control bowser's feet
|
|
bne NoBFall ;if not expired, skip all of this
|
|
lda #$04
|
|
sta BowserFeetCounter ;otherwise, set timer now
|
|
lda BowserBodyControls
|
|
eor #$01 ;invert bit to control bowser's feet
|
|
sta BowserBodyControls
|
|
lda #$22 ;put high byte of name table address here for now
|
|
sta $05
|
|
ldy BridgeCollapseOffset ;get bridge collapse offset here
|
|
lda BridgeCollapseData,y ;load low byte of name table address and store here
|
|
sta $04
|
|
ldy VRAM_Buffer1_Offset ;increment vram buffer offset
|
|
iny
|
|
ldx #$0c ;set offset for tile data for sub to draw blank metatile
|
|
jsr RemBridge ;do sub here to remove bowser's bridge metatiles
|
|
ldx ObjectOffset ;get enemy offset
|
|
jsr MoveVOffset ;set new vram buffer offset
|
|
lda #Sfx_Blast ;load the fireworks/gunfire sound into the square 2 sfx
|
|
sta Square2SoundQueue ;queue while at the same time loading the brick
|
|
lda #Sfx_BrickShatter ;shatter sound into the noise sfx queue thus
|
|
sta NoiseSoundQueue ;producing the unique sound of the bridge collapsing
|
|
inc BridgeCollapseOffset ;increment bridge collapse offset
|
|
lda BridgeCollapseOffset
|
|
cmp #$0f ;if bridge collapse offset has not yet reached
|
|
bne NoBFall ;the end, go ahead and skip this part
|
|
jsr InitVStf ;initialize whatever vertical speed bowser has
|
|
lda #%01000000
|
|
sta Enemy_State,x ;set bowser's state to one of defeated states (d6 set)
|
|
lda #Sfx_BowserFall
|
|
sta Square2SoundQueue ;play bowser defeat sound
|
|
NoBFall jmp BowserGfxHandler ;jump to code that draws bowser
|
|
|
|
;--------------------------------
|
|
|
|
PRandomRange
|
|
db $21,$41,$11,$31
|
|
|
|
RunBowser
|
|
lda Enemy_State,x ;if d5 in enemy state is not set
|
|
and #%00100000 ;then branch elsewhere to run bowser
|
|
beq BowserControl
|
|
lda Enemy_Y_Position,x ;otherwise check vertical position
|
|
cmp #$e0 ;if above a certain point, branch to move defeated bowser
|
|
bcc MoveD_Bowser ;otherwise proceed to KillAllEnemies
|
|
|
|
KillAllEnemies
|
|
ldx #$04 ;start with last enemy slot
|
|
KillLoop jsr EraseEnemyObject ;branch to kill enemy objects
|
|
dex ;move onto next enemy slot
|
|
bpl KillLoop ;do this until all slots are emptied
|
|
sta EnemyFrenzyBuffer ;empty frenzy buffer
|
|
ldx ObjectOffset ;get enemy object offset and leave
|
|
rts
|
|
|
|
BowserControl
|
|
lda #$00
|
|
sta EnemyFrenzyBuffer ;empty frenzy buffer
|
|
lda TimerControl ;if master timer control not set,
|
|
beq ChkMouth ;skip jump and execute code here
|
|
jmp SkipToFB ;otherwise, jump over a bunch of code
|
|
ChkMouth lda BowserBodyControls ;check bowser's mouth
|
|
bpl FeetTmr ;if bit clear, go ahead with code here
|
|
jmp HammerChk ;otherwise skip a whole section starting here
|
|
FeetTmr dec BowserFeetCounter ;decrement timer to control bowser's feet
|
|
bne ResetMDr ;if not expired, skip this part
|
|
lda #$20 ;otherwise, reset timer
|
|
sta BowserFeetCounter
|
|
lda BowserBodyControls ;and invert bit used
|
|
eor #%00000001 ;to control bowser's feet
|
|
sta BowserBodyControls
|
|
ResetMDr lda FrameCounter ;check frame counter
|
|
and #%00001111 ;if not on every sixteenth frame, skip
|
|
bne B_FaceP ;ahead to continue code
|
|
lda #$02 ;otherwise reset moving/facing direction every
|
|
sta Enemy_MovingDir,x ;sixteen frames
|
|
B_FaceP lda EnemyFrameTimer,x ;if timer set here expired,
|
|
beq GetPRCmp ;branch to next section
|
|
jsr PlayerEnemyDiff ;get horizontal difference between player and bowser,
|
|
bpl GetPRCmp ;and branch if bowser to the right of the player
|
|
lda #$01
|
|
sta Enemy_MovingDir,x ;set bowser to move and face to the right
|
|
lda #$02
|
|
sta BowserMovementSpeed ;set movement speed
|
|
lda #$20
|
|
sta EnemyFrameTimer,x ;set timer here
|
|
sta BowserFireBreathTimer ;set timer used for bowser's flame
|
|
lda Enemy_X_Position,x
|
|
cmp #$c8 ;if bowser to the right past a certain point,
|
|
bcs HammerChk ;skip ahead to some other section
|
|
GetPRCmp lda FrameCounter ;get frame counter
|
|
and #%00000011
|
|
bne HammerChk ;execute this code every fourth frame, otherwise branch
|
|
lda Enemy_X_Position,x
|
|
cmp BowserOrigXPos ;if bowser not at original horizontal position,
|
|
bne GetDToO ;branch to skip this part
|
|
lda PseudoRandomBitReg,x
|
|
and #%00000011 ;get pseudorandom offset
|
|
tay
|
|
lda PRandomRange,y ;load value using pseudorandom offset
|
|
sta MaxRangeFromOrigin ;and store here
|
|
GetDToO lda Enemy_X_Position,x
|
|
clc ;add movement speed to bowser's horizontal
|
|
adc BowserMovementSpeed ;coordinate and save as new horizontal position
|
|
sta Enemy_X_Position,x
|
|
ldy Enemy_MovingDir,x
|
|
cpy #$01 ;if bowser moving and facing to the right, skip ahead
|
|
beq HammerChk
|
|
ldy #$ff ;set default movement speed here (move left)
|
|
sec ;get difference of current vs. original
|
|
sbc BowserOrigXPos ;horizontal position
|
|
bpl CompDToO ;if current position to the right of original, skip ahead
|
|
eor #$ff
|
|
clc ;get two's compliment
|
|
adc #$01
|
|
ldy #$01 ;set alternate movement speed here (move right)
|
|
CompDToO cmp MaxRangeFromOrigin ;compare difference with pseudorandom value
|
|
bcc HammerChk ;if difference < pseudorandom value, leave speed alone
|
|
sty BowserMovementSpeed ;otherwise change bowser's movement speed
|
|
HammerChk lda EnemyFrameTimer,x ;if timer set here not expired yet, skip ahead to
|
|
bne MakeBJump ;some other section of code
|
|
jsr MoveEnemySlowVert ;otherwise start by moving bowser downwards
|
|
lda WorldNumber ;check world number
|
|
cmp #World6
|
|
bcc SetHmrTmr ;if world 1-5, skip this part (not time to throw hammers yet)
|
|
lda FrameCounter
|
|
and #%00000011 ;check to see if it's time to execute sub
|
|
bne SetHmrTmr ;if not, skip sub, otherwise
|
|
jsr SpawnHammerObj ;execute sub on every fourth frame to spawn misc object (hammer)
|
|
SetHmrTmr lda Enemy_Y_Position,x ;get current vertical position
|
|
cmp #$80 ;if still above a certain point
|
|
bcc ChkFireB ;then skip to world number check for flames
|
|
lda PseudoRandomBitReg,x
|
|
and #%00000011 ;get pseudorandom offset
|
|
tay
|
|
lda PRandomRange,y ;get value using pseudorandom offset
|
|
sta EnemyFrameTimer,x ;set for timer here
|
|
SkipToFB jmp ChkFireB ;jump to execute flames code
|
|
MakeBJump cmp #$01 ;if timer not yet about to expire,
|
|
bne ChkFireB ;skip ahead to next part
|
|
dec Enemy_Y_Position,x ;otherwise decrement vertical coordinate
|
|
jsr InitVStf ;initialize movement amount
|
|
lda #$fe
|
|
sta Enemy_Y_Speed,x ;set vertical speed to move bowser upwards
|
|
ChkFireB lda WorldNumber ;check world number here
|
|
cmp #World8 ;world 8?
|
|
beq SpawnFBr ;if so, execute this part here
|
|
cmp #World6 ;world 6-7?
|
|
bcs BowserGfxHandler ;if so, skip this part here
|
|
SpawnFBr lda BowserFireBreathTimer ;check timer here
|
|
bne BowserGfxHandler ;if not expired yet, skip all of this
|
|
lda #$20
|
|
sta BowserFireBreathTimer ;set timer here
|
|
lda BowserBodyControls
|
|
eor #%10000000 ;invert bowser's mouth bit to open
|
|
sta BowserBodyControls ;and close bowser's mouth
|
|
bmi ChkFireB ;if bowser's mouth open, loop back
|
|
jsr SetFlameTimer ;get timing for bowser's flame
|
|
ldy SecondaryHardMode
|
|
beq SetFBTmr ;if secondary hard mode flag not set, skip this
|
|
sec
|
|
sbc #$10 ;otherwise subtract from value in A
|
|
SetFBTmr sta BowserFireBreathTimer ;set value as timer here
|
|
lda #BowserFlame ;put bowser's flame identifier
|
|
sta EnemyFrenzyBuffer ;in enemy frenzy buffer
|
|
|
|
;--------------------------------
|
|
|
|
BowserGfxHandler
|
|
jsr ProcessBowserHalf ;do a sub here to process bowser's front
|
|
ldy #$10 ;load default value here to position bowser's rear
|
|
lda Enemy_MovingDir,x ;check moving direction
|
|
lsr
|
|
bcc CopyFToR ;if moving left, use default
|
|
ldy #$f0 ;otherwise load alternate positioning value here
|
|
CopyFToR tya ;move bowser's rear object position value to A
|
|
clc
|
|
adc Enemy_X_Position,x ;add to bowser's front object horizontal coordinate
|
|
ldy DuplicateObj_Offset ;get bowser's rear object offset
|
|
sta Enemy_X_Position,y ;store A as bowser's rear horizontal coordinate
|
|
lda Enemy_Y_Position,x
|
|
clc ;add eight pixels to bowser's front object
|
|
adc #$08 ;vertical coordinate and store as vertical coordinate
|
|
sta Enemy_Y_Position,y ;for bowser's rear
|
|
lda Enemy_State,x
|
|
sta Enemy_State,y ;copy enemy state directly from front to rear
|
|
lda Enemy_MovingDir,x
|
|
sta Enemy_MovingDir,y ;copy moving direction also
|
|
lda ObjectOffset ;save enemy object offset of front to stack
|
|
pha
|
|
ldx DuplicateObj_Offset ;put enemy object offset of rear as current
|
|
stx ObjectOffset
|
|
lda #Bowser ;set bowser's enemy identifier
|
|
sta Enemy_ID,x ;store in bowser's rear object
|
|
jsr ProcessBowserHalf ;do a sub here to process bowser's rear
|
|
pla
|
|
sta ObjectOffset ;get original enemy object offset
|
|
tax
|
|
lda #$00 ;nullify bowser's front/rear graphics flag
|
|
sta BowserGfxFlag
|
|
ExBGfxH rts ;leave!
|
|
|
|
ProcessBowserHalf
|
|
inc BowserGfxFlag ;increment bowser's graphics flag, then run subroutines
|
|
jsr RunRetainerObj ;to get offscreen bits, relative position and draw bowser (finally!)
|
|
lda Enemy_State,x
|
|
bne ExBGfxH ;if either enemy object not in normal state, branch to leave
|
|
lda #$0a
|
|
sta Enemy_BoundBoxCtrl,x ;set bounding box size control
|
|
jsr GetEnemyBoundBox ;get bounding box coordinates
|
|
jmp PlayerEnemyCollision ;do player-to-enemy collision detection
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$00 - used to hold movement force and tile number
|
|
;$01 - used to hold sprite attribute data
|
|
|
|
FlameTimerData
|
|
db $bf,$40,$bf,$bf,$bf,$40,$40,$bf
|
|
|
|
SetFlameTimer
|
|
ldy BowserFlameTimerCtrl ;load counter as offset
|
|
inc BowserFlameTimerCtrl ;increment
|
|
lda BowserFlameTimerCtrl ;mask out all but 3 LSB
|
|
and #%00000111 ;to keep in range of 0-7
|
|
sta BowserFlameTimerCtrl
|
|
lda FlameTimerData,y ;load value to be used then leave
|
|
ExFl rts
|
|
|
|
ProcBowserFlame
|
|
lda TimerControl ;if master timer control flag set,
|
|
bne SetGfxF ;skip all of this
|
|
lda #$40 ;load default movement force
|
|
ldy SecondaryHardMode
|
|
beq SFlmX ;if secondary hard mode flag not set, use default
|
|
lda #$60 ;otherwise load alternate movement force to go faster
|
|
SFlmX sta $00 ;store value here
|
|
lda Enemy_X_MoveForce,x
|
|
sec ;subtract value from movement force
|
|
sbc $00
|
|
sta Enemy_X_MoveForce,x ;save new value
|
|
lda Enemy_X_Position,x
|
|
sbc #$01 ;subtract one from horizontal position to move
|
|
sta Enemy_X_Position,x ;to the left
|
|
lda Enemy_PageLoc,x
|
|
sbc #$00 ;subtract borrow from page location
|
|
sta Enemy_PageLoc,x
|
|
ldy BowserFlamePRandomOfs,x ;get some value here and use as offset
|
|
lda Enemy_Y_Position,x ;load vertical coordinate
|
|
cmp FlameYPosData,y ;compare against coordinate data using $0417,x as offset
|
|
beq SetGfxF ;if equal, branch and do not modify coordinate
|
|
clc
|
|
adc Enemy_Y_MoveForce,x ;otherwise add value here to coordinate and store
|
|
sta Enemy_Y_Position,x ;as new vertical coordinate
|
|
SetGfxF jsr RelativeEnemyPosition ;get new relative coordinates
|
|
lda Enemy_State,x ;if bowser's flame not in normal state,
|
|
bne ExFl ;branch to leave
|
|
lda #$51 ;otherwise, continue
|
|
sta $00 ;write first tile number
|
|
ldy #$02 ;load attributes without vertical flip by default
|
|
lda FrameCounter
|
|
and #%00000010 ;invert vertical flip bit every 2 frames
|
|
beq FlmeAt ;if d1 not set, write default value
|
|
ldy #$82 ;otherwise write value with vertical flip bit set
|
|
FlmeAt sty $01 ;set bowser's flame sprite attributes here
|
|
ldy Enemy_SprDataOffset,x ;get OAM data offset
|
|
ldx #$00
|
|
|
|
DrawFlameLoop
|
|
lda Enemy_Rel_YPos ;get Y relative coordinate of current enemy object
|
|
sta Sprite_Y_Position,y ;write into Y coordinate of OAM data
|
|
lda $00
|
|
sta Sprite_Tilenumber,y ;write current tile number into OAM data
|
|
inc $00 ;increment tile number to draw more bowser's flame
|
|
lda $01
|
|
sta Sprite_Attributes,y ;write saved attributes into OAM data
|
|
lda Enemy_Rel_XPos
|
|
sta Sprite_X_Position,y ;write X relative coordinate of current enemy object
|
|
clc
|
|
adc #$08
|
|
sta Enemy_Rel_XPos ;then add eight to it and store
|
|
iny
|
|
iny
|
|
iny
|
|
iny ;increment Y four times to move onto the next OAM
|
|
inx ;move onto the next OAM, and branch if three
|
|
cpx #$03 ;have not yet been done
|
|
bcc DrawFlameLoop
|
|
ldx ObjectOffset ;reload original enemy offset
|
|
jsr GetEnemyOffscreenBits ;get offscreen information
|
|
ldy Enemy_SprDataOffset,x ;get OAM data offset
|
|
lda Enemy_OffscreenBits ;get enemy object offscreen bits
|
|
lsr ;move d0 to carry and result to stack
|
|
pha
|
|
bcc M3FOfs ;branch if carry not set
|
|
lda #$f8 ;otherwise move sprite offscreen, this part likely
|
|
sta Sprite_Y_Position+12,y ;residual since flame is only made of three sprites
|
|
M3FOfs pla ;get bits from stack
|
|
lsr ;move d1 to carry and move bits back to stack
|
|
pha
|
|
bcc M2FOfs ;branch if carry not set again
|
|
lda #$f8 ;otherwise move third sprite offscreen
|
|
sta Sprite_Y_Position+8,y
|
|
M2FOfs pla ;get bits from stack again
|
|
lsr ;move d2 to carry and move bits back to stack again
|
|
pha
|
|
bcc M1FOfs ;branch if carry not set yet again
|
|
lda #$f8 ;otherwise move second sprite offscreen
|
|
sta Sprite_Y_Position+4,y
|
|
M1FOfs pla ;get bits from stack one last time
|
|
lsr ;move d3 to carry
|
|
bcc ExFlmeD ;branch if carry not set one last time
|
|
lda #$f8
|
|
sta Sprite_Y_Position,y ;otherwise move first sprite offscreen
|
|
ExFlmeD rts ;leave
|
|
|
|
;--------------------------------
|
|
|
|
RunFireworks
|
|
dec ExplosionTimerCounter,x ;decrement explosion timing counter here
|
|
bne SetupExpl ;if not expired, skip this part
|
|
lda #$08
|
|
sta ExplosionTimerCounter,x ;reset counter
|
|
inc ExplosionGfxCounter,x ;increment explosion graphics counter
|
|
lda ExplosionGfxCounter,x
|
|
cmp #$03 ;check explosion graphics counter
|
|
bcs FireworksSoundScore ;if at a certain point, branch to kill this object
|
|
SetupExpl jsr RelativeEnemyPosition ;get relative coordinates of explosion
|
|
lda Enemy_Rel_YPos ;copy relative coordinates
|
|
sta Fireball_Rel_YPos ;from the enemy object to the fireball object
|
|
lda Enemy_Rel_XPos ;first vertical, then horizontal
|
|
sta Fireball_Rel_XPos
|
|
ldy Enemy_SprDataOffset,x ;get OAM data offset
|
|
lda ExplosionGfxCounter,x ;get explosion graphics counter
|
|
jsr DrawExplosion_Fireworks ;do a sub to draw the explosion then leave
|
|
rts
|
|
|
|
FireworksSoundScore
|
|
lda #$00 ;disable enemy buffer flag
|
|
sta Enemy_Flag,x
|
|
lda #Sfx_Blast ;play fireworks/gunfire sound
|
|
sta Square2SoundQueue
|
|
lda #$05 ;set part of score modifier for 500 points
|
|
sta DigitModifier+4
|
|
jmp EndAreaPoints ;jump to award points accordingly then leave
|
|
|
|
;--------------------------------
|
|
|
|
StarFlagYPosAdder
|
|
db $00,$00,$08,$08
|
|
|
|
StarFlagXPosAdder
|
|
db $00,$08,$00,$08
|
|
|
|
StarFlagTileData
|
|
db $54,$55,$56,$57
|
|
|
|
RunStarFlagObj
|
|
lda #$00 ;initialize enemy frenzy buffer
|
|
sta EnemyFrenzyBuffer
|
|
lda StarFlagTaskControl ;check star flag object task number here
|
|
cmp #$05 ;if greater than 5, branch to exit
|
|
bcs StarFlagExit
|
|
jsr JumpEngine ;otherwise jump to appropriate sub
|
|
|
|
dw StarFlagExit
|
|
dw GameTimerFireworks
|
|
dw AwardGameTimerPoints
|
|
dw RaiseFlagSetoffFWorks
|
|
dw DelayToAreaEnd
|
|
|
|
GameTimerFireworks
|
|
ldy #$05 ;set default state for star flag object
|
|
lda GameTimerDisplay+2 ;get game timer's last digit
|
|
cmp #$01
|
|
beq SetFWC ;if last digit of game timer set to 1, skip ahead
|
|
ldy #$03 ;otherwise load new value for state
|
|
cmp #$03
|
|
beq SetFWC ;if last digit of game timer set to 3, skip ahead
|
|
ldy #$00 ;otherwise load one more potential value for state
|
|
cmp #$06
|
|
beq SetFWC ;if last digit of game timer set to 6, skip ahead
|
|
lda #$ff ;otherwise set value for no fireworks
|
|
SetFWC sta FireworksCounter ;set fireworks counter here
|
|
sty Enemy_State,x ;set whatever state we have in star flag object
|
|
|
|
IncrementSFTask1
|
|
inc StarFlagTaskControl ;increment star flag object task number
|
|
|
|
StarFlagExit
|
|
rts ;leave
|
|
|
|
AwardGameTimerPoints
|
|
lda GameTimerDisplay ;check all game timer digits for any intervals left
|
|
ora GameTimerDisplay+1
|
|
ora GameTimerDisplay+2
|
|
beq IncrementSFTask1 ;if no time left on game timer at all, branch to next task
|
|
lda FrameCounter
|
|
and #%00000100 ;check frame counter for d2 set (skip ahead
|
|
beq NoTTick ;for four frames every four frames) branch if not set
|
|
lda #Sfx_TimerTick
|
|
sta Square2SoundQueue ;load timer tick sound
|
|
NoTTick ldy #$23 ;set offset here to subtract from game timer's last digit
|
|
lda #$ff ;set adder here to $ff, or -1, to subtract one
|
|
sta DigitModifier+5 ;from the last digit of the game timer
|
|
jsr DigitsMathRoutine ;subtract digit
|
|
lda #$05 ;set now to add 50 points
|
|
sta DigitModifier+5 ;per game timer interval subtracted
|
|
|
|
EndAreaPoints
|
|
ldy #$0b ;load offset for mario's score by default
|
|
lda CurrentPlayer ;check player on the screen
|
|
beq ELPGive ;if mario, do not change
|
|
ldy #$11 ;otherwise load offset for luigi's score
|
|
ELPGive jsr DigitsMathRoutine ;award 50 points per game timer interval
|
|
lda CurrentPlayer ;get player on the screen (or 500 points per
|
|
asl ;fireworks explosion if branched here from there)
|
|
asl ;shift to high nybble
|
|
asl
|
|
asl
|
|
ora #%00000100 ;add four to set nybble for game timer
|
|
jmp UpdateNumber ;jump to print the new score and game timer
|
|
|
|
RaiseFlagSetoffFWorks
|
|
lda Enemy_Y_Position,x ;check star flag's vertical position
|
|
cmp #$72 ;against preset value
|
|
bcc SetoffF ;if star flag higher vertically, branch to other code
|
|
dec Enemy_Y_Position,x ;otherwise, raise star flag by one pixel
|
|
jmp DrawStarFlag ;and skip this part here
|
|
SetoffF lda FireworksCounter ;check fireworks counter
|
|
beq DrawFlagSetTimer ;if no fireworks left to go off, skip this part
|
|
bmi DrawFlagSetTimer ;if no fireworks set to go off, skip this part
|
|
lda #Fireworks
|
|
sta EnemyFrenzyBuffer ;otherwise set fireworks object in frenzy queue
|
|
|
|
DrawStarFlag
|
|
jsr RelativeEnemyPosition ;get relative coordinates of star flag
|
|
ldy Enemy_SprDataOffset,x ;get OAM data offset
|
|
ldx #$03 ;do four sprites
|
|
DSFLoop lda Enemy_Rel_YPos ;get relative vertical coordinate
|
|
clc
|
|
adc StarFlagYPosAdder,x ;add Y coordinate adder data
|
|
sta Sprite_Y_Position,y ;store as Y coordinate
|
|
lda StarFlagTileData,x ;get tile number
|
|
sta Sprite_Tilenumber,y ;store as tile number
|
|
lda #$22 ;set palette and background priority bits
|
|
sta Sprite_Attributes,y ;store as attributes
|
|
lda Enemy_Rel_XPos ;get relative horizontal coordinate
|
|
clc
|
|
adc StarFlagXPosAdder,x ;add X coordinate adder data
|
|
sta Sprite_X_Position,y ;store as X coordinate
|
|
iny
|
|
iny ;increment OAM data offset four bytes
|
|
iny ;for next sprite
|
|
iny
|
|
dex ;move onto next sprite
|
|
bpl DSFLoop ;do this until all sprites are done
|
|
ldx ObjectOffset ;get enemy object offset and leave
|
|
rts
|
|
|
|
DrawFlagSetTimer
|
|
jsr DrawStarFlag ;do sub to draw star flag
|
|
lda #$06
|
|
sta EnemyIntervalTimer,x ;set interval timer here
|
|
|
|
IncrementSFTask2
|
|
inc StarFlagTaskControl ;move onto next task
|
|
rts
|
|
|
|
DelayToAreaEnd
|
|
jsr DrawStarFlag ;do sub to draw star flag
|
|
lda EnemyIntervalTimer,x ;if interval timer set in previous task
|
|
bne StarFlagExit2 ;not yet expired, branch to leave
|
|
lda EventMusicBuffer ;if event music buffer empty,
|
|
beq IncrementSFTask2 ;branch to increment task
|
|
|
|
StarFlagExit2
|
|
rts ;otherwise leave
|
|
|
|
;--------------------------------
|
|
;$00 - used to store horizontal difference between player and piranha plant
|
|
|
|
MovePiranhaPlant
|
|
lda Enemy_State,x ;check enemy state
|
|
bne PutinPipe ;if set at all, branch to leave
|
|
lda EnemyFrameTimer,x ;check enemy's timer here
|
|
bne PutinPipe ;branch to end if not yet expired
|
|
lda PiranhaPlant_MoveFlag,x ;check movement flag
|
|
bne SetupToMovePPlant ;if moving, skip to part ahead
|
|
lda PiranhaPlant_Y_Speed,x ;if currently rising, branch
|
|
bmi ReversePlantSpeed ;to move enemy upwards out of pipe
|
|
jsr PlayerEnemyDiff ;get horizontal difference between player and
|
|
bpl ChkPlayerNearPipe ;piranha plant, and branch if enemy to right of player
|
|
lda $00 ;otherwise get saved horizontal difference
|
|
eor #$ff
|
|
clc ;and change to two's compliment
|
|
adc #$01
|
|
sta $00 ;save as new horizontal difference
|
|
|
|
ChkPlayerNearPipe
|
|
lda $00 ;get saved horizontal difference
|
|
cmp #$21
|
|
bcc PutinPipe ;if player within a certain distance, branch to leave
|
|
|
|
ReversePlantSpeed
|
|
lda PiranhaPlant_Y_Speed,x ;get vertical speed
|
|
eor #$ff
|
|
clc ;change to two's compliment
|
|
adc #$01
|
|
sta PiranhaPlant_Y_Speed,x ;save as new vertical speed
|
|
inc PiranhaPlant_MoveFlag,x ;increment to set movement flag
|
|
|
|
SetupToMovePPlant
|
|
lda PiranhaPlantDownYPos,x ;get original vertical coordinate (lowest point)
|
|
ldy PiranhaPlant_Y_Speed,x ;get vertical speed
|
|
bpl RiseFallPiranhaPlant ;branch if moving downwards
|
|
lda PiranhaPlantUpYPos,x ;otherwise get other vertical coordinate (highest point)
|
|
|
|
RiseFallPiranhaPlant
|
|
sta $00 ;save vertical coordinate here
|
|
lda FrameCounter ;get frame counter
|
|
lsr
|
|
bcc PutinPipe ;branch to leave if d0 set (execute code every other frame)
|
|
lda TimerControl ;get master timer control
|
|
bne PutinPipe ;branch to leave if set (likely not necessary)
|
|
lda Enemy_Y_Position,x ;get current vertical coordinate
|
|
clc
|
|
adc PiranhaPlant_Y_Speed,x ;add vertical speed to move up or down
|
|
sta Enemy_Y_Position,x ;save as new vertical coordinate
|
|
cmp $00 ;compare against low or high coordinate
|
|
bne PutinPipe ;branch to leave if not yet reached
|
|
lda #$00
|
|
sta PiranhaPlant_MoveFlag,x ;otherwise clear movement flag
|
|
lda #$40
|
|
sta EnemyFrameTimer,x ;set timer to delay piranha plant movement
|
|
|
|
PutinPipe
|
|
lda #%00100000 ;set background priority bit in sprite
|
|
sta Enemy_SprAttrib,x ;attributes to give illusion of being inside pipe
|
|
rts ;then leave
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$07 - spinning speed
|
|
|
|
FirebarSpin
|
|
sta $07 ;save spinning speed here
|
|
lda FirebarSpinDirection,x ;check spinning direction
|
|
bne SpinCounterClockwise ;if moving counter-clockwise, branch to other part
|
|
ldy #$18 ;possibly residual ldy
|
|
lda FirebarSpinState_Low,x
|
|
clc ;add spinning speed to what would normally be
|
|
adc $07 ;the horizontal speed
|
|
sta FirebarSpinState_Low,x
|
|
lda FirebarSpinState_High,x ;add carry to what would normally be the vertical speed
|
|
adc #$00
|
|
rts
|
|
|
|
SpinCounterClockwise
|
|
ldy #$08 ;possibly residual ldy
|
|
lda FirebarSpinState_Low,x
|
|
sec ;subtract spinning speed to what would normally be
|
|
sbc $07 ;the horizontal speed
|
|
sta FirebarSpinState_Low,x
|
|
lda FirebarSpinState_High,x ;add carry to what would normally be the vertical speed
|
|
sbc #$00
|
|
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
|
|
|
|
BalancePlatform
|
|
lda Enemy_Y_HighPos,x ;check high byte of vertical position
|
|
cmp #$03
|
|
bne DoBPl
|
|
jmp EraseEnemyObject ;if far below screen, kill the object
|
|
DoBPl lda Enemy_State,x ;get object's state (set to $ff or other platform offset)
|
|
bpl CheckBalPlatform ;if doing other balance platform, branch to leave
|
|
rts
|
|
|
|
CheckBalPlatform
|
|
tay ;save offset from state as Y
|
|
lda PlatformCollisionFlag,x ;get collision flag of platform
|
|
sta $00 ;store here
|
|
lda Enemy_MovingDir,x ;get moving direction
|
|
beq ChkForFall
|
|
jmp PlatformFall ;if set, jump here
|
|
|
|
ChkForFall
|
|
lda #$2d ;check if platform is above a certain point
|
|
cmp Enemy_Y_Position,x
|
|
bcc ChkOtherForFall ;if not, branch elsewhere
|
|
cpy $00 ;if collision flag is set to same value as
|
|
beq MakePlatformFall ;enemy state, branch to make platforms fall
|
|
clc
|
|
adc #$02 ;otherwise add 2 pixels to vertical position
|
|
sta Enemy_Y_Position,x ;of current platform and branch elsewhere
|
|
jmp StopPlatforms ;to make platforms stop
|
|
|
|
MakePlatformFall
|
|
jmp InitPlatformFall ;make platforms fall
|
|
|
|
ChkOtherForFall
|
|
cmp Enemy_Y_Position,y ;check if other platform is above a certain point
|
|
bcc ChkToMoveBalPlat ;if not, branch elsewhere
|
|
cpx $00 ;if collision flag is set to same value as
|
|
beq MakePlatformFall ;enemy state, branch to make platforms fall
|
|
clc
|
|
adc #$02 ;otherwise add 2 pixels to vertical position
|
|
sta Enemy_Y_Position,y ;of other platform and branch elsewhere
|
|
jmp StopPlatforms ;jump to stop movement and do not return
|
|
|
|
ChkToMoveBalPlat
|
|
lda Enemy_Y_Position,x ;save vertical position to stack
|
|
pha
|
|
lda PlatformCollisionFlag,x ;get collision flag
|
|
bpl ColFlg ;branch if collision
|
|
lda Enemy_Y_MoveForce,x
|
|
clc ;add $05 to contents of moveforce, whatever they be
|
|
adc #$05
|
|
sta $00 ;store here
|
|
lda Enemy_Y_Speed,x
|
|
adc #$00 ;add carry to vertical speed
|
|
bmi PlatDn ;branch if moving downwards
|
|
bne PlatUp ;branch elsewhere if moving upwards
|
|
lda $00
|
|
cmp #$0b ;check if there's still a little force left
|
|
bcc PlatSt ;if not enough, branch to stop movement
|
|
bcs PlatUp ;otherwise keep branch to move upwards
|
|
ColFlg cmp ObjectOffset ;if collision flag matches
|
|
beq PlatDn ;current enemy object offset, branch
|
|
PlatUp jsr MovePlatformUp ;do a sub to move upwards
|
|
jmp DoOtherPlatform ;jump ahead to remaining code
|
|
PlatSt jsr StopPlatforms ;do a sub to stop movement
|
|
jmp DoOtherPlatform ;jump ahead to remaining code
|
|
PlatDn jsr MovePlatformDown ;do a sub to move downwards
|
|
|
|
DoOtherPlatform
|
|
ldy Enemy_State,x ;get offset of other platform
|
|
pla ;get old vertical coordinate from stack
|
|
sec
|
|
sbc Enemy_Y_Position,x ;get difference of old vs. new coordinate
|
|
clc
|
|
adc Enemy_Y_Position,y ;add difference to vertical coordinate of other
|
|
sta Enemy_Y_Position,y ;platform to move it in the opposite direction
|
|
lda PlatformCollisionFlag,x ;if no collision, skip this part here
|
|
bmi DrawEraseRope
|
|
tax ;put offset which collision occurred here
|
|
jsr PositionPlayerOnVPlat ;and use it to position player accordingly
|
|
|
|
DrawEraseRope
|
|
ldy ObjectOffset ;get enemy object offset
|
|
lda Enemy_Y_Speed,y ;check to see if current platform is
|
|
ora Enemy_Y_MoveForce,y ;moving at all
|
|
beq ExitRp ;if not, skip all of this and branch to leave
|
|
ldx VRAM_Buffer1_Offset ;get vram buffer offset
|
|
cpx #$20 ;if offset beyond a certain point, go ahead
|
|
bcs ExitRp ;and skip this, branch to leave
|
|
lda Enemy_Y_Speed,y
|
|
pha ;save two copies of vertical speed to stack
|
|
pha
|
|
jsr SetupPlatformRope ;do a sub to figure out where to put new bg tiles
|
|
lda $01 ;write name table address to vram buffer
|
|
sta VRAM_Buffer1,x ;first the high byte, then the low
|
|
lda $00
|
|
sta VRAM_Buffer1+1,x
|
|
lda #$02 ;set length for 2 bytes
|
|
sta VRAM_Buffer1+2,x
|
|
lda Enemy_Y_Speed,y ;if platform moving upwards, branch
|
|
bmi EraseR1 ;to do something else
|
|
lda #$a2
|
|
sta VRAM_Buffer1+3,x ;otherwise put tile numbers for left
|
|
lda #$a3 ;and right sides of rope in vram buffer
|
|
sta VRAM_Buffer1+4,x
|
|
jmp OtherRope ;jump to skip this part
|
|
EraseR1 lda #$24 ;put blank tiles in vram buffer
|
|
sta VRAM_Buffer1+3,x ;to erase rope
|
|
sta VRAM_Buffer1+4,x
|
|
|
|
OtherRope
|
|
lda Enemy_State,y ;get offset of other platform from state
|
|
tay ;use as Y here
|
|
pla ;pull second copy of vertical speed from stack
|
|
eor #$ff ;invert bits to reverse speed
|
|
jsr SetupPlatformRope ;do sub again to figure out where to put bg tiles
|
|
lda $01 ;write name table address to vram buffer
|
|
sta VRAM_Buffer1+5,x ;this time we're doing putting tiles for
|
|
lda $00 ;the other platform
|
|
sta VRAM_Buffer1+6,x
|
|
lda #$02
|
|
sta VRAM_Buffer1+7,x ;set length again for 2 bytes
|
|
pla ;pull first copy of vertical speed from stack
|
|
bpl EraseR2 ;if moving upwards (note inversion earlier), skip this
|
|
lda #$a2
|
|
sta VRAM_Buffer1+8,x ;otherwise put tile numbers for left
|
|
lda #$a3 ;and right sides of rope in vram
|
|
sta VRAM_Buffer1+9,x ;transfer buffer
|
|
jmp EndRp ;jump to skip this part
|
|
EraseR2 lda #$24 ;put blank tiles in vram buffer
|
|
sta VRAM_Buffer1+8,x ;to erase rope
|
|
sta VRAM_Buffer1+9,x
|
|
EndRp lda #$00 ;put null terminator at the end
|
|
sta VRAM_Buffer1+10,x
|
|
lda VRAM_Buffer1_Offset ;add ten bytes to the vram buffer offset
|
|
clc ;and store
|
|
adc #10
|
|
sta VRAM_Buffer1_Offset
|
|
ExitRp ldx ObjectOffset ;get enemy object buffer offset and leave
|
|
rts
|
|
|
|
SetupPlatformRope
|
|
pha ;save second/third copy to stack
|
|
lda Enemy_X_Position,y ;get horizontal coordinate
|
|
clc
|
|
adc #$08 ;add eight pixels
|
|
ldx SecondaryHardMode ;if secondary hard mode flag set,
|
|
bne GetLRp ;use coordinate as-is
|
|
clc
|
|
adc #$10 ;otherwise add sixteen more pixels
|
|
GetLRp pha ;save modified horizontal coordinate to stack
|
|
lda Enemy_PageLoc,y
|
|
adc #$00 ;add carry to page location
|
|
sta $02 ;and save here
|
|
pla ;pull modified horizontal coordinate
|
|
and #%11110000 ;from the stack, mask out low nybble
|
|
lsr ;and shift three bits to the right
|
|
lsr
|
|
lsr
|
|
sta $00 ;store result here as part of name table low byte
|
|
ldx Enemy_Y_Position,y ;get vertical coordinate
|
|
pla ;get second/third copy of vertical speed from stack
|
|
bpl GetHRp ;skip this part if moving downwards or not at all
|
|
txa
|
|
clc
|
|
adc #$08 ;add eight to vertical coordinate and
|
|
tax ;save as X
|
|
GetHRp txa ;move vertical coordinate to A
|
|
ldx VRAM_Buffer1_Offset ;get vram buffer offset
|
|
asl
|
|
rol ;rotate d7 to d0 and d6 into carry
|
|
pha ;save modified vertical coordinate to stack
|
|
rol ;rotate carry to d0, thus d7 and d6 are at 2 LSB
|
|
and #%00000011 ;mask out all bits but d7 and d6, then set
|
|
ora #%00100000 ;d5 to get appropriate high byte of name table
|
|
sta $01 ;address, then store
|
|
lda $02 ;get saved page location from earlier
|
|
and #$01 ;mask out all but LSB
|
|
asl
|
|
asl ;shift twice to the left and save with the
|
|
ora $01 ;rest of the bits of the high byte, to get
|
|
sta $01 ;the proper name table and the right place on it
|
|
pla ;get modified vertical coordinate from stack
|
|
and #%11100000 ;mask out low nybble and LSB of high nybble
|
|
clc
|
|
adc $00 ;add to horizontal part saved here
|
|
sta $00 ;save as name table low byte
|
|
lda Enemy_Y_Position,y
|
|
cmp #$e8 ;if vertical position not below the
|
|
bcc ExPRp ;bottom of the screen, we're done, branch to leave
|
|
lda $00
|
|
and #%10111111 ;mask out d6 of low byte of name table address
|
|
sta $00
|
|
ExPRp rts ;leave!
|
|
|
|
InitPlatformFall
|
|
tya ;move offset of other platform from Y to X
|
|
tax
|
|
jsr GetEnemyOffscreenBits ;get offscreen bits
|
|
lda #$06
|
|
jsr SetupFloateyNumber ;award 1000 points to player
|
|
lda Player_Rel_XPos
|
|
sta FloateyNum_X_Pos,x ;put floatey number coordinates where player is
|
|
lda Player_Y_Position
|
|
sta FloateyNum_Y_Pos,x
|
|
lda #$01 ;set moving direction as flag for
|
|
sta Enemy_MovingDir,x ;falling platforms
|
|
|
|
StopPlatforms
|
|
jsr InitVStf ;initialize vertical speed and low byte
|
|
sta Enemy_Y_Speed,y ;for both platforms and leave
|
|
sta Enemy_Y_MoveForce,y
|
|
rts
|
|
|
|
PlatformFall
|
|
tya ;save offset for other platform to stack
|
|
pha
|
|
jsr MoveFallingPlatform ;make current platform fall
|
|
pla
|
|
tax ;pull offset from stack and save to X
|
|
jsr MoveFallingPlatform ;make other platform fall
|
|
ldx ObjectOffset
|
|
lda PlatformCollisionFlag,x ;if player not standing on either platform,
|
|
bmi ExPF ;skip this part
|
|
tax ;transfer collision flag offset as offset to X
|
|
jsr PositionPlayerOnVPlat ;and position player appropriately
|
|
ExPF ldx ObjectOffset ;get enemy object buffer offset and leave
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
YMovingPlatform
|
|
lda Enemy_Y_Speed,x ;if platform moving up or down, skip ahead to
|
|
ora Enemy_Y_MoveForce,x ;check on other position
|
|
bne ChkYCenterPos
|
|
sta Enemy_YMF_Dummy,x ;initialize dummy variable
|
|
lda Enemy_Y_Position,x
|
|
cmp YPlatformTopYPos,x ;if current vertical position => top position, branch
|
|
bcs ChkYCenterPos ;ahead of all this
|
|
lda FrameCounter
|
|
and #%00000111 ;check for every eighth frame
|
|
bne SkipIY
|
|
inc Enemy_Y_Position,x ;increase vertical position every eighth frame
|
|
SkipIY jmp ChkYPCollision ;skip ahead to last part
|
|
|
|
ChkYCenterPos
|
|
lda Enemy_Y_Position,x ;if current vertical position < central position, branch
|
|
cmp YPlatformCenterYPos,x ;to slow ascent/move downwards
|
|
bcc YMDown
|
|
jsr MovePlatformUp ;otherwise start slowing descent/moving upwards
|
|
jmp ChkYPCollision
|
|
YMDown jsr MovePlatformDown ;start slowing ascent/moving downwards
|
|
|
|
ChkYPCollision
|
|
lda PlatformCollisionFlag,x ;if collision flag not set here, branch
|
|
bmi ExYPl ;to leave
|
|
jsr PositionPlayerOnVPlat ;otherwise position player appropriately
|
|
ExYPl rts ;leave
|
|
|
|
;--------------------------------
|
|
;$00 - used as adder to position player hotizontally
|
|
|
|
XMovingPlatform
|
|
lda #$0e ;load preset maximum value for secondary counter
|
|
jsr XMoveCntr_Platform ;do a sub to increment counters for movement
|
|
jsr MoveWithXMCntrs ;do a sub to move platform accordingly, and return value
|
|
lda PlatformCollisionFlag,x ;if no collision with player,
|
|
bmi ExXMP ;branch ahead to leave
|
|
|
|
PositionPlayerOnHPlat
|
|
lda Player_X_Position
|
|
clc ;add saved value from second subroutine to
|
|
adc $00 ;current player's position to position
|
|
sta Player_X_Position ;player accordingly in horizontal position
|
|
lda Player_PageLoc ;get player's page location
|
|
ldy $00 ;check to see if saved value here is positive or negative
|
|
bmi PPHSubt ;if negative, branch to subtract
|
|
adc #$00 ;otherwise add carry to page location
|
|
jmp SetPVar ;jump to skip subtraction
|
|
PPHSubt sbc #$00 ;subtract borrow from page location
|
|
SetPVar sta Player_PageLoc ;save result to player's page location
|
|
sty Platform_X_Scroll ;put saved value from second sub here to be used later
|
|
jsr PositionPlayerOnVPlat ;position player vertically and appropriately
|
|
ExXMP rts ;and we are done here
|
|
|
|
;--------------------------------
|
|
|
|
DropPlatform
|
|
lda PlatformCollisionFlag,x ;if no collision between platform and player
|
|
bmi ExDPl ;occurred, just leave without moving anything
|
|
jsr MoveDropPlatform ;otherwise do a sub to move platform down very quickly
|
|
jsr PositionPlayerOnVPlat ;do a sub to position player appropriately
|
|
ExDPl rts ;leave
|
|
|
|
;--------------------------------
|
|
;$00 - residual value from sub
|
|
|
|
RightPlatform
|
|
jsr MoveEnemyHorizontally ;move platform with current horizontal speed, if any
|
|
sta $00 ;store saved value here (residual code)
|
|
lda PlatformCollisionFlag,x ;check collision flag, if no collision between player
|
|
bmi ExRPl ;and platform, branch ahead, leave speed unaltered
|
|
lda #$10
|
|
sta Enemy_X_Speed,x ;otherwise set new speed (gets moving if motionless)
|
|
jsr PositionPlayerOnHPlat ;use saved value from earlier sub to position player
|
|
ExRPl rts ;then leave
|
|
|
|
;--------------------------------
|
|
|
|
MoveLargeLiftPlat
|
|
jsr MoveLiftPlatforms ;execute common to all large and small lift platforms
|
|
jmp ChkYPCollision ;branch to position player correctly
|
|
|
|
MoveSmallPlatform
|
|
jsr MoveLiftPlatforms ;execute common to all large and small lift platforms
|
|
jmp ChkSmallPlatCollision ;branch to position player correctly
|
|
|
|
MoveLiftPlatforms
|
|
lda TimerControl ;if master timer control set, skip all of this
|
|
bne ExLiftP ;and branch to leave
|
|
lda Enemy_YMF_Dummy,x
|
|
clc ;add contents of movement amount to whatever's here
|
|
adc Enemy_Y_MoveForce,x
|
|
sta Enemy_YMF_Dummy,x
|
|
lda Enemy_Y_Position,x ;add whatever vertical speed is set to current
|
|
adc Enemy_Y_Speed,x ;vertical position plus carry to move up or down
|
|
sta Enemy_Y_Position,x ;and then leave
|
|
rts
|
|
|
|
ChkSmallPlatCollision
|
|
lda PlatformCollisionFlag,x ;get bounding box counter saved in collision flag
|
|
beq ExLiftP ;if none found, leave player position alone
|
|
jsr PositionPlayerOnS_Plat ;use to position player correctly
|
|
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
|
|
lda Enemy_ID,x ;check for cheep-cheep object
|
|
cmp #FlyingCheepCheep ;branch to leave if found
|
|
beq ExScrnBd
|
|
lda ScreenLeft_X_Pos ;get horizontal coordinate for left side of screen
|
|
ldy Enemy_ID,x
|
|
cpy #HammerBro ;check for hammer bro object
|
|
beq LimitB
|
|
cpy #PiranhaPlant ;check for piranha plant object
|
|
bne ExtendLB ;these two will be erased sooner than others if too far left
|
|
LimitB adc #$38 ;add 56 pixels to coordinate if hammer bro or piranha plant
|
|
ExtendLB sbc #$48 ;subtract 72 pixels regardless of enemy object
|
|
sta $01 ;store result here
|
|
lda ScreenLeft_PageLoc
|
|
sbc #$00 ;subtract borrow from page location of left side
|
|
sta $00 ;store result here
|
|
lda ScreenRight_X_Pos ;add 72 pixels to the right side horizontal coordinate
|
|
adc #$48
|
|
sta $03 ;store result here
|
|
lda ScreenRight_PageLoc
|
|
adc #$00 ;then add the carry to the page location
|
|
sta $02 ;and store result here
|
|
lda Enemy_X_Position,x ;compare horizontal coordinate of the enemy object
|
|
cmp $01 ;to modified horizontal left edge coordinate to get carry
|
|
lda Enemy_PageLoc,x
|
|
sbc $00 ;then subtract it from the page coordinate of the enemy object
|
|
bmi TooFar ;if enemy object is too far left, branch to erase it
|
|
lda Enemy_X_Position,x ;compare horizontal coordinate of the enemy object
|
|
cmp $03 ;to modified horizontal right edge coordinate to get carry
|
|
lda Enemy_PageLoc,x
|
|
sbc $02 ;then subtract it from the page coordinate of the enemy object
|
|
bmi ExScrnBd ;if enemy object is on the screen, leave, do not erase enemy
|
|
lda Enemy_State,x ;if at this point, enemy is offscreen to the right, so check
|
|
cmp #HammerBro ;if in state used by spiny's egg, do not erase
|
|
beq ExScrnBd
|
|
cpy #PiranhaPlant ;if piranha plant, do not erase
|
|
beq ExScrnBd
|
|
cpy #FlagpoleFlagObject ;if flagpole flag, do not erase
|
|
beq ExScrnBd
|
|
cpy #StarFlagObject ;if star flag, do not erase
|
|
beq ExScrnBd
|
|
cpy #JumpspringObject ;if jumpspring, do not erase
|
|
beq ExScrnBd ;erase all others too far to the right
|
|
TooFar jsr EraseEnemyObject ;erase object if necessary
|
|
ExScrnBd rts ;leave
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
;some unused space
|
|
db $ff,$ff,$ff
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$01 - enemy buffer offset
|
|
|
|
FireballEnemyCollision
|
|
lda Fireball_State,x ;check to see if fireball state is set at all
|
|
beq ExitFBallEnemy ;branch to leave if not
|
|
asl
|
|
bcs ExitFBallEnemy ;branch to leave also if d7 in state is set
|
|
lda FrameCounter
|
|
lsr ;get LSB of frame counter
|
|
bcs ExitFBallEnemy ;branch to leave if set (do routine every other frame)
|
|
txa
|
|
asl ;multiply fireball offset by four
|
|
asl
|
|
clc
|
|
adc #$1c ;then add $1c or 28 bytes to it
|
|
tay ;to use fireball's bounding box coordinates
|
|
ldx #$04
|
|
|
|
FireballEnemyCDLoop
|
|
stx $01 ;store enemy object offset here
|
|
tya
|
|
pha ;push fireball offset to the stack
|
|
lda Enemy_State,x
|
|
and #%00100000 ;check to see if d5 is set in enemy state
|
|
bne NoFToECol ;if so, skip to next enemy slot
|
|
lda Enemy_Flag,x ;check to see if buffer flag is set
|
|
beq NoFToECol ;if not, skip to next enemy slot
|
|
lda Enemy_ID,x ;check enemy identifier
|
|
cmp #$24
|
|
bcc GoombaDie ;if < $24, branch to check further
|
|
cmp #$2b
|
|
bcc NoFToECol ;if in range $24-$2a, skip to next enemy slot
|
|
GoombaDie cmp #Goomba ;check for goomba identifier
|
|
bne NotGoomba ;if not found, continue with code
|
|
lda Enemy_State,x ;otherwise check for defeated state
|
|
cmp #$02 ;if stomped or otherwise defeated,
|
|
bcs NoFToECol ;skip to next enemy slot
|
|
NotGoomba lda EnemyOffscrBitsMasked,x ;if any masked offscreen bits set,
|
|
bne NoFToECol ;skip to next enemy slot
|
|
txa
|
|
asl ;otherwise multiply enemy offset by four
|
|
asl
|
|
clc
|
|
adc #$04 ;add 4 bytes to it
|
|
tax ;to use enemy's bounding box coordinates
|
|
jsr SprObjectCollisionCore ;do fireball-to-enemy collision detection
|
|
ldx ObjectOffset ;return fireball's original offset
|
|
bcc NoFToECol ;if carry clear, no collision, thus do next enemy slot
|
|
lda #%10000000
|
|
sta Fireball_State,x ;set d7 in enemy state
|
|
ldx $01 ;get enemy offset
|
|
jsr HandleEnemyFBallCol ;jump to handle fireball to enemy collision
|
|
NoFToECol pla ;pull fireball offset from stack
|
|
tay ;put it in Y
|
|
ldx $01 ;get enemy object offset
|
|
dex ;decrement it
|
|
bpl FireballEnemyCDLoop ;loop back until collision detection done on all enemies
|
|
|
|
ExitFBallEnemy
|
|
ldx ObjectOffset ;get original fireball offset and leave
|
|
rts
|
|
|
|
BowserIdentities
|
|
db Goomba, GreenKoopa,
|
|
|
|
HandleEnemyFBallCol
|
|
jsr RelativeEnemyPosition ;get relative coordinate of enemy
|
|
ldx $01 ;get current enemy object offset
|
|
lda Enemy_Flag,x ;check buffer flag for d7 set
|
|
bpl ChkBuzzyBeetle ;branch if not set to continue
|
|
and #%00001111 ;otherwise mask out high nybble and
|
|
tax ;use low nybble as enemy offset
|
|
lda Enemy_ID,x
|
|
cmp #Bowser ;check enemy identifier for bowser
|
|
beq HurtBowser ;branch if found
|
|
ldx $01 ;otherwise retrieve current enemy offset
|
|
|
|
ChkBuzzyBeetle
|
|
lda Enemy_ID,x
|
|
cmp #BuzzyBeetle ;check for buzzy beetle
|
|
beq ExHCF ;branch if found to leave (buzzy beetles fireproof)
|
|
cmp #Bowser ;check for bowser one more time (necessary if d7 of flag was clear)
|
|
bne ChkOtherEnemies ;if not found, branch to check other enemies
|
|
|
|
HurtBowser
|
|
dec BowserHitPoints ;decrement bowser's hit points
|
|
bne ExHCF ;if bowser still has hit points, branch to leave
|
|
jsr InitVStf ;otherwise do sub to init vertical speed and movement force
|
|
sta Enemy_X_Speed,x ;initialize horizontal speed
|
|
sta EnemyFrenzyBuffer ;init enemy frenzy buffer
|
|
lda #$fe
|
|
sta Enemy_Y_Speed,x ;set vertical speed to make defeated bowser jump a little
|
|
ldy WorldNumber ;use world number as offset
|
|
lda BowserIdentities,y ;get enemy identifier to replace bowser with
|
|
sta Enemy_ID,x ;set as new enemy identifier
|
|
lda #$20 ;set A to use starting value for state
|
|
cpy #$03 ;check to see if using offset of 3 or more
|
|
bcs SetDBSte ;branch if so
|
|
ora #$03 ;otherwise add 3 to enemy state
|
|
SetDBSte sta Enemy_State,x ;set defeated enemy state
|
|
lda #Sfx_BowserFall
|
|
sta Square2SoundQueue ;load bowser defeat sound
|
|
ldx $01 ;get enemy offset
|
|
lda #$09 ;award 5000 points to player for defeating bowser
|
|
bne EnemySmackScore ;unconditional branch to award points
|
|
|
|
ChkOtherEnemies
|
|
cmp #BulletBill_FrenzyVar
|
|
beq ExHCF ;branch to leave if bullet bill (frenzy variant)
|
|
cmp #Podoboo
|
|
beq ExHCF ;branch to leave if podoboo
|
|
cmp #$15
|
|
bcs ExHCF ;branch to leave if identifier => $15
|
|
|
|
ShellOrBlockDefeat
|
|
lda Enemy_ID,x ;check for piranha plant
|
|
cmp #PiranhaPlant
|
|
bne StnE ;branch if not found
|
|
lda Enemy_Y_Position,x
|
|
adc #$18 ;add 24 pixels to enemy object's vertical position
|
|
sta Enemy_Y_Position,x
|
|
StnE jsr ChkToStunEnemies ;do yet another sub
|
|
lda Enemy_State,x
|
|
and #%00011111 ;mask out 2 MSB of enemy object's state
|
|
ora #%00100000 ;set d5 to defeat enemy and save as new state
|
|
sta Enemy_State,x
|
|
lda #$02 ;award 200 points by default
|
|
ldy Enemy_ID,x ;check for hammer bro
|
|
cpy #HammerBro
|
|
bne GoombaPoints ;branch if not found
|
|
lda #$06 ;award 1000 points for hammer bro
|
|
|
|
GoombaPoints
|
|
cpy #Goomba ;check for goomba
|
|
bne EnemySmackScore ;branch if not found
|
|
lda #$01 ;award 100 points for goomba
|
|
|
|
EnemySmackScore
|
|
jsr SetupFloateyNumber ;update necessary score variables
|
|
lda #Sfx_EnemySmack ;play smack enemy sound
|
|
sta Square1SoundQueue
|
|
ExHCF rts ;and now let's leave
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
PlayerHammerCollision
|
|
lda FrameCounter ;get frame counter
|
|
lsr ;shift d0 into carry
|
|
bcc ExPHC ;branch to leave if d0 not set to execute every other frame
|
|
lda TimerControl ;if either master timer control
|
|
ora Misc_OffscreenBits ;or any offscreen bits for hammer are set,
|
|
bne ExPHC ;branch to leave
|
|
txa
|
|
asl ;multiply misc object offset by four
|
|
asl
|
|
clc
|
|
adc #$24 ;add 36 or $24 bytes to get proper offset
|
|
tay ;for misc object bounding box coordinates
|
|
jsr PlayerCollisionCore ;do player-to-hammer collision detection
|
|
ldx ObjectOffset ;get misc object offset
|
|
bcc ClHCol ;if no collision, then branch
|
|
lda Misc_Collision_Flag,x ;otherwise read collision flag
|
|
bne ExPHC ;if collision flag already set, branch to leave
|
|
lda #$01
|
|
sta Misc_Collision_Flag,x ;otherwise set collision flag now
|
|
lda Misc_X_Speed,x
|
|
eor #$ff ;get two's compliment of
|
|
clc ;hammer's horizontal speed
|
|
adc #$01
|
|
sta Misc_X_Speed,x ;set to send hammer flying the opposite direction
|
|
lda StarInvincibleTimer ;if star mario invincibility timer set,
|
|
bne ExPHC ;branch to leave
|
|
jmp InjurePlayer ;otherwise jump to hurt player, do not return
|
|
ClHCol lda #$00 ;clear collision flag
|
|
sta Misc_Collision_Flag,x
|
|
ExPHC rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
HandlePowerUpCollision
|
|
jsr EraseEnemyObject ;erase the power-up object
|
|
lda #$06
|
|
jsr SetupFloateyNumber ;award 1000 points to player by default
|
|
lda #Sfx_PowerUpGrab
|
|
sta Square2SoundQueue ;play the power-up sound
|
|
lda PowerUpType ;check power-up type
|
|
cmp #$02
|
|
bcc Shroom_Flower_PUp ;if mushroom or fire flower, branch
|
|
cmp #$03
|
|
beq SetFor1Up ;if 1-up mushroom, branch
|
|
lda #$23 ;otherwise set star mario invincibility
|
|
sta StarInvincibleTimer ;timer, and load the star mario music
|
|
lda #StarPowerMusic ;into the area music queue, then leave
|
|
sta AreaMusicQueue
|
|
rts
|
|
|
|
Shroom_Flower_PUp
|
|
lda PlayerStatus ;if player status = small, branch
|
|
beq UpToSuper
|
|
cmp #$01 ;if player status not super, leave
|
|
bne NoPUp
|
|
ldx ObjectOffset ;get enemy offset, not necessary
|
|
lda #$02 ;set player status to fiery
|
|
sta PlayerStatus
|
|
jsr GetPlayerColors ;run sub to change colors of player
|
|
ldx ObjectOffset ;get enemy offset again, and again not necessary
|
|
lda #$0c ;set value to be used by subroutine tree (fiery)
|
|
jmp UpToFiery ;jump to set values accordingly
|
|
|
|
SetFor1Up
|
|
lda #$0b ;change 1000 points into 1-up instead
|
|
sta FloateyNum_Control,x ;and then leave
|
|
rts
|
|
|
|
UpToSuper
|
|
lda #$01 ;set player status to super
|
|
sta PlayerStatus
|
|
lda #$09 ;set value to be used by subroutine tree (super)
|
|
|
|
UpToFiery
|
|
ldy #$00 ;set value to be used as new player state
|
|
jsr SetPRout ;set values to stop certain things in motion
|
|
NoPUp rts
|
|
|
|
;--------------------------------
|
|
|
|
ResidualXSpdData
|
|
db $18,$e8
|
|
|
|
KickedShellXSpdData
|
|
db $30,$d0
|
|
|
|
DemotedKoopaXSpdData
|
|
db $08,$f8
|
|
|
|
PlayerEnemyCollision
|
|
lda FrameCounter ;check counter for d0 set
|
|
lsr
|
|
bcs NoPUp ;if set, branch to leave
|
|
jsr CheckPlayerVertical ;if player object is completely offscreen or
|
|
bcs NoPECol ;if down past 224th pixel row, branch to leave
|
|
lda EnemyOffscrBitsMasked,x ;if current enemy is offscreen by any amount,
|
|
bne NoPECol ;go ahead and branch to leave
|
|
lda GameEngineSubroutine
|
|
cmp #$08 ;if not set to run player control routine
|
|
bne NoPECol ;on next frame, branch to leave
|
|
lda Enemy_State,x
|
|
and #%00100000 ;if enemy state has d5 set, branch to leave
|
|
bne NoPECol
|
|
jsr GetEnemyBoundBoxOfs ;get bounding box offset for current enemy object
|
|
jsr PlayerCollisionCore ;do collision detection on player vs. enemy
|
|
ldx ObjectOffset ;get enemy object buffer offset
|
|
bcs CheckForPUpCollision ;if collision, branch past this part here
|
|
lda Enemy_CollisionBits,x
|
|
and #%11111110 ;otherwise, clear d0 of current enemy object's
|
|
sta Enemy_CollisionBits,x ;collision bit
|
|
NoPECol rts
|
|
|
|
CheckForPUpCollision
|
|
ldy Enemy_ID,x
|
|
cpy #PowerUpObject ;check for power-up object
|
|
bne EColl ;if not found, branch to next part
|
|
jmp HandlePowerUpCollision ;otherwise, unconditional jump backwards
|
|
EColl lda StarInvincibleTimer ;if star mario invincibility timer expired,
|
|
beq HandlePECollisions ;perform task here, otherwise kill enemy like
|
|
jmp ShellOrBlockDefeat ;hit with a shell, or from beneath
|
|
|
|
KickedShellPtsData
|
|
db $0a,$06,$04
|
|
|
|
HandlePECollisions
|
|
lda Enemy_CollisionBits,x ;check enemy collision bits for d0 set
|
|
and #%00000001 ;or for being offscreen at all
|
|
ora EnemyOffscrBitsMasked,x
|
|
bne ExPEC ;branch to leave if either is true
|
|
lda #$01
|
|
ora Enemy_CollisionBits,x ;otherwise set d0 now
|
|
sta Enemy_CollisionBits,x
|
|
cpy #Spiny ;branch if spiny
|
|
beq ChkForPlayerInjury
|
|
cpy #PiranhaPlant ;branch if piranha plant
|
|
beq InjurePlayer
|
|
cpy #Podoboo ;branch if podoboo
|
|
beq InjurePlayer
|
|
cpy #BulletBill_CannonVar ;branch if bullet bill
|
|
beq ChkForPlayerInjury
|
|
cpy #$15 ;branch if object => $15
|
|
bcs InjurePlayer
|
|
lda AreaType ;branch if water type level
|
|
beq InjurePlayer
|
|
lda Enemy_State,x ;branch if d7 of enemy state was set
|
|
asl
|
|
bcs ChkForPlayerInjury
|
|
lda Enemy_State,x ;mask out all but 3 LSB of enemy state
|
|
and #%00000111
|
|
cmp #$02 ;branch if enemy is in normal or falling state
|
|
bcc ChkForPlayerInjury
|
|
lda Enemy_ID,x ;branch to leave if goomba in defeated state
|
|
cmp #Goomba
|
|
beq ExPEC
|
|
lda #Sfx_EnemySmack ;play smack enemy sound
|
|
sta Square1SoundQueue
|
|
lda Enemy_State,x ;set d7 in enemy state, thus become moving shell
|
|
ora #%10000000
|
|
sta Enemy_State,x
|
|
jsr EnemyFacePlayer ;set moving direction and get offset
|
|
lda KickedShellXSpdData,y ;load and set horizontal speed data with offset
|
|
sta Enemy_X_Speed,x
|
|
lda #$03 ;add three to whatever the stomp counter contains
|
|
clc ;to give points for kicking the shell
|
|
adc StompChainCounter
|
|
ldy EnemyIntervalTimer,x ;check shell enemy's timer
|
|
cpy #$03 ;if above a certain point, branch using the points
|
|
bcs KSPts ;data obtained from the stomp counter + 3
|
|
lda KickedShellPtsData,y ;otherwise, set points based on proximity to timer expiration
|
|
KSPts jsr SetupFloateyNumber ;set values for floatey number now
|
|
ExPEC rts ;leave!!!
|
|
|
|
ChkForPlayerInjury
|
|
lda Player_Y_Speed ;check player's vertical speed
|
|
bmi ChkInj ;perform procedure below if player moving upwards
|
|
bne EnemyStomped ;or not at all, and branch elsewhere if moving downwards
|
|
ChkInj lda Enemy_ID,x ;branch if enemy object < $07
|
|
cmp #Bloober
|
|
bcc ChkETmrs
|
|
lda Player_Y_Position ;add 12 pixels to player's vertical position
|
|
clc
|
|
adc #$0c
|
|
cmp Enemy_Y_Position,x ;compare modified player's position to enemy's position
|
|
bcc EnemyStomped ;branch if this player's position above (less than) enemy's
|
|
ChkETmrs lda StompTimer ;check stomp timer
|
|
bne EnemyStomped ;branch if set
|
|
lda InjuryTimer ;check to see if injured invincibility timer still
|
|
bne ExInjColRoutines ;counting down, and branch elsewhere to leave if so
|
|
lda Player_Rel_XPos
|
|
cmp Enemy_Rel_XPos ;if player's relative position to the left of enemy's
|
|
bcc TInjE ;relative position, branch here
|
|
jmp ChkEnemyFaceRight ;otherwise do a jump here
|
|
TInjE lda Enemy_MovingDir,x ;if enemy moving towards the left,
|
|
cmp #$01 ;branch, otherwise do a jump here
|
|
bne InjurePlayer ;to turn the enemy around
|
|
jmp LInj
|
|
|
|
InjurePlayer
|
|
lda InjuryTimer ;check again to see if injured invincibility timer is
|
|
bne ExInjColRoutines ;at zero, and branch to leave if so
|
|
|
|
ForceInjury
|
|
ldx PlayerStatus ;check player's status
|
|
beq KillPlayer ;branch if small
|
|
sta PlayerStatus ;otherwise set player's status to small
|
|
lda #$08
|
|
sta InjuryTimer ;set injured invincibility timer
|
|
asl
|
|
sta Square1SoundQueue ;play pipedown/injury sound
|
|
jsr GetPlayerColors ;change player's palette if necessary
|
|
lda #$0a ;set subroutine to run on next frame
|
|
SetKRout ldy #$01 ;set new player state
|
|
SetPRout sta GameEngineSubroutine ;load new value to run subroutine on next frame
|
|
sty Player_State ;store new player state
|
|
ldy #$ff
|
|
sty TimerControl ;set master timer control flag to halt timers
|
|
iny
|
|
sty ScrollAmount ;initialize scroll speed
|
|
|
|
ExInjColRoutines
|
|
ldx ObjectOffset ;get enemy offset and leave
|
|
rts
|
|
|
|
KillPlayer
|
|
stx Player_X_Speed ;halt player's horizontal movement by initializing speed
|
|
inx
|
|
stx EventMusicQueue ;set event music queue to death music
|
|
lda #$fc
|
|
sta Player_Y_Speed ;set new vertical speed
|
|
lda #$0b ;set subroutine to run on next frame
|
|
bne SetKRout ;branch to set player's state and other things
|
|
|
|
StompedEnemyPtsData
|
|
db $02,$06,$05,$06
|
|
|
|
EnemyStomped
|
|
lda Enemy_ID,x ;check for spiny, branch to hurt player
|
|
cmp #Spiny ;if found
|
|
beq InjurePlayer
|
|
lda #Sfx_EnemyStomp ;otherwise play stomp/swim sound
|
|
sta Square1SoundQueue
|
|
lda Enemy_ID,x
|
|
ldy #$00 ;initialize points data offset for stomped enemies
|
|
cmp #FlyingCheepCheep ;branch for cheep-cheep
|
|
beq EnemyStompedPts
|
|
cmp #BulletBill_FrenzyVar ;branch for either bullet bill object
|
|
beq EnemyStompedPts
|
|
cmp #BulletBill_CannonVar
|
|
beq EnemyStompedPts
|
|
cmp #Podoboo ;branch for podoboo (this branch is logically impossible
|
|
beq EnemyStompedPts ;for cpu to take due to earlier checking of podoboo)
|
|
iny ;increment points data offset
|
|
cmp #HammerBro ;branch for hammer bro
|
|
beq EnemyStompedPts
|
|
iny ;increment points data offset
|
|
cmp #Lakitu ;branch for lakitu
|
|
beq EnemyStompedPts
|
|
iny ;increment points data offset
|
|
cmp #Bloober ;branch if NOT bloober
|
|
bne ChkForDemoteKoopa
|
|
|
|
EnemyStompedPts
|
|
lda StompedEnemyPtsData,y ;load points data using offset in Y
|
|
jsr SetupFloateyNumber ;run sub to set floatey number controls
|
|
lda Enemy_MovingDir,x
|
|
pha ;save enemy movement direction to stack
|
|
jsr SetStun ;run sub to kill enemy
|
|
pla
|
|
sta Enemy_MovingDir,x ;return enemy movement direction from stack
|
|
lda #%00100000
|
|
sta Enemy_State,x ;set d5 in enemy state
|
|
jsr InitVStf ;nullify vertical speed, physics-related thing,
|
|
sta Enemy_X_Speed,x ;and horizontal speed
|
|
lda #$fd ;set player's vertical speed, to give bounce
|
|
sta Player_Y_Speed
|
|
rts
|
|
|
|
ChkForDemoteKoopa
|
|
cmp #$09 ;branch elsewhere if enemy object < $09
|
|
bcc HandleStompedShellE
|
|
and #%00000001 ;demote koopa paratroopas to ordinary troopas
|
|
sta Enemy_ID,x
|
|
ldy #$00 ;return enemy to normal state
|
|
sty Enemy_State,x
|
|
lda #$03 ;award 400 points to the player
|
|
jsr SetupFloateyNumber
|
|
jsr InitVStf ;nullify physics-related thing and vertical speed
|
|
jsr EnemyFacePlayer ;turn enemy around if necessary
|
|
lda DemotedKoopaXSpdData,y
|
|
sta Enemy_X_Speed,x ;set appropriate moving speed based on direction
|
|
jmp SBnce ;then move onto something else
|
|
|
|
RevivalRateData
|
|
db $10,$0b
|
|
|
|
HandleStompedShellE
|
|
lda #$04 ;set defeated state for enemy
|
|
sta Enemy_State,x
|
|
inc StompChainCounter ;increment the stomp counter
|
|
lda StompChainCounter ;add whatever is in the stomp counter
|
|
clc ;to whatever is in the stomp timer
|
|
adc StompTimer
|
|
jsr SetupFloateyNumber ;award points accordingly
|
|
inc StompTimer ;increment stomp timer of some sort
|
|
ldy PrimaryHardMode ;check primary hard mode flag
|
|
lda RevivalRateData,y ;load timer setting according to flag
|
|
sta EnemyIntervalTimer,x ;set as enemy timer to revive stomped enemy
|
|
SBnce lda #$fc ;set player's vertical speed for bounce
|
|
sta Player_Y_Speed ;and then leave!!!
|
|
rts
|
|
|
|
ChkEnemyFaceRight
|
|
lda Enemy_MovingDir,x ;check to see if enemy is moving to the right
|
|
cmp #$01
|
|
bne LInj ;if not, branch
|
|
jmp InjurePlayer ;otherwise go back to hurt player
|
|
LInj jsr EnemyTurnAround ;turn the enemy around, if necessary
|
|
jmp InjurePlayer ;go back to hurt player
|
|
|
|
|
|
EnemyFacePlayer
|
|
ldy #$01 ;set to move right by default
|
|
jsr PlayerEnemyDiff ;get horizontal difference between player and enemy
|
|
bpl SFcRt ;if enemy is to the right of player, do not increment
|
|
iny ;otherwise, increment to set to move to the left
|
|
SFcRt sty Enemy_MovingDir,x ;set moving direction here
|
|
dey ;then decrement to use as a proper offset
|
|
rts
|
|
|
|
SetupFloateyNumber
|
|
sta FloateyNum_Control,x ;set number of points control for floatey numbers
|
|
lda #$30
|
|
sta FloateyNum_Timer,x ;set timer for floatey numbers
|
|
lda Enemy_Y_Position,x
|
|
sta FloateyNum_Y_Pos,x ;set vertical coordinate
|
|
lda Enemy_Rel_XPos
|
|
sta FloateyNum_X_Pos,x ;set horizontal coordinate and leave
|
|
ExSFN rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$01 - used to hold enemy offset for second enemy
|
|
|
|
SetBitsMask
|
|
db %10000000, %01000000,
|
|
|
|
ClearBitsMask
|
|
db %01111111, %10111111,
|
|
|
|
EnemiesCollision
|
|
lda FrameCounter ;check counter for d0 set
|
|
lsr
|
|
bcc ExSFN ;if d0 not set, leave
|
|
lda AreaType
|
|
beq ExSFN ;if water area type, leave
|
|
lda Enemy_ID,x
|
|
cmp #$15 ;if enemy object => $15, branch to leave
|
|
bcs ExitECRoutine
|
|
cmp #Lakitu ;if lakitu, branch to leave
|
|
beq ExitECRoutine
|
|
cmp #PiranhaPlant ;if piranha plant, branch to leave
|
|
beq ExitECRoutine
|
|
lda EnemyOffscrBitsMasked,x ;if masked offscreen bits nonzero, branch to leave
|
|
bne ExitECRoutine
|
|
jsr GetEnemyBoundBoxOfs ;otherwise, do sub, get appropriate bounding box offset for
|
|
dex ;first enemy we're going to compare, then decrement for second
|
|
bmi ExitECRoutine ;branch to leave if there are no other enemies
|
|
ECLoop stx $01 ;save enemy object buffer offset for second enemy here
|
|
tya ;save first enemy's bounding box offset to stack
|
|
pha
|
|
lda Enemy_Flag,x ;check enemy object enable flag
|
|
beq ReadyNextEnemy ;branch if flag not set
|
|
lda Enemy_ID,x
|
|
cmp #$15 ;check for enemy object => $15
|
|
bcs ReadyNextEnemy ;branch if true
|
|
cmp #Lakitu
|
|
beq ReadyNextEnemy ;branch if enemy object is lakitu
|
|
cmp #PiranhaPlant
|
|
beq ReadyNextEnemy ;branch if enemy object is piranha plant
|
|
lda EnemyOffscrBitsMasked,x
|
|
bne ReadyNextEnemy ;branch if masked offscreen bits set
|
|
txa ;get second enemy object's bounding box offset
|
|
asl ;multiply by four, then add four
|
|
asl
|
|
clc
|
|
adc #$04
|
|
tax ;use as new contents of X
|
|
jsr SprObjectCollisionCore ;do collision detection using the two enemies here
|
|
ldx ObjectOffset ;use first enemy offset for X
|
|
ldy $01 ;use second enemy offset for Y
|
|
bcc NoEnemyCollision ;if carry clear, no collision, branch ahead of this
|
|
lda Enemy_State,x
|
|
ora Enemy_State,y ;check both enemy states for d7 set
|
|
and #%10000000
|
|
bne YesEC ;branch if at least one of them is set
|
|
lda Enemy_CollisionBits,y ;load first enemy's collision-related bits
|
|
and SetBitsMask,x ;check to see if bit connected to second enemy is
|
|
bne ReadyNextEnemy ;already set, and move onto next enemy slot if set
|
|
lda Enemy_CollisionBits,y
|
|
ora SetBitsMask,x ;if the bit is not set, set it now
|
|
sta Enemy_CollisionBits,y
|
|
YesEC jsr ProcEnemyCollisions ;react according to the nature of collision
|
|
jmp ReadyNextEnemy ;move onto next enemy slot
|
|
|
|
NoEnemyCollision
|
|
lda Enemy_CollisionBits,y ;load first enemy's collision-related bits
|
|
and ClearBitsMask,x ;clear bit connected to second enemy
|
|
sta Enemy_CollisionBits,y ;then move onto next enemy slot
|
|
|
|
ReadyNextEnemy
|
|
pla ;get first enemy's bounding box offset from the stack
|
|
tay ;use as Y again
|
|
ldx $01 ;get and decrement second enemy's object buffer offset
|
|
dex
|
|
bpl ECLoop ;loop until all enemy slots have been checked
|
|
|
|
ExitECRoutine
|
|
ldx ObjectOffset ;get enemy object buffer offset
|
|
rts ;leave
|
|
|
|
ProcEnemyCollisions
|
|
lda Enemy_State,y ;check both enemy states for d5 set
|
|
ora Enemy_State,x
|
|
and #%00100000 ;if d5 is set in either state, or both, branch
|
|
bne ExitProcessEColl ;to leave and do nothing else at this point
|
|
lda Enemy_State,x
|
|
cmp #$06 ;if second enemy state < $06, branch elsewhere
|
|
bcc ProcSecondEnemyColl
|
|
lda Enemy_ID,x ;check second enemy identifier for hammer bro
|
|
cmp #HammerBro ;if hammer bro found in alt state, branch to leave
|
|
beq ExitProcessEColl
|
|
lda Enemy_State,y ;check first enemy state for d7 set
|
|
asl
|
|
bcc ShellCollisions ;branch if d7 is clear
|
|
lda #$06
|
|
jsr SetupFloateyNumber ;award 1000 points for killing enemy
|
|
jsr ShellOrBlockDefeat ;then kill enemy, then load
|
|
ldy $01 ;original offset of second enemy
|
|
|
|
ShellCollisions
|
|
tya ;move Y to X
|
|
tax
|
|
jsr ShellOrBlockDefeat ;kill second enemy
|
|
ldx ObjectOffset
|
|
lda ShellChainCounter,x ;get chain counter for shell
|
|
clc
|
|
adc #$04 ;add four to get appropriate point offset
|
|
ldx $01
|
|
jsr SetupFloateyNumber ;award appropriate number of points for second enemy
|
|
ldx ObjectOffset ;load original offset of first enemy
|
|
inc ShellChainCounter,x ;increment chain counter for additional enemies
|
|
|
|
ExitProcessEColl
|
|
rts ;leave!!!
|
|
|
|
ProcSecondEnemyColl
|
|
lda Enemy_State,y ;if first enemy state < $06, branch elsewhere
|
|
cmp #$06
|
|
bcc MoveEOfs
|
|
lda Enemy_ID,y ;check first enemy identifier for hammer bro
|
|
cmp #HammerBro ;if hammer bro found in alt state, branch to leave
|
|
beq ExitProcessEColl
|
|
jsr ShellOrBlockDefeat ;otherwise, kill first enemy
|
|
ldy $01
|
|
lda ShellChainCounter,y ;get chain counter for shell
|
|
clc
|
|
adc #$04 ;add four to get appropriate point offset
|
|
ldx ObjectOffset
|
|
jsr SetupFloateyNumber ;award appropriate number of points for first enemy
|
|
ldx $01 ;load original offset of second enemy
|
|
inc ShellChainCounter,x ;increment chain counter for additional enemies
|
|
rts ;leave!!!
|
|
|
|
MoveEOfs
|
|
tya ;move Y ($01) to X
|
|
tax
|
|
jsr EnemyTurnAround ;do the sub here using value from $01
|
|
ldx ObjectOffset ;then do it again using value from $08
|
|
|
|
EnemyTurnAround
|
|
lda Enemy_ID,x ;check for specific enemies
|
|
cmp #PiranhaPlant
|
|
beq ExTA ;if piranha plant, leave
|
|
cmp #Lakitu
|
|
beq ExTA ;if lakitu, leave
|
|
cmp #HammerBro
|
|
beq ExTA ;if hammer bro, leave
|
|
cmp #Spiny
|
|
beq RXSpd ;if spiny, turn it around
|
|
cmp #GreenParatroopaJump
|
|
beq RXSpd ;if green paratroopa, turn it around
|
|
cmp #$07
|
|
bcs ExTA ;if any OTHER enemy object => $07, leave
|
|
RXSpd lda Enemy_X_Speed,x ;load horizontal speed
|
|
eor #$ff ;get two's compliment for horizontal speed
|
|
tay
|
|
iny
|
|
sty Enemy_X_Speed,x ;store as new horizontal speed
|
|
lda Enemy_MovingDir,x
|
|
eor #%00000011 ;invert moving direction and store, then leave
|
|
sta Enemy_MovingDir,x ;thus effectively turning the enemy around
|
|
ExTA rts ;leave!!!
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$00 - vertical position of platform
|
|
|
|
LargePlatformCollision
|
|
lda #$ff ;save value here
|
|
sta PlatformCollisionFlag,x
|
|
lda TimerControl ;check master timer control
|
|
bne ExLPC ;if set, branch to leave
|
|
lda Enemy_State,x ;if d7 set in object state,
|
|
bmi ExLPC ;branch to leave
|
|
lda Enemy_ID,x
|
|
cmp #$24 ;check enemy object identifier for
|
|
bne ChkForPlayerC_LargeP ;balance platform, branch if not found
|
|
lda Enemy_State,x
|
|
tax ;set state as enemy offset here
|
|
jsr ChkForPlayerC_LargeP ;perform code with state offset, then original offset, in X
|
|
|
|
ChkForPlayerC_LargeP
|
|
jsr CheckPlayerVertical ;figure out if player is below a certain point
|
|
bcs ExLPC ;or offscreen, branch to leave if true
|
|
txa
|
|
jsr GetEnemyBoundBoxOfsArg ;get bounding box offset in Y
|
|
lda Enemy_Y_Position,x ;store vertical coordinate in
|
|
sta $00 ;temp variable for now
|
|
txa ;send offset we're on to the stack
|
|
pha
|
|
jsr PlayerCollisionCore ;do player-to-platform collision detection
|
|
pla ;retrieve offset from the stack
|
|
tax
|
|
bcc ExLPC ;if no collision, branch to leave
|
|
jsr ProcLPlatCollisions ;otherwise collision, perform sub
|
|
ExLPC ldx ObjectOffset ;get enemy object buffer offset and leave
|
|
rts
|
|
|
|
;--------------------------------
|
|
;$00 - counter for bounding boxes
|
|
|
|
SmallPlatformCollision
|
|
lda TimerControl ;if master timer control set,
|
|
bne ExSPC ;branch to leave
|
|
sta PlatformCollisionFlag,x ;otherwise initialize collision flag
|
|
jsr CheckPlayerVertical ;do a sub to see if player is below a certain point
|
|
bcs ExSPC ;or entirely offscreen, and branch to leave if true
|
|
lda #$02
|
|
sta $00 ;load counter here for 2 bounding boxes
|
|
|
|
ChkSmallPlatLoop
|
|
ldx ObjectOffset ;get enemy object offset
|
|
jsr GetEnemyBoundBoxOfs ;get bounding box offset in Y
|
|
and #%00000010 ;if d1 of offscreen lower nybble bits was set
|
|
bne ExSPC ;then branch to leave
|
|
lda BoundingBox_UL_YPos,y ;check top of platform's bounding box for being
|
|
cmp #$20 ;above a specific point
|
|
bcc MoveBoundBox ;if so, branch, don't do collision detection
|
|
jsr PlayerCollisionCore ;otherwise, perform player-to-platform collision detection
|
|
bcs ProcSPlatCollisions ;skip ahead if collision
|
|
|
|
MoveBoundBox
|
|
lda BoundingBox_UL_YPos,y ;move bounding box vertical coordinates
|
|
clc ;128 pixels downwards
|
|
adc #$80
|
|
sta BoundingBox_UL_YPos,y
|
|
lda BoundingBox_DR_YPos,y
|
|
clc
|
|
adc #$80
|
|
sta BoundingBox_DR_YPos,y
|
|
dec $00 ;decrement counter we set earlier
|
|
bne ChkSmallPlatLoop ;loop back until both bounding boxes are checked
|
|
ExSPC ldx ObjectOffset ;get enemy object buffer offset, then leave
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
ProcSPlatCollisions
|
|
ldx ObjectOffset ;return enemy object buffer offset to X, then continue
|
|
|
|
ProcLPlatCollisions
|
|
lda BoundingBox_DR_YPos,y ;get difference by subtracting the top
|
|
sec ;of the player's bounding box from the bottom
|
|
sbc BoundingBox_UL_YPos ;of the platform's bounding box
|
|
cmp #$04 ;if difference too large or negative,
|
|
bcs ChkForTopCollision ;branch, do not alter vertical speed of player
|
|
lda Player_Y_Speed ;check to see if player's vertical speed is moving down
|
|
bpl ChkForTopCollision ;if so, don't mess with it
|
|
lda #$01 ;otherwise, set vertical
|
|
sta Player_Y_Speed ;speed of player to kill jump
|
|
|
|
ChkForTopCollision
|
|
lda BoundingBox_DR_YPos ;get difference by subtracting the top
|
|
sec ;of the platform's bounding box from the bottom
|
|
sbc BoundingBox_UL_YPos,y ;of the player's bounding box
|
|
cmp #$06
|
|
bcs PlatformSideCollisions ;if difference not close enough, skip all of this
|
|
lda Player_Y_Speed
|
|
bmi PlatformSideCollisions ;if player's vertical speed moving upwards, skip this
|
|
lda $00 ;get saved bounding box counter from earlier
|
|
ldy Enemy_ID,x
|
|
cpy #$2b ;if either of the two small platform objects are found,
|
|
beq SetCollisionFlag ;regardless of which one, branch to use bounding box counter
|
|
cpy #$2c ;as contents of collision flag
|
|
beq SetCollisionFlag
|
|
txa ;otherwise use enemy object buffer offset
|
|
|
|
SetCollisionFlag
|
|
ldx ObjectOffset ;get enemy object buffer offset
|
|
sta PlatformCollisionFlag,x ;save either bounding box counter or enemy offset here
|
|
lda #$00
|
|
sta Player_State ;set player state to normal then leave
|
|
rts
|
|
|
|
PlatformSideCollisions
|
|
lda #$01 ;set value here to indicate possible horizontal
|
|
sta $00 ;collision on left side of platform
|
|
lda BoundingBox_DR_XPos ;get difference by subtracting platform's left edge
|
|
sec ;from player's right edge
|
|
sbc BoundingBox_UL_XPos,y
|
|
cmp #$08 ;if difference close enough, skip all of this
|
|
bcc SideC
|
|
inc $00 ;otherwise increment value set here for right side collision
|
|
lda BoundingBox_DR_XPos,y ;get difference by subtracting player's left edge
|
|
clc ;from platform's right edge
|
|
sbc BoundingBox_UL_XPos
|
|
cmp #$09 ;if difference not close enough, skip subroutine
|
|
bcs NoSideC ;and instead branch to leave (no collision)
|
|
SideC jsr ImpedePlayerMove ;deal with horizontal collision
|
|
NoSideC ldx ObjectOffset ;return with enemy object buffer offset
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
PlayerPosSPlatData
|
|
db $80,$00
|
|
|
|
PositionPlayerOnS_Plat
|
|
tay ;use bounding box counter saved in collision flag
|
|
lda Enemy_Y_Position,x ;for offset
|
|
clc ;add positioning data using offset to the vertical
|
|
adc PlayerPosSPlatData-1,y ;coordinate
|
|
db $2c ;BIT instruction opcode
|
|
|
|
PositionPlayerOnVPlat
|
|
lda Enemy_Y_Position,x ;get vertical coordinate
|
|
ldy GameEngineSubroutine
|
|
cpy #$0b ;if certain routine being executed on this frame,
|
|
beq ExPlPos ;skip all of this
|
|
ldy Enemy_Y_HighPos,x
|
|
cpy #$01 ;if vertical high byte offscreen, skip this
|
|
bne ExPlPos
|
|
sec ;subtract 32 pixels from vertical coordinate
|
|
sbc #$20 ;for the player object's height
|
|
sta Player_Y_Position ;save as player's new vertical coordinate
|
|
tya
|
|
sbc #$00 ;subtract borrow and store as player's
|
|
sta Player_Y_HighPos ;new vertical high byte
|
|
lda #$00
|
|
sta Player_Y_Speed ;initialize vertical speed and low byte of force
|
|
sta Player_Y_MoveForce ;and then leave
|
|
ExPlPos rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
CheckPlayerVertical
|
|
lda Player_OffscreenBits ;if player object is completely offscreen
|
|
cmp #$f0 ;vertically, leave this routine
|
|
bcs ExCPV
|
|
ldy Player_Y_HighPos ;if player high vertical byte is not
|
|
dey ;within the screen, leave this routine
|
|
bne ExCPV
|
|
lda Player_Y_Position ;if on the screen, check to see how far down
|
|
cmp #$d0 ;the player is vertically
|
|
ExCPV rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
GetEnemyBoundBoxOfs
|
|
lda ObjectOffset ;get enemy object buffer offset
|
|
|
|
GetEnemyBoundBoxOfsArg
|
|
asl ;multiply A by four, then add four
|
|
asl ;to skip player's bounding box
|
|
clc
|
|
adc #$04
|
|
tay ;send to Y
|
|
lda Enemy_OffscreenBits ;get offscreen bits for enemy object
|
|
and #%00001111 ;save low nybble
|
|
cmp #%00001111 ;check for all bits set
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$00-$01 - used to hold many values, essentially temp variables
|
|
;$04 - holds lower nybble of vertical coordinate from block buffer routine
|
|
;$eb - used to hold block buffer adder
|
|
|
|
PlayerBGUpperExtent
|
|
db $20,$10
|
|
|
|
PlayerBGCollision
|
|
lda DisableCollisionDet ;if collision detection disabled flag set,
|
|
bne ExPBGCol ;branch to leave
|
|
lda GameEngineSubroutine
|
|
cmp #$0b ;if running routine #11 or $0b
|
|
beq ExPBGCol ;branch to leave
|
|
cmp #$04
|
|
bcc ExPBGCol ;if running routines $00-$03 branch to leave
|
|
lda #$01 ;load default player state for swimming
|
|
ldy SwimmingFlag ;if swimming flag set,
|
|
bne SetPSte ;branch ahead to set default state
|
|
lda Player_State ;if player in normal state,
|
|
beq SetFallS ;branch to set default state for falling
|
|
cmp #$03
|
|
bne ChkOnScr ;if in any other state besides climbing, skip to next part
|
|
SetFallS lda #$02 ;load default player state for falling
|
|
SetPSte sta Player_State ;set whatever player state is appropriate
|
|
ChkOnScr lda Player_Y_HighPos
|
|
cmp #$01 ;check player's vertical high byte for still on the screen
|
|
bne ExPBGCol ;branch to leave if not
|
|
lda #$ff
|
|
sta Player_CollisionBits ;initialize player's collision flag
|
|
lda Player_Y_Position
|
|
cmp #$cf ;check player's vertical coordinate
|
|
bcc ChkCollSize ;if not too close to the bottom of screen, continue
|
|
ExPBGCol rts ;otherwise leave
|
|
|
|
ChkCollSize
|
|
ldy #$02 ;load default offset
|
|
lda CrouchingFlag
|
|
bne GBBAdr ;if player crouching, skip ahead
|
|
lda PlayerSize
|
|
bne GBBAdr ;if player small, skip ahead
|
|
dey ;otherwise decrement offset for big player not crouching
|
|
lda SwimmingFlag
|
|
bne GBBAdr ;if swimming flag set, skip ahead
|
|
dey ;otherwise decrement offset
|
|
GBBAdr lda BlockBufferAdderData,y ;get value using offset
|
|
sta $eb ;store value here
|
|
tay ;put value into Y, as offset for block buffer routine
|
|
ldx PlayerSize ;get player's size as offset
|
|
lda CrouchingFlag
|
|
beq HeadChk ;if player not crouching, branch ahead
|
|
inx ;otherwise increment size as offset
|
|
HeadChk lda Player_Y_Position ;get player's vertical coordinate
|
|
cmp PlayerBGUpperExtent,x ;compare with upper extent value based on offset
|
|
bcc DoFootCheck ;if player is too high, skip this part
|
|
jsr BlockBufferColli_Head ;do player-to-bg collision detection on top of
|
|
beq DoFootCheck ;player, and branch if nothing above player's head
|
|
jsr CheckForCoinMTiles ;check to see if player touched coin with their head
|
|
bcs AwardTouchedCoin ;if so, branch to some other part of code
|
|
ldy Player_Y_Speed ;check player's vertical speed
|
|
bpl DoFootCheck ;if player not moving upwards, branch elsewhere
|
|
ldy $04 ;check lower nybble of vertical coordinate returned
|
|
cpy #$04 ;from collision detection routine
|
|
bcc DoFootCheck ;if low nybble < 4, branch
|
|
jsr CheckForSolidMTiles ;check to see what player's head bumped on
|
|
bcs SolidOrClimb ;if player collided with solid metatile, branch
|
|
ldy AreaType ;otherwise check area type
|
|
beq NYSpd ;if water level, branch ahead
|
|
ldy BlockBounceTimer ;if block bounce timer not expired,
|
|
bne NYSpd ;branch ahead, do not process collision
|
|
jsr PlayerHeadCollision ;otherwise do a sub to process collision
|
|
jmp DoFootCheck ;jump ahead to skip these other parts here
|
|
|
|
SolidOrClimb
|
|
cmp #$26 ;if climbing metatile,
|
|
beq NYSpd ;branch ahead and do not play sound
|
|
lda #Sfx_Bump
|
|
sta Square1SoundQueue ;otherwise load bump sound
|
|
NYSpd lda #$01 ;set player's vertical speed to nullify
|
|
sta Player_Y_Speed ;jump or swim
|
|
|
|
DoFootCheck
|
|
ldy $eb ;get block buffer adder offset
|
|
lda Player_Y_Position
|
|
cmp #$cf ;check to see how low player is
|
|
bcs DoPlayerSideCheck ;if player is too far down on screen, skip all of this
|
|
jsr BlockBufferColli_Feet ;do player-to-bg collision detection on bottom left of player
|
|
jsr CheckForCoinMTiles ;check to see if player touched coin with their left foot
|
|
bcs AwardTouchedCoin ;if so, branch to some other part of code
|
|
pha ;save bottom left metatile to stack
|
|
jsr BlockBufferColli_Feet ;do player-to-bg collision detection on bottom right of player
|
|
sta $00 ;save bottom right metatile here
|
|
pla
|
|
sta $01 ;pull bottom left metatile and save here
|
|
bne ChkFootMTile ;if anything here, skip this part
|
|
lda $00 ;otherwise check for anything in bottom right metatile
|
|
beq DoPlayerSideCheck ;and skip ahead if not
|
|
jsr CheckForCoinMTiles ;check to see if player touched coin with their right foot
|
|
bcc ChkFootMTile ;if not, skip unconditional jump and continue code
|
|
|
|
AwardTouchedCoin
|
|
jmp HandleCoinMetatile ;follow the code to erase coin and award to player 1 coin
|
|
|
|
ChkFootMTile
|
|
jsr CheckForClimbMTiles ;check to see if player landed on climbable metatiles
|
|
bcs DoPlayerSideCheck ;if so, branch
|
|
ldy Player_Y_Speed ;check player's vertical speed
|
|
bmi DoPlayerSideCheck ;if player moving upwards, branch
|
|
cmp #$c5
|
|
bne ContChk ;if player did not touch axe, skip ahead
|
|
jmp HandleAxeMetatile ;otherwise jump to set modes of operation
|
|
ContChk jsr ChkInvisibleMTiles ;do sub to check for hidden coin or 1-up blocks
|
|
beq DoPlayerSideCheck ;if either found, branch
|
|
ldy JumpspringAnimCtrl ;if jumpspring animating right now,
|
|
bne InitSteP ;branch ahead
|
|
ldy $04 ;check lower nybble of vertical coordinate returned
|
|
cpy #$05 ;from collision detection routine
|
|
bcc LandPlyr ;if lower nybble < 5, branch
|
|
lda Player_MovingDir
|
|
sta $00 ;use player's moving direction as temp variable
|
|
jmp ImpedePlayerMove ;jump to impede player's movement in that direction
|
|
LandPlyr jsr ChkForLandJumpSpring ;do sub to check for jumpspring metatiles and deal with it
|
|
lda #$f0
|
|
and Player_Y_Position ;mask out lower nybble of player's vertical position
|
|
sta Player_Y_Position ;and store as new vertical position to land player properly
|
|
jsr HandlePipeEntry ;do sub to process potential pipe entry
|
|
lda #$00
|
|
sta Player_Y_Speed ;initialize vertical speed and fractional
|
|
sta Player_Y_MoveForce ;movement force to stop player's vertical movement
|
|
sta StompChainCounter ;initialize enemy stomp counter
|
|
InitSteP lda #$00
|
|
sta Player_State ;set player's state to normal
|
|
|
|
DoPlayerSideCheck
|
|
ldy $eb ;get block buffer adder offset
|
|
iny
|
|
iny ;increment offset 2 bytes to use adders for side collisions
|
|
lda #$02 ;set value here to be used as counter
|
|
sta $00
|
|
|
|
SideCheckLoop
|
|
iny ;move onto the next one
|
|
sty $eb ;store it
|
|
lda Player_Y_Position
|
|
cmp #$20 ;check player's vertical position
|
|
bcc BHalf ;if player is in status bar area, branch ahead to skip this part
|
|
cmp #$e4
|
|
bcs ExSCH ;branch to leave if player is too far down
|
|
jsr BlockBufferColli_Side ;do player-to-bg collision detection on one half of player
|
|
beq BHalf ;branch ahead if nothing found
|
|
cmp #$1c ;otherwise check for pipe metatiles
|
|
beq BHalf ;if collided with sideways pipe (top), branch ahead
|
|
cmp #$6b
|
|
beq BHalf ;if collided with water pipe (top), branch ahead
|
|
jsr CheckForClimbMTiles ;do sub to see if player bumped into anything climbable
|
|
bcc CheckSideMTiles ;if not, branch to alternate section of code
|
|
BHalf ldy $eb ;load block adder offset
|
|
iny ;increment it
|
|
lda Player_Y_Position ;get player's vertical position
|
|
cmp #$08
|
|
bcc ExSCH ;if too high, branch to leave
|
|
cmp #$d0
|
|
bcs ExSCH ;if too low, branch to leave
|
|
jsr BlockBufferColli_Side ;do player-to-bg collision detection on other half of player
|
|
bne CheckSideMTiles ;if something found, branch
|
|
dec $00 ;otherwise decrement counter
|
|
bne SideCheckLoop ;run code until both sides of player are checked
|
|
ExSCH rts ;leave
|
|
|
|
CheckSideMTiles
|
|
jsr ChkInvisibleMTiles ;check for hidden or coin 1-up blocks
|
|
beq ExCSM ;branch to leave if either found
|
|
jsr CheckForClimbMTiles ;check for climbable metatiles
|
|
bcc ContSChk ;if not found, skip and continue with code
|
|
jmp HandleClimbing ;otherwise jump to handle climbing
|
|
ContSChk jsr CheckForCoinMTiles ;check to see if player touched coin
|
|
bcs HandleCoinMetatile ;if so, execute code to erase coin and award to player 1 coin
|
|
jsr ChkJumpspringMetatiles ;check for jumpspring metatiles
|
|
bcc ChkPBtm ;if not found, branch ahead to continue cude
|
|
lda JumpspringAnimCtrl ;otherwise check jumpspring animation control
|
|
bne ExCSM ;branch to leave if set
|
|
jmp StopPlayerMove ;otherwise jump to impede player's movement
|
|
ChkPBtm ldy Player_State ;get player's state
|
|
cpy #$00 ;check for player's state set to normal
|
|
bne StopPlayerMove ;if not, branch to impede player's movement
|
|
ldy PlayerFacingDir ;get player's facing direction
|
|
dey
|
|
bne StopPlayerMove ;if facing left, branch to impede movement
|
|
cmp #$6c ;otherwise check for pipe metatiles
|
|
beq PipeDwnS ;if collided with sideways pipe (bottom), branch
|
|
cmp #$1f ;if collided with water pipe (bottom), continue
|
|
bne StopPlayerMove ;otherwise branch to impede player's movement
|
|
PipeDwnS lda Player_SprAttrib ;check player's attributes
|
|
bne PlyrPipe ;if already set, branch, do not play sound again
|
|
ldy #Sfx_PipeDown_Injury
|
|
sty Square1SoundQueue ;otherwise load pipedown/injury sound
|
|
PlyrPipe ora #%00100000
|
|
sta Player_SprAttrib ;set background priority bit in player attributes
|
|
lda Player_X_Position
|
|
and #%00001111 ;get lower nybble of player's horizontal coordinate
|
|
beq ChkGERtn ;if at zero, branch ahead to skip this part
|
|
ldy #$00 ;set default offset for timer setting data
|
|
lda ScreenLeft_PageLoc ;load page location for left side of screen
|
|
beq SetCATmr ;if at page zero, use default offset
|
|
iny ;otherwise increment offset
|
|
SetCATmr lda AreaChangeTimerData,y ;set timer for change of area as appropriate
|
|
sta ChangeAreaTimer
|
|
ChkGERtn lda GameEngineSubroutine ;get number of game engine routine running
|
|
cmp #$07
|
|
beq ExCSM ;if running player entrance routine or
|
|
cmp #$08 ;player control routine, go ahead and branch to leave
|
|
bne ExCSM
|
|
lda #$02
|
|
sta GameEngineSubroutine ;otherwise set sideways pipe entry routine to run
|
|
rts ;and leave
|
|
|
|
;--------------------------------
|
|
;$02 - high nybble of vertical coordinate from block buffer
|
|
;$04 - low nybble of horizontal coordinate from block buffer
|
|
;$06-$07 - block buffer address
|
|
|
|
StopPlayerMove
|
|
jsr ImpedePlayerMove ;stop player's movement
|
|
ExCSM rts ;leave
|
|
|
|
AreaChangeTimerData
|
|
db $a0,$34
|
|
|
|
HandleCoinMetatile
|
|
jsr ErACM ;do sub to erase coin metatile from block buffer
|
|
inc CoinTallyFor1Ups ;increment coin tally used for 1-up blocks
|
|
jmp GiveOneCoin ;update coin amount and tally on the screen
|
|
|
|
HandleAxeMetatile
|
|
lda #$00
|
|
sta OperMode_Task ;reset secondary mode
|
|
lda #$02
|
|
sta OperMode ;set primary mode to autoctrl mode
|
|
lda #$18
|
|
sta Player_X_Speed ;set horizontal speed and continue to erase axe metatile
|
|
ErACM ldy $02 ;load vertical high nybble offset for block buffer
|
|
lda #$00 ;load blank metatile
|
|
sta ($06),y ;store to remove old contents from block buffer
|
|
jmp RemoveCoin_Axe ;update the screen accordingly
|
|
|
|
;--------------------------------
|
|
;$02 - high nybble of vertical coordinate from block buffer
|
|
;$04 - low nybble of horizontal coordinate from block buffer
|
|
;$06-$07 - block buffer address
|
|
|
|
ClimbXPosAdder
|
|
db $f9,$07
|
|
|
|
ClimbPLocAdder
|
|
db $ff,$00
|
|
|
|
FlagpoleYPosData
|
|
db $18,$22,$50,$68,$90
|
|
|
|
HandleClimbing
|
|
ldy $04 ;check low nybble of horizontal coordinate returned from
|
|
cpy #$06 ;collision detection routine against certain values, this
|
|
bcc ExHC ;makes actual physical part of vine or flagpole thinner
|
|
cpy #$0a ;than 16 pixels
|
|
bcc ChkForFlagpole
|
|
ExHC rts ;leave if too far left or too far right
|
|
|
|
ChkForFlagpole
|
|
cmp #$24 ;check climbing metatiles
|
|
beq FlagpoleCollision ;branch if flagpole ball found
|
|
cmp #$25
|
|
bne VineCollision ;branch to alternate code if flagpole shaft not found
|
|
|
|
FlagpoleCollision
|
|
lda GameEngineSubroutine
|
|
cmp #$05 ;check for end-of-level routine running
|
|
beq PutPlayerOnVine ;if running, branch to end of climbing code
|
|
lda #$01
|
|
sta PlayerFacingDir ;set player's facing direction to right
|
|
inc ScrollLock ;set scroll lock flag
|
|
lda GameEngineSubroutine
|
|
cmp #$04 ;check for flagpole slide routine running
|
|
beq RunFR ;if running, branch to end of flagpole code here
|
|
lda #BulletBill_CannonVar ;load identifier for bullet bills (cannon variant)
|
|
jsr KillEnemies ;get rid of them
|
|
lda #Silence
|
|
sta EventMusicQueue ;silence music
|
|
lsr
|
|
sta FlagpoleSoundQueue ;load flagpole sound into flagpole sound queue
|
|
ldx #$04 ;start at end of vertical coordinate data
|
|
lda Player_Y_Position
|
|
sta FlagpoleCollisionYPos ;store player's vertical coordinate here to be used later
|
|
|
|
ChkFlagpoleYPosLoop
|
|
cmp FlagpoleYPosData,x ;compare with current vertical coordinate data
|
|
bcs MtchF ;if player's => current, branch to use current offset
|
|
dex ;otherwise decrement offset to use
|
|
bne ChkFlagpoleYPosLoop ;do this until all data is checked (use last one if all checked)
|
|
MtchF stx FlagpoleScore ;store offset here to be used later
|
|
RunFR lda #$04
|
|
sta GameEngineSubroutine ;set value to run flagpole slide routine
|
|
jmp PutPlayerOnVine ;jump to end of climbing code
|
|
|
|
VineCollision
|
|
cmp #$26 ;check for climbing metatile used on vines
|
|
bne PutPlayerOnVine
|
|
lda Player_Y_Position ;check player's vertical coordinate
|
|
cmp #$20 ;for being in status bar area
|
|
bcs PutPlayerOnVine ;branch if not that far up
|
|
lda #$01
|
|
sta GameEngineSubroutine ;otherwise set to run autoclimb routine next frame
|
|
|
|
PutPlayerOnVine
|
|
lda #$03 ;set player state to climbing
|
|
sta Player_State
|
|
lda #$00 ;nullify player's horizontal speed
|
|
sta Player_X_Speed ;and fractional horizontal movement force
|
|
sta Player_X_MoveForce
|
|
lda Player_X_Position ;get player's horizontal coordinate
|
|
sec
|
|
sbc ScreenLeft_X_Pos ;subtract from left side horizontal coordinate
|
|
cmp #$10
|
|
bcs SetVXPl ;if 16 or more pixels difference, do not alter facing direction
|
|
lda #$02
|
|
sta PlayerFacingDir ;otherwise force player to face left
|
|
SetVXPl ldy PlayerFacingDir ;get current facing direction, use as offset
|
|
lda $06 ;get low byte of block buffer address
|
|
asl
|
|
asl ;move low nybble to high
|
|
asl
|
|
asl
|
|
clc
|
|
adc ClimbXPosAdder-1,y ;add pixels depending on facing direction
|
|
sta Player_X_Position ;store as player's horizontal coordinate
|
|
lda $06 ;get low byte of block buffer address again
|
|
bne ExPVne ;if not zero, branch
|
|
lda ScreenRight_PageLoc ;load page location of right side of screen
|
|
clc
|
|
adc ClimbPLocAdder-1,y ;add depending on facing location
|
|
sta Player_PageLoc ;store as player's page location
|
|
ExPVne rts ;finally, we're done!
|
|
|
|
;--------------------------------
|
|
|
|
ChkInvisibleMTiles
|
|
cmp #$5f ;check for hidden coin block
|
|
beq ExCInvT ;branch to leave if found
|
|
cmp #$60 ;check for hidden 1-up block
|
|
ExCInvT rts ;leave with zero flag set if either found
|
|
|
|
;--------------------------------
|
|
;$00-$01 - used to hold bottom right and bottom left metatiles (in that order)
|
|
;$00 - used as flag by ImpedePlayerMove to restrict specific movement
|
|
|
|
ChkForLandJumpSpring
|
|
jsr ChkJumpspringMetatiles ;do sub to check if player landed on jumpspring
|
|
bcc ExCJSp ;if carry not set, jumpspring not found, therefore leave
|
|
lda #$70
|
|
sta VerticalForce ;otherwise set vertical movement force for player
|
|
lda #$f9
|
|
sta JumpspringForce ;set default jumpspring force
|
|
lda #$03
|
|
sta JumpspringTimer ;set jumpspring timer to be used later
|
|
lsr
|
|
sta JumpspringAnimCtrl ;set jumpspring animation control to start animating
|
|
ExCJSp rts ;and leave
|
|
|
|
ChkJumpspringMetatiles
|
|
cmp #$67 ;check for top jumpspring metatile
|
|
beq JSFnd ;branch to set carry if found
|
|
cmp #$68 ;check for bottom jumpspring metatile
|
|
clc ;clear carry flag
|
|
bne NoJSFnd ;branch to use cleared carry if not found
|
|
JSFnd sec ;set carry if found
|
|
NoJSFnd rts ;leave
|
|
|
|
HandlePipeEntry
|
|
lda Up_Down_Buttons ;check saved controller bits from earlier
|
|
and #%00000100 ;for pressing down
|
|
beq ExPipeE ;if not pressing down, branch to leave
|
|
lda $00
|
|
cmp #$11 ;check right foot metatile for warp pipe right metatile
|
|
bne ExPipeE ;branch to leave if not found
|
|
lda $01
|
|
cmp #$10 ;check left foot metatile for warp pipe left metatile
|
|
bne ExPipeE ;branch to leave if not found
|
|
lda #$30
|
|
sta ChangeAreaTimer ;set timer for change of area
|
|
lda #$03
|
|
sta GameEngineSubroutine ;set to run vertical pipe entry routine on next frame
|
|
lda #Sfx_PipeDown_Injury
|
|
sta Square1SoundQueue ;load pipedown/injury sound
|
|
lda #%00100000
|
|
sta Player_SprAttrib ;set background priority bit in player's attributes
|
|
lda WarpZoneControl ;check warp zone control
|
|
beq ExPipeE ;branch to leave if none found
|
|
and #%00000011 ;mask out all but 2 LSB
|
|
asl
|
|
asl ;multiply by four
|
|
tax ;save as offset to warp zone numbers (starts at left pipe)
|
|
lda Player_X_Position ;get player's horizontal position
|
|
cmp #$60
|
|
bcc GetWNum ;if player at left, not near middle, use offset and skip ahead
|
|
inx ;otherwise increment for middle pipe
|
|
cmp #$a0
|
|
bcc GetWNum ;if player at middle, but not too far right, use offset and skip
|
|
inx ;otherwise increment for last pipe
|
|
GetWNum ldy WarpZoneNumbers,x ;get warp zone numbers
|
|
dey ;decrement for use as world number
|
|
sty WorldNumber ;store as world number and offset
|
|
ldx WorldAddrOffsets,y ;get offset to where this world's area offsets are
|
|
lda AreaAddrOffsets,x ;get area offset based on world offset
|
|
sta AreaPointer ;store area offset here to be used to change areas
|
|
lda #Silence
|
|
sta EventMusicQueue ;silence music
|
|
lda #$00
|
|
sta EntrancePage ;initialize starting page number
|
|
sta AreaNumber ;initialize area number used for area address offset
|
|
sta LevelNumber ;initialize level number used for world display
|
|
sta AltEntranceControl ;initialize mode of entry
|
|
inc Hidden1UpFlag ;set flag for hidden 1-up blocks
|
|
inc FetchNewGameTimerFlag ;set flag to load new game timer
|
|
ExPipeE rts ;leave!!!
|
|
|
|
ImpedePlayerMove
|
|
lda #$00 ;initialize value here
|
|
ldy Player_X_Speed ;get player's horizontal speed
|
|
ldx $00 ;check value set earlier for
|
|
dex ;left side collision
|
|
bne RImpd ;if right side collision, skip this part
|
|
inx ;return value to X
|
|
cpy #$00 ;if player moving to the left,
|
|
bmi ExIPM ;branch to invert bit and leave
|
|
lda #$ff ;otherwise load A with value to be used later
|
|
jmp NXSpd ;and jump to affect movement
|
|
RImpd ldx #$02 ;return $02 to X
|
|
cpy #$01 ;if player moving to the right,
|
|
bpl ExIPM ;branch to invert bit and leave
|
|
lda #$01 ;otherwise load A with value to be used here
|
|
NXSpd ldy #$10
|
|
sty SideCollisionTimer ;set timer of some sort
|
|
ldy #$00
|
|
sty Player_X_Speed ;nullify player's horizontal speed
|
|
cmp #$00 ;if value set in A not set to $ff,
|
|
bpl PlatF ;branch ahead, do not decrement Y
|
|
dey ;otherwise decrement Y now
|
|
PlatF sty $00 ;store Y as high bits of horizontal adder
|
|
clc
|
|
adc Player_X_Position ;add contents of A to player's horizontal
|
|
sta Player_X_Position ;position to move player left or right
|
|
lda Player_PageLoc
|
|
adc $00 ;add high bits and carry to
|
|
sta Player_PageLoc ;page location if necessary
|
|
ExIPM txa ;invert contents of X
|
|
eor #$ff
|
|
and Player_CollisionBits ;mask out bit that was set here
|
|
sta Player_CollisionBits ;store to clear bit
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
SolidMTileUpperExt
|
|
db $10,$61,$88,$c4
|
|
|
|
CheckForSolidMTiles
|
|
jsr GetMTileAttrib ;find appropriate offset based on metatile's 2 MSB
|
|
cmp SolidMTileUpperExt,x ;compare current metatile with solid metatiles
|
|
rts
|
|
|
|
ClimbMTileUpperExt
|
|
db $24,$6d,$8a,$c6
|
|
|
|
CheckForClimbMTiles
|
|
jsr GetMTileAttrib ;find appropriate offset based on metatile's 2 MSB
|
|
cmp ClimbMTileUpperExt,x ;compare current metatile with climbable metatiles
|
|
rts
|
|
|
|
CheckForCoinMTiles
|
|
cmp #$c2 ;check for regular coin
|
|
beq CoinSd ;branch if found
|
|
cmp #$c3 ;check for underwater coin
|
|
beq CoinSd ;branch if found
|
|
clc ;otherwise clear carry and leave
|
|
rts
|
|
CoinSd lda #Sfx_CoinGrab
|
|
sta Square2SoundQueue ;load coin grab sound and leave
|
|
rts
|
|
|
|
GetMTileAttrib
|
|
tay ;save metatile value into Y
|
|
and #%11000000 ;mask out all but 2 MSB
|
|
asl
|
|
rol ;shift and rotate d7-d6 to d1-d0
|
|
rol
|
|
tax ;use as offset for metatile data
|
|
tya ;get original metatile value back
|
|
ExEBG rts ;leave
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$06-$07 - address from block buffer routine
|
|
|
|
EnemyBGCStateData
|
|
db $01,$01,$02,$02,$02,$05
|
|
|
|
EnemyBGCXSpdData
|
|
db $10,$f0
|
|
|
|
EnemyToBGCollisionDet
|
|
lda Enemy_State,x ;check enemy state for d6 set
|
|
and #%00100000
|
|
bne ExEBG ;if set, branch to leave
|
|
jsr SubtEnemyYPos ;otherwise, do a subroutine here
|
|
bcc ExEBG ;if enemy vertical coord + 62 < 68, branch to leave
|
|
ldy Enemy_ID,x
|
|
cpy #Spiny ;if enemy object is not spiny, branch elsewhere
|
|
bne DoIDCheckBGColl
|
|
lda Enemy_Y_Position,x
|
|
cmp #$25 ;if enemy vertical coordinate < 36 branch to leave
|
|
bcc ExEBG
|
|
|
|
DoIDCheckBGColl
|
|
cpy #GreenParatroopaJump ;check for some other enemy object
|
|
bne HBChk ;branch if not found
|
|
jmp EnemyJump ;otherwise jump elsewhere
|
|
HBChk cpy #HammerBro ;check for hammer bro
|
|
bne CInvu ;branch if not found
|
|
jmp HammerBroBGColl ;otherwise jump elsewhere
|
|
CInvu cpy #Spiny ;if enemy object is spiny, branch
|
|
beq YesIn
|
|
cpy #PowerUpObject ;if special power-up object, branch
|
|
beq YesIn
|
|
cpy #$07 ;if enemy object =>$07, branch to leave
|
|
bcs ExEBGChk
|
|
YesIn jsr ChkUnderEnemy ;if enemy object < $07, or = $12 or $2e, do this sub
|
|
bne HandleEToBGCollision ;if block underneath enemy, branch
|
|
|
|
NoEToBGCollision
|
|
jmp ChkForRedKoopa ;otherwise skip and do something else
|
|
|
|
;--------------------------------
|
|
;$02 - vertical coordinate from block buffer routine
|
|
|
|
HandleEToBGCollision
|
|
jsr ChkForNonSolids ;if something is underneath enemy, find out what
|
|
beq NoEToBGCollision ;if blank $26, coins, or hidden blocks, jump, enemy falls through
|
|
cmp #$23
|
|
bne LandEnemyProperly ;check for blank metatile $23 and branch if not found
|
|
ldy $02 ;get vertical coordinate used to find block
|
|
lda #$00 ;store default blank metatile in that spot so we won't
|
|
sta ($06),y ;trigger this routine accidentally again
|
|
lda Enemy_ID,x
|
|
cmp #$15 ;if enemy object => $15, branch ahead
|
|
bcs ChkToStunEnemies
|
|
cmp #Goomba ;if enemy object not goomba, branch ahead of this routine
|
|
bne GiveOEPoints
|
|
jsr KillEnemyAboveBlock ;if enemy object IS goomba, do this sub
|
|
|
|
GiveOEPoints
|
|
lda #$01 ;award 100 points for hitting block beneath enemy
|
|
jsr SetupFloateyNumber
|
|
|
|
ChkToStunEnemies
|
|
cmp #$09 ;perform many comparisons on enemy object identifier
|
|
bcc SetStun
|
|
cmp #$11 ;if the enemy object identifier is equal to the values
|
|
bcs SetStun ;$09,$0e,$0f or $10, it will be modified, and not
|
|
cmp #$0a ;modified if not any of those values, note that piranha plant will
|
|
bcc Demote ;always fail this test because A will still have vertical
|
|
cmp #PiranhaPlant ;coordinate from previous addition, also these comparisons
|
|
bcc SetStun ;are only necessary if branching from $d7a1
|
|
Demote and #%00000001 ;erase all but LSB, essentially turning enemy object
|
|
sta Enemy_ID,x ;into green or red koopa troopa to demote them
|
|
SetStun lda Enemy_State,x ;load enemy state
|
|
and #%11110000 ;save high nybble
|
|
ora #%00000010
|
|
sta Enemy_State,x ;set d1 of enemy state
|
|
dec Enemy_Y_Position,x
|
|
dec Enemy_Y_Position,x ;subtract two pixels from enemy's vertical position
|
|
lda Enemy_ID,x
|
|
cmp #Bloober ;check for bloober object
|
|
beq SetWYSpd
|
|
lda #$fd ;set default vertical speed
|
|
ldy AreaType
|
|
bne SetNotW ;if area type not water, set as speed, otherwise
|
|
SetWYSpd lda #$ff ;change the vertical speed
|
|
SetNotW sta Enemy_Y_Speed,x ;set vertical speed now
|
|
ldy #$01
|
|
jsr PlayerEnemyDiff ;get horizontal difference between player and enemy object
|
|
bpl ChkBBill ;branch if enemy is to the right of player
|
|
iny ;increment Y if not
|
|
ChkBBill lda Enemy_ID,x
|
|
cmp #BulletBill_CannonVar ;check for bullet bill (cannon variant)
|
|
beq NoCDirF
|
|
cmp #BulletBill_FrenzyVar ;check for bullet bill (frenzy variant)
|
|
beq NoCDirF ;branch if either found, direction does not change
|
|
sty Enemy_MovingDir,x ;store as moving direction
|
|
NoCDirF dey ;decrement and use as offset
|
|
lda EnemyBGCXSpdData,y ;get proper horizontal speed
|
|
sta Enemy_X_Speed,x ;and store, then leave
|
|
ExEBGChk rts
|
|
|
|
;--------------------------------
|
|
;$04 - low nybble of vertical coordinate from block buffer routine
|
|
|
|
LandEnemyProperly
|
|
lda $04 ;check lower nybble of vertical coordinate saved earlier
|
|
sec
|
|
sbc #$08 ;subtract eight pixels
|
|
cmp #$05 ;used to determine whether enemy landed from falling
|
|
bcs ChkForRedKoopa ;branch if lower nybble in range of $0d-$0f before subtract
|
|
lda Enemy_State,x
|
|
and #%01000000 ;branch if d6 in enemy state is set
|
|
bne LandEnemyInitState
|
|
lda Enemy_State,x
|
|
asl ;branch if d7 in enemy state is not set
|
|
bcc ChkLandedEnemyState
|
|
SChkA jmp DoEnemySideCheck ;if lower nybble < $0d, d7 set but d6 not set, jump here
|
|
|
|
ChkLandedEnemyState
|
|
lda Enemy_State,x ;if enemy in normal state, branch back to jump here
|
|
beq SChkA
|
|
cmp #$05 ;if in state used by spiny's egg
|
|
beq ProcEnemyDirection ;then branch elsewhere
|
|
cmp #$03 ;if already in state used by koopas and buzzy beetles
|
|
bcs ExSteChk ;or in higher numbered state, branch to leave
|
|
lda Enemy_State,x ;load enemy state again (why?)
|
|
cmp #$02 ;if not in $02 state (used by koopas and buzzy beetles)
|
|
bne ProcEnemyDirection ;then branch elsewhere
|
|
lda #$10 ;load default timer here
|
|
ldy Enemy_ID,x ;check enemy identifier for spiny
|
|
cpy #Spiny
|
|
bne SetForStn ;branch if not found
|
|
lda #$00 ;set timer for $00 if spiny
|
|
SetForStn sta EnemyIntervalTimer,x ;set timer here
|
|
lda #$03 ;set state here, apparently used to render
|
|
sta Enemy_State,x ;upside-down koopas and buzzy beetles
|
|
jsr EnemyLanding ;then land it properly
|
|
ExSteChk rts ;then leave
|
|
|
|
ProcEnemyDirection
|
|
lda Enemy_ID,x ;check enemy identifier for goomba
|
|
cmp #Goomba ;branch if found
|
|
beq LandEnemyInitState
|
|
cmp #Spiny ;check for spiny
|
|
bne InvtD ;branch if not found
|
|
lda #$01
|
|
sta Enemy_MovingDir,x ;send enemy moving to the right by default
|
|
lda #$08
|
|
sta Enemy_X_Speed,x ;set horizontal speed accordingly
|
|
lda FrameCounter
|
|
and #%00000111 ;if timed appropriately, spiny will skip over
|
|
beq LandEnemyInitState ;trying to face the player
|
|
InvtD ldy #$01 ;load 1 for enemy to face the left (inverted here)
|
|
jsr PlayerEnemyDiff ;get horizontal difference between player and enemy
|
|
bpl CNwCDir ;if enemy to the right of player, branch
|
|
iny ;if to the left, increment by one for enemy to face right (inverted)
|
|
CNwCDir tya
|
|
cmp Enemy_MovingDir,x ;compare direction in A with current direction in memory
|
|
bne LandEnemyInitState
|
|
jsr ChkForBump_HammerBroJ ;if equal, not facing in correct dir, do sub to turn around
|
|
|
|
LandEnemyInitState
|
|
jsr EnemyLanding ;land enemy properly
|
|
lda Enemy_State,x
|
|
and #%10000000 ;if d7 of enemy state is set, branch
|
|
bne NMovShellFallBit
|
|
lda #$00 ;otherwise initialize enemy state and leave
|
|
sta Enemy_State,x ;note this will also turn spiny's egg into spiny
|
|
rts
|
|
|
|
NMovShellFallBit
|
|
lda Enemy_State,x ;nullify d6 of enemy state, save other bits
|
|
and #%10111111 ;and store, then leave
|
|
sta Enemy_State,x
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
ChkForRedKoopa
|
|
lda Enemy_ID,x ;check for red koopa troopa $03
|
|
cmp #RedKoopa
|
|
bne Chk2MSBSt ;branch if not found
|
|
lda Enemy_State,x
|
|
beq ChkForBump_HammerBroJ ;if enemy found and in normal state, branch
|
|
Chk2MSBSt lda Enemy_State,x ;save enemy state into Y
|
|
tay
|
|
asl ;check for d7 set
|
|
bcc GetSteFromD ;branch if not set
|
|
lda Enemy_State,x
|
|
ora #%01000000 ;set d6
|
|
jmp SetD6Ste ;jump ahead of this part
|
|
GetSteFromD lda EnemyBGCStateData,y ;load new enemy state with old as offset
|
|
SetD6Ste sta Enemy_State,x ;set as new state
|
|
|
|
;--------------------------------
|
|
;$00 - used to store bitmask (not used but initialized here)
|
|
;$eb - used in DoEnemySideCheck as counter and to compare moving directions
|
|
|
|
DoEnemySideCheck
|
|
lda Enemy_Y_Position,x ;if enemy within status bar, branch to leave
|
|
cmp #$20 ;because there's nothing there that impedes movement
|
|
bcc ExESdeC
|
|
ldy #$16 ;start by finding block to the left of enemy ($00,$14)
|
|
lda #$02 ;set value here in what is also used as
|
|
sta $eb ;OAM data offset
|
|
SdeCLoop lda $eb ;check value
|
|
cmp Enemy_MovingDir,x ;compare value against moving direction
|
|
bne NextSdeC ;branch if different and do not seek block there
|
|
lda #$01 ;set flag in A for save horizontal coordinate
|
|
jsr BlockBufferChk_Enemy ;find block to left or right of enemy object
|
|
beq NextSdeC ;if nothing found, branch
|
|
jsr ChkForNonSolids ;check for non-solid blocks
|
|
bne ChkForBump_HammerBroJ ;branch if not found
|
|
NextSdeC dec $eb ;move to the next direction
|
|
iny
|
|
cpy #$18 ;increment Y, loop only if Y < $18, thus we check
|
|
bcc SdeCLoop ;enemy ($00,$14) and ($10,$14) pixel coordinates
|
|
ExESdeC rts
|
|
|
|
ChkForBump_HammerBroJ
|
|
cpx #$05 ;check if we're on the special use slot
|
|
beq NoBump ;and if so, branch ahead and do not play sound
|
|
lda Enemy_State,x ;if enemy state d7 not set, branch
|
|
asl ;ahead and do not play sound
|
|
bcc NoBump
|
|
lda #Sfx_Bump ;otherwise, play bump sound
|
|
sta Square1SoundQueue ;sound will never be played if branching from ChkForRedKoopa
|
|
NoBump lda Enemy_ID,x ;check for hammer bro
|
|
cmp #$05
|
|
bne InvEnemyDir ;branch if not found
|
|
lda #$00
|
|
sta $00 ;initialize value here for bitmask
|
|
ldy #$fa ;load default vertical speed for jumping
|
|
jmp SetHJ ;jump to code that makes hammer bro jump
|
|
|
|
InvEnemyDir
|
|
jmp RXSpd ;jump to turn the enemy around
|
|
|
|
;--------------------------------
|
|
;$00 - used to hold horizontal difference between player and enemy
|
|
|
|
PlayerEnemyDiff
|
|
lda Enemy_X_Position,x ;get distance between enemy object's
|
|
sec ;horizontal coordinate and the player's
|
|
sbc Player_X_Position ;horizontal coordinate
|
|
sta $00 ;and store here
|
|
lda Enemy_PageLoc,x
|
|
sbc Player_PageLoc ;subtract borrow, then leave
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
EnemyLanding
|
|
jsr InitVStf ;do something here to vertical speed and something else
|
|
lda Enemy_Y_Position,x
|
|
and #%11110000 ;save high nybble of vertical coordinate, and
|
|
ora #%00001000 ;set d3, then store, probably used to set enemy object
|
|
sta Enemy_Y_Position,x ;neatly on whatever it's landing on
|
|
rts
|
|
|
|
SubtEnemyYPos
|
|
lda Enemy_Y_Position,x ;add 62 pixels to enemy object's
|
|
clc ;vertical coordinate
|
|
adc #$3e
|
|
cmp #$44 ;compare against a certain range
|
|
rts ;and leave with flags set for conditional branch
|
|
|
|
EnemyJump
|
|
jsr SubtEnemyYPos ;do a sub here
|
|
bcc DoSide ;if enemy vertical coord + 62 < 68, branch to leave
|
|
lda Enemy_Y_Speed,x
|
|
clc ;add two to vertical speed
|
|
adc #$02
|
|
cmp #$03 ;if green paratroopa not falling, branch ahead
|
|
bcc DoSide
|
|
jsr ChkUnderEnemy ;otherwise, check to see if green paratroopa is
|
|
beq DoSide ;standing on anything, then branch to same place if not
|
|
jsr ChkForNonSolids ;check for non-solid blocks
|
|
beq DoSide ;branch if found
|
|
jsr EnemyLanding ;change vertical coordinate and speed
|
|
lda #$fd
|
|
sta Enemy_Y_Speed,x ;make the paratroopa jump again
|
|
DoSide jmp DoEnemySideCheck ;check for horizontal blockage, then leave
|
|
|
|
;--------------------------------
|
|
|
|
HammerBroBGColl
|
|
jsr ChkUnderEnemy ;check to see if hammer bro is standing on anything
|
|
beq NoUnderHammerBro
|
|
cmp #$23 ;check for blank metatile $23 and branch if not found
|
|
bne UnderHammerBro
|
|
|
|
KillEnemyAboveBlock
|
|
jsr ShellOrBlockDefeat ;do this sub to kill enemy
|
|
lda #$fc ;alter vertical speed of enemy and leave
|
|
sta Enemy_Y_Speed,x
|
|
rts
|
|
|
|
UnderHammerBro
|
|
lda EnemyFrameTimer,x ;check timer used by hammer bro
|
|
bne NoUnderHammerBro ;branch if not expired
|
|
lda Enemy_State,x
|
|
and #%10001000 ;save d7 and d3 from enemy state, nullify other bits
|
|
sta Enemy_State,x ;and store
|
|
jsr EnemyLanding ;modify vertical coordinate, speed and something else
|
|
jmp DoEnemySideCheck ;then check for horizontal blockage and leave
|
|
|
|
NoUnderHammerBro
|
|
lda Enemy_State,x ;if hammer bro is not standing on anything, set d0
|
|
ora #$01 ;in the enemy state to indicate jumping or falling, then leave
|
|
sta Enemy_State,x
|
|
rts
|
|
|
|
ChkUnderEnemy
|
|
lda #$00 ;set flag in A for save vertical coordinate
|
|
ldy #$15 ;set Y to check the bottom middle (8,18) of enemy object
|
|
jmp BlockBufferChk_Enemy ;hop to it!
|
|
|
|
ChkForNonSolids
|
|
cmp #$26 ;blank metatile used for vines?
|
|
beq NSFnd
|
|
cmp #$c2 ;regular coin?
|
|
beq NSFnd
|
|
cmp #$c3 ;underwater coin?
|
|
beq NSFnd
|
|
cmp #$5f ;hidden coin block?
|
|
beq NSFnd
|
|
cmp #$60 ;hidden 1-up block?
|
|
NSFnd rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
FireballBGCollision
|
|
lda Fireball_Y_Position,x ;check fireball's vertical coordinate
|
|
cmp #$18
|
|
bcc ClearBounceFlag ;if within the status bar area of the screen, branch ahead
|
|
jsr BlockBufferChk_FBall ;do fireball to background collision detection on bottom of it
|
|
beq ClearBounceFlag ;if nothing underneath fireball, branch
|
|
jsr ChkForNonSolids ;check for non-solid metatiles
|
|
beq ClearBounceFlag ;branch if any found
|
|
lda Fireball_Y_Speed,x ;if fireball's vertical speed set to move upwards,
|
|
bmi InitFireballExplode ;branch to set exploding bit in fireball's state
|
|
lda FireballBouncingFlag,x ;if bouncing flag already set,
|
|
bne InitFireballExplode ;branch to set exploding bit in fireball's state
|
|
lda #$fd
|
|
sta Fireball_Y_Speed,x ;otherwise set vertical speed to move upwards (give it bounce)
|
|
lda #$01
|
|
sta FireballBouncingFlag,x ;set bouncing flag
|
|
lda Fireball_Y_Position,x
|
|
and #$f8 ;modify vertical coordinate to land it properly
|
|
sta Fireball_Y_Position,x ;store as new vertical coordinate
|
|
rts ;leave
|
|
|
|
ClearBounceFlag
|
|
lda #$00
|
|
sta FireballBouncingFlag,x ;clear bouncing flag by default
|
|
rts ;leave
|
|
|
|
InitFireballExplode
|
|
lda #$80
|
|
sta Fireball_State,x ;set exploding flag in fireball's state
|
|
lda #Sfx_Bump
|
|
sta Square1SoundQueue ;load bump sound
|
|
rts ;leave
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$00 - used to hold one of bitmasks, or offset
|
|
;$01 - used for relative X coordinate, also used to store middle screen page location
|
|
;$02 - used for relative Y coordinate, also used to store middle screen coordinate
|
|
|
|
;this data added to relative coordinates of sprite objects
|
|
;stored in order left edge, top edge, right edge, bottom edge
|
|
BoundBoxCtrlData
|
|
db $02,$08,$0e,$20
|
|
db $03,$14,$0d,$20
|
|
db $02,$14,$0e,$20
|
|
db $02,$09,$0e,$15
|
|
db $00,$00,$18,$06
|
|
db $00,$00,$20,$0d
|
|
db $00,$00,$30,$0d
|
|
db $00,$00,$08,$08
|
|
db $06,$04,$0a,$08
|
|
db $03,$0e,$0d,$14
|
|
db $00,$02,$10,$15
|
|
db $04,$04,$0c,$1c
|
|
|
|
GetFireballBoundBox
|
|
txa ;add seven bytes to offset
|
|
clc ;to use in routines as offset for fireball
|
|
adc #$07
|
|
tax
|
|
ldy #$02 ;set offset for relative coordinates
|
|
bne FBallB ;unconditional branch
|
|
|
|
GetMiscBoundBox
|
|
txa ;add nine bytes to offset
|
|
clc ;to use in routines as offset for misc object
|
|
adc #$09
|
|
tax
|
|
ldy #$06 ;set offset for relative coordinates
|
|
FBallB jsr BoundingBoxCore ;get bounding box coordinates
|
|
jmp CheckRightScreenBBox ;jump to handle any offscreen coordinates
|
|
|
|
GetEnemyBoundBox
|
|
ldy #$48 ;store bitmask here for now
|
|
sty $00
|
|
ldy #$44 ;store another bitmask here for now and jump
|
|
jmp GetMaskedOffScrBits
|
|
|
|
SmallPlatformBoundBox
|
|
ldy #$08 ;store bitmask here for now
|
|
sty $00
|
|
ldy #$04 ;store another bitmask here for now
|
|
|
|
GetMaskedOffScrBits
|
|
lda Enemy_X_Position,x ;get enemy object position relative
|
|
sec ;to the left side of the screen
|
|
sbc ScreenLeft_X_Pos
|
|
sta $01 ;store here
|
|
lda Enemy_PageLoc,x ;subtract borrow from current page location
|
|
sbc ScreenLeft_PageLoc ;of left side
|
|
bmi CMBits ;if enemy object is beyond left edge, branch
|
|
ora $01
|
|
beq CMBits ;if precisely at the left edge, branch
|
|
ldy $00 ;if to the right of left edge, use value in $00 for A
|
|
CMBits tya ;otherwise use contents of Y
|
|
and Enemy_OffscreenBits ;preserve bitwise whatever's in here
|
|
sta EnemyOffscrBitsMasked,x ;save masked offscreen bits here
|
|
bne MoveBoundBoxOffscreen ;if anything set here, branch
|
|
jmp SetupEOffsetFBBox ;otherwise, do something else
|
|
|
|
LargePlatformBoundBox
|
|
inx ;increment X to get the proper offset
|
|
jsr GetXOffscreenBits ;then jump directly to the sub for horizontal offscreen bits
|
|
dex ;decrement to return to original offset
|
|
cmp #$fe ;if completely offscreen, branch to put entire bounding
|
|
bcs MoveBoundBoxOffscreen ;box offscreen, otherwise start getting coordinates
|
|
|
|
SetupEOffsetFBBox
|
|
txa ;add 1 to offset to properly address
|
|
clc ;the enemy object memory locations
|
|
adc #$01
|
|
tax
|
|
ldy #$01 ;load 1 as offset here, same reason
|
|
jsr BoundingBoxCore ;do a sub to get the coordinates of the bounding box
|
|
jmp CheckRightScreenBBox ;jump to handle offscreen coordinates of bounding box
|
|
|
|
MoveBoundBoxOffscreen
|
|
txa ;multiply offset by 4
|
|
asl
|
|
asl
|
|
tay ;use as offset here
|
|
lda #$ff
|
|
sta EnemyBoundingBoxCoord,y ;load value into four locations here and leave
|
|
sta EnemyBoundingBoxCoord+1,y
|
|
sta EnemyBoundingBoxCoord+2,y
|
|
sta EnemyBoundingBoxCoord+3,y
|
|
rts
|
|
|
|
BoundingBoxCore
|
|
stx $00 ;save offset here
|
|
lda SprObject_Rel_YPos,y ;store object coordinates relative to screen
|
|
sta $02 ;vertically and horizontally, respectively
|
|
lda SprObject_Rel_XPos,y
|
|
sta $01
|
|
txa ;multiply offset by four and save to stack
|
|
asl
|
|
asl
|
|
pha
|
|
tay ;use as offset for Y, X is left alone
|
|
lda SprObj_BoundBoxCtrl,x ;load value here to be used as offset for X
|
|
asl ;multiply that by four and use as X
|
|
asl
|
|
tax
|
|
lda $01 ;add the first number in the bounding box data to the
|
|
clc ;relative horizontal coordinate using enemy object offset
|
|
adc BoundBoxCtrlData,x ;and store somewhere using same offset * 4
|
|
sta BoundingBox_UL_Corner,y ;store here
|
|
lda $01
|
|
clc
|
|
adc BoundBoxCtrlData+2,x ;add the third number in the bounding box data to the
|
|
sta BoundingBox_LR_Corner,y ;relative horizontal coordinate and store
|
|
inx ;increment both offsets
|
|
iny
|
|
lda $02 ;add the second number to the relative vertical coordinate
|
|
clc ;using incremented offset and store using the other
|
|
adc BoundBoxCtrlData,x ;incremented offset
|
|
sta BoundingBox_UL_Corner,y
|
|
lda $02
|
|
clc
|
|
adc BoundBoxCtrlData+2,x ;add the fourth number to the relative vertical coordinate
|
|
sta BoundingBox_LR_Corner,y ;and store
|
|
pla ;get original offset loaded into $00 * y from stack
|
|
tay ;use as Y
|
|
ldx $00 ;get original offset and use as X again
|
|
rts
|
|
|
|
CheckRightScreenBBox
|
|
lda ScreenLeft_X_Pos ;add 128 pixels to left side of screen
|
|
clc ;and store as horizontal coordinate of middle
|
|
adc #$80
|
|
sta $02
|
|
lda ScreenLeft_PageLoc ;add carry to page location of left side of screen
|
|
adc #$00 ;and store as page location of middle
|
|
sta $01
|
|
lda SprObject_X_Position,x ;get horizontal coordinate
|
|
cmp $02 ;compare against middle horizontal coordinate
|
|
lda SprObject_PageLoc,x ;get page location
|
|
sbc $01 ;subtract from middle page location
|
|
bcc CheckLeftScreenBBox ;if object is on the left side of the screen, branch
|
|
lda BoundingBox_DR_XPos,y ;check right-side edge of bounding box for offscreen
|
|
bmi NoOfs ;coordinates, branch if still on the screen
|
|
lda #$ff ;load offscreen value here to use on one or both horizontal sides
|
|
ldx BoundingBox_UL_XPos,y ;check left-side edge of bounding box for offscreen
|
|
bmi SORte ;coordinates, and branch if still on the screen
|
|
sta BoundingBox_UL_XPos,y ;store offscreen value for left side
|
|
SORte sta BoundingBox_DR_XPos,y ;store offscreen value for right side
|
|
NoOfs ldx ObjectOffset ;get object offset and leave
|
|
rts
|
|
|
|
CheckLeftScreenBBox
|
|
lda BoundingBox_UL_XPos,y ;check left-side edge of bounding box for offscreen
|
|
bpl NoOfs2 ;coordinates, and branch if still on the screen
|
|
cmp #$a0 ;check to see if left-side edge is in the middle of the
|
|
bcc NoOfs2 ;screen or really offscreen, and branch if still on
|
|
lda #$00
|
|
ldx BoundingBox_DR_XPos,y ;check right-side edge of bounding box for offscreen
|
|
bpl SOLft ;coordinates, branch if still onscreen
|
|
sta BoundingBox_DR_XPos,y ;store offscreen value for right side
|
|
SOLft sta BoundingBox_UL_XPos,y ;store offscreen value for left side
|
|
NoOfs2 ldx ObjectOffset ;get object offset and leave
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$06 - second object's offset
|
|
;$07 - counter
|
|
|
|
PlayerCollisionCore
|
|
ldx #$00 ;initialize X to use player's bounding box for comparison
|
|
|
|
SprObjectCollisionCore
|
|
sty $06 ;save contents of Y here
|
|
lda #$01
|
|
sta $07 ;save value 1 here as counter, compare horizontal coordinates first
|
|
|
|
CollisionCoreLoop
|
|
lda BoundingBox_UL_Corner,y ;compare left/top coordinates
|
|
cmp BoundingBox_UL_Corner,x ;of first and second objects' bounding boxes
|
|
bcs FirstBoxGreater ;if first left/top => second, branch
|
|
cmp BoundingBox_LR_Corner,x ;otherwise compare to right/bottom of second
|
|
bcc SecondBoxVerticalChk ;if first left/top < second right/bottom, branch elsewhere
|
|
beq CollisionFound ;if somehow equal, collision, thus branch
|
|
lda BoundingBox_LR_Corner,y ;if somehow greater, check to see if bottom of
|
|
cmp BoundingBox_UL_Corner,y ;first object's bounding box is greater than its top
|
|
bcc CollisionFound ;if somehow less, vertical wrap collision, thus branch
|
|
cmp BoundingBox_UL_Corner,x ;otherwise compare bottom of first bounding box to the top
|
|
bcs CollisionFound ;of second box, and if equal or greater, collision, thus branch
|
|
ldy $06 ;otherwise return with carry clear and Y = $0006
|
|
rts ;note horizontal wrapping never occurs
|
|
|
|
SecondBoxVerticalChk
|
|
lda BoundingBox_LR_Corner,x ;check to see if the vertical bottom of the box
|
|
cmp BoundingBox_UL_Corner,x ;is greater than the vertical top
|
|
bcc CollisionFound ;if somehow less, vertical wrap collision, thus branch
|
|
lda BoundingBox_LR_Corner,y ;otherwise compare horizontal right or vertical bottom
|
|
cmp BoundingBox_UL_Corner,x ;of first box with horizontal left or vertical top of second box
|
|
bcs CollisionFound ;if equal or greater, collision, thus branch
|
|
ldy $06 ;otherwise return with carry clear and Y = $0006
|
|
rts
|
|
|
|
FirstBoxGreater
|
|
cmp BoundingBox_UL_Corner,x ;compare first and second box horizontal left/vertical top again
|
|
beq CollisionFound ;if first coordinate = second, collision, thus branch
|
|
cmp BoundingBox_LR_Corner,x ;if not, compare with second object right or bottom edge
|
|
bcc CollisionFound ;if left/top of first less than or equal to right/bottom of second
|
|
beq CollisionFound ;then collision, thus branch
|
|
cmp BoundingBox_LR_Corner,y ;otherwise check to see if top of first box is greater than bottom
|
|
bcc NoCollisionFound ;if less than or equal, no collision, branch to end
|
|
beq NoCollisionFound
|
|
lda BoundingBox_LR_Corner,y ;otherwise compare bottom of first to top of second
|
|
cmp BoundingBox_UL_Corner,x ;if bottom of first is greater than top of second, vertical wrap
|
|
bcs CollisionFound ;collision, and branch, otherwise, proceed onwards here
|
|
|
|
NoCollisionFound
|
|
clc ;clear carry, then load value set earlier, then leave
|
|
ldy $06 ;like previous ones, if horizontal coordinates do not collide, we do
|
|
rts ;not bother checking vertical ones, because what's the point?
|
|
|
|
CollisionFound
|
|
inx ;increment offsets on both objects to check
|
|
iny ;the vertical coordinates
|
|
dec $07 ;decrement counter to reflect this
|
|
bpl CollisionCoreLoop ;if counter not expired, branch to loop
|
|
sec ;otherwise we already did both sets, therefore collision, so set carry
|
|
ldy $06 ;load original value set here earlier, then leave
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$02 - modified y coordinate
|
|
;$03 - stores metatile involved in block buffer collisions
|
|
;$04 - comes in with offset to block buffer adder data, goes out with low nybble x/y coordinate
|
|
;$05 - modified x coordinate
|
|
;$06-$07 - block buffer address
|
|
|
|
BlockBufferChk_Enemy
|
|
pha ;save contents of A to stack
|
|
txa
|
|
clc ;add 1 to X to run sub with enemy offset in mind
|
|
adc #$01
|
|
tax
|
|
pla ;pull A from stack and jump elsewhere
|
|
jmp BBChk_E
|
|
|
|
ResidualMiscObjectCode
|
|
txa
|
|
clc ;supposedly used once to set offset for
|
|
adc #$0d ;miscellaneous objects
|
|
tax
|
|
ldy #$1b ;supposedly used once to set offset for block buffer data
|
|
jmp ResJmpM ;probably used in early stages to do misc to bg collision detection
|
|
|
|
BlockBufferChk_FBall
|
|
ldy #$1a ;set offset for block buffer adder data
|
|
txa
|
|
clc
|
|
adc #$07 ;add seven bytes to use
|
|
tax
|
|
ResJmpM lda #$00 ;set A to return vertical coordinate
|
|
BBChk_E jsr BlockBufferCollision ;do collision detection subroutine for sprite object
|
|
ldx ObjectOffset ;get object offset
|
|
cmp #$00 ;check to see if object bumped into anything
|
|
rts
|
|
|
|
BlockBufferAdderData
|
|
db $00,$07,$0e
|
|
|
|
BlockBuffer_X_Adder
|
|
db $08,$03,$0c,$02,$02,$0d,$0d,$08
|
|
db $03,$0c,$02,$02,$0d,$0d,$08,$03
|
|
db $0c,$02,$02,$0d,$0d,$08,$00,$10
|
|
db $04,$14,$04,$04
|
|
|
|
BlockBuffer_Y_Adder
|
|
db $04,$20,$20,$08,$18,$08,$18,$02
|
|
db $20,$20,$08,$18,$08,$18,$12,$20
|
|
db $20,$18,$18,$18,$18,$18,$14,$14
|
|
db $06,$06,$08,$10
|
|
|
|
BlockBufferColli_Feet
|
|
iny ;if branched here, increment to next set of adders
|
|
|
|
BlockBufferColli_Head
|
|
lda #$00 ;set flag to return vertical coordinate
|
|
db $2c ;BIT instruction opcode
|
|
|
|
BlockBufferColli_Side
|
|
lda #$01 ;set flag to return horizontal coordinate
|
|
ldx #$00 ;set offset for player object
|
|
|
|
BlockBufferCollision
|
|
pha ;save contents of A to stack
|
|
sty $04 ;save contents of Y here
|
|
lda BlockBuffer_X_Adder,y ;add horizontal coordinate
|
|
clc ;of object to value obtained using Y as offset
|
|
adc SprObject_X_Position,x
|
|
sta $05 ;store here
|
|
lda SprObject_PageLoc,x
|
|
adc #$00 ;add carry to page location
|
|
and #$01 ;get LSB, mask out all other bits
|
|
lsr ;move to carry
|
|
ora $05 ;get stored value
|
|
ror ;rotate carry to MSB of A
|
|
lsr ;and effectively move high nybble to
|
|
lsr ;lower, LSB which became MSB will be
|
|
lsr ;d4 at this point
|
|
jsr GetBlockBufferAddr ;get address of block buffer into $06,$07
|
|
ldy $04 ;get old contents of Y
|
|
lda SprObject_Y_Position,x ;get vertical coordinate of object
|
|
clc
|
|
adc BlockBuffer_Y_Adder,y ;add it to value obtained using Y as offset
|
|
and #%11110000 ;mask out low nybble
|
|
sec
|
|
sbc #$20 ;subtract 32 pixels for the status bar
|
|
sta $02 ;store result here
|
|
tay ;use as offset for block buffer
|
|
lda ($06),y ;check current content of block buffer
|
|
sta $03 ;and store here
|
|
ldy $04 ;get old contents of Y again
|
|
pla ;pull A from stack
|
|
bne RetXC ;if A = 1, branch
|
|
lda SprObject_Y_Position,x ;if A = 0, load vertical coordinate
|
|
jmp RetYC ;and jump
|
|
RetXC lda SprObject_X_Position,x ;otherwise load horizontal coordinate
|
|
RetYC and #%00001111 ;and mask out high nybble
|
|
sta $04 ;store masked out result here
|
|
lda $03 ;get saved content of block buffer
|
|
rts ;and leave
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
;unused byte
|
|
db $ff
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$00 - offset to vine Y coordinate adder
|
|
;$02 - offset to sprite data
|
|
|
|
VineYPosAdder
|
|
db $00,$30
|
|
|
|
DrawVine
|
|
sty $00 ;save offset here
|
|
lda Enemy_Rel_YPos ;get relative vertical coordinate
|
|
clc
|
|
adc VineYPosAdder,y ;add value using offset in Y to get value
|
|
ldx VineObjOffset,y ;get offset to vine
|
|
ldy Enemy_SprDataOffset,x ;get sprite data offset
|
|
sty $02 ;store sprite data offset here
|
|
jsr SixSpriteStacker ;stack six sprites on top of each other vertically
|
|
lda Enemy_Rel_XPos ;get relative horizontal coordinate
|
|
sta Sprite_X_Position,y ;store in first, third and fifth sprites
|
|
sta Sprite_X_Position+8,y
|
|
sta Sprite_X_Position+16,y
|
|
clc
|
|
adc #$06 ;add six pixels to second, fourth and sixth sprites
|
|
sta Sprite_X_Position+4,y ;to give characteristic staggered vine shape to
|
|
sta Sprite_X_Position+12,y ;our vertical stack of sprites
|
|
sta Sprite_X_Position+20,y
|
|
lda #%00100001 ;set bg priority and palette attribute bits
|
|
sta Sprite_Attributes,y ;set in first, third and fifth sprites
|
|
sta Sprite_Attributes+8,y
|
|
sta Sprite_Attributes+16,y
|
|
ora #%01000000 ;additionally, set horizontal flip bit
|
|
sta Sprite_Attributes+4,y ;for second, fourth and sixth sprites
|
|
sta Sprite_Attributes+12,y
|
|
sta Sprite_Attributes+20,y
|
|
ldx #$05 ;set tiles for six sprites
|
|
VineTL lda #$e1 ;set tile number for sprite
|
|
sta Sprite_Tilenumber,y
|
|
iny ;move offset to next sprite data
|
|
iny
|
|
iny
|
|
iny
|
|
dex ;move onto next sprite
|
|
bpl VineTL ;loop until all sprites are done
|
|
ldy $02 ;get original offset
|
|
lda $00 ;get offset to vine adding data
|
|
bne SkpVTop ;if offset not zero, skip this part
|
|
lda #$e0
|
|
sta Sprite_Tilenumber,y ;set other tile number for top of vine
|
|
SkpVTop ldx #$00 ;start with the first sprite again
|
|
ChkFTop lda VineStart_Y_Position ;get original starting vertical coordinate
|
|
sec
|
|
sbc Sprite_Y_Position,y ;subtract top-most sprite's Y coordinate
|
|
cmp #$64 ;if two coordinates are less than 100/$64 pixels
|
|
bcc NextVSp ;apart, skip this to leave sprite alone
|
|
lda #$f8
|
|
sta Sprite_Y_Position,y ;otherwise move sprite offscreen
|
|
NextVSp iny ;move offset to next OAM data
|
|
iny
|
|
iny
|
|
iny
|
|
inx ;move onto next sprite
|
|
cpx #$06 ;do this until all sprites are checked
|
|
bne ChkFTop
|
|
ldy $00 ;return offset set earlier
|
|
rts
|
|
|
|
SixSpriteStacker
|
|
ldx #$06 ;do six sprites
|
|
StkLp sta Sprite_Data,y ;store X or Y coordinate into OAM data
|
|
clc
|
|
adc #$08 ;add eight pixels
|
|
iny
|
|
iny ;move offset four bytes forward
|
|
iny
|
|
iny
|
|
dex ;do another sprite
|
|
bne StkLp ;do this until all sprites are done
|
|
ldy $02 ;get saved OAM data offset and leave
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
FirstSprXPos
|
|
db $04,$00,$04,$00
|
|
|
|
FirstSprYPos
|
|
db $00,$04,$00,$04
|
|
|
|
SecondSprXPos
|
|
db $00,$08,$00,$08
|
|
|
|
SecondSprYPos
|
|
db $08,$00,$08,$00
|
|
|
|
FirstSprTilenum
|
|
db $80,$82,$81,$83
|
|
|
|
SecondSprTilenum
|
|
db $81,$83,$80,$82
|
|
|
|
HammerSprAttrib
|
|
db $03,$03,$c3,$c3
|
|
|
|
DrawHammer
|
|
ldy Misc_SprDataOffset,x ;get misc object OAM data offset
|
|
lda TimerControl
|
|
bne ForceHPose ;if master timer control set, skip this part
|
|
lda Misc_State,x ;otherwise get hammer's state
|
|
and #%01111111 ;mask out d7
|
|
cmp #$01 ;check to see if set to 1 yet
|
|
beq GetHPose ;if so, branch
|
|
ForceHPose ldx #$00 ;reset offset here
|
|
beq RenderH ;do unconditional branch to rendering part
|
|
GetHPose lda FrameCounter ;get frame counter
|
|
lsr ;move d3-d2 to d1-d0
|
|
lsr
|
|
and #%00000011 ;mask out all but d1-d0 (changes every four frames)
|
|
tax ;use as timing offset
|
|
RenderH lda Misc_Rel_YPos ;get relative vertical coordinate
|
|
clc
|
|
adc FirstSprYPos,x ;add first sprite vertical adder based on offset
|
|
sta Sprite_Y_Position,y ;store as sprite Y coordinate for first sprite
|
|
clc
|
|
adc SecondSprYPos,x ;add second sprite vertical adder based on offset
|
|
sta Sprite_Y_Position+4,y ;store as sprite Y coordinate for second sprite
|
|
lda Misc_Rel_XPos ;get relative horizontal coordinate
|
|
clc
|
|
adc FirstSprXPos,x ;add first sprite horizontal adder based on offset
|
|
sta Sprite_X_Position,y ;store as sprite X coordinate for first sprite
|
|
clc
|
|
adc SecondSprXPos,x ;add second sprite horizontal adder based on offset
|
|
sta Sprite_X_Position+4,y ;store as sprite X coordinate for second sprite
|
|
lda FirstSprTilenum,x
|
|
sta Sprite_Tilenumber,y ;get and store tile number of first sprite
|
|
lda SecondSprTilenum,x
|
|
sta Sprite_Tilenumber+4,y ;get and store tile number of second sprite
|
|
lda HammerSprAttrib,x
|
|
sta Sprite_Attributes,y ;get and store attribute bytes for both
|
|
sta Sprite_Attributes+4,y ;note in this case they use the same data
|
|
ldx ObjectOffset ;get misc object offset
|
|
lda Misc_OffscreenBits
|
|
and #%11111100 ;check offscreen bits
|
|
beq NoHOffscr ;if all bits clear, leave object alone
|
|
lda #$00
|
|
sta Misc_State,x ;otherwise nullify misc object state
|
|
lda #$f8
|
|
jsr DumpTwoSpr ;do sub to move hammer sprites offscreen
|
|
NoHOffscr rts ;leave
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$00-$01 - used to hold tile numbers ($01 addressed in draw floatey number part)
|
|
;$02 - used to hold Y coordinate for floatey number
|
|
;$03 - residual byte used for flip (but value set here affects nothing)
|
|
;$04 - attribute byte for floatey number
|
|
;$05 - used as X coordinate for floatey number
|
|
|
|
FlagpoleScoreNumTiles
|
|
db $f9,$50
|
|
db $f7,$50
|
|
db $fa,$fb
|
|
db $f8,$fb
|
|
db $f6,$fb
|
|
|
|
FlagpoleGfxHandler
|
|
ldy Enemy_SprDataOffset,x ;get sprite data offset for flagpole flag
|
|
lda Enemy_Rel_XPos ;get relative horizontal coordinate
|
|
sta Sprite_X_Position,y ;store as X coordinate for first sprite
|
|
clc
|
|
adc #$08 ;add eight pixels and store
|
|
sta Sprite_X_Position+4,y ;as X coordinate for second and third sprites
|
|
sta Sprite_X_Position+8,y
|
|
clc
|
|
adc #$0c ;add twelve more pixels and
|
|
sta $05 ;store here to be used later by floatey number
|
|
lda Enemy_Y_Position,x ;get vertical coordinate
|
|
jsr DumpTwoSpr ;and do sub to dump into first and second sprites
|
|
adc #$08 ;add eight pixels
|
|
sta Sprite_Y_Position+8,y ;and store into third sprite
|
|
lda FlagpoleFNum_Y_Pos ;get vertical coordinate for floatey number
|
|
sta $02 ;store it here
|
|
lda #$01
|
|
sta $03 ;set value for flip which will not be used, and
|
|
sta $04 ;attribute byte for floatey number
|
|
sta Sprite_Attributes,y ;set attribute bytes for all three sprites
|
|
sta Sprite_Attributes+4,y
|
|
sta Sprite_Attributes+8,y
|
|
lda #$7e
|
|
sta Sprite_Tilenumber,y ;put triangle shaped tile
|
|
sta Sprite_Tilenumber+8,y ;into first and third sprites
|
|
lda #$7f
|
|
sta Sprite_Tilenumber+4,y ;put skull tile into second sprite
|
|
lda FlagpoleCollisionYPos ;get vertical coordinate at time of collision
|
|
beq ChkFlagOffscreen ;if zero, branch ahead
|
|
tya
|
|
clc ;add 12 bytes to sprite data offset
|
|
adc #$0c
|
|
tay ;put back in Y
|
|
lda FlagpoleScore ;get offset used to award points for touching flagpole
|
|
asl ;multiply by 2 to get proper offset here
|
|
tax
|
|
lda FlagpoleScoreNumTiles,x ;get appropriate tile data
|
|
sta $00
|
|
lda FlagpoleScoreNumTiles+1,x
|
|
jsr DrawOneSpriteRow ;use it to render floatey number
|
|
|
|
ChkFlagOffscreen
|
|
ldx ObjectOffset ;get object offset for flag
|
|
ldy Enemy_SprDataOffset,x ;get OAM data offset
|
|
lda Enemy_OffscreenBits ;get offscreen bits
|
|
and #%00001110 ;mask out all but d3-d1
|
|
beq ExitDumpSpr ;if none of these bits set, branch to leave
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
MoveSixSpritesOffscreen
|
|
lda #$f8 ;set offscreen coordinate if jumping here
|
|
|
|
DumpSixSpr
|
|
sta Sprite_Data+20,y ;dump A contents
|
|
sta Sprite_Data+16,y ;into third row sprites
|
|
|
|
DumpFourSpr
|
|
sta Sprite_Data+12,y ;into second row sprites
|
|
|
|
DumpThreeSpr
|
|
sta Sprite_Data+8,y
|
|
|
|
DumpTwoSpr
|
|
sta Sprite_Data+4,y ;and into first row sprites
|
|
sta Sprite_Data,y
|
|
|
|
ExitDumpSpr
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
DrawLargePlatform
|
|
ldy Enemy_SprDataOffset,x ;get OAM data offset
|
|
sty $02 ;store here
|
|
iny ;add 3 to it for offset
|
|
iny ;to X coordinate
|
|
iny
|
|
lda Enemy_Rel_XPos ;get horizontal relative coordinate
|
|
jsr SixSpriteStacker ;store X coordinates using A as base, stack horizontally
|
|
ldx ObjectOffset
|
|
lda Enemy_Y_Position,x ;get vertical coordinate
|
|
jsr DumpFourSpr ;dump into first four sprites as Y coordinate
|
|
ldy AreaType
|
|
cpy #$03 ;check for castle-type level
|
|
beq ShrinkPlatform
|
|
ldy SecondaryHardMode ;check for secondary hard mode flag set
|
|
beq SetLast2Platform ;branch if not set elsewhere
|
|
|
|
ShrinkPlatform
|
|
lda #$f8 ;load offscreen coordinate if flag set or castle-type level
|
|
|
|
SetLast2Platform
|
|
ldy Enemy_SprDataOffset,x ;get OAM data offset
|
|
sta Sprite_Y_Position+16,y ;store vertical coordinate or offscreen
|
|
sta Sprite_Y_Position+20,y ;coordinate into last two sprites as Y coordinate
|
|
lda #$5b ;load default tile for platform (girder)
|
|
ldx CloudTypeOverride
|
|
beq SetPlatformTilenum ;if cloud level override flag not set, use
|
|
lda #$75 ;otherwise load other tile for platform (puff)
|
|
|
|
SetPlatformTilenum
|
|
ldx ObjectOffset ;get enemy object buffer offset
|
|
iny ;increment Y for tile offset
|
|
jsr DumpSixSpr ;dump tile number into all six sprites
|
|
lda #$02 ;set palette controls
|
|
iny ;increment Y for sprite attributes
|
|
jsr DumpSixSpr ;dump attributes into all six sprites
|
|
inx ;increment X for enemy objects
|
|
jsr GetXOffscreenBits ;get offscreen bits again
|
|
dex
|
|
ldy Enemy_SprDataOffset,x ;get OAM data offset
|
|
asl ;rotate d7 into carry, save remaining
|
|
pha ;bits to the stack
|
|
bcc SChk2
|
|
lda #$f8 ;if d7 was set, move first sprite offscreen
|
|
sta Sprite_Y_Position,y
|
|
SChk2 pla ;get bits from stack
|
|
asl ;rotate d6 into carry
|
|
pha ;save to stack
|
|
bcc SChk3
|
|
lda #$f8 ;if d6 was set, move second sprite offscreen
|
|
sta Sprite_Y_Position+4,y
|
|
SChk3 pla ;get bits from stack
|
|
asl ;rotate d5 into carry
|
|
pha ;save to stack
|
|
bcc SChk4
|
|
lda #$f8 ;if d5 was set, move third sprite offscreen
|
|
sta Sprite_Y_Position+8,y
|
|
SChk4 pla ;get bits from stack
|
|
asl ;rotate d4 into carry
|
|
pha ;save to stack
|
|
bcc SChk5
|
|
lda #$f8 ;if d4 was set, move fourth sprite offscreen
|
|
sta Sprite_Y_Position+12,y
|
|
SChk5 pla ;get bits from stack
|
|
asl ;rotate d3 into carry
|
|
pha ;save to stack
|
|
bcc SChk6
|
|
lda #$f8 ;if d3 was set, move fifth sprite offscreen
|
|
sta Sprite_Y_Position+16,y
|
|
SChk6 pla ;get bits from stack
|
|
asl ;rotate d2 into carry
|
|
bcc SLChk ;save to stack
|
|
lda #$f8
|
|
sta Sprite_Y_Position+20,y ;if d2 was set, move sixth sprite offscreen
|
|
SLChk lda Enemy_OffscreenBits ;check d7 of offscreen bits
|
|
asl ;and if d7 is not set, skip sub
|
|
bcc ExDLPl
|
|
jsr MoveSixSpritesOffscreen ;otherwise branch to move all sprites offscreen
|
|
ExDLPl rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
DrawFloateyNumber_Coin
|
|
lda FrameCounter ;get frame counter
|
|
lsr ;divide by 2
|
|
bcs NotRsNum ;branch if d0 not set to raise number every other frame
|
|
dec Misc_Y_Position,x ;otherwise, decrement vertical coordinate
|
|
NotRsNum lda Misc_Y_Position,x ;get vertical coordinate
|
|
jsr DumpTwoSpr ;dump into both sprites
|
|
lda Misc_Rel_XPos ;get relative horizontal coordinate
|
|
sta Sprite_X_Position,y ;store as X coordinate for first sprite
|
|
clc
|
|
adc #$08 ;add eight pixels
|
|
sta Sprite_X_Position+4,y ;store as X coordinate for second sprite
|
|
lda #$02
|
|
sta Sprite_Attributes,y ;store attribute byte in both sprites
|
|
sta Sprite_Attributes+4,y
|
|
lda #$f7
|
|
sta Sprite_Tilenumber,y ;put tile numbers into both sprites
|
|
lda #$fb ;that resemble "200"
|
|
sta Sprite_Tilenumber+4,y
|
|
jmp ExJCGfx ;then jump to leave (why not an rts here instead?)
|
|
|
|
JumpingCoinTiles
|
|
db $60,$61,$62,$63
|
|
|
|
JCoinGfxHandler
|
|
ldy Misc_SprDataOffset,x ;get coin/floatey number's OAM data offset
|
|
lda Misc_State,x ;get state of misc object
|
|
cmp #$02 ;if 2 or greater,
|
|
bcs DrawFloateyNumber_Coin ;branch to draw floatey number
|
|
lda Misc_Y_Position,x ;store vertical coordinate as
|
|
sta Sprite_Y_Position,y ;Y coordinate for first sprite
|
|
clc
|
|
adc #$08 ;add eight pixels
|
|
sta Sprite_Y_Position+4,y ;store as Y coordinate for second sprite
|
|
lda Misc_Rel_XPos ;get relative horizontal coordinate
|
|
sta Sprite_X_Position,y
|
|
sta Sprite_X_Position+4,y ;store as X coordinate for first and second sprites
|
|
lda FrameCounter ;get frame counter
|
|
lsr ;divide by 2 to alter every other frame
|
|
and #%00000011 ;mask out d2-d1
|
|
tax ;use as graphical offset
|
|
lda JumpingCoinTiles,x ;load tile number
|
|
iny ;increment OAM data offset to write tile numbers
|
|
jsr DumpTwoSpr ;do sub to dump tile number into both sprites
|
|
dey ;decrement to get old offset
|
|
lda #$02
|
|
sta Sprite_Attributes,y ;set attribute byte in first sprite
|
|
lda #$82
|
|
sta Sprite_Attributes+4,y ;set attribute byte with vertical flip in second sprite
|
|
ldx ObjectOffset ;get misc object offset
|
|
ExJCGfx rts ;leave
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$00-$01 - used to hold tiles for drawing the power-up,$00 also used to hold power-up type
|
|
;$02 - used to hold bottom row Y position
|
|
;$03 - used to hold flip control (not used here)
|
|
;$04 - used to hold sprite attributes
|
|
;$05 - used to hold X position
|
|
;$07 - counter
|
|
|
|
;tiles arranged in top left, right, bottom left, right order
|
|
PowerUpGfxTable
|
|
db $76,$77,$78,$79 ;regular mushroom
|
|
db $d6,$d6,$d9,$d9 ;fire flower
|
|
db $8d,$8d,$e4,$e4 ;star
|
|
db $76,$77,$78,$79 ;1-up mushroom
|
|
|
|
PowerUpAttributes
|
|
db $02,$01,$02,$01
|
|
|
|
DrawPowerUp
|
|
ldy Enemy_SprDataOffset+5 ;get power-up's sprite data offset
|
|
lda Enemy_Rel_YPos ;get relative vertical coordinate
|
|
clc
|
|
adc #$08 ;add eight pixels
|
|
sta $02 ;store result here
|
|
lda Enemy_Rel_XPos ;get relative horizontal coordinate
|
|
sta $05 ;store here
|
|
ldx PowerUpType ;get power-up type
|
|
lda PowerUpAttributes,x ;get attribute data for power-up type
|
|
ora Enemy_SprAttrib+5 ;add background priority bit if set
|
|
sta $04 ;store attributes here
|
|
txa
|
|
pha ;save power-up type to the stack
|
|
asl
|
|
asl ;multiply by four to get proper offset
|
|
tax ;use as X
|
|
lda #$01
|
|
sta $07 ;set counter here to draw two rows of sprite object
|
|
sta $03 ;init d1 of flip control
|
|
|
|
PUpDrawLoop
|
|
lda PowerUpGfxTable,x ;load left tile of power-up object
|
|
sta $00
|
|
lda PowerUpGfxTable+1,x ;load right tile
|
|
jsr DrawOneSpriteRow ;branch to draw one row of our power-up object
|
|
dec $07 ;decrement counter
|
|
bpl PUpDrawLoop ;branch until two rows are drawn
|
|
ldy Enemy_SprDataOffset+5 ;get sprite data offset again
|
|
pla ;pull saved power-up type from the stack
|
|
beq PUpOfs ;if regular mushroom, branch, do not change colors or flip
|
|
cmp #$03
|
|
beq PUpOfs ;if 1-up mushroom, branch, do not change colors or flip
|
|
sta $00 ;store power-up type here now
|
|
lda FrameCounter ;get frame counter
|
|
lsr ;divide by 2 to change colors every two frames
|
|
and #%00000011 ;mask out all but d1 and d0 (previously d2 and d1)
|
|
ora Enemy_SprAttrib+5 ;add background priority bit if any set
|
|
sta Sprite_Attributes,y ;set as new palette bits for top left and
|
|
sta Sprite_Attributes+4,y ;top right sprites for fire flower and star
|
|
ldx $00
|
|
dex ;check power-up type for fire flower
|
|
beq FlipPUpRightSide ;if found, skip this part
|
|
sta Sprite_Attributes+8,y ;otherwise set new palette bits for bottom left
|
|
sta Sprite_Attributes+12,y ;and bottom right sprites as well for star only
|
|
|
|
FlipPUpRightSide
|
|
lda Sprite_Attributes+4,y
|
|
ora #%01000000 ;set horizontal flip bit for top right sprite
|
|
sta Sprite_Attributes+4,y
|
|
lda Sprite_Attributes+12,y
|
|
ora #%01000000 ;set horizontal flip bit for bottom right sprite
|
|
sta Sprite_Attributes+12,y ;note these are only done for fire flower and star power-ups
|
|
PUpOfs jmp SprObjectOffscrChk ;jump to check to see if power-up is offscreen at all, then leave
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$00-$01 - used in DrawEnemyObjRow to hold sprite tile numbers
|
|
;$02 - used to store Y position
|
|
;$03 - used to store moving direction, used to flip enemies horizontally
|
|
;$04 - used to store enemy's sprite attributes
|
|
;$05 - used to store X position
|
|
;$eb - used to hold sprite data offset
|
|
;$ec - used to hold either altered enemy state or special value used in gfx handler as condition
|
|
;$ed - used to hold enemy state from buffer
|
|
;$ef - used to hold enemy code used in gfx handler (may or may not resemble Enemy_ID values)
|
|
|
|
;tiles arranged in top left, right, middle left, right, bottom left, right order
|
|
EnemyGraphicsTable
|
|
db $fc,$fc,$aa,$ab,$ac,$ad ;buzzy beetle frame 1
|
|
db $fc,$fc,$ae,$af,$b0,$b1 ; frame 2
|
|
db $fc,$a5,$a6,$a7,$a8,$a9 ;koopa troopa frame 1
|
|
db $fc,$a0,$a1,$a2,$a3,$a4 ; frame 2
|
|
db $69,$a5,$6a,$a7,$a8,$a9 ;koopa paratroopa frame 1
|
|
db $6b,$a0,$6c,$a2,$a3,$a4 ; frame 2
|
|
db $fc,$fc,$96,$97,$98,$99 ;spiny frame 1
|
|
db $fc,$fc,$9a,$9b,$9c,$9d ; frame 2
|
|
db $fc,$fc,$8f,$8e,$8e,$8f ;spiny's egg frame 1
|
|
db $fc,$fc,$95,$94,$94,$95 ; frame 2
|
|
db $fc,$fc,$dc,$dc,$df,$df ;bloober frame 1
|
|
db $dc,$dc,$dd,$dd,$de,$de ; frame 2
|
|
db $fc,$fc,$b2,$b3,$b4,$b5 ;cheep-cheep frame 1
|
|
db $fc,$fc,$b6,$b3,$b7,$b5 ; frame 2
|
|
db $fc,$fc,$70,$71,$72,$73 ;goomba
|
|
db $fc,$fc,$6e,$6e,$6f,$6f ;koopa shell frame 1 (upside-down)
|
|
db $fc,$fc,$6d,$6d,$6f,$6f ; frame 2
|
|
db $fc,$fc,$6f,$6f,$6e,$6e ;koopa shell frame 1 (rightsideup)
|
|
db $fc,$fc,$6f,$6f,$6d,$6d ; frame 2
|
|
db $fc,$fc,$f4,$f4,$f5,$f5 ;buzzy beetle shell frame 1 (rightsideup)
|
|
db $fc,$fc,$f4,$f4,$f5,$f5 ; frame 2
|
|
db $fc,$fc,$f5,$f5,$f4,$f4 ;buzzy beetle shell frame 1 (upside-down)
|
|
db $fc,$fc,$f5,$f5,$f4,$f4 ; frame 2
|
|
db $fc,$fc,$fc,$fc,$ef,$ef ;defeated goomba
|
|
db $b9,$b8,$bb,$ba,$bc,$bc ;lakitu frame 1
|
|
db $fc,$fc,$bd,$bd,$bc,$bc ; frame 2
|
|
db $7a,$7b,$da,$db,$d8,$d8 ;princess
|
|
db $cd,$cd,$ce,$ce,$cf,$cf ;mushroom retainer
|
|
db $7d,$7c,$d1,$8c,$d3,$d2 ;hammer bro frame 1
|
|
db $7d,$7c,$89,$88,$8b,$8a ; frame 2
|
|
db $d5,$d4,$e3,$e2,$d3,$d2 ; frame 3
|
|
db $d5,$d4,$e3,$e2,$8b,$8a ; frame 4
|
|
db $e5,$e5,$e6,$e6,$eb,$eb ;piranha plant frame 1
|
|
db $ec,$ec,$ed,$ed,$ee,$ee ; frame 2
|
|
db $fc,$fc,$d0,$d0,$d7,$d7 ;podoboo
|
|
db $bf,$be,$c1,$c0,$c2,$fc ;bowser front frame 1
|
|
db $c4,$c3,$c6,$c5,$c8,$c7 ;bowser rear frame 1
|
|
db $bf,$be,$ca,$c9,$c2,$fc ; front frame 2
|
|
db $c4,$c3,$c6,$c5,$cc,$cb ; rear frame 2
|
|
db $fc,$fc,$e8,$e7,$ea,$e9 ;bullet bill
|
|
db $f2,$f2,$f3,$f3,$f2,$f2 ;jumpspring frame 1
|
|
db $f1,$f1,$f1,$f1,$fc,$fc ; frame 2
|
|
db $f0,$f0,$fc,$fc,$fc,$fc ; frame 3
|
|
|
|
EnemyGfxTableOffsets
|
|
db $0c,$0c,$00,$0c,$0c,$a8,$54,$3c
|
|
db $ea,$18,$48,$48,$cc,$c0,$18,$18
|
|
db $18,$90,$24,$ff,$48,$9c,$d2,$d8
|
|
db $f0,$f6,$fc
|
|
|
|
EnemyAttributeData
|
|
db $01,$02,$03,$02,$01,$01,$03,$03
|
|
db $03,$01,$01,$02,$02,$21,$01,$02
|
|
db $01,$01,$02,$ff,$02,$02,$01,$01
|
|
db $02,$02,$02
|
|
|
|
EnemyAnimTimingBMask
|
|
db $08,$18
|
|
|
|
JumpspringFrameOffsets
|
|
db $18,$19,$1a,$19,$18
|
|
|
|
EnemyGfxHandler
|
|
lda Enemy_Y_Position,x ;get enemy object vertical position
|
|
sta $02
|
|
lda Enemy_Rel_XPos ;get enemy object horizontal position
|
|
sta $05 ;relative to screen
|
|
ldy Enemy_SprDataOffset,x
|
|
sty $eb ;get sprite data offset
|
|
lda #$00
|
|
sta VerticalFlipFlag ;initialize vertical flip flag by default
|
|
lda Enemy_MovingDir,x
|
|
sta $03 ;get enemy object moving direction
|
|
lda Enemy_SprAttrib,x
|
|
sta $04 ;get enemy object sprite attributes
|
|
lda Enemy_ID,x
|
|
cmp #PiranhaPlant ;is enemy object piranha plant?
|
|
bne CheckForRetainerObj ;if not, branch
|
|
ldy PiranhaPlant_Y_Speed,x
|
|
bmi CheckForRetainerObj ;if piranha plant moving upwards, branch
|
|
ldy EnemyFrameTimer,x
|
|
beq CheckForRetainerObj ;if timer for movement expired, branch
|
|
rts ;if all conditions fail, leave
|
|
|
|
CheckForRetainerObj
|
|
lda Enemy_State,x ;store enemy state
|
|
sta $ed
|
|
and #%00011111 ;nullify all but 5 LSB and use as Y
|
|
tay
|
|
lda Enemy_ID,x ;check for mushroom retainer/princess object
|
|
cmp #RetainerObject
|
|
bne CheckForBulletBillCV ;if not found, branch
|
|
ldy #$00 ;if found, nullify saved state in Y
|
|
lda #$01 ;set value that will not be used
|
|
sta $03
|
|
lda #$15 ;set value $15 as code for mushroom retainer/princess object
|
|
|
|
CheckForBulletBillCV
|
|
cmp #BulletBill_CannonVar ;otherwise check for bullet bill object
|
|
bne CheckForJumpspring ;if not found, branch again
|
|
dec $02 ;decrement saved vertical position
|
|
lda #$03
|
|
ldy EnemyFrameTimer,x ;get timer for enemy object
|
|
beq SBBAt ;if expired, do not set priority bit
|
|
ora #%00100000 ;otherwise do so
|
|
SBBAt sta $04 ;set new sprite attributes
|
|
ldy #$00 ;nullify saved enemy state both in Y and in
|
|
sty $ed ;memory location here
|
|
lda #$08 ;set specific value to unconditionally branch once
|
|
|
|
CheckForJumpspring
|
|
cmp #JumpspringObject ;check for jumpspring object
|
|
bne CheckForPodoboo
|
|
ldy #$03 ;set enemy state -2 MSB here for jumpspring object
|
|
ldx JumpspringAnimCtrl ;get current frame number for jumpspring object
|
|
lda JumpspringFrameOffsets,x ;load data using frame number as offset
|
|
|
|
CheckForPodoboo
|
|
sta $ef ;store saved enemy object value here
|
|
sty $ec ;and Y here (enemy state -2 MSB if not changed)
|
|
ldx ObjectOffset ;get enemy object offset
|
|
cmp #$0c ;check for podoboo object
|
|
bne CheckBowserGfxFlag ;branch if not found
|
|
lda Enemy_Y_Speed,x ;if moving upwards, branch
|
|
bmi CheckBowserGfxFlag
|
|
inc VerticalFlipFlag ;otherwise, set flag for vertical flip
|
|
|
|
CheckBowserGfxFlag
|
|
lda BowserGfxFlag ;if not drawing bowser at all, skip to something else
|
|
beq CheckForGoomba
|
|
ldy #$16 ;if set to 1, draw bowser's front
|
|
cmp #$01
|
|
beq SBwsrGfxOfs
|
|
iny ;otherwise draw bowser's rear
|
|
SBwsrGfxOfs sty $ef
|
|
|
|
CheckForGoomba
|
|
ldy $ef ;check value for goomba object
|
|
cpy #Goomba
|
|
bne CheckBowserFront ;branch if not found
|
|
lda Enemy_State,x
|
|
cmp #$02 ;check for defeated state
|
|
bcc GmbaAnim ;if not defeated, go ahead and animate
|
|
ldx #$04 ;if defeated, write new value here
|
|
stx $ec
|
|
GmbaAnim and #%00100000 ;check for d5 set in enemy object state
|
|
ora TimerControl ;or timer disable flag set
|
|
bne CheckBowserFront ;if either condition true, do not animate goomba
|
|
lda FrameCounter
|
|
and #%00001000 ;check for every eighth frame
|
|
bne CheckBowserFront
|
|
lda $03
|
|
eor #%00000011 ;invert bits to flip horizontally every eight frames
|
|
sta $03 ;leave alone otherwise
|
|
|
|
CheckBowserFront
|
|
lda EnemyAttributeData,y ;load sprite attribute using enemy object
|
|
ora $04 ;as offset, and add to bits already loaded
|
|
sta $04
|
|
lda EnemyGfxTableOffsets,y ;load value based on enemy object as offset
|
|
tax ;save as X
|
|
ldy $ec ;get previously saved value
|
|
lda BowserGfxFlag
|
|
beq CheckForSpiny ;if not drawing bowser object at all, skip all of this
|
|
cmp #$01
|
|
bne CheckBowserRear ;if not drawing front part, branch to draw the rear part
|
|
lda BowserBodyControls ;check bowser's body control bits
|
|
bpl ChkFrontSte ;branch if d7 not set (control's bowser's mouth)
|
|
ldx #$de ;otherwise load offset for second frame
|
|
ChkFrontSte lda $ed ;check saved enemy state
|
|
and #%00100000 ;if bowser not defeated, do not set flag
|
|
beq DrawBowser
|
|
|
|
FlipBowserOver
|
|
stx VerticalFlipFlag ;set vertical flip flag to nonzero
|
|
|
|
DrawBowser
|
|
jmp DrawEnemyObject ;draw bowser's graphics now
|
|
|
|
CheckBowserRear
|
|
lda BowserBodyControls ;check bowser's body control bits
|
|
and #$01
|
|
beq ChkRearSte ;branch if d0 not set (control's bowser's feet)
|
|
ldx #$e4 ;otherwise load offset for second frame
|
|
ChkRearSte lda $ed ;check saved enemy state
|
|
and #%00100000 ;if bowser not defeated, do not set flag
|
|
beq DrawBowser
|
|
lda $02 ;subtract 16 pixels from
|
|
sec ;saved vertical coordinate
|
|
sbc #$10
|
|
sta $02
|
|
jmp FlipBowserOver ;jump to set vertical flip flag
|
|
|
|
CheckForSpiny
|
|
cpx #$24 ;check if value loaded is for spiny
|
|
bne CheckForLakitu ;if not found, branch
|
|
cpy #$05 ;if enemy state set to $05, do this,
|
|
bne NotEgg ;otherwise branch
|
|
ldx #$30 ;set to spiny egg offset
|
|
lda #$02
|
|
sta $03 ;set enemy direction to reverse sprites horizontally
|
|
lda #$05
|
|
sta $ec ;set enemy state
|
|
NotEgg jmp CheckForHammerBro ;skip a big chunk of this if we found spiny but not in egg
|
|
|
|
CheckForLakitu
|
|
cpx #$90 ;check value for lakitu's offset loaded
|
|
bne CheckUpsideDownShell ;branch if not loaded
|
|
lda $ed
|
|
and #%00100000 ;check for d5 set in enemy state
|
|
bne NoLAFr ;branch if set
|
|
lda FrenzyEnemyTimer
|
|
cmp #$10 ;check timer to see if we've reached a certain range
|
|
bcs NoLAFr ;branch if not
|
|
ldx #$96 ;if d6 not set and timer in range, load alt frame for lakitu
|
|
NoLAFr jmp CheckDefeatedState ;skip this next part if we found lakitu but alt frame not needed
|
|
|
|
CheckUpsideDownShell
|
|
lda $ef ;check for enemy object => $04
|
|
cmp #$04
|
|
bcs CheckRightSideUpShell ;branch if true
|
|
cpy #$02
|
|
bcc CheckRightSideUpShell ;branch if enemy state < $02
|
|
ldx #$5a ;set for upside-down koopa shell by default
|
|
ldy $ef
|
|
cpy #BuzzyBeetle ;check for buzzy beetle object
|
|
bne CheckRightSideUpShell
|
|
ldx #$7e ;set for upside-down buzzy beetle shell if found
|
|
inc $02 ;increment vertical position by one pixel
|
|
|
|
CheckRightSideUpShell
|
|
lda $ec ;check for value set here
|
|
cmp #$04 ;if enemy state < $02, do not change to shell, if
|
|
bne CheckForHammerBro ;enemy state => $02 but not = $04, leave shell upside-down
|
|
ldx #$72 ;set right-side up buzzy beetle shell by default
|
|
inc $02 ;increment saved vertical position by one pixel
|
|
ldy $ef
|
|
cpy #BuzzyBeetle ;check for buzzy beetle object
|
|
beq CheckForDefdGoomba ;branch if found
|
|
ldx #$66 ;change to right-side up koopa shell if not found
|
|
inc $02 ;and increment saved vertical position again
|
|
|
|
CheckForDefdGoomba
|
|
cpy #Goomba ;check for goomba object (necessary if previously
|
|
bne CheckForHammerBro ;failed buzzy beetle object test)
|
|
ldx #$54 ;load for regular goomba
|
|
lda $ed ;note that this only gets performed if enemy state => $02
|
|
and #%00100000 ;check saved enemy state for d5 set
|
|
bne CheckForHammerBro ;branch if set
|
|
ldx #$8a ;load offset for defeated goomba
|
|
dec $02 ;set different value and decrement saved vertical position
|
|
|
|
CheckForHammerBro
|
|
ldy ObjectOffset
|
|
lda $ef ;check for hammer bro object
|
|
cmp #HammerBro
|
|
bne CheckForBloober ;branch if not found
|
|
lda $ed
|
|
beq CheckToAnimateEnemy ;branch if not in normal enemy state
|
|
and #%00001000
|
|
beq CheckDefeatedState ;if d3 not set, branch further away
|
|
ldx #$b4 ;otherwise load offset for different frame
|
|
bne CheckToAnimateEnemy ;unconditional branch
|
|
|
|
CheckForBloober
|
|
cpx #$48 ;check for cheep-cheep offset loaded
|
|
beq CheckToAnimateEnemy ;branch if found
|
|
lda EnemyIntervalTimer,y
|
|
cmp #$05
|
|
bcs CheckDefeatedState ;branch if some timer is above a certain point
|
|
cpx #$3c ;check for bloober offset loaded
|
|
bne CheckToAnimateEnemy ;branch if not found this time
|
|
cmp #$01
|
|
beq CheckDefeatedState ;branch if timer is set to certain point
|
|
inc $02 ;increment saved vertical coordinate three pixels
|
|
inc $02
|
|
inc $02
|
|
jmp CheckAnimationStop ;and do something else
|
|
|
|
CheckToAnimateEnemy
|
|
lda $ef ;check for specific enemy objects
|
|
cmp #Goomba
|
|
beq CheckDefeatedState ;branch if goomba
|
|
cmp #$08
|
|
beq CheckDefeatedState ;branch if bullet bill (note both variants use $08 here)
|
|
cmp #Podoboo
|
|
beq CheckDefeatedState ;branch if podoboo
|
|
cmp #$18 ;branch if => $18
|
|
bcs CheckDefeatedState
|
|
ldy #$00
|
|
cmp #$15 ;check for mushroom retainer/princess object
|
|
bne CheckForSecondFrame ;which uses different code here, branch if not found
|
|
iny ;residual instruction
|
|
lda WorldNumber ;are we on world 8?
|
|
cmp #World8
|
|
bcs CheckDefeatedState ;if so, leave the offset alone (use princess)
|
|
ldx #$a2 ;otherwise, set for mushroom retainer object instead
|
|
lda #$03 ;set alternate state here
|
|
sta $ec
|
|
bne CheckDefeatedState ;unconditional branch
|
|
|
|
CheckForSecondFrame
|
|
lda FrameCounter ;load frame counter
|
|
and EnemyAnimTimingBMask,y ;mask it (partly residual, one byte not ever used)
|
|
bne CheckDefeatedState ;branch if timing is off
|
|
|
|
CheckAnimationStop
|
|
lda $ed ;check saved enemy state
|
|
and #%10100000 ;for d7 or d5, or check for timers stopped
|
|
ora TimerControl
|
|
bne CheckDefeatedState ;if either condition true, branch
|
|
txa
|
|
clc
|
|
adc #$06 ;add $06 to current enemy offset
|
|
tax ;to animate various enemy objects
|
|
|
|
CheckDefeatedState
|
|
lda $ed ;check saved enemy state
|
|
and #%00100000 ;for d5 set
|
|
beq DrawEnemyObject ;branch if not set
|
|
lda $ef
|
|
cmp #$04 ;check for saved enemy object => $04
|
|
bcc DrawEnemyObject ;branch if less
|
|
ldy #$01
|
|
sty VerticalFlipFlag ;set vertical flip flag
|
|
dey
|
|
sty $ec ;init saved value here
|
|
|
|
DrawEnemyObject
|
|
ldy $eb ;load sprite data offset
|
|
jsr DrawEnemyObjRow ;draw six tiles of data
|
|
jsr DrawEnemyObjRow ;into sprite data
|
|
jsr DrawEnemyObjRow
|
|
ldx ObjectOffset ;get enemy object offset
|
|
ldy Enemy_SprDataOffset,x ;get sprite data offset
|
|
lda $ef
|
|
cmp #$08 ;get saved enemy object and check
|
|
bne CheckForVerticalFlip ;for bullet bill, branch if not found
|
|
|
|
SkipToOffScrChk
|
|
jmp SprObjectOffscrChk ;jump if found
|
|
|
|
CheckForVerticalFlip
|
|
lda VerticalFlipFlag ;check if vertical flip flag is set here
|
|
beq CheckForESymmetry ;branch if not
|
|
lda Sprite_Attributes,y ;get attributes of first sprite we dealt with
|
|
ora #%10000000 ;set bit for vertical flip
|
|
iny
|
|
iny ;increment two bytes so that we store the vertical flip
|
|
jsr DumpSixSpr ;in attribute bytes of enemy obj sprite data
|
|
dey
|
|
dey ;now go back to the Y coordinate offset
|
|
tya
|
|
tax ;give offset to X
|
|
lda $ef
|
|
cmp #HammerBro ;check saved enemy object for hammer bro
|
|
beq FlipEnemyVertically
|
|
cmp #Lakitu ;check saved enemy object for lakitu
|
|
beq FlipEnemyVertically ;branch for hammer bro or lakitu
|
|
cmp #$15
|
|
bcs FlipEnemyVertically ;also branch if enemy object => $15
|
|
txa
|
|
clc
|
|
adc #$08 ;if not selected objects or => $15, set
|
|
tax ;offset in X for next row
|
|
|
|
FlipEnemyVertically
|
|
lda Sprite_Tilenumber,x ;load first or second row tiles
|
|
pha ;and save tiles to the stack
|
|
lda Sprite_Tilenumber+4,x
|
|
pha
|
|
lda Sprite_Tilenumber+16,y ;exchange third row tiles
|
|
sta Sprite_Tilenumber,x ;with first or second row tiles
|
|
lda Sprite_Tilenumber+20,y
|
|
sta Sprite_Tilenumber+4,x
|
|
pla ;pull first or second row tiles from stack
|
|
sta Sprite_Tilenumber+20,y ;and save in third row
|
|
pla
|
|
sta Sprite_Tilenumber+16,y
|
|
|
|
CheckForESymmetry
|
|
lda BowserGfxFlag ;are we drawing bowser at all?
|
|
bne SkipToOffScrChk ;branch if so
|
|
lda $ef
|
|
ldx $ec ;get alternate enemy state
|
|
cmp #$05 ;check for hammer bro object
|
|
bne ContES
|
|
jmp SprObjectOffscrChk ;jump if found
|
|
ContES cmp #Bloober ;check for bloober object
|
|
beq MirrorEnemyGfx
|
|
cmp #PiranhaPlant ;check for piranha plant object
|
|
beq MirrorEnemyGfx
|
|
cmp #Podoboo ;check for podoboo object
|
|
beq MirrorEnemyGfx ;branch if either of three are found
|
|
cmp #Spiny ;check for spiny object
|
|
bne ESRtnr ;branch closer if not found
|
|
cpx #$05 ;check spiny's state
|
|
bne CheckToMirrorLakitu ;branch if not an egg, otherwise
|
|
ESRtnr cmp #$15 ;check for princess/mushroom retainer object
|
|
bne SpnySC
|
|
lda #$42 ;set horizontal flip on bottom right sprite
|
|
sta Sprite_Attributes+20,y ;note that palette bits were already set earlier
|
|
SpnySC cpx #$02 ;if alternate enemy state set to 1 or 0, branch
|
|
bcc CheckToMirrorLakitu
|
|
|
|
MirrorEnemyGfx
|
|
lda BowserGfxFlag ;if enemy object is bowser, skip all of this
|
|
bne CheckToMirrorLakitu
|
|
lda Sprite_Attributes,y ;load attribute bits of first sprite
|
|
and #%10100011
|
|
sta Sprite_Attributes,y ;save vertical flip, priority, and palette bits
|
|
sta Sprite_Attributes+8,y ;in left sprite column of enemy object OAM data
|
|
sta Sprite_Attributes+16,y
|
|
ora #%01000000 ;set horizontal flip
|
|
cpx #$05 ;check for state used by spiny's egg
|
|
bne EggExc ;if alternate state not set to $05, branch
|
|
ora #%10000000 ;otherwise set vertical flip
|
|
EggExc sta Sprite_Attributes+4,y ;set bits of right sprite column
|
|
sta Sprite_Attributes+12,y ;of enemy object sprite data
|
|
sta Sprite_Attributes+20,y
|
|
cpx #$04 ;check alternate enemy state
|
|
bne CheckToMirrorLakitu ;branch if not $04
|
|
lda Sprite_Attributes+8,y ;get second row left sprite attributes
|
|
ora #%10000000
|
|
sta Sprite_Attributes+8,y ;store bits with vertical flip in
|
|
sta Sprite_Attributes+16,y ;second and third row left sprites
|
|
ora #%01000000
|
|
sta Sprite_Attributes+12,y ;store with horizontal and vertical flip in
|
|
sta Sprite_Attributes+20,y ;second and third row right sprites
|
|
|
|
CheckToMirrorLakitu
|
|
lda $ef ;check for lakitu enemy object
|
|
cmp #Lakitu
|
|
bne CheckToMirrorJSpring ;branch if not found
|
|
lda VerticalFlipFlag
|
|
bne NVFLak ;branch if vertical flip flag not set
|
|
lda Sprite_Attributes+16,y ;save vertical flip and palette bits
|
|
and #%10000001 ;in third row left sprite
|
|
sta Sprite_Attributes+16,y
|
|
lda Sprite_Attributes+20,y ;set horizontal flip and palette bits
|
|
ora #%01000001 ;in third row right sprite
|
|
sta Sprite_Attributes+20,y
|
|
ldx FrenzyEnemyTimer ;check timer
|
|
cpx #$10
|
|
bcs SprObjectOffscrChk ;branch if timer has not reached a certain range
|
|
sta Sprite_Attributes+12,y ;otherwise set same for second row right sprite
|
|
and #%10000001
|
|
sta Sprite_Attributes+8,y ;preserve vertical flip and palette bits for left sprite
|
|
bcc SprObjectOffscrChk ;unconditional branch
|
|
NVFLak lda Sprite_Attributes,y ;get first row left sprite attributes
|
|
and #%10000001
|
|
sta Sprite_Attributes,y ;save vertical flip and palette bits
|
|
lda Sprite_Attributes+4,y ;get first row right sprite attributes
|
|
ora #%01000001 ;set horizontal flip and palette bits
|
|
sta Sprite_Attributes+4,y ;note that vertical flip is left as-is
|
|
|
|
CheckToMirrorJSpring
|
|
lda $ef ;check for jumpspring object (any frame)
|
|
cmp #$18
|
|
bcc SprObjectOffscrChk ;branch if not jumpspring object at all
|
|
lda #$82
|
|
sta Sprite_Attributes+8,y ;set vertical flip and palette bits of
|
|
sta Sprite_Attributes+16,y ;second and third row left sprites
|
|
ora #%01000000
|
|
sta Sprite_Attributes+12,y ;set, in addition to those, horizontal flip
|
|
sta Sprite_Attributes+20,y ;for second and third row right sprites
|
|
|
|
SprObjectOffscrChk
|
|
ldx ObjectOffset ;get enemy buffer offset
|
|
lda Enemy_OffscreenBits ;check offscreen information
|
|
lsr
|
|
lsr ;shift three times to the right
|
|
lsr ;which puts d2 into carry
|
|
pha ;save to stack
|
|
bcc LcChk ;branch if not set
|
|
lda #$04 ;set for right column sprites
|
|
jsr MoveESprColOffscreen ;and move them offscreen
|
|
LcChk pla ;get from stack
|
|
lsr ;move d3 to carry
|
|
pha ;save to stack
|
|
bcc Row3C ;branch if not set
|
|
lda #$00 ;set for left column sprites,
|
|
jsr MoveESprColOffscreen ;move them offscreen
|
|
Row3C pla ;get from stack again
|
|
lsr ;move d5 to carry this time
|
|
lsr
|
|
pha ;save to stack again
|
|
bcc Row23C ;branch if carry not set
|
|
lda #$10 ;set for third row of sprites
|
|
jsr MoveESprRowOffscreen ;and move them offscreen
|
|
Row23C pla ;get from stack
|
|
lsr ;move d6 into carry
|
|
pha ;save to stack
|
|
bcc AllRowC
|
|
lda #$08 ;set for second and third rows
|
|
jsr MoveESprRowOffscreen ;move them offscreen
|
|
AllRowC pla ;get from stack once more
|
|
lsr ;move d7 into carry
|
|
bcc ExEGHandler
|
|
jsr MoveESprRowOffscreen ;move all sprites offscreen (A should be 0 by now)
|
|
lda Enemy_ID,x
|
|
cmp #Podoboo ;check enemy identifier for podoboo
|
|
beq ExEGHandler ;skip this part if found, we do not want to erase podoboo!
|
|
lda Enemy_Y_HighPos,x ;check high byte of vertical position
|
|
cmp #$02 ;if not yet past the bottom of the screen, branch
|
|
bne ExEGHandler
|
|
jsr EraseEnemyObject ;what it says
|
|
|
|
ExEGHandler
|
|
rts
|
|
|
|
DrawEnemyObjRow
|
|
lda EnemyGraphicsTable,x ;load two tiles of enemy graphics
|
|
sta $00
|
|
lda EnemyGraphicsTable+1,x
|
|
|
|
DrawOneSpriteRow
|
|
sta $01
|
|
jmp DrawSpriteObject ;draw them
|
|
|
|
MoveESprRowOffscreen
|
|
clc ;add A to enemy object OAM data offset
|
|
adc Enemy_SprDataOffset,x
|
|
tay ;use as offset
|
|
lda #$f8
|
|
jmp DumpTwoSpr ;move first row of sprites offscreen
|
|
|
|
MoveESprColOffscreen
|
|
clc ;add A to enemy object OAM data offset
|
|
adc Enemy_SprDataOffset,x
|
|
tay ;use as offset
|
|
jsr MoveColOffscreen ;move first and second row sprites in column offscreen
|
|
sta Sprite_Data+16,y ;move third row sprite in column offscreen
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$00-$01 - tile numbers
|
|
;$02 - relative Y position
|
|
;$03 - horizontal flip flag (not used here)
|
|
;$04 - attributes
|
|
;$05 - relative X position
|
|
|
|
DefaultBlockObjTiles
|
|
db $85,$85,$86,$86 ;brick w/ line (these are sprite tiles, not BG!)
|
|
|
|
DrawBlock
|
|
lda Block_Rel_YPos ;get relative vertical coordinate of block object
|
|
sta $02 ;store here
|
|
lda Block_Rel_XPos ;get relative horizontal coordinate of block object
|
|
sta $05 ;store here
|
|
lda #$03
|
|
sta $04 ;set attribute byte here
|
|
lsr
|
|
sta $03 ;set horizontal flip bit here (will not be used)
|
|
ldy Block_SprDataOffset,x ;get sprite data offset
|
|
ldx #$00 ;reset X for use as offset to tile data
|
|
DBlkLoop lda DefaultBlockObjTiles,x ;get left tile number
|
|
sta $00 ;set here
|
|
lda DefaultBlockObjTiles+1,x ;get right tile number
|
|
jsr DrawOneSpriteRow ;do sub to write tile numbers to first row of sprites
|
|
cpx #$04 ;check incremented offset
|
|
bne DBlkLoop ;and loop back until all four sprites are done
|
|
ldx ObjectOffset ;get block object offset
|
|
ldy Block_SprDataOffset,x ;get sprite data offset
|
|
lda AreaType
|
|
cmp #$01 ;check for ground level type area
|
|
beq ChkRep ;if found, branch to next part
|
|
lda #$86
|
|
sta Sprite_Tilenumber,y ;otherwise remove brick tiles with lines
|
|
sta Sprite_Tilenumber+4,y ;and replace then with lineless brick tiles
|
|
ChkRep lda Block_Metatile,x ;check replacement metatile
|
|
cmp #$c4 ;if not used block metatile, then
|
|
bne BlkOffscr ;branch ahead to use current graphics
|
|
lda #$87 ;set A for used block tile
|
|
iny ;increment Y to write to tile bytes
|
|
jsr DumpFourSpr ;do sub to dump into all four sprites
|
|
dey ;return Y to original offset
|
|
lda #$03 ;set palette bits
|
|
ldx AreaType
|
|
dex ;check for ground level type area again
|
|
beq SetBFlip ;if found, use current palette bits
|
|
lsr ;otherwise set to $01
|
|
SetBFlip ldx ObjectOffset ;put block object offset back in X
|
|
sta Sprite_Attributes,y ;store attribute byte as-is in first sprite
|
|
ora #%01000000
|
|
sta Sprite_Attributes+4,y ;set horizontal flip bit for second sprite
|
|
ora #%10000000
|
|
sta Sprite_Attributes+12,y ;set both flip bits for fourth sprite
|
|
and #%10000011
|
|
sta Sprite_Attributes+8,y ;set vertical flip bit for third sprite
|
|
BlkOffscr lda Block_OffscreenBits ;get offscreen bits for block object
|
|
pha ;save to stack
|
|
and #%00000100 ;check to see if d2 in offscreen bits are set
|
|
beq PullOfsB ;if not set, branch, otherwise move sprites offscreen
|
|
lda #$f8 ;move offscreen two OAMs
|
|
sta Sprite_Y_Position+4,y ;on the right side
|
|
sta Sprite_Y_Position+12,y
|
|
PullOfsB pla ;pull offscreen bits from stack
|
|
ChkLeftCo and #%00001000 ;check to see if d3 in offscreen bits are set
|
|
beq ExDBlk ;if not set, branch, otherwise move sprites offscreen
|
|
|
|
MoveColOffscreen
|
|
lda #$f8 ;move offscreen two OAMs
|
|
sta Sprite_Y_Position,y ;on the left side (or two rows of enemy on either side
|
|
sta Sprite_Y_Position+8,y ;if branched here from enemy graphics handler)
|
|
ExDBlk rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$00 - used to hold palette bits for attribute byte or relative X position
|
|
|
|
DrawBrickChunks
|
|
lda #$02 ;set palette bits here
|
|
sta $00
|
|
lda #$75 ;set tile number for ball (something residual, likely)
|
|
ldy GameEngineSubroutine
|
|
cpy #$05 ;if end-of-level routine running,
|
|
beq DChunks ;use palette and tile number assigned
|
|
lda #$03 ;otherwise set different palette bits
|
|
sta $00
|
|
lda #$84 ;and set tile number for brick chunks
|
|
DChunks ldy Block_SprDataOffset,x ;get OAM data offset
|
|
iny ;increment to start with tile bytes in OAM
|
|
jsr DumpFourSpr ;do sub to dump tile number into all four sprites
|
|
lda FrameCounter ;get frame counter
|
|
asl
|
|
asl
|
|
asl ;move low nybble to high
|
|
asl
|
|
and #$c0 ;get what was originally d3-d2 of low nybble
|
|
ora $00 ;add palette bits
|
|
iny ;increment offset for attribute bytes
|
|
jsr DumpFourSpr ;do sub to dump attribute data into all four sprites
|
|
dey
|
|
dey ;decrement offset to Y coordinate
|
|
lda Block_Rel_YPos ;get first block object's relative vertical coordinate
|
|
jsr DumpTwoSpr ;do sub to dump current Y coordinate into two sprites
|
|
lda Block_Rel_XPos ;get first block object's relative horizontal coordinate
|
|
sta Sprite_X_Position,y ;save into X coordinate of first sprite
|
|
lda Block_Orig_XPos,x ;get original horizontal coordinate
|
|
sec
|
|
sbc ScreenLeft_X_Pos ;subtract coordinate of left side from original coordinate
|
|
sta $00 ;store result as relative horizontal coordinate of original
|
|
sec
|
|
sbc Block_Rel_XPos ;get difference of relative positions of original - current
|
|
adc $00 ;add original relative position to result
|
|
adc #$06 ;plus 6 pixels to position second brick chunk correctly
|
|
sta Sprite_X_Position+4,y ;save into X coordinate of second sprite
|
|
lda Block_Rel_YPos+1 ;get second block object's relative vertical coordinate
|
|
sta Sprite_Y_Position+8,y
|
|
sta Sprite_Y_Position+12,y ;dump into Y coordinates of third and fourth sprites
|
|
lda Block_Rel_XPos+1 ;get second block object's relative horizontal coordinate
|
|
sta Sprite_X_Position+8,y ;save into X coordinate of third sprite
|
|
lda $00 ;use original relative horizontal position
|
|
sec
|
|
sbc Block_Rel_XPos+1 ;get difference of relative positions of original - current
|
|
adc $00 ;add original relative position to result
|
|
adc #$06 ;plus 6 pixels to position fourth brick chunk correctly
|
|
sta Sprite_X_Position+12,y ;save into X coordinate of fourth sprite
|
|
lda Block_OffscreenBits ;get offscreen bits for block object
|
|
jsr ChkLeftCo ;do sub to move left half of sprites offscreen if necessary
|
|
lda Block_OffscreenBits ;get offscreen bits again
|
|
asl ;shift d7 into carry
|
|
bcc ChnkOfs ;if d7 not set, branch to last part
|
|
lda #$f8
|
|
jsr DumpTwoSpr ;otherwise move top sprites offscreen
|
|
ChnkOfs lda $00 ;if relative position on left side of screen,
|
|
bpl ExBCDr ;go ahead and leave
|
|
lda Sprite_X_Position,y ;otherwise compare left-side X coordinate
|
|
cmp Sprite_X_Position+4,y ;to right-side X coordinate
|
|
bcc ExBCDr ;branch to leave if less
|
|
lda #$f8 ;otherwise move right half of sprites offscreen
|
|
sta Sprite_Y_Position+4,y
|
|
sta Sprite_Y_Position+12,y
|
|
ExBCDr rts ;leave
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
DrawFireball
|
|
ldy FBall_SprDataOffset,x ;get fireball's sprite data offset
|
|
lda Fireball_Rel_YPos ;get relative vertical coordinate
|
|
sta Sprite_Y_Position,y ;store as sprite Y coordinate
|
|
lda Fireball_Rel_XPos ;get relative horizontal coordinate
|
|
sta Sprite_X_Position,y ;store as sprite X coordinate, then do shared code
|
|
|
|
DrawFirebar
|
|
lda FrameCounter ;get frame counter
|
|
lsr ;divide by four
|
|
lsr
|
|
pha ;save result to stack
|
|
and #$01 ;mask out all but last bit
|
|
eor #$64 ;set either tile $64 or $65 as fireball tile
|
|
sta Sprite_Tilenumber,y ;thus tile changes every four frames
|
|
pla ;get from stack
|
|
lsr ;divide by four again
|
|
lsr
|
|
lda #$02 ;load value $02 to set palette in attrib byte
|
|
bcc FireA ;if last bit shifted out was not set, skip this
|
|
ora #%11000000 ;otherwise flip both ways every eight frames
|
|
FireA sta Sprite_Attributes,y ;store attribute byte and leave
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
ExplosionTiles
|
|
db $68,$67,$66
|
|
|
|
DrawExplosion_Fireball
|
|
ldy Alt_SprDataOffset,x ;get OAM data offset of alternate sort for fireball's explosion
|
|
lda Fireball_State,x ;load fireball state
|
|
inc Fireball_State,x ;increment state for next frame
|
|
lsr ;divide by 2
|
|
and #%00000111 ;mask out all but d3-d1
|
|
cmp #$03 ;check to see if time to kill fireball
|
|
bcs KillFireBall ;branch if so, otherwise continue to draw explosion
|
|
|
|
DrawExplosion_Fireworks
|
|
tax ;use whatever's in A for offset
|
|
lda ExplosionTiles,x ;get tile number using offset
|
|
iny ;increment Y (contains sprite data offset)
|
|
jsr DumpFourSpr ;and dump into tile number part of sprite data
|
|
dey ;decrement Y so we have the proper offset again
|
|
ldx ObjectOffset ;return enemy object buffer offset to X
|
|
lda Fireball_Rel_YPos ;get relative vertical coordinate
|
|
sec ;subtract four pixels vertically
|
|
sbc #$04 ;for first and third sprites
|
|
sta Sprite_Y_Position,y
|
|
sta Sprite_Y_Position+8,y
|
|
clc ;add eight pixels vertically
|
|
adc #$08 ;for second and fourth sprites
|
|
sta Sprite_Y_Position+4,y
|
|
sta Sprite_Y_Position+12,y
|
|
lda Fireball_Rel_XPos ;get relative horizontal coordinate
|
|
sec ;subtract four pixels horizontally
|
|
sbc #$04 ;for first and second sprites
|
|
sta Sprite_X_Position,y
|
|
sta Sprite_X_Position+4,y
|
|
clc ;add eight pixels horizontally
|
|
adc #$08 ;for third and fourth sprites
|
|
sta Sprite_X_Position+8,y
|
|
sta Sprite_X_Position+12,y
|
|
lda #$02 ;set palette attributes for all sprites, but
|
|
sta Sprite_Attributes,y ;set no flip at all for first sprite
|
|
lda #$82
|
|
sta Sprite_Attributes+4,y ;set vertical flip for second sprite
|
|
lda #$42
|
|
sta Sprite_Attributes+8,y ;set horizontal flip for third sprite
|
|
lda #$c2
|
|
sta Sprite_Attributes+12,y ;set both flips for fourth sprite
|
|
rts ;we are done
|
|
|
|
KillFireBall
|
|
lda #$00 ;clear fireball state to kill it
|
|
sta Fireball_State,x
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
DrawSmallPlatform
|
|
ldy Enemy_SprDataOffset,x ;get OAM data offset
|
|
lda #$5b ;load tile number for small platforms
|
|
iny ;increment offset for tile numbers
|
|
jsr DumpSixSpr ;dump tile number into all six sprites
|
|
iny ;increment offset for attributes
|
|
lda #$02 ;load palette controls
|
|
jsr DumpSixSpr ;dump attributes into all six sprites
|
|
dey ;decrement for original offset
|
|
dey
|
|
lda Enemy_Rel_XPos ;get relative horizontal coordinate
|
|
sta Sprite_X_Position,y
|
|
sta Sprite_X_Position+12,y ;dump as X coordinate into first and fourth sprites
|
|
clc
|
|
adc #$08 ;add eight pixels
|
|
sta Sprite_X_Position+4,y ;dump into second and fifth sprites
|
|
sta Sprite_X_Position+16,y
|
|
clc
|
|
adc #$08 ;add eight more pixels
|
|
sta Sprite_X_Position+8,y ;dump into third and sixth sprites
|
|
sta Sprite_X_Position+20,y
|
|
lda Enemy_Y_Position,x ;get vertical coordinate
|
|
tax
|
|
pha ;save to stack
|
|
cpx #$20 ;if vertical coordinate below status bar,
|
|
bcs TopSP ;do not mess with it
|
|
lda #$f8 ;otherwise move first three sprites offscreen
|
|
TopSP jsr DumpThreeSpr ;dump vertical coordinate into Y coordinates
|
|
pla ;pull from stack
|
|
clc
|
|
adc #$80 ;add 128 pixels
|
|
tax
|
|
cpx #$20 ;if below status bar (taking wrap into account)
|
|
bcs BotSP ;then do not change altered coordinate
|
|
lda #$f8 ;otherwise move last three sprites offscreen
|
|
BotSP sta Sprite_Y_Position+12,y ;dump vertical coordinate + 128 pixels
|
|
sta Sprite_Y_Position+16,y ;into Y coordinates
|
|
sta Sprite_Y_Position+20,y
|
|
lda Enemy_OffscreenBits ;get offscreen bits
|
|
pha ;save to stack
|
|
and #%00001000 ;check d3
|
|
beq SOfs
|
|
lda #$f8 ;if d3 was set, move first and
|
|
sta Sprite_Y_Position,y ;fourth sprites offscreen
|
|
sta Sprite_Y_Position+12,y
|
|
SOfs pla ;move out and back into stack
|
|
pha
|
|
and #%00000100 ;check d2
|
|
beq SOfs2
|
|
lda #$f8 ;if d2 was set, move second and
|
|
sta Sprite_Y_Position+4,y ;fifth sprites offscreen
|
|
sta Sprite_Y_Position+16,y
|
|
SOfs2 pla ;get from stack
|
|
and #%00000010 ;check d1
|
|
beq ExSPl
|
|
lda #$f8 ;if d1 was set, move third and
|
|
sta Sprite_Y_Position+8,y ;sixth sprites offscreen
|
|
sta Sprite_Y_Position+20,y
|
|
ExSPl ldx ObjectOffset ;get enemy object offset and leave
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
DrawBubble
|
|
ldy Player_Y_HighPos ;if player's vertical high position
|
|
dey ;not within screen, skip all of this
|
|
bne ExDBub
|
|
lda Bubble_OffscreenBits ;check air bubble's offscreen bits
|
|
and #%00001000
|
|
bne ExDBub ;if bit set, branch to leave
|
|
ldy Bubble_SprDataOffset,x ;get air bubble's OAM data offset
|
|
lda Bubble_Rel_XPos ;get relative horizontal coordinate
|
|
sta Sprite_X_Position,y ;store as X coordinate here
|
|
lda Bubble_Rel_YPos ;get relative vertical coordinate
|
|
sta Sprite_Y_Position,y ;store as Y coordinate here
|
|
lda #$74
|
|
sta Sprite_Tilenumber,y ;put air bubble tile into OAM data
|
|
lda #$02
|
|
sta Sprite_Attributes,y ;set attribute byte
|
|
ExDBub rts ;leave
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$00 - used to store player's vertical offscreen bits
|
|
|
|
PlayerGfxTblOffsets
|
|
db $20,$28,$c8,$18,$00,$40,$50,$58
|
|
db $80,$88,$b8,$78,$60,$a0,$b0,$b8
|
|
|
|
;tiles arranged in order, 2 tiles per row, top to bottom
|
|
|
|
PlayerGraphicsTable
|
|
;big player table
|
|
db $00,$01,$02,$03,$04,$05,$06,$07 ;walking frame 1
|
|
db $08,$09,$0a,$0b,$0c,$0d,$0e,$0f ; frame 2
|
|
db $10,$11,$12,$13,$14,$15,$16,$17 ; frame 3
|
|
db $18,$19,$1a,$1b,$1c,$1d,$1e,$1f ;skidding
|
|
db $20,$21,$22,$23,$24,$25,$26,$27 ;jumping
|
|
db $08,$09,$28,$29,$2a,$2b,$2c,$2d ;swimming frame 1
|
|
db $08,$09,$0a,$0b,$0c,$30,$2c,$2d ; frame 2
|
|
db $08,$09,$0a,$0b,$2e,$2f,$2c,$2d ; frame 3
|
|
db $08,$09,$28,$29,$2a,$2b,$5c,$5d ;climbing frame 1
|
|
db $08,$09,$0a,$0b,$0c,$0d,$5e,$5f ; frame 2
|
|
db $fc,$fc,$08,$09,$58,$59,$5a,$5a ;crouching
|
|
db $08,$09,$28,$29,$2a,$2b,$0e,$0f ;fireball throwing
|
|
|
|
;small player table
|
|
db $fc,$fc,$fc,$fc,$32,$33,$34,$35 ;walking frame 1
|
|
db $fc,$fc,$fc,$fc,$36,$37,$38,$39 ; frame 2
|
|
db $fc,$fc,$fc,$fc,$3a,$37,$3b,$3c ; frame 3
|
|
db $fc,$fc,$fc,$fc,$3d,$3e,$3f,$40 ;skidding
|
|
db $fc,$fc,$fc,$fc,$32,$41,$42,$43 ;jumping
|
|
db $fc,$fc,$fc,$fc,$32,$33,$44,$45 ;swimming frame 1
|
|
db $fc,$fc,$fc,$fc,$32,$33,$44,$47 ; frame 2
|
|
db $fc,$fc,$fc,$fc,$32,$33,$48,$49 ; frame 3
|
|
db $fc,$fc,$fc,$fc,$32,$33,$90,$91 ;climbing frame 1
|
|
db $fc,$fc,$fc,$fc,$3a,$37,$92,$93 ; frame 2
|
|
db $fc,$fc,$fc,$fc,$9e,$9e,$9f,$9f ;killed
|
|
|
|
;used by both player sizes
|
|
db $fc,$fc,$fc,$fc,$3a,$37,$4f,$4f ;small player standing
|
|
db $fc,$fc,$00,$01,$4c,$4d,$4e,$4e ;intermediate grow frame
|
|
db $00,$01,$4c,$4d,$4a,$4a,$4b,$4b ;big player standing
|
|
|
|
SwimKickTileNum
|
|
db $31,$46
|
|
|
|
PlayerGfxHandler
|
|
lda InjuryTimer ;if player's injured invincibility timer
|
|
beq CntPl ;not set, skip checkpoint and continue code
|
|
lda FrameCounter
|
|
lsr ;otherwise check frame counter and branch
|
|
bcs ExPGH ;to leave on every other frame (when d0 is set)
|
|
CntPl lda GameEngineSubroutine ;if executing specific game engine routine,
|
|
cmp #$0b ;branch ahead to some other part
|
|
beq PlayerKilled
|
|
lda PlayerChangeSizeFlag ;if grow/shrink flag set
|
|
bne DoChangeSize ;then branch to some other code
|
|
ldy SwimmingFlag ;if swimming flag set, branch to
|
|
beq FindPlayerAction ;different part, do not return
|
|
lda Player_State
|
|
cmp #$00 ;if player status normal,
|
|
beq FindPlayerAction ;branch and do not return
|
|
jsr FindPlayerAction ;otherwise jump and return
|
|
lda FrameCounter
|
|
and #%00000100 ;check frame counter for d2 set (8 frames every
|
|
bne ExPGH ;eighth frame), and branch if set to leave
|
|
tax ;initialize X to zero
|
|
ldy Player_SprDataOffset ;get player sprite data offset
|
|
lda PlayerFacingDir ;get player's facing direction
|
|
lsr
|
|
bcs SwimKT ;if player facing to the right, use current offset
|
|
iny
|
|
iny ;otherwise move to next OAM data
|
|
iny
|
|
iny
|
|
SwimKT lda PlayerSize ;check player's size
|
|
beq BigKTS ;if big, use first tile
|
|
lda Sprite_Tilenumber+24,y ;check tile number of seventh/eighth sprite
|
|
cmp SwimTileRepOffset ;against tile number in player graphics table
|
|
beq ExPGH ;if spr7/spr8 tile number = value, branch to leave
|
|
inx ;otherwise increment X for second tile
|
|
BigKTS lda SwimKickTileNum,x ;overwrite tile number in sprite 7/8
|
|
sta Sprite_Tilenumber+24,y ;to animate player's feet when swimming
|
|
ExPGH rts ;then leave
|
|
|
|
FindPlayerAction
|
|
jsr ProcessPlayerAction ;find proper offset to graphics table by player's actions
|
|
jmp PlayerGfxProcessing ;draw player, then process for fireball throwing
|
|
|
|
DoChangeSize
|
|
jsr HandleChangeSize ;find proper offset to graphics table for grow/shrink
|
|
jmp PlayerGfxProcessing ;draw player, then process for fireball throwing
|
|
|
|
PlayerKilled
|
|
ldy #$0e ;load offset for player killed
|
|
lda PlayerGfxTblOffsets,y ;get offset to graphics table
|
|
|
|
PlayerGfxProcessing
|
|
sta PlayerGfxOffset ;store offset to graphics table here
|
|
lda #$04
|
|
jsr RenderPlayerSub ;draw player based on offset loaded
|
|
jsr ChkForPlayerAttrib ;set horizontal flip bits as necessary
|
|
lda FireballThrowingTimer
|
|
beq PlayerOffscreenChk ;if fireball throw timer not set, skip to the end
|
|
ldy #$00 ;set value to initialize by default
|
|
lda PlayerAnimTimer ;get animation frame timer
|
|
cmp FireballThrowingTimer ;compare to fireball throw timer
|
|
sty FireballThrowingTimer ;initialize fireball throw timer
|
|
bcs PlayerOffscreenChk ;if animation frame timer => fireball throw timer skip to end
|
|
sta FireballThrowingTimer ;otherwise store animation timer into fireball throw timer
|
|
ldy #$07 ;load offset for throwing
|
|
lda PlayerGfxTblOffsets,y ;get offset to graphics table
|
|
sta PlayerGfxOffset ;store it for use later
|
|
ldy #$04 ;set to update four sprite rows by default
|
|
lda Player_X_Speed
|
|
ora Left_Right_Buttons ;check for horizontal speed or left/right button press
|
|
beq SUpdR ;if no speed or button press, branch using set value in Y
|
|
dey ;otherwise set to update only three sprite rows
|
|
SUpdR tya ;save in A for use
|
|
jsr RenderPlayerSub ;in sub, draw player object again
|
|
|
|
PlayerOffscreenChk
|
|
lda Player_OffscreenBits ;get player's offscreen bits
|
|
lsr
|
|
lsr ;move vertical bits to low nybble
|
|
lsr
|
|
lsr
|
|
sta $00 ;store here
|
|
ldx #$03 ;check all four rows of player sprites
|
|
lda Player_SprDataOffset ;get player's sprite data offset
|
|
clc
|
|
adc #$18 ;add 24 bytes to start at bottom row
|
|
tay ;set as offset here
|
|
PROfsLoop lda #$f8 ;load offscreen Y coordinate just in case
|
|
lsr $00 ;shift bit into carry
|
|
bcc NPROffscr ;if bit not set, skip, do not move sprites
|
|
jsr DumpTwoSpr ;otherwise dump offscreen Y coordinate into sprite data
|
|
NPROffscr tya
|
|
sec ;subtract eight bytes to do
|
|
sbc #$08 ;next row up
|
|
tay
|
|
dex ;decrement row counter
|
|
bpl PROfsLoop ;do this until all sprite rows are checked
|
|
rts ;then we are done!
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
IntermediatePlayerData
|
|
db $58,$01,$00,$60,$ff,$04
|
|
|
|
DrawPlayer_Intermediate
|
|
ldx #$05 ;store data into zero page memory
|
|
PIntLoop lda IntermediatePlayerData,x ;load data to display player as he always
|
|
sta $02,x ;appears on world/lives display
|
|
dex
|
|
bpl PIntLoop ;do this until all data is loaded
|
|
ldx #$b8 ;load offset for small standing
|
|
ldy #$04 ;load sprite data offset
|
|
jsr DrawPlayerLoop ;draw player accordingly
|
|
lda Sprite_Attributes+36 ;get empty sprite attributes
|
|
ora #%01000000 ;set horizontal flip bit for bottom-right sprite
|
|
sta Sprite_Attributes+32 ;store and leave
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$00-$01 - used to hold tile numbers,$00 also used to hold upper extent of animation frames
|
|
;$02 - vertical position
|
|
;$03 - facing direction, used as horizontal flip control
|
|
;$04 - attributes
|
|
;$05 - horizontal position
|
|
;$07 - number of rows to draw
|
|
;these also used in IntermediatePlayerData
|
|
|
|
RenderPlayerSub
|
|
sta $07 ;store number of rows of sprites to draw
|
|
lda Player_Rel_XPos
|
|
sta Player_Pos_ForScroll ;store player's relative horizontal position
|
|
sta $05 ;store it here also
|
|
lda Player_Rel_YPos
|
|
sta $02 ;store player's vertical position
|
|
lda PlayerFacingDir
|
|
sta $03 ;store player's facing direction
|
|
lda Player_SprAttrib
|
|
sta $04 ;store player's sprite attributes
|
|
ldx PlayerGfxOffset ;load graphics table offset
|
|
ldy Player_SprDataOffset ;get player's sprite data offset
|
|
|
|
DrawPlayerLoop
|
|
lda PlayerGraphicsTable,x ;load player's left side
|
|
sta $00
|
|
lda PlayerGraphicsTable+1,x ;now load right side
|
|
jsr DrawOneSpriteRow
|
|
dec $07 ;decrement rows of sprites to draw
|
|
bne DrawPlayerLoop ;do this until all rows are drawn
|
|
rts
|
|
|
|
ProcessPlayerAction
|
|
lda Player_State ;get player's state
|
|
cmp #$03
|
|
beq ActionClimbing ;if climbing, branch here
|
|
cmp #$02
|
|
beq ActionFalling ;if falling, branch here
|
|
cmp #$01
|
|
bne ProcOnGroundActs ;if not jumping, branch here
|
|
lda SwimmingFlag
|
|
bne ActionSwimming ;if swimming flag set, branch elsewhere
|
|
ldy #$06 ;load offset for crouching
|
|
lda CrouchingFlag ;get crouching flag
|
|
bne NonAnimatedActs ;if set, branch to get offset for graphics table
|
|
ldy #$00 ;otherwise load offset for jumping
|
|
jmp NonAnimatedActs ;go to get offset to graphics table
|
|
|
|
ProcOnGroundActs
|
|
ldy #$06 ;load offset for crouching
|
|
lda CrouchingFlag ;get crouching flag
|
|
bne NonAnimatedActs ;if set, branch to get offset for graphics table
|
|
ldy #$02 ;load offset for standing
|
|
lda Player_X_Speed ;check player's horizontal speed
|
|
ora Left_Right_Buttons ;and left/right controller bits
|
|
beq NonAnimatedActs ;if no speed or buttons pressed, use standing offset
|
|
lda Player_XSpeedAbsolute ;load walking/running speed
|
|
cmp #$09
|
|
bcc ActionWalkRun ;if less than a certain amount, branch, too slow to skid
|
|
lda Player_MovingDir ;otherwise check to see if moving direction
|
|
and PlayerFacingDir ;and facing direction are the same
|
|
bne ActionWalkRun ;if moving direction = facing direction, branch, don't skid
|
|
iny ;otherwise increment to skid offset ($03)
|
|
|
|
NonAnimatedActs
|
|
jsr GetGfxOffsetAdder ;do a sub here to get offset adder for graphics table
|
|
lda #$00
|
|
sta PlayerAnimCtrl ;initialize animation frame control
|
|
lda PlayerGfxTblOffsets,y ;load offset to graphics table using size as offset
|
|
rts
|
|
|
|
ActionFalling
|
|
ldy #$04 ;load offset for walking/running
|
|
jsr GetGfxOffsetAdder ;get offset to graphics table
|
|
jmp GetCurrentAnimOffset ;execute instructions for falling state
|
|
|
|
ActionWalkRun
|
|
ldy #$04 ;load offset for walking/running
|
|
jsr GetGfxOffsetAdder ;get offset to graphics table
|
|
jmp FourFrameExtent ;execute instructions for normal state
|
|
|
|
ActionClimbing
|
|
ldy #$05 ;load offset for climbing
|
|
lda Player_Y_Speed ;check player's vertical speed
|
|
beq NonAnimatedActs ;if no speed, branch, use offset as-is
|
|
jsr GetGfxOffsetAdder ;otherwise get offset for graphics table
|
|
jmp ThreeFrameExtent ;then skip ahead to more code
|
|
|
|
ActionSwimming
|
|
ldy #$01 ;load offset for swimming
|
|
jsr GetGfxOffsetAdder
|
|
lda JumpSwimTimer ;check jump/swim timer
|
|
ora PlayerAnimCtrl ;and animation frame control
|
|
bne FourFrameExtent ;if any one of these set, branch ahead
|
|
lda A_B_Buttons
|
|
asl ;check for A button pressed
|
|
bcs FourFrameExtent ;branch to same place if A button pressed
|
|
|
|
GetCurrentAnimOffset
|
|
lda PlayerAnimCtrl ;get animation frame control
|
|
jmp GetOffsetFromAnimCtrl ;jump to get proper offset to graphics table
|
|
|
|
FourFrameExtent
|
|
lda #$03 ;load upper extent for frame control
|
|
jmp AnimationControl ;jump to get offset and animate player object
|
|
|
|
ThreeFrameExtent
|
|
lda #$02 ;load upper extent for frame control for climbing
|
|
|
|
AnimationControl
|
|
sta $00 ;store upper extent here
|
|
jsr GetCurrentAnimOffset ;get proper offset to graphics table
|
|
pha ;save offset to stack
|
|
lda PlayerAnimTimer ;load animation frame timer
|
|
bne ExAnimC ;branch if not expired
|
|
lda PlayerAnimTimerSet ;get animation frame timer amount
|
|
sta PlayerAnimTimer ;and set timer accordingly
|
|
lda PlayerAnimCtrl
|
|
clc ;add one to animation frame control
|
|
adc #$01
|
|
cmp $00 ;compare to upper extent
|
|
bcc SetAnimC ;if frame control + 1 < upper extent, use as next
|
|
lda #$00 ;otherwise initialize frame control
|
|
SetAnimC sta PlayerAnimCtrl ;store as new animation frame control
|
|
ExAnimC pla ;get offset to graphics table from stack and leave
|
|
rts
|
|
|
|
GetGfxOffsetAdder
|
|
lda PlayerSize ;get player's size
|
|
beq SzOfs ;if player big, use current offset as-is
|
|
tya ;for big player
|
|
clc ;otherwise add eight bytes to offset
|
|
adc #$08 ;for small player
|
|
tay
|
|
SzOfs rts ;go back
|
|
|
|
ChangeSizeOffsetAdder
|
|
db $00,$01,$00,$01,$00,$01,$02,$00,$01,$02
|
|
db $02,$00,$02,$00,$02,$00,$02,$00,$02,$00
|
|
|
|
HandleChangeSize
|
|
ldy PlayerAnimCtrl ;get animation frame control
|
|
lda FrameCounter
|
|
and #%00000011 ;get frame counter and execute this code every
|
|
bne GorSLog ;fourth frame, otherwise branch ahead
|
|
iny ;increment frame control
|
|
cpy #$0a ;check for preset upper extent
|
|
bcc CSzNext ;if not there yet, skip ahead to use
|
|
ldy #$00 ;otherwise initialize both grow/shrink flag
|
|
sty PlayerChangeSizeFlag ;and animation frame control
|
|
CSzNext sty PlayerAnimCtrl ;store proper frame control
|
|
GorSLog lda PlayerSize ;get player's size
|
|
bne ShrinkPlayer ;if player small, skip ahead to next part
|
|
lda ChangeSizeOffsetAdder,y ;get offset adder based on frame control as offset
|
|
ldy #$0f ;load offset for player growing
|
|
|
|
GetOffsetFromAnimCtrl
|
|
asl ;multiply animation frame control
|
|
asl ;by eight to get proper amount
|
|
asl ;to add to our offset
|
|
adc PlayerGfxTblOffsets,y ;add to offset to graphics table
|
|
rts ;and return with result in A
|
|
|
|
ShrinkPlayer
|
|
tya ;add ten bytes to frame control as offset
|
|
clc
|
|
adc #$0a ;this thing apparently uses two of the swimming frames
|
|
tax ;to draw the player shrinking
|
|
ldy #$09 ;load offset for small player swimming
|
|
lda ChangeSizeOffsetAdder,x ;get what would normally be offset adder
|
|
bne ShrPlF ;and branch to use offset if nonzero
|
|
ldy #$01 ;otherwise load offset for big player swimming
|
|
ShrPlF lda PlayerGfxTblOffsets,y ;get offset to graphics table based on offset loaded
|
|
rts ;and leave
|
|
|
|
ChkForPlayerAttrib
|
|
ldy Player_SprDataOffset ;get sprite data offset
|
|
lda GameEngineSubroutine
|
|
cmp #$0b ;if executing specific game engine routine,
|
|
beq KilledAtt ;branch to change third and fourth row OAM attributes
|
|
lda PlayerGfxOffset ;get graphics table offset
|
|
cmp #$50
|
|
beq C_S_IGAtt ;if crouch offset, either standing offset,
|
|
cmp #$b8 ;or intermediate growing offset,
|
|
beq C_S_IGAtt ;go ahead and execute code to change
|
|
cmp #$c0 ;fourth row OAM attributes only
|
|
beq C_S_IGAtt
|
|
cmp #$c8
|
|
bne ExPlyrAt ;if none of these, branch to leave
|
|
KilledAtt lda Sprite_Attributes+16,y
|
|
and #%00111111 ;mask out horizontal and vertical flip bits
|
|
sta Sprite_Attributes+16,y ;for third row sprites and save
|
|
lda Sprite_Attributes+20,y
|
|
and #%00111111
|
|
ora #%01000000 ;set horizontal flip bit for second
|
|
sta Sprite_Attributes+20,y ;sprite in the third row
|
|
C_S_IGAtt lda Sprite_Attributes+24,y
|
|
and #%00111111 ;mask out horizontal and vertical flip bits
|
|
sta Sprite_Attributes+24,y ;for fourth row sprites and save
|
|
lda Sprite_Attributes+28,y
|
|
and #%00111111
|
|
ora #%01000000 ;set horizontal flip bit for second
|
|
sta Sprite_Attributes+28,y ;sprite in the fourth row
|
|
ExPlyrAt rts ;leave
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$00 - used in adding to get proper offset
|
|
|
|
RelativePlayerPosition
|
|
ldx #$00 ;set offsets for relative cooordinates
|
|
ldy #$00 ;routine to correspond to player object
|
|
jmp RelWOfs ;get the coordinates
|
|
|
|
RelativeBubblePosition
|
|
ldy #$01 ;set for air bubble offsets
|
|
jsr GetProperObjOffset ;modify X to get proper air bubble offset
|
|
ldy #$03
|
|
jmp RelWOfs ;get the coordinates
|
|
|
|
RelativeFireballPosition
|
|
ldy #$00 ;set for fireball offsets
|
|
jsr GetProperObjOffset ;modify X to get proper fireball offset
|
|
ldy #$02
|
|
RelWOfs jsr GetObjRelativePosition ;get the coordinates
|
|
ldx ObjectOffset ;return original offset
|
|
rts ;leave
|
|
|
|
RelativeMiscPosition
|
|
ldy #$02 ;set for misc object offsets
|
|
jsr GetProperObjOffset ;modify X to get proper misc object offset
|
|
ldy #$06
|
|
jmp RelWOfs ;get the coordinates
|
|
|
|
RelativeEnemyPosition
|
|
lda #$01 ;get coordinates of enemy object
|
|
ldy #$01 ;relative to the screen
|
|
jmp VariableObjOfsRelPos
|
|
|
|
RelativeBlockPosition
|
|
lda #$09 ;get coordinates of one block object
|
|
ldy #$04 ;relative to the screen
|
|
jsr VariableObjOfsRelPos
|
|
inx ;adjust offset for other block object if any
|
|
inx
|
|
lda #$09
|
|
iny ;adjust other and get coordinates for other one
|
|
|
|
VariableObjOfsRelPos
|
|
stx $00 ;store value to add to A here
|
|
clc
|
|
adc $00 ;add A to value stored
|
|
tax ;use as enemy offset
|
|
jsr GetObjRelativePosition
|
|
ldx ObjectOffset ;reload old object offset and leave
|
|
rts
|
|
|
|
GetObjRelativePosition
|
|
lda SprObject_Y_Position,x ;load vertical coordinate low
|
|
sta SprObject_Rel_YPos,y ;store here
|
|
lda SprObject_X_Position,x ;load horizontal coordinate
|
|
sec ;subtract left edge coordinate
|
|
sbc ScreenLeft_X_Pos
|
|
sta SprObject_Rel_XPos,y ;store result here
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$00 - used as temp variable to hold offscreen bits
|
|
|
|
GetPlayerOffscreenBits
|
|
ldx #$00 ;set offsets for player-specific variables
|
|
ldy #$00 ;and get offscreen information about player
|
|
jmp GetOffScreenBitsSet
|
|
|
|
GetFireballOffscreenBits
|
|
ldy #$00 ;set for fireball offsets
|
|
jsr GetProperObjOffset ;modify X to get proper fireball offset
|
|
ldy #$02 ;set other offset for fireball's offscreen bits
|
|
jmp GetOffScreenBitsSet ;and get offscreen information about fireball
|
|
|
|
GetBubbleOffscreenBits
|
|
ldy #$01 ;set for air bubble offsets
|
|
jsr GetProperObjOffset ;modify X to get proper air bubble offset
|
|
ldy #$03 ;set other offset for airbubble's offscreen bits
|
|
jmp GetOffScreenBitsSet ;and get offscreen information about air bubble
|
|
|
|
GetMiscOffscreenBits
|
|
ldy #$02 ;set for misc object offsets
|
|
jsr GetProperObjOffset ;modify X to get proper misc object offset
|
|
ldy #$06 ;set other offset for misc object's offscreen bits
|
|
jmp GetOffScreenBitsSet ;and get offscreen information about misc object
|
|
|
|
ObjOffsetData
|
|
db $07,$16,$0d
|
|
|
|
GetProperObjOffset
|
|
txa ;move offset to A
|
|
clc
|
|
adc ObjOffsetData,y ;add amount of bytes to offset depending on setting in Y
|
|
tax ;put back in X and leave
|
|
rts
|
|
|
|
GetEnemyOffscreenBits
|
|
lda #$01 ;set A to add 1 byte in order to get enemy offset
|
|
ldy #$01 ;set Y to put offscreen bits in Enemy_OffscreenBits
|
|
jmp SetOffscrBitsOffset
|
|
|
|
GetBlockOffscreenBits
|
|
lda #$09 ;set A to add 9 bytes in order to get block obj offset
|
|
ldy #$04 ;set Y to put offscreen bits in Block_OffscreenBits
|
|
|
|
SetOffscrBitsOffset
|
|
stx $00
|
|
clc ;add contents of X to A to get
|
|
adc $00 ;appropriate offset, then give back to X
|
|
tax
|
|
|
|
GetOffScreenBitsSet
|
|
tya ;save offscreen bits offset to stack for now
|
|
pha
|
|
jsr RunOffscrBitsSubs
|
|
asl ;move low nybble to high nybble
|
|
asl
|
|
asl
|
|
asl
|
|
ora $00 ;mask together with previously saved low nybble
|
|
sta $00 ;store both here
|
|
pla ;get offscreen bits offset from stack
|
|
tay
|
|
lda $00 ;get value here and store elsewhere
|
|
sta SprObject_OffscrBits,y
|
|
ldx ObjectOffset
|
|
rts
|
|
|
|
RunOffscrBitsSubs
|
|
jsr GetXOffscreenBits ;do subroutine here
|
|
lsr ;move high nybble to low
|
|
lsr
|
|
lsr
|
|
lsr
|
|
sta $00 ;store here
|
|
jmp GetYOffscreenBits
|
|
|
|
;--------------------------------
|
|
;(these apply to these three subsections)
|
|
;$04 - used to store proper offset
|
|
;$05 - used as adder in DividePDiff
|
|
;$06 - used to store preset value used to compare to pixel difference in $07
|
|
;$07 - used to store difference between coordinates of object and screen edges
|
|
|
|
XOffscreenBitsData
|
|
db $7f,$3f,$1f,$0f,$07,$03,$01,$00
|
|
db $80,$c0,$e0,$f0,$f8,$fc,$fe,$ff
|
|
|
|
DefaultXOnscreenOfs
|
|
db $07,$0f,$07
|
|
|
|
GetXOffscreenBits
|
|
stx $04 ;save position in buffer to here
|
|
ldy #$01 ;start with right side of screen
|
|
XOfsLoop lda ScreenEdge_X_Pos,y ;get pixel coordinate of edge
|
|
sec ;get difference between pixel coordinate of edge
|
|
sbc SprObject_X_Position,x ;and pixel coordinate of object position
|
|
sta $07 ;store here
|
|
lda ScreenEdge_PageLoc,y ;get page location of edge
|
|
sbc SprObject_PageLoc,x ;subtract from page location of object position
|
|
ldx DefaultXOnscreenOfs,y ;load offset value here
|
|
cmp #$00
|
|
bmi XLdBData ;if beyond right edge or in front of left edge, branch
|
|
ldx DefaultXOnscreenOfs+1,y ;if not, load alternate offset value here
|
|
cmp #$01
|
|
bpl XLdBData ;if one page or more to the left of either edge, branch
|
|
lda #$38 ;if no branching, load value here and store
|
|
sta $06
|
|
lda #$08 ;load some other value and execute subroutine
|
|
jsr DividePDiff
|
|
XLdBData lda XOffscreenBitsData,x ;get bits here
|
|
ldx $04 ;reobtain position in buffer
|
|
cmp #$00 ;if bits not zero, branch to leave
|
|
bne ExXOfsBS
|
|
dey ;otherwise, do left side of screen now
|
|
bpl XOfsLoop ;branch if not already done with left side
|
|
ExXOfsBS rts
|
|
|
|
;--------------------------------
|
|
|
|
YOffscreenBitsData
|
|
db $00,$08,$0c,$0e
|
|
db $0f,$07,$03,$01
|
|
db $00
|
|
|
|
DefaultYOnscreenOfs
|
|
db $04,$00,$04
|
|
|
|
HighPosUnitData
|
|
db $ff,$00
|
|
|
|
GetYOffscreenBits
|
|
stx $04 ;save position in buffer to here
|
|
ldy #$01 ;start with top of screen
|
|
YOfsLoop lda HighPosUnitData,y ;load coordinate for edge of vertical unit
|
|
sec
|
|
sbc SprObject_Y_Position,x ;subtract from vertical coordinate of object
|
|
sta $07 ;store here
|
|
lda #$01 ;subtract one from vertical high byte of object
|
|
sbc SprObject_Y_HighPos,x
|
|
ldx DefaultYOnscreenOfs,y ;load offset value here
|
|
cmp #$00
|
|
bmi YLdBData ;if under top of the screen or beyond bottom, branch
|
|
ldx DefaultYOnscreenOfs+1,y ;if not, load alternate offset value here
|
|
cmp #$01
|
|
bpl YLdBData ;if one vertical unit or more above the screen, branch
|
|
lda #$20 ;if no branching, load value here and store
|
|
sta $06
|
|
lda #$04 ;load some other value and execute subroutine
|
|
jsr DividePDiff
|
|
YLdBData lda YOffscreenBitsData,x ;get offscreen data bits using offset
|
|
ldx $04 ;reobtain position in buffer
|
|
cmp #$00
|
|
bne ExYOfsBS ;if bits not zero, branch to leave
|
|
dey ;otherwise, do bottom of the screen now
|
|
bpl YOfsLoop
|
|
ExYOfsBS rts
|
|
|
|
;--------------------------------
|
|
|
|
DividePDiff
|
|
sta $05 ;store current value in A here
|
|
lda $07 ;get pixel difference
|
|
cmp $06 ;compare to preset value
|
|
bcs ExDivPD ;if pixel difference >= preset value, branch
|
|
lsr ;divide by eight
|
|
lsr
|
|
lsr
|
|
and #$07 ;mask out all but 3 LSB
|
|
cpy #$01 ;right side of the screen or top?
|
|
bcs SetOscrO ;if so, branch, use difference / 8 as offset
|
|
adc $05 ;if not, add value to difference / 8
|
|
SetOscrO tax ;use as offset
|
|
ExDivPD rts ;leave
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;$00-$01 - tile numbers
|
|
;$02 - Y coordinate
|
|
;$03 - flip control
|
|
;$04 - sprite attributes
|
|
;$05 - X coordinate
|
|
|
|
DrawSpriteObject
|
|
lda $03 ;get saved flip control bits
|
|
lsr
|
|
lsr ;move d1 into carry
|
|
lda $00
|
|
bcc NoHFlip ;if d1 not set, branch
|
|
sta Sprite_Tilenumber+4,y ;store first tile into second sprite
|
|
lda $01 ;and second into first sprite
|
|
sta Sprite_Tilenumber,y
|
|
lda #$40 ;activate horizontal flip OAM attribute
|
|
bne SetHFAt ;and unconditionally branch
|
|
NoHFlip sta Sprite_Tilenumber,y ;store first tile into first sprite
|
|
lda $01 ;and second into second sprite
|
|
sta Sprite_Tilenumber+4,y
|
|
lda #$00 ;clear bit for horizontal flip
|
|
SetHFAt ora $04 ;add other OAM attributes if necessary
|
|
sta Sprite_Attributes,y ;store sprite attributes
|
|
sta Sprite_Attributes+4,y
|
|
lda $02 ;now the y coordinates
|
|
sta Sprite_Y_Position,y ;note because they are
|
|
sta Sprite_Y_Position+4,y ;side by side, they are the same
|
|
lda $05
|
|
sta Sprite_X_Position,y ;store x coordinate, then
|
|
clc ;add 8 pixels and store another to
|
|
adc #$08 ;put them side by side
|
|
sta Sprite_X_Position+4,y
|
|
lda $02 ;add eight pixels to the next y
|
|
clc ;coordinate
|
|
adc #$08
|
|
sta $02
|
|
tya ;add eight to the offset in Y to
|
|
clc ;move to the next two sprites
|
|
adc #$08
|
|
tay
|
|
inx ;increment offset to return it to the
|
|
inx ;routine that called this subroutine
|
|
rts
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
;unused space
|
|
db $ff,$ff,$ff,$ff,$ff,$ff
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
SoundEngine
|
|
lda OperMode ;are we in title screen mode?
|
|
bne SndOn
|
|
sta SND_MASTERCTRL_REG ;if so, disable sound and leave
|
|
rts
|
|
SndOn lda #$ff
|
|
sta JOYPAD_PORT2 ;disable irqs and set frame counter mode???
|
|
lda #$0f
|
|
sta SND_MASTERCTRL_REG ;enable first four channels
|
|
lda PauseModeFlag ;is sound already in pause mode?
|
|
bne InPause
|
|
lda PauseSoundQueue ;if not, check pause sfx queue
|
|
cmp #$01
|
|
bne RunSoundSubroutines ;if queue is empty, skip pause mode routine
|
|
InPause lda PauseSoundBuffer ;check pause sfx buffer
|
|
bne ContPau
|
|
lda PauseSoundQueue ;check pause queue
|
|
beq SkipSoundSubroutines
|
|
sta PauseSoundBuffer ;if queue full, store in buffer and activate
|
|
sta PauseModeFlag ;pause mode to interrupt game sounds
|
|
lda #$00 ;disable sound and clear sfx buffers
|
|
sta SND_MASTERCTRL_REG
|
|
sta Square1SoundBuffer
|
|
sta Square2SoundBuffer
|
|
sta NoiseSoundBuffer
|
|
lda #$0f
|
|
sta SND_MASTERCTRL_REG ;enable sound again
|
|
lda #$2a ;store length of sound in pause counter
|
|
sta Squ1_SfxLenCounter
|
|
PTone1F lda #$44 ;play first tone
|
|
bne PTRegC ;unconditional branch
|
|
ContPau lda Squ1_SfxLenCounter ;check pause length left
|
|
cmp #$24 ;time to play second?
|
|
beq PTone2F
|
|
cmp #$1e ;time to play first again?
|
|
beq PTone1F
|
|
cmp #$18 ;time to play second again?
|
|
bne DecPauC ;only load regs during times, otherwise skip
|
|
PTone2F lda #$64 ;store reg contents and play the pause sfx
|
|
PTRegC ldx #$84
|
|
ldy #$7f
|
|
jsr PlaySqu1Sfx
|
|
DecPauC dec Squ1_SfxLenCounter ;decrement pause sfx counter
|
|
bne SkipSoundSubroutines
|
|
lda #$00 ;disable sound if in pause mode and
|
|
sta SND_MASTERCTRL_REG ;not currently playing the pause sfx
|
|
lda PauseSoundBuffer ;if no longer playing pause sfx, check to see
|
|
cmp #$02 ;if we need to be playing sound again
|
|
bne SkipPIn
|
|
lda #$00 ;clear pause mode to allow game sounds again
|
|
sta PauseModeFlag
|
|
SkipPIn lda #$00 ;clear pause sfx buffer
|
|
sta PauseSoundBuffer
|
|
beq SkipSoundSubroutines
|
|
|
|
RunSoundSubroutines
|
|
jsr Square1SfxHandler ;play sfx on square channel 1
|
|
jsr Square2SfxHandler ; '' '' '' square channel 2
|
|
jsr NoiseSfxHandler ; '' '' '' noise channel
|
|
jsr MusicHandler ;play music on all channels
|
|
lda #$00 ;clear the music queues
|
|
sta AreaMusicQueue
|
|
sta EventMusicQueue
|
|
|
|
SkipSoundSubroutines
|
|
lda #$00 ;clear the sound effects queues
|
|
sta Square1SoundQueue
|
|
sta Square2SoundQueue
|
|
sta NoiseSoundQueue
|
|
sta PauseSoundQueue
|
|
ldy DAC_Counter ;load some sort of counter
|
|
lda AreaMusicBuffer
|
|
and #%00000011 ;check for specific music
|
|
beq NoIncDAC
|
|
inc DAC_Counter ;increment and check counter
|
|
cpy #$30
|
|
bcc StrWave ;if not there yet, just store it
|
|
NoIncDAC tya
|
|
beq StrWave ;if we are at zero, do not decrement
|
|
dec DAC_Counter ;decrement counter
|
|
StrWave sty SND_DELTA_REG+1 ;store into DMC load register (??)
|
|
rts ;we are done here
|
|
|
|
;--------------------------------
|
|
|
|
Dump_Squ1_Regs
|
|
sty SND_SQUARE1_REG+1 ;dump the contents of X and Y into square 1's control regs
|
|
stx SND_SQUARE1_REG
|
|
rts
|
|
|
|
PlaySqu1Sfx
|
|
jsr Dump_Squ1_Regs ;do sub to set ctrl regs for square 1, then set frequency regs
|
|
|
|
SetFreq_Squ1
|
|
ldx #$00 ;set frequency reg offset for square 1 sound channel
|
|
|
|
Dump_Freq_Regs
|
|
tay
|
|
lda FreqRegLookupTbl+1,y ;use previous contents of A for sound reg offset
|
|
beq NoTone ;if zero, then do not load
|
|
sta SND_REGISTER+2,x ;first byte goes into LSB of frequency divider
|
|
lda FreqRegLookupTbl,y ;second byte goes into 3 MSB plus extra bit for
|
|
ora #%00001000 ;length counter
|
|
sta SND_REGISTER+3,x
|
|
NoTone rts
|
|
|
|
Dump_Sq2_Regs
|
|
stx SND_SQUARE2_REG ;dump the contents of X and Y into square 2's control regs
|
|
sty SND_SQUARE2_REG+1
|
|
rts
|
|
|
|
PlaySqu2Sfx
|
|
jsr Dump_Sq2_Regs ;do sub to set ctrl regs for square 2, then set frequency regs
|
|
|
|
SetFreq_Squ2
|
|
ldx #$04 ;set frequency reg offset for square 2 sound channel
|
|
bne Dump_Freq_Regs ;unconditional branch
|
|
|
|
SetFreq_Tri
|
|
ldx #$08 ;set frequency reg offset for triangle sound channel
|
|
bne Dump_Freq_Regs ;unconditional branch
|
|
|
|
;--------------------------------
|
|
|
|
SwimStompEnvelopeData
|
|
db $9f,$9b,$98,$96,$95,$94,$92,$90
|
|
db $90,$9a,$97,$95,$93,$92
|
|
|
|
PlayFlagpoleSlide
|
|
lda #$40 ;store length of flagpole sound
|
|
sta Squ1_SfxLenCounter
|
|
lda #$62 ;load part of reg contents for flagpole sound
|
|
jsr SetFreq_Squ1
|
|
ldx #$99 ;now load the rest
|
|
bne FPS2nd
|
|
|
|
PlaySmallJump
|
|
lda #$26 ;branch here for small mario jumping sound
|
|
bne JumpRegContents
|
|
|
|
PlayBigJump
|
|
lda #$18 ;branch here for big mario jumping sound
|
|
|
|
JumpRegContents
|
|
ldx #$82 ;note that small and big jump borrow each others' reg contents
|
|
ldy #$a7 ;anyway, this loads the first part of mario's jumping sound
|
|
jsr PlaySqu1Sfx
|
|
lda #$28 ;store length of sfx for both jumping sounds
|
|
sta Squ1_SfxLenCounter ;then continue on here
|
|
|
|
ContinueSndJump
|
|
lda Squ1_SfxLenCounter ;jumping sounds seem to be composed of three parts
|
|
cmp #$25 ;check for time to play second part yet
|
|
bne N2Prt
|
|
ldx #$5f ;load second part
|
|
ldy #$f6
|
|
bne DmpJpFPS ;unconditional branch
|
|
N2Prt cmp #$20 ;check for third part
|
|
bne DecJpFPS
|
|
ldx #$48 ;load third part
|
|
FPS2nd ldy #$bc ;the flagpole slide sound shares part of third part
|
|
DmpJpFPS jsr Dump_Squ1_Regs
|
|
bne DecJpFPS ;unconditional branch outta here
|
|
|
|
PlayFireballThrow
|
|
lda #$05
|
|
ldy #$99 ;load reg contents for fireball throw sound
|
|
bne Fthrow ;unconditional branch
|
|
|
|
PlayBump
|
|
lda #$0a ;load length of sfx and reg contents for bump sound
|
|
ldy #$93
|
|
Fthrow ldx #$9e ;the fireball sound shares reg contents with the bump sound
|
|
sta Squ1_SfxLenCounter
|
|
lda #$0c ;load offset for bump sound
|
|
jsr PlaySqu1Sfx
|
|
|
|
ContinueBumpThrow
|
|
lda Squ1_SfxLenCounter ;check for second part of bump sound
|
|
cmp #$06
|
|
bne DecJpFPS
|
|
lda #$bb ;load second part directly
|
|
sta SND_SQUARE1_REG+1
|
|
DecJpFPS bne BranchToDecLength1 ;unconditional branch
|
|
|
|
|
|
Square1SfxHandler
|
|
ldy Square1SoundQueue ;check for sfx in queue
|
|
beq CheckSfx1Buffer
|
|
sty Square1SoundBuffer ;if found, put in buffer
|
|
bmi PlaySmallJump ;small jump
|
|
lsr Square1SoundQueue
|
|
bcs PlayBigJump ;big jump
|
|
lsr Square1SoundQueue
|
|
bcs PlayBump ;bump
|
|
lsr Square1SoundQueue
|
|
bcs PlaySwimStomp ;swim/stomp
|
|
lsr Square1SoundQueue
|
|
bcs PlaySmackEnemy ;smack enemy
|
|
lsr Square1SoundQueue
|
|
bcs PlayPipeDownInj ;pipedown/injury
|
|
lsr Square1SoundQueue
|
|
bcs PlayFireballThrow ;fireball throw
|
|
lsr Square1SoundQueue
|
|
bcs PlayFlagpoleSlide ;slide flagpole
|
|
|
|
CheckSfx1Buffer
|
|
lda Square1SoundBuffer ;check for sfx in buffer
|
|
beq ExS1H ;if not found, exit sub
|
|
bmi ContinueSndJump ;small mario jump
|
|
lsr
|
|
bcs ContinueSndJump ;big mario jump
|
|
lsr
|
|
bcs ContinueBumpThrow ;bump
|
|
lsr
|
|
bcs ContinueSwimStomp ;swim/stomp
|
|
lsr
|
|
bcs ContinueSmackEnemy ;smack enemy
|
|
lsr
|
|
bcs ContinuePipeDownInj ;pipedown/injury
|
|
lsr
|
|
bcs ContinueBumpThrow ;fireball throw
|
|
lsr
|
|
bcs DecrementSfx1Length ;slide flagpole
|
|
ExS1H rts
|
|
|
|
PlaySwimStomp
|
|
lda #$0e ;store length of swim/stomp sound
|
|
sta Squ1_SfxLenCounter
|
|
ldy #$9c ;store reg contents for swim/stomp sound
|
|
ldx #$9e
|
|
lda #$26
|
|
jsr PlaySqu1Sfx
|
|
|
|
ContinueSwimStomp
|
|
ldy Squ1_SfxLenCounter ;look up reg contents in data section based on
|
|
lda SwimStompEnvelopeData-1,y ;length of sound left, used to control sound's
|
|
sta SND_SQUARE1_REG ;envelope
|
|
cpy #$06
|
|
bne BranchToDecLength1
|
|
lda #$9e ;when the length counts down to a certain point, put this
|
|
sta SND_SQUARE1_REG+2 ;directly into the LSB of square 1's frequency divider
|
|
|
|
BranchToDecLength1
|
|
bne DecrementSfx1Length ;unconditional branch (regardless of how we got here)
|
|
|
|
PlaySmackEnemy
|
|
lda #$0e ;store length of smack enemy sound
|
|
ldy #$cb
|
|
ldx #$9f
|
|
sta Squ1_SfxLenCounter
|
|
lda #$28 ;store reg contents for smack enemy sound
|
|
jsr PlaySqu1Sfx
|
|
bne DecrementSfx1Length ;unconditional branch
|
|
|
|
ContinueSmackEnemy
|
|
ldy Squ1_SfxLenCounter ;check about halfway through
|
|
cpy #$08
|
|
bne SmSpc
|
|
lda #$a0 ;if we're at the about-halfway point, make the second tone
|
|
sta SND_SQUARE1_REG+2 ;in the smack enemy sound
|
|
lda #$9f
|
|
bne SmTick
|
|
SmSpc lda #$90 ;this creates spaces in the sound, giving it its distinct noise
|
|
SmTick sta SND_SQUARE1_REG
|
|
|
|
DecrementSfx1Length
|
|
dec Squ1_SfxLenCounter ;decrement length of sfx
|
|
bne ExSfx1
|
|
|
|
StopSquare1Sfx
|
|
ldx #$00 ;if end of sfx reached, clear buffer
|
|
stx $f1 ;and stop making the sfx
|
|
ldx #$0e
|
|
stx SND_MASTERCTRL_REG
|
|
ldx #$0f
|
|
stx SND_MASTERCTRL_REG
|
|
ExSfx1 rts
|
|
|
|
PlayPipeDownInj
|
|
lda #$2f ;load length of pipedown sound
|
|
sta Squ1_SfxLenCounter
|
|
|
|
ContinuePipeDownInj
|
|
lda Squ1_SfxLenCounter ;some bitwise logic, forces the regs
|
|
lsr ;to be written to only during six specific times
|
|
bcs NoPDwnL ;during which d3 must be set and d1-0 must be clear
|
|
lsr
|
|
bcs NoPDwnL
|
|
and #%00000010
|
|
beq NoPDwnL
|
|
ldy #$91 ;and this is where it actually gets written in
|
|
ldx #$9a
|
|
lda #$44
|
|
jsr PlaySqu1Sfx
|
|
NoPDwnL jmp DecrementSfx1Length
|
|
|
|
;--------------------------------
|
|
|
|
ExtraLifeFreqData
|
|
db $58,$02,$54,$56,$4e,$44
|
|
|
|
PowerUpGrabFreqData
|
|
db $4c,$52,$4c,$48,$3e,$36,$3e,$36,$30
|
|
db $28,$4a,$50,$4a,$64,$3c,$32,$3c,$32
|
|
db $2c,$24,$3a,$64,$3a,$34,$2c,$22,$2c
|
|
|
|
;residual frequency data
|
|
db $22,$1c,$14
|
|
|
|
PUp_VGrow_FreqData
|
|
db $14,$04,$22,$24,$16,$04,$24,$26 ;used by both
|
|
db $18,$04,$26,$28,$1a,$04,$28,$2a
|
|
db $1c,$04,$2a,$2c,$1e,$04,$2c,$2e ;used by vinegrow
|
|
db $20,$04,$2e,$30,$22,$04,$30,$32
|
|
|
|
PlayCoinGrab
|
|
lda #$35 ;load length of coin grab sound
|
|
ldx #$8d ;and part of reg contents
|
|
bne CGrab_TTickRegL
|
|
|
|
PlayTimerTick
|
|
lda #$06 ;load length of timer tick sound
|
|
ldx #$98 ;and part of reg contents
|
|
|
|
CGrab_TTickRegL
|
|
sta Squ2_SfxLenCounter
|
|
ldy #$7f ;load the rest of reg contents
|
|
lda #$42 ;of coin grab and timer tick sound
|
|
jsr PlaySqu2Sfx
|
|
|
|
ContinueCGrabTTick
|
|
lda Squ2_SfxLenCounter ;check for time to play second tone yet
|
|
cmp #$30 ;timer tick sound also executes this, not sure why
|
|
bne N2Tone
|
|
lda #$54 ;if so, load the tone directly into the reg
|
|
sta SND_SQUARE2_REG+2
|
|
N2Tone bne DecrementSfx2Length
|
|
|
|
PlayBlast
|
|
lda #$20 ;load length of fireworks/gunfire sound
|
|
sta Squ2_SfxLenCounter
|
|
ldy #$94 ;load reg contents of fireworks/gunfire sound
|
|
lda #$5e
|
|
bne SBlasJ
|
|
|
|
ContinueBlast
|
|
lda Squ2_SfxLenCounter ;check for time to play second part
|
|
cmp #$18
|
|
bne DecrementSfx2Length
|
|
ldy #$93 ;load second part reg contents then
|
|
lda #$18
|
|
SBlasJ bne BlstSJp ;unconditional branch to load rest of reg contents
|
|
|
|
PlayPowerUpGrab
|
|
lda #$36 ;load length of power-up grab sound
|
|
sta Squ2_SfxLenCounter
|
|
|
|
ContinuePowerUpGrab
|
|
lda Squ2_SfxLenCounter ;load frequency reg based on length left over
|
|
lsr ;divide by 2
|
|
bcs DecrementSfx2Length ;alter frequency every other frame
|
|
tay
|
|
lda PowerUpGrabFreqData-1,y ;use length left over / 2 for frequency offset
|
|
ldx #$5d ;store reg contents of power-up grab sound
|
|
ldy #$7f
|
|
|
|
LoadSqu2Regs
|
|
jsr PlaySqu2Sfx
|
|
|
|
DecrementSfx2Length
|
|
dec Squ2_SfxLenCounter ;decrement length of sfx
|
|
bne ExSfx2
|
|
|
|
EmptySfx2Buffer
|
|
ldx #$00 ;initialize square 2's sound effects buffer
|
|
stx Square2SoundBuffer
|
|
|
|
StopSquare2Sfx
|
|
ldx #$0d ;stop playing the sfx
|
|
stx SND_MASTERCTRL_REG
|
|
ldx #$0f
|
|
stx SND_MASTERCTRL_REG
|
|
ExSfx2 rts
|
|
|
|
Square2SfxHandler
|
|
lda Square2SoundBuffer ;special handling for the 1-up sound to keep it
|
|
and #Sfx_ExtraLife ;from being interrupted by other sounds on square 2
|
|
bne ContinueExtraLife
|
|
ldy Square2SoundQueue ;check for sfx in queue
|
|
beq CheckSfx2Buffer
|
|
sty Square2SoundBuffer ;if found, put in buffer and check for the following
|
|
bmi PlayBowserFall ;bowser fall
|
|
lsr Square2SoundQueue
|
|
bcs PlayCoinGrab ;coin grab
|
|
lsr Square2SoundQueue
|
|
bcs PlayGrowPowerUp ;power-up reveal
|
|
lsr Square2SoundQueue
|
|
bcs PlayGrowVine ;vine grow
|
|
lsr Square2SoundQueue
|
|
bcs PlayBlast ;fireworks/gunfire
|
|
lsr Square2SoundQueue
|
|
bcs PlayTimerTick ;timer tick
|
|
lsr Square2SoundQueue
|
|
bcs PlayPowerUpGrab ;power-up grab
|
|
lsr Square2SoundQueue
|
|
bcs PlayExtraLife ;1-up
|
|
|
|
CheckSfx2Buffer
|
|
lda Square2SoundBuffer ;check for sfx in buffer
|
|
beq ExS2H ;if not found, exit sub
|
|
bmi ContinueBowserFall ;bowser fall
|
|
lsr
|
|
bcs Cont_CGrab_TTick ;coin grab
|
|
lsr
|
|
bcs ContinueGrowItems ;power-up reveal
|
|
lsr
|
|
bcs ContinueGrowItems ;vine grow
|
|
lsr
|
|
bcs ContinueBlast ;fireworks/gunfire
|
|
lsr
|
|
bcs Cont_CGrab_TTick ;timer tick
|
|
lsr
|
|
bcs ContinuePowerUpGrab ;power-up grab
|
|
lsr
|
|
bcs ContinueExtraLife ;1-up
|
|
ExS2H rts
|
|
|
|
Cont_CGrab_TTick
|
|
jmp ContinueCGrabTTick
|
|
|
|
JumpToDecLength2
|
|
jmp DecrementSfx2Length
|
|
|
|
PlayBowserFall
|
|
lda #$38 ;load length of bowser defeat sound
|
|
sta Squ2_SfxLenCounter
|
|
ldy #$c4 ;load contents of reg for bowser defeat sound
|
|
lda #$18
|
|
BlstSJp bne PBFRegs
|
|
|
|
ContinueBowserFall
|
|
lda Squ2_SfxLenCounter ;check for almost near the end
|
|
cmp #$08
|
|
bne DecrementSfx2Length
|
|
ldy #$a4 ;if so, load the rest of reg contents for bowser defeat sound
|
|
lda #$5a
|
|
PBFRegs ldx #$9f ;the fireworks/gunfire sound shares part of reg contents here
|
|
EL_LRegs bne LoadSqu2Regs ;this is an unconditional branch outta here
|
|
|
|
PlayExtraLife
|
|
lda #$30 ;load length of 1-up sound
|
|
sta Squ2_SfxLenCounter
|
|
|
|
ContinueExtraLife
|
|
lda Squ2_SfxLenCounter
|
|
ldx #$03 ;load new tones only every eight frames
|
|
DivLLoop lsr
|
|
bcs JumpToDecLength2 ;if any bits set here, branch to dec the length
|
|
dex
|
|
bne DivLLoop ;do this until all bits checked, if none set, continue
|
|
tay
|
|
lda ExtraLifeFreqData-1,y ;load our reg contents
|
|
ldx #$82
|
|
ldy #$7f
|
|
bne EL_LRegs ;unconditional branch
|
|
|
|
PlayGrowPowerUp
|
|
lda #$10 ;load length of power-up reveal sound
|
|
bne GrowItemRegs
|
|
|
|
PlayGrowVine
|
|
lda #$20 ;load length of vine grow sound
|
|
|
|
GrowItemRegs
|
|
sta Squ2_SfxLenCounter
|
|
lda #$7f ;load contents of reg for both sounds directly
|
|
sta SND_SQUARE2_REG+1
|
|
lda #$00 ;start secondary counter for both sounds
|
|
sta Sfx_SecondaryCounter
|
|
|
|
ContinueGrowItems
|
|
inc Sfx_SecondaryCounter ;increment secondary counter for both sounds
|
|
lda Sfx_SecondaryCounter ;this sound doesn't decrement the usual counter
|
|
lsr ;divide by 2 to get the offset
|
|
tay
|
|
cpy Squ2_SfxLenCounter ;have we reached the end yet?
|
|
beq StopGrowItems ;if so, branch to jump, and stop playing sounds
|
|
lda #$9d ;load contents of other reg directly
|
|
sta SND_SQUARE2_REG
|
|
lda PUp_VGrow_FreqData,y ;use secondary counter / 2 as offset for frequency regs
|
|
jsr SetFreq_Squ2
|
|
rts
|
|
|
|
StopGrowItems
|
|
jmp EmptySfx2Buffer ;branch to stop playing sounds
|
|
|
|
;--------------------------------
|
|
|
|
BrickShatterFreqData
|
|
db $01,$0e,$0e,$0d,$0b,$06,$0c,$0f
|
|
db $0a,$09,$03,$0d,$08,$0d,$06,$0c
|
|
|
|
PlayBrickShatter
|
|
lda #$20 ;load length of brick shatter sound
|
|
sta Noise_SfxLenCounter
|
|
|
|
ContinueBrickShatter
|
|
lda Noise_SfxLenCounter
|
|
lsr ;divide by 2 and check for bit set to use offset
|
|
bcc DecrementSfx3Length
|
|
tay
|
|
ldx BrickShatterFreqData,y ;load reg contents of brick shatter sound
|
|
lda BrickShatterEnvData,y
|
|
|
|
PlayNoiseSfx
|
|
sta SND_NOISE_REG ;play the sfx
|
|
stx SND_NOISE_REG+2
|
|
lda #$18
|
|
sta SND_NOISE_REG+3
|
|
|
|
DecrementSfx3Length
|
|
dec Noise_SfxLenCounter ;decrement length of sfx
|
|
bne ExSfx3
|
|
lda #$f0 ;if done, stop playing the sfx
|
|
sta SND_NOISE_REG
|
|
lda #$00
|
|
sta NoiseSoundBuffer
|
|
ExSfx3 rts
|
|
|
|
NoiseSfxHandler
|
|
ldy NoiseSoundQueue ;check for sfx in queue
|
|
beq CheckNoiseBuffer
|
|
sty NoiseSoundBuffer ;if found, put in buffer
|
|
lsr NoiseSoundQueue
|
|
bcs PlayBrickShatter ;brick shatter
|
|
lsr NoiseSoundQueue
|
|
bcs PlayBowserFlame ;bowser flame
|
|
|
|
CheckNoiseBuffer
|
|
lda NoiseSoundBuffer ;check for sfx in buffer
|
|
beq ExNH ;if not found, exit sub
|
|
lsr
|
|
bcs ContinueBrickShatter ;brick shatter
|
|
lsr
|
|
bcs ContinueBowserFlame ;bowser flame
|
|
ExNH rts
|
|
|
|
PlayBowserFlame
|
|
lda #$40 ;load length of bowser flame sound
|
|
sta Noise_SfxLenCounter
|
|
|
|
ContinueBowserFlame
|
|
lda Noise_SfxLenCounter
|
|
lsr
|
|
tay
|
|
ldx #$0f ;load reg contents of bowser flame sound
|
|
lda BowserFlameEnvData-1,y
|
|
bne PlayNoiseSfx ;unconditional branch here
|
|
|
|
;--------------------------------
|
|
|
|
ContinueMusic
|
|
jmp HandleSquare2Music ;if we have music, start with square 2 channel
|
|
|
|
MusicHandler
|
|
lda EventMusicQueue ;check event music queue
|
|
bne LoadEventMusic
|
|
lda AreaMusicQueue ;check area music queue
|
|
bne LoadAreaMusic
|
|
lda EventMusicBuffer ;check both buffers
|
|
ora AreaMusicBuffer
|
|
bne ContinueMusic
|
|
rts ;no music, then leave
|
|
|
|
LoadEventMusic
|
|
sta EventMusicBuffer ;copy event music queue contents to buffer
|
|
cmp #DeathMusic ;is it death music?
|
|
bne NoStopSfx ;if not, jump elsewhere
|
|
jsr StopSquare1Sfx ;stop sfx in square 1 and 2
|
|
jsr StopSquare2Sfx ;but clear only square 1's sfx buffer
|
|
NoStopSfx ldx AreaMusicBuffer
|
|
stx AreaMusicBuffer_Alt ;save current area music buffer to be re-obtained later
|
|
ldy #$00
|
|
sty NoteLengthTblAdder ;default value for additional length byte offset
|
|
sty AreaMusicBuffer ;clear area music buffer
|
|
cmp #TimeRunningOutMusic ;is it time running out music?
|
|
bne FindEventMusicHeader
|
|
ldx #$08 ;load offset to be added to length byte of header
|
|
stx NoteLengthTblAdder
|
|
bne FindEventMusicHeader ;unconditional branch
|
|
|
|
LoadAreaMusic
|
|
cmp #$04 ;is it underground music?
|
|
bne NoStop1 ;no, do not stop square 1 sfx
|
|
jsr StopSquare1Sfx
|
|
NoStop1 ldy #$10 ;start counter used only by ground level music
|
|
GMLoopB sty GroundMusicHeaderOfs
|
|
|
|
HandleAreaMusicLoopB
|
|
ldy #$00 ;clear event music buffer
|
|
sty EventMusicBuffer
|
|
sta AreaMusicBuffer ;copy area music queue contents to buffer
|
|
cmp #$01 ;is it ground level music?
|
|
bne FindAreaMusicHeader
|
|
inc GroundMusicHeaderOfs ;increment but only if playing ground level music
|
|
ldy GroundMusicHeaderOfs ;is it time to loopback ground level music?
|
|
cpy #$32
|
|
bne LoadHeader ;branch ahead with alternate offset
|
|
ldy #$11
|
|
bne GMLoopB ;unconditional branch
|
|
|
|
FindAreaMusicHeader
|
|
ldy #$08 ;load Y for offset of area music
|
|
sty MusicOffset_Square2 ;residual instruction here
|
|
|
|
FindEventMusicHeader
|
|
iny ;increment Y pointer based on previously loaded queue contents
|
|
lsr ;bit shift and increment until we find a set bit for music
|
|
bcc FindEventMusicHeader
|
|
|
|
LoadHeader
|
|
lda MusicHeaderOffsetData,y ;load offset for header
|
|
tay
|
|
lda MusicHeaderData,y ;now load the header
|
|
sta NoteLenLookupTblOfs
|
|
lda MusicHeaderData+1,y
|
|
sta MusicDataLow
|
|
lda MusicHeaderData+2,y
|
|
sta MusicDataHigh
|
|
lda MusicHeaderData+3,y
|
|
sta MusicOffset_Triangle
|
|
lda MusicHeaderData+4,y
|
|
sta MusicOffset_Square1
|
|
lda MusicHeaderData+5,y
|
|
sta MusicOffset_Noise
|
|
sta NoiseDataLoopbackOfs
|
|
lda #$01 ;initialize music note counters
|
|
sta Squ2_NoteLenCounter
|
|
sta Squ1_NoteLenCounter
|
|
sta Tri_NoteLenCounter
|
|
sta Noise_BeatLenCounter
|
|
lda #$00 ;initialize music data offset for square 2
|
|
sta MusicOffset_Square2
|
|
sta AltRegContentFlag ;initialize alternate control reg data used by square 1
|
|
lda #$0b ;disable triangle channel and reenable it
|
|
sta SND_MASTERCTRL_REG
|
|
lda #$0f
|
|
sta SND_MASTERCTRL_REG
|
|
|
|
HandleSquare2Music
|
|
dec Squ2_NoteLenCounter ;decrement square 2 note length
|
|
bne MiscSqu2MusicTasks ;is it time for more data? if not, branch to end tasks
|
|
ldy MusicOffset_Square2 ;increment square 2 music offset and fetch data
|
|
inc MusicOffset_Square2
|
|
lda (MusicData),y
|
|
beq EndOfMusicData ;if zero, the data is a null terminator
|
|
bpl Squ2NoteHandler ;if non-negative, data is a note
|
|
bne Squ2LengthHandler ;otherwise it is length data
|
|
|
|
EndOfMusicData
|
|
lda EventMusicBuffer ;check secondary buffer for time running out music
|
|
cmp #TimeRunningOutMusic
|
|
bne NotTRO
|
|
lda AreaMusicBuffer_Alt ;load previously saved contents of primary buffer
|
|
bne MusicLoopBack ;and start playing the song again if there is one
|
|
NotTRO and #VictoryMusic ;check for victory music (the only secondary that loops)
|
|
bne VictoryMLoopBack
|
|
lda AreaMusicBuffer ;check primary buffer for any music except pipe intro
|
|
and #%01011111
|
|
bne MusicLoopBack ;if any area music except pipe intro, music loops
|
|
lda #$00 ;clear primary and secondary buffers and initialize
|
|
sta AreaMusicBuffer ;control regs of square and triangle channels
|
|
sta EventMusicBuffer
|
|
sta SND_TRIANGLE_REG
|
|
lda #$90
|
|
sta SND_SQUARE1_REG
|
|
sta SND_SQUARE2_REG
|
|
rts
|
|
|
|
MusicLoopBack
|
|
jmp HandleAreaMusicLoopB
|
|
|
|
VictoryMLoopBack
|
|
jmp LoadEventMusic
|
|
|
|
Squ2LengthHandler
|
|
jsr ProcessLengthData ;store length of note
|
|
sta Squ2_NoteLenBuffer
|
|
ldy MusicOffset_Square2 ;fetch another byte (MUST NOT BE LENGTH BYTE!)
|
|
inc MusicOffset_Square2
|
|
lda (MusicData),y
|
|
|
|
Squ2NoteHandler
|
|
ldx Square2SoundBuffer ;is there a sound playing on this channel?
|
|
bne SkipFqL1
|
|
jsr SetFreq_Squ2 ;no, then play the note
|
|
beq Rest ;check to see if note is rest
|
|
jsr LoadControlRegs ;if not, load control regs for square 2
|
|
Rest sta Squ2_EnvelopeDataCtrl ;save contents of A
|
|
jsr Dump_Sq2_Regs ;dump X and Y into square 2 control regs
|
|
SkipFqL1 lda Squ2_NoteLenBuffer ;save length in square 2 note counter
|
|
sta Squ2_NoteLenCounter
|
|
|
|
MiscSqu2MusicTasks
|
|
lda Square2SoundBuffer ;is there a sound playing on square 2?
|
|
bne HandleSquare1Music
|
|
lda EventMusicBuffer ;check for death music or d4 set on secondary buffer
|
|
and #%10010001 ;note that regs for death music or d4 are loaded by default
|
|
bne HandleSquare1Music
|
|
ldy Squ2_EnvelopeDataCtrl ;check for contents saved from LoadControlRegs
|
|
beq NoDecEnv1
|
|
dec Squ2_EnvelopeDataCtrl ;decrement unless already zero
|
|
NoDecEnv1 jsr LoadEnvelopeData ;do a load of envelope data to replace default
|
|
sta SND_SQUARE2_REG ;based on offset set by first load unless playing
|
|
ldx #$7f ;death music or d4 set on secondary buffer
|
|
stx SND_SQUARE2_REG+1
|
|
|
|
HandleSquare1Music
|
|
ldy MusicOffset_Square1 ;is there a nonzero offset here?
|
|
beq HandleTriangleMusic ;if not, skip ahead to the triangle channel
|
|
dec Squ1_NoteLenCounter ;decrement square 1 note length
|
|
bne MiscSqu1MusicTasks ;is it time for more data?
|
|
|
|
FetchSqu1MusicData
|
|
ldy MusicOffset_Square1 ;increment square 1 music offset and fetch data
|
|
inc MusicOffset_Square1
|
|
lda (MusicData),y
|
|
bne Squ1NoteHandler ;if nonzero, then skip this part
|
|
lda #$83
|
|
sta SND_SQUARE1_REG ;store some data into control regs for square 1
|
|
lda #$94 ;and fetch another byte of data, used to give
|
|
sta SND_SQUARE1_REG+1 ;death music its unique sound
|
|
sta AltRegContentFlag
|
|
bne FetchSqu1MusicData ;unconditional branch
|
|
|
|
Squ1NoteHandler
|
|
jsr AlternateLengthHandler
|
|
sta Squ1_NoteLenCounter ;save contents of A in square 1 note counter
|
|
ldy Square1SoundBuffer ;is there a sound playing on square 1?
|
|
bne HandleTriangleMusic
|
|
txa
|
|
and #%00111110 ;change saved data to appropriate note format
|
|
jsr SetFreq_Squ1 ;play the note
|
|
beq SkipCtrlL
|
|
jsr LoadControlRegs
|
|
SkipCtrlL sta Squ1_EnvelopeDataCtrl ;save envelope offset
|
|
jsr Dump_Squ1_Regs
|
|
|
|
MiscSqu1MusicTasks
|
|
lda Square1SoundBuffer ;is there a sound playing on square 1?
|
|
bne HandleTriangleMusic
|
|
lda EventMusicBuffer ;check for death music or d4 set on secondary buffer
|
|
and #%10010001
|
|
bne DeathMAltReg
|
|
ldy Squ1_EnvelopeDataCtrl ;check saved envelope offset
|
|
beq NoDecEnv2
|
|
dec Squ1_EnvelopeDataCtrl ;decrement unless already zero
|
|
NoDecEnv2 jsr LoadEnvelopeData ;do a load of envelope data
|
|
sta SND_SQUARE1_REG ;based on offset set by first load
|
|
DeathMAltReg lda AltRegContentFlag ;check for alternate control reg data
|
|
bne DoAltLoad
|
|
lda #$7f ;load this value if zero, the alternate value
|
|
DoAltLoad sta SND_SQUARE1_REG+1 ;if nonzero, and let's move on
|
|
|
|
HandleTriangleMusic
|
|
lda MusicOffset_Triangle
|
|
dec Tri_NoteLenCounter ;decrement triangle note length
|
|
bne HandleNoiseMusic ;is it time for more data?
|
|
ldy MusicOffset_Triangle ;increment square 1 music offset and fetch data
|
|
inc MusicOffset_Triangle
|
|
lda (MusicData),y
|
|
beq LoadTriCtrlReg ;if zero, skip all this and move on to noise
|
|
bpl TriNoteHandler ;if non-negative, data is note
|
|
jsr ProcessLengthData ;otherwise, it is length data
|
|
sta Tri_NoteLenBuffer ;save contents of A
|
|
lda #$1f
|
|
sta SND_TRIANGLE_REG ;load some default data for triangle control reg
|
|
ldy MusicOffset_Triangle ;fetch another byte
|
|
inc MusicOffset_Triangle
|
|
lda (MusicData),y
|
|
beq LoadTriCtrlReg ;check once more for nonzero data
|
|
|
|
TriNoteHandler
|
|
jsr SetFreq_Tri
|
|
ldx Tri_NoteLenBuffer ;save length in triangle note counter
|
|
stx Tri_NoteLenCounter
|
|
lda EventMusicBuffer
|
|
and #%01101110 ;check for death music or d4 set on secondary buffer
|
|
bne NotDOrD4 ;if playing any other secondary, skip primary buffer check
|
|
lda AreaMusicBuffer ;check primary buffer for water or castle level music
|
|
and #%00001010
|
|
beq HandleNoiseMusic ;if playing any other primary, or death or d4, go on to noise routine
|
|
NotDOrD4 txa ;if playing water or castle music or any secondary
|
|
cmp #$12 ;besides death music or d4 set, check length of note
|
|
bcs LongN
|
|
lda EventMusicBuffer ;check for win castle music again if not playing a long note
|
|
and #EndOfCastleMusic
|
|
beq MediN
|
|
lda #$0f ;load value $0f if playing the win castle music and playing a short
|
|
bne LoadTriCtrlReg ;note, load value $1f if playing water or castle level music or any
|
|
MediN lda #$1f ;secondary besides death and d4 except win castle or win castle and playing
|
|
bne LoadTriCtrlReg ;a short note, and load value $ff if playing a long note on water, castle
|
|
LongN lda #$ff ;or any secondary (including win castle) except death and d4
|
|
|
|
LoadTriCtrlReg
|
|
sta SND_TRIANGLE_REG ;save final contents of A into control reg for triangle
|
|
|
|
HandleNoiseMusic
|
|
lda AreaMusicBuffer ;check if playing underground or castle music
|
|
and #%11110011
|
|
beq ExitMusicHandler ;if so, skip the noise routine
|
|
dec Noise_BeatLenCounter ;decrement noise beat length
|
|
bne ExitMusicHandler ;is it time for more data?
|
|
|
|
FetchNoiseBeatData
|
|
ldy MusicOffset_Noise ;increment noise beat offset and fetch data
|
|
inc MusicOffset_Noise
|
|
lda (MusicData),y ;get noise beat data, if nonzero, branch to handle
|
|
bne NoiseBeatHandler
|
|
lda NoiseDataLoopbackOfs ;if data is zero, reload original noise beat offset
|
|
sta MusicOffset_Noise ;and loopback next time around
|
|
bne FetchNoiseBeatData ;unconditional branch
|
|
|
|
NoiseBeatHandler
|
|
jsr AlternateLengthHandler
|
|
sta Noise_BeatLenCounter ;store length in noise beat counter
|
|
txa
|
|
and #%00111110 ;reload data and erase length bits
|
|
beq SilentBeat ;if no beat data, silence
|
|
cmp #$30 ;check the beat data and play the appropriate
|
|
beq LongBeat ;noise accordingly
|
|
cmp #$20
|
|
beq StrongBeat
|
|
and #%00010000
|
|
beq SilentBeat
|
|
lda #$1c ;short beat data
|
|
ldx #$03
|
|
ldy #$18
|
|
bne PlayBeat
|
|
|
|
StrongBeat
|
|
lda #$1c ;strong beat data
|
|
ldx #$0c
|
|
ldy #$18
|
|
bne PlayBeat
|
|
|
|
LongBeat
|
|
lda #$1c ;long beat data
|
|
ldx #$03
|
|
ldy #$58
|
|
bne PlayBeat
|
|
|
|
SilentBeat
|
|
lda #$10 ;silence
|
|
|
|
PlayBeat
|
|
sta SND_NOISE_REG ;load beat data into noise regs
|
|
stx SND_NOISE_REG+2
|
|
sty SND_NOISE_REG+3
|
|
|
|
ExitMusicHandler
|
|
rts
|
|
|
|
AlternateLengthHandler
|
|
tax ;save a copy of original byte into X
|
|
ror ;save LSB from original byte into carry
|
|
txa ;reload original byte and rotate three times
|
|
rol ;turning xx00000x into 00000xxx, with the
|
|
rol ;bit in carry as the MSB here
|
|
rol
|
|
|
|
ProcessLengthData
|
|
and #%00000111 ;clear all but the three LSBs
|
|
clc
|
|
adc $f0 ;add offset loaded from first header byte
|
|
adc NoteLengthTblAdder ;add extra if time running out music
|
|
tay
|
|
lda MusicLengthLookupTbl,y ;load length
|
|
rts
|
|
|
|
LoadControlRegs
|
|
lda EventMusicBuffer ;check secondary buffer for win castle music
|
|
and #EndOfCastleMusic
|
|
beq NotECstlM
|
|
lda #$04 ;this value is only used for win castle music
|
|
bne AllMus ;unconditional branch
|
|
NotECstlM lda AreaMusicBuffer
|
|
and #%01111101 ;check primary buffer for water music
|
|
beq WaterMus
|
|
lda #$08 ;this is the default value for all other music
|
|
bne AllMus
|
|
WaterMus lda #$28 ;this value is used for water music and all other event music
|
|
AllMus ldx #$82 ;load contents of other sound regs for square 2
|
|
ldy #$7f
|
|
rts
|
|
|
|
LoadEnvelopeData
|
|
lda EventMusicBuffer ;check secondary buffer for win castle music
|
|
and #EndOfCastleMusic
|
|
beq LoadUsualEnvData
|
|
lda EndOfCastleMusicEnvData,y ;load data from offset for win castle music
|
|
rts
|
|
|
|
LoadUsualEnvData
|
|
lda AreaMusicBuffer ;check primary buffer for water music
|
|
and #%01111101
|
|
beq LoadWaterEventMusEnvData
|
|
lda AreaMusicEnvData,y ;load default data from offset for all other music
|
|
rts
|
|
|
|
LoadWaterEventMusEnvData
|
|
lda WaterEventMusEnvData,y ;load data from offset for water music and all other event music
|
|
rts
|
|
|
|
;--------------------------------
|
|
|
|
;music header offsets
|
|
|
|
MusicHeaderData
|
|
db DeathMusHdr-MHD ;event music
|
|
db GameOverMusHdr-MHD
|
|
db VictoryMusHdr-MHD
|
|
db WinCastleMusHdr-MHD
|
|
db GameOverMusHdr-MHD
|
|
db EndOfLevelMusHdr-MHD
|
|
db TimeRunningOutHdr-MHD
|
|
db SilenceHdr-MHD
|
|
|
|
db GroundLevelPart1Hdr-MHD ;area music
|
|
db WaterMusHdr-MHD
|
|
db UndergroundMusHdr-MHD
|
|
db CastleMusHdr-MHD
|
|
db Star_CloudHdr-MHD
|
|
db GroundLevelLeadInHdr-MHD
|
|
db Star_CloudHdr-MHD
|
|
db SilenceHdr-MHD
|
|
|
|
db GroundLevelLeadInHdr-MHD ;ground level music layout
|
|
db GroundLevelPart1Hdr-MHD, GroundLevelPart1Hdr-MHD
|
|
db GroundLevelPart2AHdr-MHD, GroundLevelPart2BHdr-MHD,
|
|
db GroundLevelPart2AHdr-MHD, GroundLevelPart2BHdr-MHD,
|
|
db GroundLevelPart3AHdr-MHD, GroundLevelPart3BHdr-MHD,
|
|
db GroundLevelPart1Hdr-MHD, GroundLevelPart1Hdr-MHD
|
|
db GroundLevelPart4AHdr-MHD, GroundLevelPart4BHdr-MHD,
|
|
db GroundLevelPart4AHdr-MHD, GroundLevelPart4BHdr-MHD,
|
|
db GroundLevelPart3AHdr-MHD, GroundLevelPart3BHdr-MHD,
|
|
db GroundLevelPart4AHdr-MHD, GroundLevelPart4BHdr-MHD,
|
|
|
|
;music headers
|
|
;header format is as follows
|
|
;1 byte - length byte offset
|
|
;2 bytes - music data address
|
|
;1 byte - triangle data offset
|
|
;1 byte - square 1 data offset
|
|
;1 byte - noise data offset (not used by secondary music)
|
|
|
|
TimeRunningOutHdr db $08, <TimeRunOutMusData,
|
|
Star_CloudHdr db $20, <Star_CloudMData,
|
|
EndOfLevelMusHdr db $20, <WinLevelMusData,
|
|
ResidualHeaderData db $20,$c4,$fc,$3f,$1d
|
|
UndergroundMusHdr db $18, <UndergroundMusData,
|
|
SilenceHdr db $08, <SilenceData,
|
|
CastleMusHdr db $00, <CastleMusData,
|
|
VictoryMusHdr db $10, <VictoryMusData,
|
|
GameOverMusHdr db $18, <GameOverMusData,
|
|
WaterMusHdr db $08, <WaterMusData,
|
|
WinCastleMusHdr db $08, <EndOfCastleMusData,
|
|
GroundLevelPart1Hdr db $18, <GroundM_P1Data,
|
|
GroundLevelPart2AHdr db $18, <GroundM_P2AData,
|
|
GroundLevelPart2BHdr db $18, <GroundM_P2BData,
|
|
GroundLevelPart2CHdr db $18, <GroundM_P2CData,
|
|
GroundLevelPart3AHdr db $18, <GroundM_P3AData,
|
|
GroundLevelPart3BHdr db $18, <GroundM_P3BData,
|
|
GroundLevelLeadInHdr db $18, <GroundMLdInData,
|
|
GroundLevelPart4AHdr db $18, <GroundM_P4AData,
|
|
GroundLevelPart4BHdr db $18, <GroundM_P4BData,
|
|
GroundLevelPart4CHdr db $18, <GroundM_P4CData,
|
|
DeathMusHdr db $18, <DeathMusData,
|
|
|
|
;--------------------------------
|
|
|
|
;MUSIC DATA
|
|
;square 2/triangle format
|
|
;d7 - length byte flag (0-note, 1-length)
|
|
;if d7 is set to 0 and d6-d0 is nonzero
|
|
;d6-d0 - note offset in frequency look-up table (must be even)
|
|
;if d7 is set to 1
|
|
;d6-d3 - unused
|
|
;d2-d0 - length offset in length look-up table
|
|
;value of $00 in square 2 data is used as null terminator, affects all sound channels
|
|
;value of $00 in triangle data causes routine to skip note
|
|
|
|
;square 1 format
|
|
;d7-d6, d0 - length offset in length look-up table (bit order is d0,d7,d6)
|
|
;d5-d1 - note offset in frequency look-up table
|
|
;value of $00 in square 1 data is flag alternate control reg data to be loaded
|
|
|
|
;noise format
|
|
;d7-d6, d0 - length offset in length look-up table (bit order is d0,d7,d6)
|
|
;d5-d4 - beat type (0 - rest, 1 - short, 2 - strong, 3 - long)
|
|
;d3-d1 - unused
|
|
;value of $00 in noise data is used as null terminator, affects only noise
|
|
|
|
;all music data is organized into sections (unless otherwise stated)
|
|
;square 2, square 1, triangle, noise
|
|
|
|
Star_CloudMData
|
|
db $84,$2c,$2c,$2c,$82,$04,$2c,$04,$85,$2c,$84,$2c,$2c
|
|
db $2a,$2a,$2a,$82,$04,$2a,$04,$85,$2a,$84,$2a,$2a,$00
|
|
|
|
db $1f,$1f,$1f,$98,$1f,$1f,$98,$9e,$98,$1f
|
|
db $1d,$1d,$1d,$94,$1d,$1d,$94,$9c,$94,$1d
|
|
|
|
db $86,$18,$85,$26,$30,$84,$04,$26,$30
|
|
db $86,$14,$85,$22,$2c,$84,$04,$22,$2c
|
|
|
|
db $21,$d0,$c4,$d0,$31,$d0,$c4,$d0,$00
|
|
|
|
GroundM_P1Data
|
|
db $85,$2c,$22,$1c,$84,$26,$2a,$82,$28,$26,$04
|
|
db $87,$22,$34,$3a,$82,$40,$04,$36,$84,$3a,$34
|
|
db $82,$2c,$30,$85,$2a
|
|
|
|
SilenceData
|
|
db $00
|
|
|
|
db $5d,$55,$4d,$15,$19,$96,$15,$d5,$e3,$eb
|
|
db $2d,$a6,$2b,$27,$9c,$9e,$59
|
|
|
|
db $85,$22,$1c,$14,$84,$1e,$22,$82,$20,$1e,$04,$87
|
|
db $1c,$2c,$34,$82,$36,$04,$30,$34,$04,$2c,$04,$26
|
|
db $2a,$85,$22
|
|
|
|
GroundM_P2AData
|
|
db $84,$04,$82,$3a,$38,$36,$32,$04,$34
|
|
db $04,$24,$26,$2c,$04,$26,$2c,$30,$00
|
|
|
|
db $05,$b4,$b2,$b0,$2b,$ac,$84
|
|
db $9c,$9e,$a2,$84,$94,$9c,$9e
|
|
|
|
db $85,$14,$22,$84,$2c,$85,$1e
|
|
db $82,$2c,$84,$2c,$1e
|
|
|
|
GroundM_P2BData
|
|
db $84,$04,$82,$3a,$38,$36,$32,$04,$34
|
|
db $04,$64,$04,$64,$86,$64,$00
|
|
|
|
db $05,$b4,$b2,$b0,$2b,$ac,$84
|
|
db $37,$b6,$b6,$45
|
|
|
|
db $85,$14,$1c,$82,$22,$84,$2c
|
|
db $4e,$82,$4e,$84,$4e,$22
|
|
|
|
GroundM_P2CData
|
|
db $84,$04,$85,$32,$85,$30,$86,$2c,$04,$00
|
|
|
|
db $05,$a4,$05,$9e,$05,$9d,$85
|
|
|
|
db $84,$14,$85,$24,$28,$2c,$82
|
|
db $22,$84,$22,$14
|
|
|
|
db $21,$d0,$c4,$d0,$31,$d0,$c4,$d0,$00
|
|
|
|
GroundM_P3AData
|
|
db $82,$2c,$84,$2c,$2c,$82,$2c,$30
|
|
db $04,$34,$2c,$04,$26,$86,$22,$00
|
|
|
|
db $a4,$25,$25,$a4,$29,$a2,$1d,$9c,$95
|
|
|
|
GroundM_P3BData
|
|
db $82,$2c,$2c,$04,$2c,$04,$2c,$30,$85,$34,$04,$04,$00
|
|
|
|
db $a4,$25,$25,$a4,$a8,$63,$04
|
|
|
|
;triangle data used by both sections of third part
|
|
db $85,$0e,$1a,$84,$24,$85,$22,$14,$84,$0c
|
|
|
|
GroundMLdInData
|
|
db $82,$34,$84,$34,$34,$82,$2c,$84,$34,$86,$3a,$04,$00
|
|
|
|
db $a0,$21,$21,$a0,$21,$2b,$05,$a3
|
|
|
|
db $82,$18,$84,$18,$18,$82,$18,$18,$04,$86,$3a,$22
|
|
|
|
;noise data used by lead-in and third part sections
|
|
db $31,$90,$31,$90,$31,$71,$31,$90,$90,$90,$00
|
|
|
|
GroundM_P4AData
|
|
db $82,$34,$84,$2c,$85,$22,$84,$24
|
|
db $82,$26,$36,$04,$36,$86,$26,$00
|
|
|
|
db $ac,$27,$5d,$1d,$9e,$2d,$ac,$9f
|
|
|
|
db $85,$14,$82,$20,$84,$22,$2c
|
|
db $1e,$1e,$82,$2c,$2c,$1e,$04
|
|
|
|
GroundM_P4BData
|
|
db $87,$2a,$40,$40,$40,$3a,$36
|
|
db $82,$34,$2c,$04,$26,$86,$22,$00
|
|
|
|
db $e3,$f7,$f7,$f7,$f5,$f1,$ac,$27,$9e,$9d
|
|
|
|
db $85,$18,$82,$1e,$84,$22,$2a
|
|
db $22,$22,$82,$2c,$2c,$22,$04
|
|
|
|
DeathMusData
|
|
db $86,$04 ;death music share data with fourth part c of ground level music
|
|
|
|
GroundM_P4CData
|
|
db $82,$2a,$36,$04,$36,$87,$36,$34,$30,$86,$2c,$04,$00
|
|
|
|
db $00,$68,$6a,$6c,$45 ;death music only
|
|
|
|
db $a2,$31,$b0,$f1,$ed,$eb,$a2,$1d,$9c,$95
|
|
|
|
db $86,$04 ;death music only
|
|
|
|
db $85,$22,$82,$22,$87,$22,$26,$2a,$84,$2c,$22,$86,$14
|
|
|
|
;noise data used by fourth part sections
|
|
db $51,$90,$31,$11,$00
|
|
|
|
CastleMusData
|
|
db $80,$22,$28,$22,$26,$22,$24,$22,$26
|
|
db $22,$28,$22,$2a,$22,$28,$22,$26
|
|
db $22,$28,$22,$26,$22,$24,$22,$26
|
|
db $22,$28,$22,$2a,$22,$28,$22,$26
|
|
db $20,$26,$20,$24,$20,$26,$20,$28
|
|
db $20,$26,$20,$28,$20,$26,$20,$24
|
|
db $20,$26,$20,$24,$20,$26,$20,$28
|
|
db $20,$26,$20,$28,$20,$26,$20,$24
|
|
db $28,$30,$28,$32,$28,$30,$28,$2e
|
|
db $28,$30,$28,$2e,$28,$2c,$28,$2e
|
|
db $28,$30,$28,$32,$28,$30,$28,$2e
|
|
db $28,$30,$28,$2e,$28,$2c,$28,$2e,$00
|
|
|
|
db $04,$70,$6e,$6c,$6e,$70,$72,$70,$6e
|
|
db $70,$6e,$6c,$6e,$70,$72,$70,$6e
|
|
db $6e,$6c,$6e,$70,$6e,$70,$6e,$6c
|
|
db $6e,$6c,$6e,$70,$6e,$70,$6e,$6c
|
|
db $76,$78,$76,$74,$76,$74,$72,$74
|
|
db $76,$78,$76,$74,$76,$74,$72,$74
|
|
|
|
db $84,$1a,$83,$18,$20,$84,$1e,$83,$1c,$28
|
|
db $26,$1c,$1a,$1c
|
|
|
|
GameOverMusData
|
|
db $82,$2c,$04,$04,$22,$04,$04,$84,$1c,$87
|
|
db $26,$2a,$26,$84,$24,$28,$24,$80,$22,$00
|
|
|
|
db $9c,$05,$94,$05,$0d,$9f,$1e,$9c,$98,$9d
|
|
|
|
db $82,$22,$04,$04,$1c,$04,$04,$84,$14
|
|
db $86,$1e,$80,$16,$80,$14
|
|
|
|
TimeRunOutMusData
|
|
db $81,$1c,$30,$04,$30,$30,$04,$1e,$32,$04,$32,$32
|
|
db $04,$20,$34,$04,$34,$34,$04,$36,$04,$84,$36,$00
|
|
|
|
db $46,$a4,$64,$a4,$48,$a6,$66,$a6,$4a,$a8,$68,$a8
|
|
db $6a,$44,$2b
|
|
|
|
db $81,$2a,$42,$04,$42,$42,$04,$2c,$64,$04,$64,$64
|
|
db $04,$2e,$46,$04,$46,$46,$04,$22,$04,$84,$22
|
|
|
|
WinLevelMusData
|
|
db $87,$04,$06,$0c,$14,$1c,$22,$86,$2c,$22
|
|
db $87,$04,$60,$0e,$14,$1a,$24,$86,$2c,$24
|
|
db $87,$04,$08,$10,$18,$1e,$28,$86,$30,$30
|
|
db $80,$64,$00
|
|
|
|
db $cd,$d5,$dd,$e3,$ed,$f5,$bb,$b5,$cf,$d5
|
|
db $db,$e5,$ed,$f3,$bd,$b3,$d1,$d9,$df,$e9
|
|
db $f1,$f7,$bf,$ff,$ff,$ff,$34
|
|
db $00 ;unused byte
|
|
|
|
db $86,$04,$87,$14,$1c,$22,$86,$34,$84,$2c
|
|
db $04,$04,$04,$87,$14,$1a,$24,$86,$32,$84
|
|
db $2c,$04,$86,$04,$87,$18,$1e,$28,$86,$36
|
|
db $87,$30,$30,$30,$80,$2c
|
|
|
|
;square 2 and triangle use the same data, square 1 is unused
|
|
UndergroundMusData
|
|
db $82,$14,$2c,$62,$26,$10,$28,$80,$04
|
|
db $82,$14,$2c,$62,$26,$10,$28,$80,$04
|
|
db $82,$08,$1e,$5e,$18,$60,$1a,$80,$04
|
|
db $82,$08,$1e,$5e,$18,$60,$1a,$86,$04
|
|
db $83,$1a,$18,$16,$84,$14,$1a,$18,$0e,$0c
|
|
db $16,$83,$14,$20,$1e,$1c,$28,$26,$87
|
|
db $24,$1a,$12,$10,$62,$0e,$80,$04,$04
|
|
db $00
|
|
|
|
;noise data directly follows square 2 here unlike in other songs
|
|
WaterMusData
|
|
db $82,$18,$1c,$20,$22,$26,$28
|
|
db $81,$2a,$2a,$2a,$04,$2a,$04,$83,$2a,$82,$22
|
|
db $86,$34,$32,$34,$81,$04,$22,$26,$2a,$2c,$30
|
|
db $86,$34,$83,$32,$82,$36,$84,$34,$85,$04,$81,$22
|
|
db $86,$30,$2e,$30,$81,$04,$22,$26,$2a,$2c,$2e
|
|
db $86,$30,$83,$22,$82,$36,$84,$34,$85,$04,$81,$22
|
|
db $86,$3a,$3a,$3a,$82,$3a,$81,$40,$82,$04,$81,$3a
|
|
db $86,$36,$36,$36,$82,$36,$81,$3a,$82,$04,$81,$36
|
|
db $86,$34,$82,$26,$2a,$36
|
|
db $81,$34,$34,$85,$34,$81,$2a,$86,$2c,$00
|
|
|
|
db $84,$90,$b0,$84,$50,$50,$b0,$00
|
|
|
|
db $98,$96,$94,$92,$94,$96,$58,$58,$58,$44
|
|
db $5c,$44,$9f,$a3,$a1,$a3,$85,$a3,$e0,$a6
|
|
db $23,$c4,$9f,$9d,$9f,$85,$9f,$d2,$a6,$23
|
|
db $c4,$b5,$b1,$af,$85,$b1,$af,$ad,$85,$95
|
|
db $9e,$a2,$aa,$6a,$6a,$6b,$5e,$9d
|
|
|
|
db $84,$04,$04,$82,$22,$86,$22
|
|
db $82,$14,$22,$2c,$12,$22,$2a,$14,$22,$2c
|
|
db $1c,$22,$2c,$14,$22,$2c,$12,$22,$2a,$14
|
|
db $22,$2c,$1c,$22,$2c,$18,$22,$2a,$16,$20
|
|
db $28,$18,$22,$2a,$12,$22,$2a,$18,$22,$2a
|
|
db $12,$22,$2a,$14,$22,$2c,$0c,$22,$2c,$14,$22,$34,$12
|
|
db $22,$30,$10,$22,$2e,$16,$22,$34,$18,$26
|
|
db $36,$16,$26,$36,$14,$26,$36,$12,$22,$36
|
|
db $5c,$22,$34,$0c,$22,$22,$81,$1e,$1e,$85,$1e
|
|
db $81,$12,$86,$14
|
|
|
|
EndOfCastleMusData
|
|
db $81,$2c,$22,$1c,$2c,$22,$1c,$85,$2c,$04
|
|
db $81,$2e,$24,$1e,$2e,$24,$1e,$85,$2e,$04
|
|
db $81,$32,$28,$22,$32,$28,$22,$85,$32
|
|
db $87,$36,$36,$36,$84,$3a,$00
|
|
|
|
db $5c,$54,$4c,$5c,$54,$4c
|
|
db $5c,$1c,$1c,$5c,$5c,$5c,$5c
|
|
db $5e,$56,$4e,$5e,$56,$4e
|
|
db $5e,$1e,$1e,$5e,$5e,$5e,$5e
|
|
db $62,$5a,$50,$62,$5a,$50
|
|
db $62,$22,$22,$62,$e7,$e7,$e7,$2b
|
|
|
|
db $86,$14,$81,$14,$80,$14,$14,$81,$14,$14,$14,$14
|
|
db $86,$16,$81,$16,$80,$16,$16,$81,$16,$16,$16,$16
|
|
db $81,$28,$22,$1a,$28,$22,$1a,$28,$80,$28,$28
|
|
db $81,$28,$87,$2c,$2c,$2c,$84,$30
|
|
|
|
VictoryMusData
|
|
db $83,$04,$84,$0c,$83,$62,$10,$84,$12
|
|
db $83,$1c,$22,$1e,$22,$26,$18,$1e,$04,$1c,$00
|
|
|
|
db $e3,$e1,$e3,$1d,$de,$e0,$23
|
|
db $ec,$75,$74,$f0,$f4,$f6,$ea,$31,$2d
|
|
|
|
db $83,$12,$14,$04,$18,$1a,$1c,$14
|
|
db $26,$22,$1e,$1c,$18,$1e,$22,$0c,$14
|
|
|
|
;unused space
|
|
db $ff,$ff,$ff
|
|
|
|
FreqRegLookupTbl
|
|
db $00,$88,$00,$2f,$00,$00
|
|
db $02,$a6,$02,$80,$02,$5c,$02,$3a
|
|
db $02,$1a,$01,$df,$01,$c4,$01,$ab
|
|
db $01,$93,$01,$7c,$01,$67,$01,$53
|
|
db $01,$40,$01,$2e,$01,$1d,$01,$0d
|
|
db $00,$fe,$00,$ef,$00,$e2,$00,$d5
|
|
db $00,$c9,$00,$be,$00,$b3,$00,$a9
|
|
db $00,$a0,$00,$97,$00,$8e,$00,$86
|
|
db $00,$77,$00,$7e,$00,$71,$00,$54
|
|
db $00,$64,$00,$5f,$00,$59,$00,$50
|
|
db $00,$47,$00,$43,$00,$3b,$00,$35
|
|
db $00,$2a,$00,$23,$04,$75,$03,$57
|
|
db $02,$f9,$02,$cf,$01,$fc,$00,$6a
|
|
|
|
MusicLengthLookupTbl
|
|
db $05,$0a,$14,$28,$50,$1e,$3c,$02
|
|
db $04,$08,$10,$20,$40,$18,$30,$0c
|
|
db $03,$06,$0c,$18,$30,$12,$24,$08
|
|
db $36,$03,$09,$06,$12,$1b,$24,$0c
|
|
db $24,$02,$06,$04,$0c,$12,$18,$08
|
|
db $12,$01,$03,$02,$06,$09,$0c,$04
|
|
|
|
EndOfCastleMusicEnvData
|
|
db $98,$99,$9a,$9b
|
|
|
|
AreaMusicEnvData
|
|
db $90,$94,$94,$95,$95,$96,$97,$98
|
|
|
|
WaterEventMusEnvData
|
|
db $90,$91,$92,$92,$93,$93,$93,$94
|
|
db $94,$94,$94,$94,$94,$95,$95,$95
|
|
db $95,$95,$95,$96,$96,$96,$96,$96
|
|
db $96,$96,$96,$96,$96,$96,$96,$96
|
|
db $96,$96,$96,$96,$95,$95,$94,$93
|
|
|
|
BowserFlameEnvData
|
|
db $15,$16,$16,$17,$17,$18,$19,$19
|
|
db $1a,$1a,$1c,$1d,$1d,$1e,$1e,$1f
|
|
db $1f,$1f,$1f,$1e,$1d,$1c,$1e,$1f
|
|
db $1f,$1e,$1d,$1c,$1a,$18,$16,$14
|
|
|
|
BrickShatterEnvData
|
|
db $15,$16,$16,$17,$17,$18,$19,$19
|
|
db $1a,$1a,$1c,$1d,$1d,$1e,$1e,$1f
|
|
|
|
;-------------------------------------------------------------------------------------
|
|
;INTERRUPT VECTORS
|
|
|
|
dw NonMaskableInterrupt
|
|
dw Start
|
|
dw $fff0 ;unused
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|