diff --git a/.github/workflows/makefile.yml b/.github/workflows/makefile.yml index d2f90ae..eb177d3 100644 --- a/.github/workflows/makefile.yml +++ b/.github/workflows/makefile.yml @@ -15,9 +15,6 @@ jobs: with: submodules: true - - name: Install dependencies - run: make - - name: Run check run: make check diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..075ecc9 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "editor.detectIndentation": false, + "editor.insertSpaces": false, + "editor.tabSize": 4 +} \ No newline at end of file diff --git a/src/music.asm b/audio/engine.asm similarity index 100% rename from src/music.asm rename to audio/engine.asm diff --git a/src/music-data.asm b/audio/music.asm similarity index 99% rename from src/music-data.asm rename to audio/music.asm index a0f53cd..934988d 100644 --- a/src/music-data.asm +++ b/audio/music.asm @@ -1,6 +1,3 @@ -MusicHeaderOffsetData = MusicHeaderData - 1 -MHD = MusicHeaderData - ;music header offsets MusicHeaderData: diff --git a/constants.asm b/constants.asm new file mode 100644 index 0000000..108eaad --- /dev/null +++ b/constants.asm @@ -0,0 +1,6 @@ + +.include "constants/hardware_constants.asm" +.include "constants/constants.asm" +.include "constants/sfx_constants.asm" +.include "constants/music_constants.asm" +.include "constants/entity_constants.asm" diff --git a/constants/constants.asm b/constants/constants.asm new file mode 100644 index 0000000..2d1ee33 --- /dev/null +++ b/constants/constants.asm @@ -0,0 +1,549 @@ + +; 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 + +; where sfx_constants used to be +; where music_constants used to be +; where entity_constants used to be + +;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 diff --git a/constants/entity_constants.asm b/constants/entity_constants.asm new file mode 100644 index 0000000..d0fe8b9 --- /dev/null +++ b/constants/entity_constants.asm @@ -0,0 +1,32 @@ +; 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 diff --git a/constants/hardware_constants.asm b/constants/hardware_constants.asm new file mode 100644 index 0000000..e78790f --- /dev/null +++ b/constants/hardware_constants.asm @@ -0,0 +1,23 @@ +; 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 diff --git a/constants/music_constants.asm b/constants/music_constants.asm new file mode 100644 index 0000000..edc8c7b --- /dev/null +++ b/constants/music_constants.asm @@ -0,0 +1,19 @@ +; 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 diff --git a/constants/sfx_constants.asm b/constants/sfx_constants.asm new file mode 100644 index 0000000..781879c --- /dev/null +++ b/constants/sfx_constants.asm @@ -0,0 +1,22 @@ +; 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 diff --git a/engine/game/core.asm b/engine/game/core.asm new file mode 100644 index 0000000..72b160a --- /dev/null +++ b/engine/game/core.asm @@ -0,0 +1,81 @@ + +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! diff --git a/engine/game/game-mode.asm b/engine/game/game-mode.asm new file mode 100644 index 0000000..d894ee7 --- /dev/null +++ b/engine/game/game-mode.asm @@ -0,0 +1,11 @@ + +;indirect jump routine called when +;$0770 is set to 1 +GameMode: + lda OperMode_Task + jsr JumpEngine + + .dw InitializeArea + .dw ScreenRoutines + .dw SecondaryGameSetup + .dw GameCoreRoutine diff --git a/engine/game/routine/flagpole-slide.asm b/engine/game/routine/flagpole-slide.asm new file mode 100644 index 0000000..f4652fc --- /dev/null +++ b/engine/game/routine/flagpole-slide.asm @@ -0,0 +1,18 @@ + +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) diff --git a/engine/game/routine/game-timer-setup.asm b/engine/game/routine/game-timer-setup.asm new file mode 100644 index 0000000..d3577a9 --- /dev/null +++ b/engine/game/routine/game-timer-setup.asm @@ -0,0 +1,83 @@ + +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 diff --git a/engine/game/routine/player-change-size.asm b/engine/game/routine/player-change-size.asm new file mode 100644 index 0000000..ab42ac4 --- /dev/null +++ b/engine/game/routine/player-change-size.asm @@ -0,0 +1,12 @@ + +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 diff --git a/engine/game/routine/player-control.asm b/engine/game/routine/player-control.asm new file mode 100644 index 0000000..5293cb8 --- /dev/null +++ b/engine/game/routine/player-control.asm @@ -0,0 +1,121 @@ +;$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 diff --git a/engine/game/routine/player-death.asm b/engine/game/routine/player-death.asm new file mode 100644 index 0000000..7622d24 --- /dev/null +++ b/engine/game/routine/player-death.asm @@ -0,0 +1,14 @@ +;$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 diff --git a/engine/game/routine/player-end-level.asm b/engine/game/routine/player-end-level.asm new file mode 100644 index 0000000..33658d3 --- /dev/null +++ b/engine/game/routine/player-end-level.asm @@ -0,0 +1,49 @@ + +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 diff --git a/engine/game/routine/player-entrance.asm b/engine/game/routine/player-entrance.asm new file mode 100644 index 0000000..af1ce01 --- /dev/null +++ b/engine/game/routine/player-entrance.asm @@ -0,0 +1,65 @@ + +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! diff --git a/engine/game/routine/player-fire-flower.asm b/engine/game/routine/player-fire-flower.asm new file mode 100644 index 0000000..0a72565 --- /dev/null +++ b/engine/game/routine/player-fire-flower.asm @@ -0,0 +1,29 @@ + +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 diff --git a/engine/game/routine/player-injury-blink.asm b/engine/game/routine/player-injury-blink.asm new file mode 100644 index 0000000..7b32236 --- /dev/null +++ b/engine/game/routine/player-injury-blink.asm @@ -0,0 +1,21 @@ + +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 diff --git a/engine/game/routine/side-pipe-entry.asm b/engine/game/routine/side-pipe-entry.asm new file mode 100644 index 0000000..3fe5b69 --- /dev/null +++ b/engine/game/routine/side-pipe-entry.asm @@ -0,0 +1,29 @@ + +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 diff --git a/engine/game/routine/vertical-pipe-entry.asm b/engine/game/routine/vertical-pipe-entry.asm new file mode 100644 index 0000000..1d7906f --- /dev/null +++ b/engine/game/routine/vertical-pipe-entry.asm @@ -0,0 +1,20 @@ + +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 diff --git a/engine/game/routine/vine-climb.asm b/engine/game/routine/vine-climb.asm new file mode 100644 index 0000000..1211eba --- /dev/null +++ b/engine/game/routine/vine-climb.asm @@ -0,0 +1,17 @@ + +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 diff --git a/engine/game/routines.asm b/engine/game/routines.asm new file mode 100644 index 0000000..f03d413 --- /dev/null +++ b/engine/game/routines.asm @@ -0,0 +1,18 @@ + +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 diff --git a/engine/game/scroll.asm b/engine/game/scroll.asm new file mode 100644 index 0000000..e8d49b9 --- /dev/null +++ b/engine/game/scroll.asm @@ -0,0 +1,97 @@ + +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 diff --git a/engine/jump-engine.asm b/engine/jump-engine.asm new file mode 100644 index 0000000..1603d80 --- /dev/null +++ b/engine/jump-engine.asm @@ -0,0 +1,20 @@ + +;$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 diff --git a/engine/opermode.asm b/engine/opermode.asm new file mode 100644 index 0000000..38757de --- /dev/null +++ b/engine/opermode.asm @@ -0,0 +1,9 @@ + +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 diff --git a/engine/title/demo.asm b/engine/title/demo.asm new file mode 100644 index 0000000..60059aa --- /dev/null +++ b/engine/title/demo.asm @@ -0,0 +1,29 @@ + +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 + diff --git a/engine/title/titlescreen.asm b/engine/title/titlescreen.asm new file mode 100644 index 0000000..48c47cf --- /dev/null +++ b/engine/title/titlescreen.asm @@ -0,0 +1,117 @@ + +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 diff --git a/header.asm b/header.asm new file mode 100644 index 0000000..31bfc0a --- /dev/null +++ b/header.asm @@ -0,0 +1,8 @@ + + .db $4e, $45, $53 ; "NES" + .db $1a ; PRG ROM size + .db $02 ; CHR ROM size + .db $01, $01 ; Mapper type + .db $00 ; PRG-RAM size + .db $00 ; TV system + .db $00, $00, $00, $00, $00, $00, $00 ; Unused diff --git a/main.asm b/main.asm index f819fcf..cb134c8 100644 --- a/main.asm +++ b/main.asm @@ -16,808 +16,14 @@ ;only be theory. ;------------------------------------------------------------------------------------- -;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 - -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 - - .db $4e, $45, $53, $1a, $02, $01, $01, $00, $00, $00, $00, $00, $00, $00, $00, $00 - .org $8000 - -;------------------------------------------------------------------------------------- - -.include "src/init.asm" - -;------------------------------------------------------------------------------------- -;$00 - vram buffer address table low, also used for pseudorandom bit -;$01 - vram buffer address table high -VRAM_AddrTable_Low: - .db VRAM_Buffer1, >WaterPaletteData, >GroundPaletteData - .db >UndergroundPaletteData, >CastlePaletteData, >VRAM_Buffer1_Offset - .db >VRAM_Buffer2, >VRAM_Buffer2, >BowserPaletteData - .db >DaySnowPaletteData, >NightSnowPaletteData, >MushroomPaletteData - .db >MarioThanksMessage, >LuigiThanksMessage, >MushroomRetainerSaved - .db >PrincessSaved1, >PrincessSaved2, >WorldSelectMessage1 - .db >WorldSelectMessage2 - -VRAM_Buffer_Offset: - .db