introducao-a-assembly

Repositório dos arquivos usados na apresentação "Introdução a Assembly" da CriptoGoma de 2020 🖥️

mario.asm (751389B)

    1 ;SMBDIS.ASM - A COMPREHENSIVE SUPER MARIO BROS. DISASSEMBLY
    2 ;by doppelganger (doppelheathen@gmail.com)
    3 
    4 ;This file is provided for your own use as-is.  It will require the character rom data
    5 ;and an iNES file header to get it to work.
    6 
    7 ;There are so many people I have to thank for this, that taking all the credit for
    8 ;myself would be an unforgivable act of arrogance. Without their help this would
    9 ;probably not be possible.  So I thank all the peeps in the nesdev scene whose insight into
   10 ;the 6502 and the NES helped me learn how it works (you guys know who you are, there's no 
   11 ;way I could have done this without your help), as well as the authors of x816 and SMB 
   12 ;Utility, and the reverse-engineers who did the original Super Mario Bros. Hacking Project, 
   13 ;which I compared notes with but did not copy from.  Last but certainly not least, I thank
   14 ;Nintendo for creating this game and the NES, without which this disassembly would
   15 ;only be theory.
   16 
   17 ;Assembles with x816.
   18 
   19 ;-------------------------------------------------------------------------------------
   20 ;DEFINES
   21 
   22 ;NES specific hardware defines
   23 
   24 PPU_CTRL_REG1         = $2000
   25 PPU_CTRL_REG2         = $2001
   26 PPU_STATUS            = $2002
   27 PPU_SPR_ADDR          = $2003
   28 PPU_SPR_DATA          = $2004
   29 PPU_SCROLL_REG        = $2005
   30 PPU_ADDRESS           = $2006
   31 PPU_DATA              = $2007
   32 
   33 SND_REGISTER          = $4000
   34 SND_SQUARE1_REG       = $4000
   35 SND_SQUARE2_REG       = $4004
   36 SND_TRIANGLE_REG      = $4008
   37 SND_NOISE_REG         = $400c
   38 SND_DELTA_REG         = $4010
   39 SND_MASTERCTRL_REG    = $4015
   40 
   41 SPR_DMA               = $4014
   42 JOYPAD_PORT           = $4016
   43 JOYPAD_PORT1          = $4016
   44 JOYPAD_PORT2          = $4017
   45 
   46 ; GAME SPECIFIC DEFINES
   47 
   48 ObjectOffset          = $08
   49 
   50 FrameCounter          = $09
   51 
   52 SavedJoypadBits       = $06fc
   53 SavedJoypad1Bits      = $06fc
   54 SavedJoypad2Bits      = $06fd
   55 JoypadBitMask         = $074a
   56 JoypadOverride        = $0758
   57 
   58 A_B_Buttons           = $0a
   59 PreviousA_B_Buttons   = $0d
   60 Up_Down_Buttons       = $0b
   61 Left_Right_Buttons    = $0c
   62 
   63 GameEngineSubroutine  = $0e
   64 
   65 Mirror_PPU_CTRL_REG1  = $0778
   66 Mirror_PPU_CTRL_REG2  = $0779
   67 
   68 OperMode              = $0770
   69 OperMode_Task         = $0772
   70 ScreenRoutineTask     = $073c
   71 
   72 GamePauseStatus       = $0776
   73 GamePauseTimer        = $0777
   74 
   75 DemoAction            = $0717
   76 DemoActionTimer       = $0718
   77 
   78 TimerControl          = $0747
   79 IntervalTimerControl  = $077f
   80 
   81 Timers                = $0780
   82 SelectTimer           = $0780
   83 PlayerAnimTimer       = $0781
   84 JumpSwimTimer         = $0782
   85 RunningTimer          = $0783
   86 BlockBounceTimer      = $0784
   87 SideCollisionTimer    = $0785
   88 JumpspringTimer       = $0786
   89 GameTimerCtrlTimer    = $0787
   90 ClimbSideTimer        = $0789
   91 EnemyFrameTimer       = $078a
   92 FrenzyEnemyTimer      = $078f
   93 BowserFireBreathTimer = $0790
   94 StompTimer            = $0791
   95 AirBubbleTimer        = $0792
   96 ScrollIntervalTimer   = $0795
   97 EnemyIntervalTimer    = $0796
   98 BrickCoinTimer        = $079d
   99 InjuryTimer           = $079e
  100 StarInvincibleTimer   = $079f
  101 ScreenTimer           = $07a0
  102 WorldEndTimer         = $07a1
  103 DemoTimer             = $07a2
  104 
  105 Sprite_Data           = $0200
  106 
  107 Sprite_Y_Position     = $0200
  108 Sprite_Tilenumber     = $0201
  109 Sprite_Attributes     = $0202
  110 Sprite_X_Position     = $0203
  111 
  112 ScreenEdge_PageLoc    = $071a
  113 ScreenEdge_X_Pos      = $071c
  114 ScreenLeft_PageLoc    = $071a
  115 ScreenRight_PageLoc   = $071b
  116 ScreenLeft_X_Pos      = $071c
  117 ScreenRight_X_Pos     = $071d
  118 
  119 PlayerFacingDir       = $33
  120 DestinationPageLoc    = $34
  121 VictoryWalkControl    = $35
  122 ScrollFractional      = $0768
  123 PrimaryMsgCounter     = $0719
  124 SecondaryMsgCounter   = $0749
  125 
  126 HorizontalScroll      = $073f
  127 VerticalScroll        = $0740
  128 ScrollLock            = $0723
  129 ScrollThirtyTwo       = $073d
  130 Player_X_Scroll       = $06ff
  131 Player_Pos_ForScroll  = $0755
  132 ScrollAmount          = $0775
  133 
  134 AreaData              = $e7
  135 AreaDataLow           = $e7
  136 AreaDataHigh          = $e8
  137 EnemyData             = $e9
  138 EnemyDataLow          = $e9
  139 EnemyDataHigh         = $ea
  140 
  141 AreaParserTaskNum     = $071f
  142 ColumnSets            = $071e
  143 CurrentPageLoc        = $0725
  144 CurrentColumnPos      = $0726
  145 BackloadingFlag       = $0728
  146 BehindAreaParserFlag  = $0729
  147 AreaObjectPageLoc     = $072a
  148 AreaObjectPageSel     = $072b
  149 AreaDataOffset        = $072c
  150 AreaObjOffsetBuffer   = $072d
  151 AreaObjectLength      = $0730
  152 StaircaseControl      = $0734
  153 AreaObjectHeight      = $0735
  154 MushroomLedgeHalfLen  = $0736
  155 EnemyDataOffset       = $0739
  156 EnemyObjectPageLoc    = $073a
  157 EnemyObjectPageSel    = $073b
  158 MetatileBuffer        = $06a1
  159 BlockBufferColumnPos  = $06a0
  160 CurrentNTAddr_Low     = $0721
  161 CurrentNTAddr_High    = $0720
  162 AttributeBuffer       = $03f9
  163 
  164 LoopCommand           = $0745
  165 
  166 DisplayDigits         = $07d7
  167 TopScoreDisplay       = $07d7
  168 ScoreAndCoinDisplay   = $07dd
  169 PlayerScoreDisplay    = $07dd
  170 GameTimerDisplay      = $07f8
  171 DigitModifier         = $0134
  172 
  173 VerticalFlipFlag      = $0109
  174 FloateyNum_Control    = $0110
  175 ShellChainCounter     = $0125
  176 FloateyNum_Timer      = $012c
  177 FloateyNum_X_Pos      = $0117
  178 FloateyNum_Y_Pos      = $011e
  179 FlagpoleFNum_Y_Pos    = $010d
  180 FlagpoleFNum_YMFDummy = $010e
  181 FlagpoleScore         = $010f
  182 FlagpoleCollisionYPos = $070f
  183 StompChainCounter     = $0484
  184 
  185 VRAM_Buffer1_Offset   = $0300
  186 VRAM_Buffer1          = $0301
  187 VRAM_Buffer2_Offset   = $0340
  188 VRAM_Buffer2          = $0341
  189 VRAM_Buffer_AddrCtrl  = $0773
  190 Sprite0HitDetectFlag  = $0722
  191 DisableScreenFlag     = $0774
  192 DisableIntermediate   = $0769
  193 ColorRotateOffset     = $06d4
  194 
  195 TerrainControl        = $0727
  196 AreaStyle             = $0733
  197 ForegroundScenery     = $0741
  198 BackgroundScenery     = $0742
  199 CloudTypeOverride     = $0743
  200 BackgroundColorCtrl   = $0744
  201 AreaType              = $074e
  202 AreaAddrsLOffset      = $074f
  203 AreaPointer           = $0750
  204 
  205 PlayerEntranceCtrl    = $0710
  206 GameTimerSetting      = $0715
  207 AltEntranceControl    = $0752
  208 EntrancePage          = $0751
  209 NumberOfPlayers       = $077a
  210 WarpZoneControl       = $06d6
  211 ChangeAreaTimer       = $06de
  212 
  213 MultiLoopCorrectCntr  = $06d9
  214 MultiLoopPassCntr     = $06da
  215 
  216 FetchNewGameTimerFlag = $0757
  217 GameTimerExpiredFlag  = $0759
  218 
  219 PrimaryHardMode       = $076a
  220 SecondaryHardMode     = $06cc
  221 WorldSelectNumber     = $076b
  222 WorldSelectEnableFlag = $07fc
  223 ContinueWorld         = $07fd
  224 
  225 CurrentPlayer         = $0753
  226 PlayerSize            = $0754
  227 PlayerStatus          = $0756
  228 
  229 OnscreenPlayerInfo    = $075a
  230 NumberofLives         = $075a ;used by current player
  231 HalfwayPage           = $075b
  232 LevelNumber           = $075c ;the actual dash number
  233 Hidden1UpFlag         = $075d
  234 CoinTally             = $075e
  235 WorldNumber           = $075f
  236 AreaNumber            = $0760 ;internal number used to find areas
  237 
  238 CoinTallyFor1Ups      = $0748
  239 
  240 OffscreenPlayerInfo   = $0761
  241 OffScr_NumberofLives  = $0761 ;used by offscreen player
  242 OffScr_HalfwayPage    = $0762
  243 OffScr_LevelNumber    = $0763
  244 OffScr_Hidden1UpFlag  = $0764
  245 OffScr_CoinTally      = $0765
  246 OffScr_WorldNumber    = $0766
  247 OffScr_AreaNumber     = $0767
  248 
  249 BalPlatformAlignment  = $03a0
  250 Platform_X_Scroll     = $03a1
  251 PlatformCollisionFlag = $03a2
  252 YPlatformTopYPos      = $0401
  253 YPlatformCenterYPos   = $58
  254 
  255 BrickCoinTimerFlag    = $06bc
  256 StarFlagTaskControl   = $0746
  257 
  258 PseudoRandomBitReg    = $07a7
  259 WarmBootValidation    = $07ff
  260 
  261 SprShuffleAmtOffset   = $06e0
  262 SprShuffleAmt         = $06e1
  263 SprDataOffset         = $06e4
  264 Player_SprDataOffset  = $06e4
  265 Enemy_SprDataOffset   = $06e5
  266 Block_SprDataOffset   = $06ec
  267 Alt_SprDataOffset     = $06ec
  268 Bubble_SprDataOffset  = $06ee
  269 FBall_SprDataOffset   = $06f1
  270 Misc_SprDataOffset    = $06f3
  271 SprDataOffset_Ctrl    = $03ee
  272 
  273 Player_State          = $1d
  274 Enemy_State           = $1e
  275 Fireball_State        = $24
  276 Block_State           = $26
  277 Misc_State            = $2a
  278 
  279 Player_MovingDir      = $45
  280 Enemy_MovingDir       = $46
  281 
  282 SprObject_X_Speed     = $57
  283 Player_X_Speed        = $57
  284 Enemy_X_Speed         = $58
  285 Fireball_X_Speed      = $5e
  286 Block_X_Speed         = $60
  287 Misc_X_Speed          = $64
  288 
  289 Jumpspring_FixedYPos  = $58
  290 JumpspringAnimCtrl    = $070e
  291 JumpspringForce       = $06db
  292 
  293 SprObject_PageLoc     = $6d
  294 Player_PageLoc        = $6d
  295 Enemy_PageLoc         = $6e
  296 Fireball_PageLoc      = $74
  297 Block_PageLoc         = $76
  298 Misc_PageLoc          = $7a
  299 Bubble_PageLoc        = $83
  300 
  301 SprObject_X_Position  = $86
  302 Player_X_Position     = $86
  303 Enemy_X_Position      = $87
  304 Fireball_X_Position   = $8d
  305 Block_X_Position      = $8f
  306 Misc_X_Position       = $93
  307 Bubble_X_Position     = $9c
  308 
  309 SprObject_Y_Speed     = $9f
  310 Player_Y_Speed        = $9f
  311 Enemy_Y_Speed         = $a0
  312 Fireball_Y_Speed      = $a6
  313 Block_Y_Speed         = $a8
  314 Misc_Y_Speed          = $ac
  315 
  316 SprObject_Y_HighPos   = $b5
  317 Player_Y_HighPos      = $b5
  318 Enemy_Y_HighPos       = $b6
  319 Fireball_Y_HighPos    = $bc
  320 Block_Y_HighPos       = $be
  321 Misc_Y_HighPos        = $c2
  322 Bubble_Y_HighPos      = $cb
  323 
  324 SprObject_Y_Position  = $ce
  325 Player_Y_Position     = $ce
  326 Enemy_Y_Position      = $cf
  327 Fireball_Y_Position   = $d5
  328 Block_Y_Position      = $d7
  329 Misc_Y_Position       = $db
  330 Bubble_Y_Position     = $e4
  331 
  332 SprObject_Rel_XPos    = $03ad
  333 Player_Rel_XPos       = $03ad
  334 Enemy_Rel_XPos        = $03ae
  335 Fireball_Rel_XPos     = $03af
  336 Bubble_Rel_XPos       = $03b0
  337 Block_Rel_XPos        = $03b1
  338 Misc_Rel_XPos         = $03b3
  339 
  340 SprObject_Rel_YPos    = $03b8
  341 Player_Rel_YPos       = $03b8
  342 Enemy_Rel_YPos        = $03b9
  343 Fireball_Rel_YPos     = $03ba
  344 Bubble_Rel_YPos       = $03bb
  345 Block_Rel_YPos        = $03bc
  346 Misc_Rel_YPos         = $03be
  347 
  348 SprObject_SprAttrib   = $03c4
  349 Player_SprAttrib      = $03c4
  350 Enemy_SprAttrib       = $03c5
  351 
  352 SprObject_X_MoveForce = $0400
  353 Enemy_X_MoveForce     = $0401
  354 
  355 SprObject_YMF_Dummy   = $0416
  356 Player_YMF_Dummy      = $0416
  357 Enemy_YMF_Dummy       = $0417
  358 Bubble_YMF_Dummy      = $042c
  359 
  360 SprObject_Y_MoveForce = $0433
  361 Player_Y_MoveForce    = $0433
  362 Enemy_Y_MoveForce     = $0434
  363 Block_Y_MoveForce     = $043c
  364 
  365 DisableCollisionDet   = $0716
  366 Player_CollisionBits  = $0490
  367 Enemy_CollisionBits   = $0491
  368 
  369 SprObj_BoundBoxCtrl   = $0499
  370 Player_BoundBoxCtrl   = $0499
  371 Enemy_BoundBoxCtrl    = $049a
  372 Fireball_BoundBoxCtrl = $04a0
  373 Misc_BoundBoxCtrl     = $04a2
  374 
  375 EnemyFrenzyBuffer     = $06cb
  376 EnemyFrenzyQueue      = $06cd
  377 Enemy_Flag            = $0f
  378 Enemy_ID              = $16
  379 
  380 PlayerGfxOffset       = $06d5
  381 Player_XSpeedAbsolute = $0700
  382 FrictionAdderHigh     = $0701
  383 FrictionAdderLow      = $0702
  384 RunningSpeed          = $0703
  385 SwimmingFlag          = $0704
  386 Player_X_MoveForce    = $0705
  387 DiffToHaltJump        = $0706
  388 JumpOrigin_Y_HighPos  = $0707
  389 JumpOrigin_Y_Position = $0708
  390 VerticalForce         = $0709
  391 VerticalForceDown     = $070a
  392 PlayerChangeSizeFlag  = $070b
  393 PlayerAnimTimerSet    = $070c
  394 PlayerAnimCtrl        = $070d
  395 DeathMusicLoaded      = $0712
  396 FlagpoleSoundQueue    = $0713
  397 CrouchingFlag         = $0714
  398 MaximumLeftSpeed      = $0450
  399 MaximumRightSpeed     = $0456
  400 
  401 SprObject_OffscrBits  = $03d0
  402 Player_OffscreenBits  = $03d0
  403 Enemy_OffscreenBits   = $03d1
  404 FBall_OffscreenBits   = $03d2
  405 Bubble_OffscreenBits  = $03d3
  406 Block_OffscreenBits   = $03d4
  407 Misc_OffscreenBits    = $03d6
  408 EnemyOffscrBitsMasked = $03d8
  409 
  410 Cannon_Offset         = $046a
  411 Cannon_PageLoc        = $046b
  412 Cannon_X_Position     = $0471
  413 Cannon_Y_Position     = $0477
  414 Cannon_Timer          = $047d
  415 
  416 Whirlpool_Offset      = $046a
  417 Whirlpool_PageLoc     = $046b
  418 Whirlpool_LeftExtent  = $0471
  419 Whirlpool_Length      = $0477
  420 Whirlpool_Flag        = $047d
  421 
  422 VineFlagOffset        = $0398
  423 VineHeight            = $0399
  424 VineObjOffset         = $039a
  425 VineStart_Y_Position  = $039d
  426 
  427 Block_Orig_YPos       = $03e4
  428 Block_BBuf_Low        = $03e6
  429 Block_Metatile        = $03e8
  430 Block_PageLoc2        = $03ea
  431 Block_RepFlag         = $03ec
  432 Block_ResidualCounter = $03f0
  433 Block_Orig_XPos       = $03f1
  434 
  435 BoundingBox_UL_XPos   = $04ac
  436 BoundingBox_UL_YPos   = $04ad
  437 BoundingBox_DR_XPos   = $04ae
  438 BoundingBox_DR_YPos   = $04af
  439 BoundingBox_UL_Corner = $04ac
  440 BoundingBox_LR_Corner = $04ae
  441 EnemyBoundingBoxCoord = $04b0
  442 
  443 PowerUpType           = $39
  444 
  445 FireballBouncingFlag  = $3a
  446 FireballCounter       = $06ce
  447 FireballThrowingTimer = $0711
  448 
  449 HammerEnemyOffset     = $06ae
  450 JumpCoinMiscOffset    = $06b7
  451 
  452 Block_Buffer_1        = $0500
  453 Block_Buffer_2        = $05d0
  454 
  455 HammerThrowingTimer   = $03a2
  456 HammerBroJumpTimer    = $3c
  457 Misc_Collision_Flag   = $06be
  458 
  459 RedPTroopaOrigXPos    = $0401
  460 RedPTroopaCenterYPos  = $58
  461 
  462 XMovePrimaryCounter   = $a0
  463 XMoveSecondaryCounter = $58
  464 
  465 CheepCheepMoveMFlag   = $58
  466 CheepCheepOrigYPos    = $0434
  467 BitMFilter            = $06dd
  468 
  469 LakituReappearTimer   = $06d1
  470 LakituMoveSpeed       = $58
  471 LakituMoveDirection   = $a0
  472 
  473 FirebarSpinState_Low  = $58
  474 FirebarSpinState_High = $a0
  475 FirebarSpinSpeed      = $0388
  476 FirebarSpinDirection  = $34
  477 
  478 DuplicateObj_Offset   = $06cf
  479 NumberofGroupEnemies  = $06d3
  480 
  481 BlooperMoveCounter    = $a0
  482 BlooperMoveSpeed      = $58
  483 
  484 BowserBodyControls    = $0363
  485 BowserFeetCounter     = $0364
  486 BowserMovementSpeed   = $0365
  487 BowserOrigXPos        = $0366
  488 BowserFlameTimerCtrl  = $0367
  489 BowserFront_Offset    = $0368
  490 BridgeCollapseOffset  = $0369
  491 BowserGfxFlag         = $036a
  492 BowserHitPoints       = $0483
  493 MaxRangeFromOrigin    = $06dc
  494 
  495 BowserFlamePRandomOfs = $0417
  496 
  497 PiranhaPlantUpYPos    = $0417
  498 PiranhaPlantDownYPos  = $0434
  499 PiranhaPlant_Y_Speed  = $58
  500 PiranhaPlant_MoveFlag = $a0
  501 
  502 FireworksCounter      = $06d7
  503 ExplosionGfxCounter   = $58
  504 ExplosionTimerCounter = $a0
  505 
  506 ;sound related defines
  507 Squ2_NoteLenBuffer    = $07b3
  508 Squ2_NoteLenCounter   = $07b4
  509 Squ2_EnvelopeDataCtrl = $07b5
  510 Squ1_NoteLenCounter   = $07b6
  511 Squ1_EnvelopeDataCtrl = $07b7
  512 Tri_NoteLenBuffer     = $07b8
  513 Tri_NoteLenCounter    = $07b9
  514 Noise_BeatLenCounter  = $07ba
  515 Squ1_SfxLenCounter    = $07bb
  516 Squ2_SfxLenCounter    = $07bd
  517 Sfx_SecondaryCounter  = $07be
  518 Noise_SfxLenCounter   = $07bf
  519 
  520 PauseSoundQueue       = $fa
  521 Square1SoundQueue     = $ff
  522 Square2SoundQueue     = $fe
  523 NoiseSoundQueue       = $fd
  524 AreaMusicQueue        = $fb
  525 EventMusicQueue       = $fc
  526 
  527 Square1SoundBuffer    = $f1
  528 Square2SoundBuffer    = $f2
  529 NoiseSoundBuffer      = $f3
  530 AreaMusicBuffer       = $f4
  531 EventMusicBuffer      = $07b1
  532 PauseSoundBuffer      = $07b2
  533 
  534 MusicData             = $f5
  535 MusicDataLow          = $f5
  536 MusicDataHigh         = $f6
  537 MusicOffset_Square2   = $f7
  538 MusicOffset_Square1   = $f8
  539 MusicOffset_Triangle  = $f9
  540 MusicOffset_Noise     = $07b0
  541 
  542 NoteLenLookupTblOfs   = $f0
  543 DAC_Counter           = $07c0
  544 NoiseDataLoopbackOfs  = $07c1
  545 NoteLengthTblAdder    = $07c4
  546 AreaMusicBuffer_Alt   = $07c5
  547 PauseModeFlag         = $07c6
  548 GroundMusicHeaderOfs  = $07c7
  549 AltRegContentFlag     = $07ca
  550 
  551 ;-------------------------------------------------------------------------------------
  552 ;CONSTANTS
  553 
  554 ;sound effects constants
  555 Sfx_SmallJump         = %10000000
  556 Sfx_Flagpole          = %01000000
  557 Sfx_Fireball          = %00100000
  558 Sfx_PipeDown_Injury   = %00010000
  559 Sfx_EnemySmack        = %00001000
  560 Sfx_EnemyStomp        = %00000100
  561 Sfx_Bump              = %00000010
  562 Sfx_BigJump           = %00000001
  563 
  564 Sfx_BowserFall        = %10000000
  565 Sfx_ExtraLife         = %01000000
  566 Sfx_PowerUpGrab       = %00100000
  567 Sfx_TimerTick         = %00010000
  568 Sfx_Blast             = %00001000
  569 Sfx_GrowVine          = %00000100
  570 Sfx_GrowPowerUp       = %00000010
  571 Sfx_CoinGrab          = %00000001
  572 
  573 Sfx_BowserFlame       = %00000010
  574 Sfx_BrickShatter      = %00000001
  575 
  576 ;music constants
  577 Silence               = %10000000
  578 
  579 StarPowerMusic        = %01000000
  580 PipeIntroMusic        = %00100000
  581 CloudMusic            = %00010000
  582 CastleMusic           = %00001000
  583 UndergroundMusic      = %00000100
  584 WaterMusic            = %00000010
  585 GroundMusic           = %00000001
  586 
  587 TimeRunningOutMusic   = %01000000
  588 EndOfLevelMusic       = %00100000
  589 AltGameOverMusic      = %00010000
  590 EndOfCastleMusic      = %00001000
  591 VictoryMusic          = %00000100
  592 GameOverMusic         = %00000010
  593 DeathMusic            = %00000001
  594 
  595 ;enemy object constants 
  596 GreenKoopa            = $00
  597 BuzzyBeetle           = $02
  598 RedKoopa              = $03
  599 HammerBro             = $05
  600 Goomba                = $06
  601 Bloober               = $07
  602 BulletBill_FrenzyVar  = $08
  603 GreyCheepCheep        = $0a
  604 RedCheepCheep         = $0b
  605 Podoboo               = $0c
  606 PiranhaPlant          = $0d
  607 GreenParatroopaJump   = $0e
  608 RedParatroopa         = $0f
  609 GreenParatroopaFly    = $10
  610 Lakitu                = $11
  611 Spiny                 = $12
  612 FlyCheepCheepFrenzy   = $14
  613 FlyingCheepCheep      = $14
  614 BowserFlame           = $15
  615 Fireworks             = $16
  616 BBill_CCheep_Frenzy   = $17
  617 Stop_Frenzy           = $18
  618 Bowser                = $2d
  619 PowerUpObject         = $2e
  620 VineObject            = $2f
  621 FlagpoleFlagObject    = $30
  622 StarFlagObject        = $31
  623 JumpspringObject      = $32
  624 BulletBill_CannonVar  = $33
  625 RetainerObject        = $35
  626 TallEnemy             = $09
  627 
  628 ;other constants
  629 World1 = 0
  630 World2 = 1
  631 World3 = 2
  632 World4 = 3
  633 World5 = 4
  634 World6 = 5
  635 World7 = 6
  636 World8 = 7
  637 Level1 = 0
  638 Level2 = 1
  639 Level3 = 2
  640 Level4 = 3
  641 
  642 WarmBootOffset        = <$07d6
  643 ColdBootOffset        = <$07fe
  644 TitleScreenDataOffset = $1ec0
  645 SoundMemory           = $07b0
  646 SwimTileRepOffset     = PlayerGraphicsTable + $9e
  647 MusicHeaderOffsetData = MusicHeaderData - 1
  648 MHD                   = MusicHeaderData
  649 
  650 A_Button              = %10000000
  651 B_Button              = %01000000
  652 Select_Button         = %00100000
  653 Start_Button          = %00010000
  654 Up_Dir                = %00001000
  655 Down_Dir              = %00000100
  656 Left_Dir              = %00000010
  657 Right_Dir             = %00000001
  658 
  659 TitleScreenModeValue  = 0
  660 GameModeValue         = 1
  661 VictoryModeValue      = 2
  662 GameOverModeValue     = 3
  663 
  664 ;-------------------------------------------------------------------------------------
  665 ;DIRECTIVES
  666 
  667        .index 8
  668        .mem 8
  669 
  670        .org $8000
  671 
  672 ;-------------------------------------------------------------------------------------
  673 
  674 Start:
  675              sei                          ;pretty standard 6502 type init here
  676              cld
  677              lda #%00010000               ;init PPU control register 1 
  678              sta PPU_CTRL_REG1
  679              ldx #$ff                     ;reset stack pointer
  680              txs
  681 VBlank1:     lda PPU_STATUS               ;wait two frames
  682              bpl VBlank1
  683 VBlank2:     lda PPU_STATUS
  684              bpl VBlank2
  685              ldy #ColdBootOffset          ;load default cold boot pointer
  686              ldx #$05                     ;this is where we check for a warm boot
  687 WBootCheck:  lda TopScoreDisplay,x        ;check each score digit in the top score
  688              cmp #10                      ;to see if we have a valid digit
  689              bcs ColdBoot                 ;if not, give up and proceed with cold boot
  690              dex                      
  691              bpl WBootCheck
  692              lda WarmBootValidation       ;second checkpoint, check to see if 
  693              cmp #$a5                     ;another location has a specific value
  694              bne ColdBoot   
  695              ldy #WarmBootOffset          ;if passed both, load warm boot pointer
  696 ColdBoot:    jsr InitializeMemory         ;clear memory using pointer in Y
  697              sta SND_DELTA_REG+1          ;reset delta counter load register
  698              sta OperMode                 ;reset primary mode of operation
  699              lda #$a5                     ;set warm boot flag
  700              sta WarmBootValidation     
  701              sta PseudoRandomBitReg       ;set seed for pseudorandom register
  702              lda #%00001111
  703              sta SND_MASTERCTRL_REG       ;enable all sound channels except dmc
  704              lda #%00000110
  705              sta PPU_CTRL_REG2            ;turn off clipping for OAM and background
  706              jsr MoveAllSpritesOffscreen
  707              jsr InitializeNameTables     ;initialize both name tables
  708              inc DisableScreenFlag        ;set flag to disable screen output
  709              lda Mirror_PPU_CTRL_REG1
  710              ora #%10000000               ;enable NMIs
  711              jsr WritePPUReg1
  712 EndlessLoop: jmp EndlessLoop              ;endless loop, need I say more?
  713 
  714 ;-------------------------------------------------------------------------------------
  715 ;$00 - vram buffer address table low, also used for pseudorandom bit
  716 ;$01 - vram buffer address table high
  717 
  718 VRAM_AddrTable_Low:
  719       .db <VRAM_Buffer1, <WaterPaletteData, <GroundPaletteData
  720       .db <UndergroundPaletteData, <CastlePaletteData, <VRAM_Buffer1_Offset
  721       .db <VRAM_Buffer2, <VRAM_Buffer2, <BowserPaletteData
  722       .db <DaySnowPaletteData, <NightSnowPaletteData, <MushroomPaletteData
  723       .db <MarioThanksMessage, <LuigiThanksMessage, <MushroomRetainerSaved
  724       .db <PrincessSaved1, <PrincessSaved2, <WorldSelectMessage1
  725       .db <WorldSelectMessage2
  726 
  727 VRAM_AddrTable_High:
  728       .db >VRAM_Buffer1, >WaterPaletteData, >GroundPaletteData
  729       .db >UndergroundPaletteData, >CastlePaletteData, >VRAM_Buffer1_Offset
  730       .db >VRAM_Buffer2, >VRAM_Buffer2, >BowserPaletteData
  731       .db >DaySnowPaletteData, >NightSnowPaletteData, >MushroomPaletteData
  732       .db >MarioThanksMessage, >LuigiThanksMessage, >MushroomRetainerSaved
  733       .db >PrincessSaved1, >PrincessSaved2, >WorldSelectMessage1
  734       .db >WorldSelectMessage2
  735 
  736 VRAM_Buffer_Offset:
  737       .db <VRAM_Buffer1_Offset, <VRAM_Buffer2_Offset
  738 
  739 NonMaskableInterrupt:
  740                lda Mirror_PPU_CTRL_REG1  ;disable NMIs in mirror reg
  741                and #%01111111            ;save all other bits
  742                sta Mirror_PPU_CTRL_REG1
  743                and #%01111110            ;alter name table address to be $2800
  744                sta PPU_CTRL_REG1         ;(essentially $2000) but save other bits
  745                lda Mirror_PPU_CTRL_REG2  ;disable OAM and background display by default
  746                and #%11100110
  747                ldy DisableScreenFlag     ;get screen disable flag
  748                bne ScreenOff             ;if set, used bits as-is
  749                lda Mirror_PPU_CTRL_REG2  ;otherwise reenable bits and save them
  750                ora #%00011110
  751 ScreenOff:     sta Mirror_PPU_CTRL_REG2  ;save bits for later but not in register at the moment
  752                and #%11100111            ;disable screen for now
  753                sta PPU_CTRL_REG2
  754                ldx PPU_STATUS            ;reset flip-flop and reset scroll registers to zero
  755                lda #$00
  756                jsr InitScroll
  757                sta PPU_SPR_ADDR          ;reset spr-ram address register
  758                lda #$02                  ;perform spr-ram DMA access on $0200-$02ff
  759                sta SPR_DMA
  760                ldx VRAM_Buffer_AddrCtrl  ;load control for pointer to buffer contents
  761                lda VRAM_AddrTable_Low,x  ;set indirect at $00 to pointer
  762                sta $00
  763                lda VRAM_AddrTable_High,x
  764                sta $01
  765                jsr UpdateScreen          ;update screen with buffer contents
  766                ldy #$00
  767                ldx VRAM_Buffer_AddrCtrl  ;check for usage of $0341
  768                cpx #$06
  769                bne InitBuffer
  770                iny                       ;get offset based on usage
  771 InitBuffer:    ldx VRAM_Buffer_Offset,y
  772                lda #$00                  ;clear buffer header at last location
  773                sta VRAM_Buffer1_Offset,x        
  774                sta VRAM_Buffer1,x
  775                sta VRAM_Buffer_AddrCtrl  ;reinit address control to $0301
  776                lda Mirror_PPU_CTRL_REG2  ;copy mirror of $2001 to register
  777                sta PPU_CTRL_REG2
  778                jsr SoundEngine           ;play sound
  779                jsr ReadJoypads           ;read joypads
  780                jsr PauseRoutine          ;handle pause
  781                jsr UpdateTopScore
  782                lda GamePauseStatus       ;check for pause status
  783                lsr
  784                bcs PauseSkip
  785                lda TimerControl          ;if master timer control not set, decrement
  786                beq DecTimers             ;all frame and interval timers
  787                dec TimerControl
  788                bne NoDecTimers
  789 DecTimers:     ldx #$14                  ;load end offset for end of frame timers
  790                dec IntervalTimerControl  ;decrement interval timer control,
  791                bpl DecTimersLoop         ;if not expired, only frame timers will decrement
  792                lda #$14
  793                sta IntervalTimerControl  ;if control for interval timers expired,
  794                ldx #$23                  ;interval timers will decrement along with frame timers
  795 DecTimersLoop: lda Timers,x              ;check current timer
  796                beq SkipExpTimer          ;if current timer expired, branch to skip,
  797                dec Timers,x              ;otherwise decrement the current timer
  798 SkipExpTimer:  dex                       ;move onto next timer
  799                bpl DecTimersLoop         ;do this until all timers are dealt with
  800 NoDecTimers:   inc FrameCounter          ;increment frame counter
  801 PauseSkip:     ldx #$00
  802                ldy #$07
  803                lda PseudoRandomBitReg    ;get first memory location of LSFR bytes
  804                and #%00000010            ;mask out all but d1
  805                sta $00                   ;save here
  806                lda PseudoRandomBitReg+1  ;get second memory location
  807                and #%00000010            ;mask out all but d1
  808                eor $00                   ;perform exclusive-OR on d1 from first and second bytes
  809                clc                       ;if neither or both are set, carry will be clear
  810                beq RotPRandomBit
  811                sec                       ;if one or the other is set, carry will be set
  812 RotPRandomBit: ror PseudoRandomBitReg,x  ;rotate carry into d7, and rotate last bit into carry
  813                inx                       ;increment to next byte
  814                dey                       ;decrement for loop
  815                bne RotPRandomBit
  816                lda Sprite0HitDetectFlag  ;check for flag here
  817                beq SkipSprite0
  818 Sprite0Clr:    lda PPU_STATUS            ;wait for sprite 0 flag to clear, which will
  819                and #%01000000            ;not happen until vblank has ended
  820                bne Sprite0Clr
  821                lda GamePauseStatus       ;if in pause mode, do not bother with sprites at all
  822                lsr
  823                bcs Sprite0Hit
  824                jsr MoveSpritesOffscreen
  825                jsr SpriteShuffler
  826 Sprite0Hit:    lda PPU_STATUS            ;do sprite #0 hit detection
  827                and #%01000000
  828                beq Sprite0Hit
  829                ldy #$14                  ;small delay, to wait until we hit horizontal blank time
  830 HBlankDelay:   dey
  831                bne HBlankDelay
  832 SkipSprite0:   lda HorizontalScroll      ;set scroll registers from variables
  833                sta PPU_SCROLL_REG
  834                lda VerticalScroll
  835                sta PPU_SCROLL_REG
  836                lda Mirror_PPU_CTRL_REG1  ;load saved mirror of $2000
  837                pha
  838                sta PPU_CTRL_REG1
  839                lda GamePauseStatus       ;if in pause mode, do not perform operation mode stuff
  840                lsr
  841                bcs SkipMainOper
  842                jsr OperModeExecutionTree ;otherwise do one of many, many possible subroutines
  843 SkipMainOper:  lda PPU_STATUS            ;reset flip-flop
  844                pla
  845                ora #%10000000            ;reactivate NMIs
  846                sta PPU_CTRL_REG1
  847                rti                       ;we are done until the next frame!
  848 
  849 ;-------------------------------------------------------------------------------------
  850 
  851 PauseRoutine:
  852                lda OperMode           ;are we in victory mode?
  853                cmp #VictoryModeValue  ;if so, go ahead
  854                beq ChkPauseTimer
  855                cmp #GameModeValue     ;are we in game mode?
  856                bne ExitPause          ;if not, leave
  857                lda OperMode_Task      ;if we are in game mode, are we running game engine?
  858                cmp #$03
  859                bne ExitPause          ;if not, leave
  860 ChkPauseTimer: lda GamePauseTimer     ;check if pause timer is still counting down
  861                beq ChkStart
  862                dec GamePauseTimer     ;if so, decrement and leave
  863                rts
  864 ChkStart:      lda SavedJoypad1Bits   ;check to see if start is pressed
  865                and #Start_Button      ;on controller 1
  866                beq ClrPauseTimer
  867                lda GamePauseStatus    ;check to see if timer flag is set
  868                and #%10000000         ;and if so, do not reset timer (residual,
  869                bne ExitPause          ;joypad reading routine makes this unnecessary)
  870                lda #$2b               ;set pause timer
  871                sta GamePauseTimer
  872                lda GamePauseStatus
  873                tay
  874                iny                    ;set pause sfx queue for next pause mode
  875                sty PauseSoundQueue
  876                eor #%00000001         ;invert d0 and set d7
  877                ora #%10000000
  878                bne SetPause           ;unconditional branch
  879 ClrPauseTimer: lda GamePauseStatus    ;clear timer flag if timer is at zero and start button
  880                and #%01111111         ;is not pressed
  881 SetPause:      sta GamePauseStatus
  882 ExitPause:     rts
  883 
  884 ;-------------------------------------------------------------------------------------
  885 ;$00 - used for preset value
  886 
  887 SpriteShuffler:
  888                ldy AreaType                ;load level type, likely residual code
  889                lda #$28                    ;load preset value which will put it at
  890                sta $00                     ;sprite #10
  891                ldx #$0e                    ;start at the end of OAM data offsets
  892 ShuffleLoop:   lda SprDataOffset,x         ;check for offset value against
  893                cmp $00                     ;the preset value
  894                bcc NextSprOffset           ;if less, skip this part
  895                ldy SprShuffleAmtOffset     ;get current offset to preset value we want to add
  896                clc
  897                adc SprShuffleAmt,y         ;get shuffle amount, add to current sprite offset
  898                bcc StrSprOffset            ;if not exceeded $ff, skip second add
  899                clc
  900                adc $00                     ;otherwise add preset value $28 to offset
  901 StrSprOffset:  sta SprDataOffset,x         ;store new offset here or old one if branched to here
  902 NextSprOffset: dex                         ;move backwards to next one
  903                bpl ShuffleLoop
  904                ldx SprShuffleAmtOffset     ;load offset
  905                inx
  906                cpx #$03                    ;check if offset + 1 goes to 3
  907                bne SetAmtOffset            ;if offset + 1 not 3, store
  908                ldx #$00                    ;otherwise, init to 0
  909 SetAmtOffset:  stx SprShuffleAmtOffset
  910                ldx #$08                    ;load offsets for values and storage
  911                ldy #$02
  912 SetMiscOffset: lda SprDataOffset+5,y       ;load one of three OAM data offsets
  913                sta Misc_SprDataOffset-2,x  ;store first one unmodified, but
  914                clc                         ;add eight to the second and eight
  915                adc #$08                    ;more to the third one
  916                sta Misc_SprDataOffset-1,x  ;note that due to the way X is set up,
  917                clc                         ;this code loads into the misc sprite offsets
  918                adc #$08
  919                sta Misc_SprDataOffset,x        
  920                dex
  921                dex
  922                dex
  923                dey
  924                bpl SetMiscOffset           ;do this until all misc spr offsets are loaded
  925                rts
  926 
  927 ;-------------------------------------------------------------------------------------
  928 
  929 OperModeExecutionTree:
  930       lda OperMode     ;this is the heart of the entire program,
  931       jsr JumpEngine   ;most of what goes on starts here
  932 
  933       .dw TitleScreenMode
  934       .dw GameMode
  935       .dw VictoryMode
  936       .dw GameOverMode
  937 
  938 ;-------------------------------------------------------------------------------------
  939 
  940 MoveAllSpritesOffscreen:
  941               ldy #$00                ;this routine moves all sprites off the screen
  942               .db $2c                 ;BIT instruction opcode
  943 
  944 MoveSpritesOffscreen:
  945               ldy #$04                ;this routine moves all but sprite 0
  946               lda #$f8                ;off the screen
  947 SprInitLoop:  sta Sprite_Y_Position,y ;write 248 into OAM data's Y coordinate
  948               iny                     ;which will move it off the screen
  949               iny
  950               iny
  951               iny
  952               bne SprInitLoop
  953               rts
  954 
  955 ;-------------------------------------------------------------------------------------
  956 
  957 TitleScreenMode:
  958       lda OperMode_Task
  959       jsr JumpEngine
  960 
  961       .dw InitializeGame
  962       .dw ScreenRoutines
  963       .dw PrimaryGameSetup
  964       .dw GameMenuRoutine
  965 
  966 ;-------------------------------------------------------------------------------------
  967 
  968 WSelectBufferTemplate:
  969       .db $04, $20, $73, $01, $00, $00
  970 
  971 GameMenuRoutine:
  972               ldy #$00
  973               lda SavedJoypad1Bits        ;check to see if either player pressed
  974               ora SavedJoypad2Bits        ;only the start button (either joypad)
  975               cmp #Start_Button
  976               beq StartGame
  977               cmp #A_Button+Start_Button  ;check to see if A + start was pressed
  978               bne ChkSelect               ;if not, branch to check select button
  979 StartGame:    jmp ChkContinue             ;if either start or A + start, execute here
  980 ChkSelect:    cmp #Select_Button          ;check to see if the select button was pressed
  981               beq SelectBLogic            ;if so, branch reset demo timer
  982               ldx DemoTimer               ;otherwise check demo timer
  983               bne ChkWorldSel             ;if demo timer not expired, branch to check world selection
  984               sta SelectTimer             ;set controller bits here if running demo
  985               jsr DemoEngine              ;run through the demo actions
  986               bcs ResetTitle              ;if carry flag set, demo over, thus branch
  987               jmp RunDemo                 ;otherwise, run game engine for demo
  988 ChkWorldSel:  ldx WorldSelectEnableFlag   ;check to see if world selection has been enabled
  989               beq NullJoypad
  990               cmp #B_Button               ;if so, check to see if the B button was pressed
  991               bne NullJoypad
  992               iny                         ;if so, increment Y and execute same code as select
  993 SelectBLogic: lda DemoTimer               ;if select or B pressed, check demo timer one last time
  994               beq ResetTitle              ;if demo timer expired, branch to reset title screen mode
  995               lda #$18                    ;otherwise reset demo timer
  996               sta DemoTimer
  997               lda SelectTimer             ;check select/B button timer
  998               bne NullJoypad              ;if not expired, branch
  999               lda #$10                    ;otherwise reset select button timer
 1000               sta SelectTimer
 1001               cpy #$01                    ;was the B button pressed earlier?  if so, branch
 1002               beq IncWorldSel             ;note this will not be run if world selection is disabled
 1003               lda NumberOfPlayers         ;if no, must have been the select button, therefore
 1004               eor #%00000001              ;change number of players and draw icon accordingly
 1005               sta NumberOfPlayers
 1006               jsr DrawMushroomIcon
 1007               jmp NullJoypad
 1008 IncWorldSel:  ldx WorldSelectNumber       ;increment world select number
 1009               inx
 1010               txa
 1011               and #%00000111              ;mask out higher bits
 1012               sta WorldSelectNumber       ;store as current world select number
 1013               jsr GoContinue
 1014 UpdateShroom: lda WSelectBufferTemplate,x ;write template for world select in vram buffer
 1015               sta VRAM_Buffer1-1,x        ;do this until all bytes are written
 1016               inx
 1017               cpx #$06
 1018               bmi UpdateShroom
 1019               ldy WorldNumber             ;get world number from variable and increment for
 1020               iny                         ;proper display, and put in blank byte before
 1021               sty VRAM_Buffer1+3          ;null terminator
 1022 NullJoypad:   lda #$00                    ;clear joypad bits for player 1
 1023               sta SavedJoypad1Bits
 1024 RunDemo:      jsr GameCoreRoutine         ;run game engine
 1025               lda GameEngineSubroutine    ;check to see if we're running lose life routine
 1026               cmp #$06
 1027               bne ExitMenu                ;if not, do not do all the resetting below
 1028 ResetTitle:   lda #$00                    ;reset game modes, disable
 1029               sta OperMode                ;sprite 0 check and disable
 1030               sta OperMode_Task           ;screen output
 1031               sta Sprite0HitDetectFlag
 1032               inc DisableScreenFlag
 1033               rts
 1034 ChkContinue:  ldy DemoTimer               ;if timer for demo has expired, reset modes
 1035               beq ResetTitle
 1036               asl                         ;check to see if A button was also pushed
 1037               bcc StartWorld1             ;if not, don't load continue function's world number
 1038               lda ContinueWorld           ;load previously saved world number for secret
 1039               jsr GoContinue              ;continue function when pressing A + start
 1040 StartWorld1:  jsr LoadAreaPointer
 1041               inc Hidden1UpFlag           ;set 1-up box flag for both players
 1042               inc OffScr_Hidden1UpFlag
 1043               inc FetchNewGameTimerFlag   ;set fetch new game timer flag
 1044               inc OperMode                ;set next game mode
 1045               lda WorldSelectEnableFlag   ;if world select flag is on, then primary
 1046               sta PrimaryHardMode         ;hard mode must be on as well
 1047               lda #$00
 1048               sta OperMode_Task           ;set game mode here, and clear demo timer
 1049               sta DemoTimer
 1050               ldx #$17
 1051               lda #$00
 1052 InitScores:   sta ScoreAndCoinDisplay,x   ;clear player scores and coin displays
 1053               dex
 1054               bpl InitScores
 1055 ExitMenu:     rts
 1056 GoContinue:   sta WorldNumber             ;start both players at the first area
 1057               sta OffScr_WorldNumber      ;of the previously saved world number
 1058               ldx #$00                    ;note that on power-up using this function
 1059               stx AreaNumber              ;will make no difference
 1060               stx OffScr_AreaNumber   
 1061               rts
 1062 
 1063 ;-------------------------------------------------------------------------------------
 1064 
 1065 MushroomIconData:
 1066       .db $07, $22, $49, $83, $ce, $24, $24, $00
 1067 
 1068 DrawMushroomIcon:
 1069               ldy #$07                ;read eight bytes to be read by transfer routine
 1070 IconDataRead: lda MushroomIconData,y  ;note that the default position is set for a
 1071               sta VRAM_Buffer1-1,y    ;1-player game
 1072               dey
 1073               bpl IconDataRead
 1074               lda NumberOfPlayers     ;check number of players
 1075               beq ExitIcon            ;if set to 1-player game, we're done
 1076               lda #$24                ;otherwise, load blank tile in 1-player position
 1077               sta VRAM_Buffer1+3
 1078               lda #$ce                ;then load shroom icon tile in 2-player position
 1079               sta VRAM_Buffer1+5
 1080 ExitIcon:     rts
 1081 
 1082 ;-------------------------------------------------------------------------------------
 1083 
 1084 DemoActionData:
 1085       .db $01, $80, $02, $81, $41, $80, $01
 1086       .db $42, $c2, $02, $80, $41, $c1, $41, $c1
 1087       .db $01, $c1, $01, $02, $80, $00
 1088 
 1089 DemoTimingData:
 1090       .db $9b, $10, $18, $05, $2c, $20, $24
 1091       .db $15, $5a, $10, $20, $28, $30, $20, $10
 1092       .db $80, $20, $30, $30, $01, $ff, $00
 1093 
 1094 DemoEngine:
 1095           ldx DemoAction         ;load current demo action
 1096           lda DemoActionTimer    ;load current action timer
 1097           bne DoAction           ;if timer still counting down, skip
 1098           inx
 1099           inc DemoAction         ;if expired, increment action, X, and
 1100           sec                    ;set carry by default for demo over
 1101           lda DemoTimingData-1,x ;get next timer
 1102           sta DemoActionTimer    ;store as current timer
 1103           beq DemoOver           ;if timer already at zero, skip
 1104 DoAction: lda DemoActionData-1,x ;get and perform action (current or next)
 1105           sta SavedJoypad1Bits
 1106           dec DemoActionTimer    ;decrement action timer
 1107           clc                    ;clear carry if demo still going
 1108 DemoOver: rts
 1109 
 1110 ;-------------------------------------------------------------------------------------
 1111 
 1112 VictoryMode:
 1113             jsr VictoryModeSubroutines  ;run victory mode subroutines
 1114             lda OperMode_Task           ;get current task of victory mode
 1115             beq AutoPlayer              ;if on bridge collapse, skip enemy processing
 1116             ldx #$00
 1117             stx ObjectOffset            ;otherwise reset enemy object offset 
 1118             jsr EnemiesAndLoopsCore     ;and run enemy code
 1119 AutoPlayer: jsr RelativePlayerPosition  ;get player's relative coordinates
 1120             jmp PlayerGfxHandler        ;draw the player, then leave
 1121 
 1122 VictoryModeSubroutines:
 1123       lda OperMode_Task
 1124       jsr JumpEngine
 1125 
 1126       .dw BridgeCollapse
 1127       .dw SetupVictoryMode
 1128       .dw PlayerVictoryWalk
 1129       .dw PrintVictoryMessages
 1130       .dw PlayerEndWorld
 1131 
 1132 ;-------------------------------------------------------------------------------------
 1133 
 1134 SetupVictoryMode:
 1135       ldx ScreenRight_PageLoc  ;get page location of right side of screen
 1136       inx                      ;increment to next page
 1137       stx DestinationPageLoc   ;store here
 1138       lda #EndOfCastleMusic
 1139       sta EventMusicQueue      ;play win castle music
 1140       jmp IncModeTask_B        ;jump to set next major task in victory mode
 1141 
 1142 ;-------------------------------------------------------------------------------------
 1143 
 1144 PlayerVictoryWalk:
 1145              ldy #$00                ;set value here to not walk player by default
 1146              sty VictoryWalkControl
 1147              lda Player_PageLoc      ;get player's page location
 1148              cmp DestinationPageLoc  ;compare with destination page location
 1149              bne PerformWalk         ;if page locations don't match, branch
 1150              lda Player_X_Position   ;otherwise get player's horizontal position
 1151              cmp #$60                ;compare with preset horizontal position
 1152              bcs DontWalk            ;if still on other page, branch ahead
 1153 PerformWalk: inc VictoryWalkControl  ;otherwise increment value and Y
 1154              iny                     ;note Y will be used to walk the player
 1155 DontWalk:    tya                     ;put contents of Y in A and
 1156              jsr AutoControlPlayer   ;use A to move player to the right or not
 1157              lda ScreenLeft_PageLoc  ;check page location of left side of screen
 1158              cmp DestinationPageLoc  ;against set value here
 1159              beq ExitVWalk           ;branch if equal to change modes if necessary
 1160              lda ScrollFractional
 1161              clc                     ;do fixed point math on fractional part of scroll
 1162              adc #$80        
 1163              sta ScrollFractional    ;save fractional movement amount
 1164              lda #$01                ;set 1 pixel per frame
 1165              adc #$00                ;add carry from previous addition
 1166              tay                     ;use as scroll amount
 1167              jsr ScrollScreen        ;do sub to scroll the screen
 1168              jsr UpdScrollVar        ;do another sub to update screen and scroll variables
 1169              inc VictoryWalkControl  ;increment value to stay in this routine
 1170 ExitVWalk:   lda VictoryWalkControl  ;load value set here
 1171              beq IncModeTask_A       ;if zero, branch to change modes
 1172              rts                     ;otherwise leave
 1173 
 1174 ;-------------------------------------------------------------------------------------
 1175 
 1176 PrintVictoryMessages:
 1177                lda SecondaryMsgCounter   ;load secondary message counter
 1178                bne IncMsgCounter         ;if set, branch to increment message counters
 1179                lda PrimaryMsgCounter     ;otherwise load primary message counter
 1180                beq ThankPlayer           ;if set to zero, branch to print first message
 1181                cmp #$09                  ;if at 9 or above, branch elsewhere (this comparison
 1182                bcs IncMsgCounter         ;is residual code, counter never reaches 9)
 1183                ldy WorldNumber           ;check world number
 1184                cpy #World8
 1185                bne MRetainerMsg          ;if not at world 8, skip to next part
 1186                cmp #$03                  ;check primary message counter again
 1187                bcc IncMsgCounter         ;if not at 3 yet (world 8 only), branch to increment
 1188                sbc #$01                  ;otherwise subtract one
 1189                jmp ThankPlayer           ;and skip to next part
 1190 MRetainerMsg:  cmp #$02                  ;check primary message counter
 1191                bcc IncMsgCounter         ;if not at 2 yet (world 1-7 only), branch
 1192 ThankPlayer:   tay                       ;put primary message counter into Y
 1193                bne SecondPartMsg         ;if counter nonzero, skip this part, do not print first message
 1194                lda CurrentPlayer         ;otherwise get player currently on the screen
 1195                beq EvalForMusic          ;if mario, branch
 1196                iny                       ;otherwise increment Y once for luigi and
 1197                bne EvalForMusic          ;do an unconditional branch to the same place
 1198 SecondPartMsg: iny                       ;increment Y to do world 8's message
 1199                lda WorldNumber
 1200                cmp #World8               ;check world number
 1201                beq EvalForMusic          ;if at world 8, branch to next part
 1202                dey                       ;otherwise decrement Y for world 1-7's message
 1203                cpy #$04                  ;if counter at 4 (world 1-7 only)
 1204                bcs SetEndTimer           ;branch to set victory end timer
 1205                cpy #$03                  ;if counter at 3 (world 1-7 only)
 1206                bcs IncMsgCounter         ;branch to keep counting
 1207 EvalForMusic:  cpy #$03                  ;if counter not yet at 3 (world 8 only), branch
 1208                bne PrintMsg              ;to print message only (note world 1-7 will only
 1209                lda #VictoryMusic         ;reach this code if counter = 0, and will always branch)
 1210                sta EventMusicQueue       ;otherwise load victory music first (world 8 only)
 1211 PrintMsg:      tya                       ;put primary message counter in A
 1212                clc                       ;add $0c or 12 to counter thus giving an appropriate value,
 1213                adc #$0c                  ;($0c-$0d = first), ($0e = world 1-7's), ($0f-$12 = world 8's)
 1214                sta VRAM_Buffer_AddrCtrl  ;write message counter to vram address controller
 1215 IncMsgCounter: lda SecondaryMsgCounter
 1216                clc
 1217                adc #$04                      ;add four to secondary message counter
 1218                sta SecondaryMsgCounter
 1219                lda PrimaryMsgCounter
 1220                adc #$00                      ;add carry to primary message counter
 1221                sta PrimaryMsgCounter
 1222                cmp #$07                      ;check primary counter one more time
 1223 SetEndTimer:   bcc ExitMsgs                  ;if not reached value yet, branch to leave
 1224                lda #$06
 1225                sta WorldEndTimer             ;otherwise set world end timer
 1226 IncModeTask_A: inc OperMode_Task             ;move onto next task in mode
 1227 ExitMsgs:      rts                           ;leave
 1228 
 1229 ;-------------------------------------------------------------------------------------
 1230 
 1231 PlayerEndWorld:
 1232                lda WorldEndTimer          ;check to see if world end timer expired
 1233                bne EndExitOne             ;branch to leave if not
 1234                ldy WorldNumber            ;check world number
 1235                cpy #World8                ;if on world 8, player is done with game, 
 1236                bcs EndChkBButton          ;thus branch to read controller
 1237                lda #$00
 1238                sta AreaNumber             ;otherwise initialize area number used as offset
 1239                sta LevelNumber            ;and level number control to start at area 1
 1240                sta OperMode_Task          ;initialize secondary mode of operation
 1241                inc WorldNumber            ;increment world number to move onto the next world
 1242                jsr LoadAreaPointer        ;get area address offset for the next area
 1243                inc FetchNewGameTimerFlag  ;set flag to load game timer from header
 1244                lda #GameModeValue
 1245                sta OperMode               ;set mode of operation to game mode
 1246 EndExitOne:    rts                        ;and leave
 1247 EndChkBButton: lda SavedJoypad1Bits
 1248                ora SavedJoypad2Bits       ;check to see if B button was pressed on
 1249                and #B_Button              ;either controller
 1250                beq EndExitTwo             ;branch to leave if not
 1251                lda #$01                   ;otherwise set world selection flag
 1252                sta WorldSelectEnableFlag
 1253                lda #$ff                   ;remove onscreen player's lives
 1254                sta NumberofLives
 1255                jsr TerminateGame          ;do sub to continue other player or end game
 1256 EndExitTwo:    rts                        ;leave
 1257 
 1258 ;-------------------------------------------------------------------------------------
 1259 
 1260 ;data is used as tiles for numbers
 1261 ;that appear when you defeat enemies
 1262 FloateyNumTileData:
 1263       .db $ff, $ff ;dummy
 1264       .db $f6, $fb ; "100"
 1265       .db $f7, $fb ; "200"
 1266       .db $f8, $fb ; "400"
 1267       .db $f9, $fb ; "500"
 1268       .db $fa, $fb ; "800"
 1269       .db $f6, $50 ; "1000"
 1270       .db $f7, $50 ; "2000"
 1271       .db $f8, $50 ; "4000"
 1272       .db $f9, $50 ; "5000"
 1273       .db $fa, $50 ; "8000"
 1274       .db $fd, $fe ; "1-UP"
 1275 
 1276 ;high nybble is digit number, low nybble is number to
 1277 ;add to the digit of the player's score
 1278 ScoreUpdateData:
 1279       .db $ff ;dummy
 1280       .db $41, $42, $44, $45, $48
 1281       .db $31, $32, $34, $35, $38, $00
 1282 
 1283 FloateyNumbersRoutine:
 1284               lda FloateyNum_Control,x     ;load control for floatey number
 1285               beq EndExitOne               ;if zero, branch to leave
 1286               cmp #$0b                     ;if less than $0b, branch
 1287               bcc ChkNumTimer
 1288               lda #$0b                     ;otherwise set to $0b, thus keeping
 1289               sta FloateyNum_Control,x     ;it in range
 1290 ChkNumTimer:  tay                          ;use as Y
 1291               lda FloateyNum_Timer,x       ;check value here
 1292               bne DecNumTimer              ;if nonzero, branch ahead
 1293               sta FloateyNum_Control,x     ;initialize floatey number control and leave
 1294               rts
 1295 DecNumTimer:  dec FloateyNum_Timer,x       ;decrement value here
 1296               cmp #$2b                     ;if not reached a certain point, branch  
 1297               bne ChkTallEnemy
 1298               cpy #$0b                     ;check offset for $0b
 1299               bne LoadNumTiles             ;branch ahead if not found
 1300               inc NumberofLives            ;give player one extra life (1-up)
 1301               lda #Sfx_ExtraLife
 1302               sta Square2SoundQueue        ;and play the 1-up sound
 1303 LoadNumTiles: lda ScoreUpdateData,y        ;load point value here
 1304               lsr                          ;move high nybble to low
 1305               lsr
 1306               lsr
 1307               lsr
 1308               tax                          ;use as X offset, essentially the digit
 1309               lda ScoreUpdateData,y        ;load again and this time
 1310               and #%00001111               ;mask out the high nybble
 1311               sta DigitModifier,x          ;store as amount to add to the digit
 1312               jsr AddToScore               ;update the score accordingly
 1313 ChkTallEnemy: ldy Enemy_SprDataOffset,x    ;get OAM data offset for enemy object
 1314               lda Enemy_ID,x               ;get enemy object identifier
 1315               cmp #Spiny
 1316               beq FloateyPart              ;branch if spiny
 1317               cmp #PiranhaPlant
 1318               beq FloateyPart              ;branch if piranha plant
 1319               cmp #HammerBro
 1320               beq GetAltOffset             ;branch elsewhere if hammer bro
 1321               cmp #GreyCheepCheep
 1322               beq FloateyPart              ;branch if cheep-cheep of either color
 1323               cmp #RedCheepCheep
 1324               beq FloateyPart
 1325               cmp #TallEnemy
 1326               bcs GetAltOffset             ;branch elsewhere if enemy object => $09
 1327               lda Enemy_State,x
 1328               cmp #$02                     ;if enemy state defeated or otherwise
 1329               bcs FloateyPart              ;$02 or greater, branch beyond this part
 1330 GetAltOffset: ldx SprDataOffset_Ctrl       ;load some kind of control bit
 1331               ldy Alt_SprDataOffset,x      ;get alternate OAM data offset
 1332               ldx ObjectOffset             ;get enemy object offset again
 1333 FloateyPart:  lda FloateyNum_Y_Pos,x       ;get vertical coordinate for
 1334               cmp #$18                     ;floatey number, if coordinate in the
 1335               bcc SetupNumSpr              ;status bar, branch
 1336               sbc #$01
 1337               sta FloateyNum_Y_Pos,x       ;otherwise subtract one and store as new
 1338 SetupNumSpr:  lda FloateyNum_Y_Pos,x       ;get vertical coordinate
 1339               sbc #$08                     ;subtract eight and dump into the
 1340               jsr DumpTwoSpr               ;left and right sprite's Y coordinates
 1341               lda FloateyNum_X_Pos,x       ;get horizontal coordinate
 1342               sta Sprite_X_Position,y      ;store into X coordinate of left sprite
 1343               clc
 1344               adc #$08                     ;add eight pixels and store into X
 1345               sta Sprite_X_Position+4,y    ;coordinate of right sprite
 1346               lda #$02
 1347               sta Sprite_Attributes,y      ;set palette control in attribute bytes
 1348               sta Sprite_Attributes+4,y    ;of left and right sprites
 1349               lda FloateyNum_Control,x
 1350               asl                          ;multiply our floatey number control by 2
 1351               tax                          ;and use as offset for look-up table
 1352               lda FloateyNumTileData,x
 1353               sta Sprite_Tilenumber,y      ;display first half of number of points
 1354               lda FloateyNumTileData+1,x
 1355               sta Sprite_Tilenumber+4,y    ;display the second half
 1356               ldx ObjectOffset             ;get enemy object offset and leave
 1357               rts
 1358 
 1359 ;-------------------------------------------------------------------------------------
 1360 
 1361 ScreenRoutines:
 1362       lda ScreenRoutineTask        ;run one of the following subroutines
 1363       jsr JumpEngine
 1364     
 1365       .dw InitScreen
 1366       .dw SetupIntermediate
 1367       .dw WriteTopStatusLine
 1368       .dw WriteBottomStatusLine
 1369       .dw DisplayTimeUp
 1370       .dw ResetSpritesAndScreenTimer
 1371       .dw DisplayIntermediate
 1372       .dw ResetSpritesAndScreenTimer
 1373       .dw AreaParserTaskControl
 1374       .dw GetAreaPalette
 1375       .dw GetBackgroundColor
 1376       .dw GetAlternatePalette1
 1377       .dw DrawTitleScreen
 1378       .dw ClearBuffersDrawIcon
 1379       .dw WriteTopScore
 1380 
 1381 ;-------------------------------------------------------------------------------------
 1382 
 1383 InitScreen:
 1384       jsr MoveAllSpritesOffscreen ;initialize all sprites including sprite #0
 1385       jsr InitializeNameTables    ;and erase both name and attribute tables
 1386       lda OperMode
 1387       beq NextSubtask             ;if mode still 0, do not load
 1388       ldx #$03                    ;into buffer pointer
 1389       jmp SetVRAMAddr_A
 1390 
 1391 ;-------------------------------------------------------------------------------------
 1392 
 1393 SetupIntermediate:
 1394       lda BackgroundColorCtrl  ;save current background color control
 1395       pha                      ;and player status to stack
 1396       lda PlayerStatus
 1397       pha
 1398       lda #$00                 ;set background color to black
 1399       sta PlayerStatus         ;and player status to not fiery
 1400       lda #$02                 ;this is the ONLY time background color control
 1401       sta BackgroundColorCtrl  ;is set to less than 4
 1402       jsr GetPlayerColors
 1403       pla                      ;we only execute this routine for
 1404       sta PlayerStatus         ;the intermediate lives display
 1405       pla                      ;and once we're done, we return bg
 1406       sta BackgroundColorCtrl  ;color ctrl and player status from stack
 1407       jmp IncSubtask           ;then move onto the next task
 1408 
 1409 ;-------------------------------------------------------------------------------------
 1410 
 1411 AreaPalette:
 1412       .db $01, $02, $03, $04
 1413 
 1414 GetAreaPalette:
 1415                ldy AreaType             ;select appropriate palette to load
 1416                ldx AreaPalette,y        ;based on area type
 1417 SetVRAMAddr_A: stx VRAM_Buffer_AddrCtrl ;store offset into buffer control
 1418 NextSubtask:   jmp IncSubtask           ;move onto next task
 1419 
 1420 ;-------------------------------------------------------------------------------------
 1421 ;$00 - used as temp counter in GetPlayerColors
 1422 
 1423 BGColorCtrl_Addr:
 1424       .db $00, $09, $0a, $04
 1425 
 1426 BackgroundColors:
 1427       .db $22, $22, $0f, $0f ;used by area type if bg color ctrl not set
 1428       .db $0f, $22, $0f, $0f ;used by background color control if set
 1429 
 1430 PlayerColors:
 1431       .db $22, $16, $27, $18 ;mario's colors
 1432       .db $22, $30, $27, $19 ;luigi's colors
 1433       .db $22, $37, $27, $16 ;fiery (used by both)
 1434 
 1435 GetBackgroundColor:
 1436            ldy BackgroundColorCtrl   ;check background color control
 1437            beq NoBGColor             ;if not set, increment task and fetch palette
 1438            lda BGColorCtrl_Addr-4,y  ;put appropriate palette into vram
 1439            sta VRAM_Buffer_AddrCtrl  ;note that if set to 5-7, $0301 will not be read
 1440 NoBGColor: inc ScreenRoutineTask     ;increment to next subtask and plod on through
 1441       
 1442 GetPlayerColors:
 1443                ldx VRAM_Buffer1_Offset  ;get current buffer offset
 1444                ldy #$00
 1445                lda CurrentPlayer        ;check which player is on the screen
 1446                beq ChkFiery
 1447                ldy #$04                 ;load offset for luigi
 1448 ChkFiery:      lda PlayerStatus         ;check player status
 1449                cmp #$02
 1450                bne StartClrGet          ;if fiery, load alternate offset for fiery player
 1451                ldy #$08
 1452 StartClrGet:   lda #$03                 ;do four colors
 1453                sta $00
 1454 ClrGetLoop:    lda PlayerColors,y       ;fetch player colors and store them
 1455                sta VRAM_Buffer1+3,x     ;in the buffer
 1456                iny
 1457                inx
 1458                dec $00
 1459                bpl ClrGetLoop
 1460                ldx VRAM_Buffer1_Offset  ;load original offset from before
 1461                ldy BackgroundColorCtrl  ;if this value is four or greater, it will be set
 1462                bne SetBGColor           ;therefore use it as offset to background color
 1463                ldy AreaType             ;otherwise use area type bits from area offset as offset
 1464 SetBGColor:    lda BackgroundColors,y   ;to background color instead
 1465                sta VRAM_Buffer1+3,x
 1466                lda #$3f                 ;set for sprite palette address
 1467                sta VRAM_Buffer1,x       ;save to buffer
 1468                lda #$10
 1469                sta VRAM_Buffer1+1,x
 1470                lda #$04                 ;write length byte to buffer
 1471                sta VRAM_Buffer1+2,x
 1472                lda #$00                 ;now the null terminator
 1473                sta VRAM_Buffer1+7,x
 1474                txa                      ;move the buffer pointer ahead 7 bytes
 1475                clc                      ;in case we want to write anything else later
 1476                adc #$07
 1477 SetVRAMOffset: sta VRAM_Buffer1_Offset  ;store as new vram buffer offset
 1478                rts
 1479 
 1480 ;-------------------------------------------------------------------------------------
 1481 
 1482 GetAlternatePalette1:
 1483                lda AreaStyle            ;check for mushroom level style
 1484                cmp #$01
 1485                bne NoAltPal
 1486                lda #$0b                 ;if found, load appropriate palette
 1487 SetVRAMAddr_B: sta VRAM_Buffer_AddrCtrl
 1488 NoAltPal:      jmp IncSubtask           ;now onto the next task
 1489 
 1490 ;-------------------------------------------------------------------------------------
 1491 
 1492 WriteTopStatusLine:
 1493       lda #$00          ;select main status bar
 1494       jsr WriteGameText ;output it
 1495       jmp IncSubtask    ;onto the next task
 1496 
 1497 ;-------------------------------------------------------------------------------------
 1498 
 1499 WriteBottomStatusLine:
 1500       jsr GetSBNybbles        ;write player's score and coin tally to screen
 1501       ldx VRAM_Buffer1_Offset
 1502       lda #$20                ;write address for world-area number on screen
 1503       sta VRAM_Buffer1,x
 1504       lda #$73
 1505       sta VRAM_Buffer1+1,x
 1506       lda #$03                ;write length for it
 1507       sta VRAM_Buffer1+2,x
 1508       ldy WorldNumber         ;first the world number
 1509       iny
 1510       tya
 1511       sta VRAM_Buffer1+3,x
 1512       lda #$28                ;next the dash
 1513       sta VRAM_Buffer1+4,x
 1514       ldy LevelNumber         ;next the level number
 1515       iny                     ;increment for proper number display
 1516       tya
 1517       sta VRAM_Buffer1+5,x    
 1518       lda #$00                ;put null terminator on
 1519       sta VRAM_Buffer1+6,x
 1520       txa                     ;move the buffer offset up by 6 bytes
 1521       clc
 1522       adc #$06
 1523       sta VRAM_Buffer1_Offset
 1524       jmp IncSubtask
 1525 
 1526 ;-------------------------------------------------------------------------------------
 1527 
 1528 DisplayTimeUp:
 1529           lda GameTimerExpiredFlag  ;if game timer not expired, increment task
 1530           beq NoTimeUp              ;control 2 tasks forward, otherwise, stay here
 1531           lda #$00
 1532           sta GameTimerExpiredFlag  ;reset timer expiration flag
 1533           lda #$02                  ;output time-up screen to buffer
 1534           jmp OutputInter
 1535 NoTimeUp: inc ScreenRoutineTask     ;increment control task 2 tasks forward
 1536           jmp IncSubtask
 1537 
 1538 ;-------------------------------------------------------------------------------------
 1539 
 1540 DisplayIntermediate:
 1541                lda OperMode                 ;check primary mode of operation
 1542                beq NoInter                  ;if in title screen mode, skip this
 1543                cmp #GameOverModeValue       ;are we in game over mode?
 1544                beq GameOverInter            ;if so, proceed to display game over screen
 1545                lda AltEntranceControl       ;otherwise check for mode of alternate entry
 1546                bne NoInter                  ;and branch if found
 1547                ldy AreaType                 ;check if we are on castle level
 1548                cpy #$03                     ;and if so, branch (possibly residual)
 1549                beq PlayerInter
 1550                lda DisableIntermediate      ;if this flag is set, skip intermediate lives display
 1551                bne NoInter                  ;and jump to specific task, otherwise
 1552 PlayerInter:   jsr DrawPlayer_Intermediate  ;put player in appropriate place for
 1553                lda #$01                     ;lives display, then output lives display to buffer
 1554 OutputInter:   jsr WriteGameText
 1555                jsr ResetScreenTimer
 1556                lda #$00
 1557                sta DisableScreenFlag        ;reenable screen output
 1558                rts
 1559 GameOverInter: lda #$12                     ;set screen timer
 1560                sta ScreenTimer
 1561                lda #$03                     ;output game over screen to buffer
 1562                jsr WriteGameText
 1563                jmp IncModeTask_B
 1564 NoInter:       lda #$08                     ;set for specific task and leave
 1565                sta ScreenRoutineTask
 1566                rts
 1567 
 1568 ;-------------------------------------------------------------------------------------
 1569 
 1570 AreaParserTaskControl:
 1571            inc DisableScreenFlag     ;turn off screen
 1572 TaskLoop:  jsr AreaParserTaskHandler ;render column set of current area
 1573            lda AreaParserTaskNum     ;check number of tasks
 1574            bne TaskLoop              ;if tasks still not all done, do another one
 1575            dec ColumnSets            ;do we need to render more column sets?
 1576            bpl OutputCol
 1577            inc ScreenRoutineTask     ;if not, move on to the next task
 1578 OutputCol: lda #$06                  ;set vram buffer to output rendered column set
 1579            sta VRAM_Buffer_AddrCtrl  ;on next NMI
 1580            rts
 1581 
 1582 ;-------------------------------------------------------------------------------------
 1583 
 1584 ;$00 - vram buffer address table low
 1585 ;$01 - vram buffer address table high
 1586 
 1587 DrawTitleScreen:
 1588             lda OperMode                 ;are we in title screen mode?
 1589             bne IncModeTask_B            ;if not, exit
 1590             lda #>TitleScreenDataOffset  ;load address $1ec0 into
 1591             sta PPU_ADDRESS              ;the vram address register
 1592             lda #<TitleScreenDataOffset
 1593             sta PPU_ADDRESS
 1594             lda #$03                     ;put address $0300 into
 1595             sta $01                      ;the indirect at $00
 1596             ldy #$00
 1597             sty $00
 1598             lda PPU_DATA                 ;do one garbage read
 1599 OutputTScr: lda PPU_DATA                 ;get title screen from chr-rom
 1600             sta ($00),y                  ;store 256 bytes into buffer
 1601             iny
 1602             bne ChkHiByte                ;if not past 256 bytes, do not increment
 1603             inc $01                      ;otherwise increment high byte of indirect
 1604 ChkHiByte:  lda $01                      ;check high byte?
 1605             cmp #$04                     ;at $0400?
 1606             bne OutputTScr               ;if not, loop back and do another
 1607             cpy #$3a                     ;check if offset points past end of data
 1608             bcc OutputTScr               ;if not, loop back and do another
 1609             lda #$05                     ;set buffer transfer control to $0300,
 1610             jmp SetVRAMAddr_B            ;increment task and exit
 1611 
 1612 ;-------------------------------------------------------------------------------------
 1613 
 1614 ClearBuffersDrawIcon:
 1615              lda OperMode               ;check game mode
 1616              bne IncModeTask_B          ;if not title screen mode, leave
 1617              ldx #$00                   ;otherwise, clear buffer space
 1618 TScrClear:   sta VRAM_Buffer1-1,x
 1619              sta VRAM_Buffer1-1+$100,x
 1620              dex
 1621              bne TScrClear
 1622              jsr DrawMushroomIcon       ;draw player select icon
 1623 IncSubtask:  inc ScreenRoutineTask      ;move onto next task
 1624              rts
 1625 
 1626 ;-------------------------------------------------------------------------------------
 1627 
 1628 WriteTopScore:
 1629                lda #$fa           ;run display routine to display top score on title
 1630                jsr UpdateNumber
 1631 IncModeTask_B: inc OperMode_Task  ;move onto next mode
 1632                rts
 1633 
 1634 ;-------------------------------------------------------------------------------------
 1635 
 1636 GameText:
 1637 TopStatusBarLine:
 1638   .db $20, $43, $05, $16, $0a, $1b, $12, $18 ; "MARIO"
 1639   .db $20, $52, $0b, $20, $18, $1b, $15, $0d ; "WORLD  TIME"
 1640   .db $24, $24, $1d, $12, $16, $0e
 1641   .db $20, $68, $05, $00, $24, $24, $2e, $29 ; score trailing digit and coin display
 1642   .db $23, $c0, $7f, $aa ; attribute table data, clears name table 0 to palette 2
 1643   .db $23, $c2, $01, $ea ; attribute table data, used for coin icon in status bar
 1644   .db $ff ; end of data block
 1645 
 1646 WorldLivesDisplay:
 1647   .db $21, $cd, $07, $24, $24 ; cross with spaces used on
 1648   .db $29, $24, $24, $24, $24 ; lives display
 1649   .db $21, $4b, $09, $20, $18 ; "WORLD  - " used on lives display
 1650   .db $1b, $15, $0d, $24, $24, $28, $24
 1651   .db $22, $0c, $47, $24 ; possibly used to clear time up
 1652   .db $23, $dc, $01, $ba ; attribute table data for crown if more than 9 lives
 1653   .db $ff
 1654 
 1655 TwoPlayerTimeUp:
 1656   .db $21, $cd, $05, $16, $0a, $1b, $12, $18 ; "MARIO"
 1657 OnePlayerTimeUp:
 1658   .db $22, $0c, $07, $1d, $12, $16, $0e, $24, $1e, $19 ; "TIME UP"
 1659   .db $ff
 1660 
 1661 TwoPlayerGameOver:
 1662   .db $21, $cd, $05, $16, $0a, $1b, $12, $18 ; "MARIO"
 1663 OnePlayerGameOver:
 1664   .db $22, $0b, $09, $10, $0a, $16, $0e, $24 ; "GAME OVER"
 1665   .db $18, $1f, $0e, $1b
 1666   .db $ff
 1667 
 1668 WarpZoneWelcome:
 1669   .db $25, $84, $15, $20, $0e, $15, $0c, $18, $16 ; "WELCOME TO WARP ZONE!"
 1670   .db $0e, $24, $1d, $18, $24, $20, $0a, $1b, $19
 1671   .db $24, $23, $18, $17, $0e, $2b
 1672   .db $26, $25, $01, $24         ; placeholder for left pipe
 1673   .db $26, $2d, $01, $24         ; placeholder for middle pipe
 1674   .db $26, $35, $01, $24         ; placeholder for right pipe
 1675   .db $27, $d9, $46, $aa         ; attribute data
 1676   .db $27, $e1, $45, $aa
 1677   .db $ff
 1678 
 1679 LuigiName:
 1680   .db $15, $1e, $12, $10, $12    ; "LUIGI", no address or length
 1681 
 1682 WarpZoneNumbers:
 1683   .db $04, $03, $02, $00         ; warp zone numbers, note spaces on middle
 1684   .db $24, $05, $24, $00         ; zone, partly responsible for
 1685   .db $08, $07, $06, $00         ; the minus world
 1686 
 1687 GameTextOffsets:
 1688   .db TopStatusBarLine-GameText, TopStatusBarLine-GameText
 1689   .db WorldLivesDisplay-GameText, WorldLivesDisplay-GameText
 1690   .db TwoPlayerTimeUp-GameText, OnePlayerTimeUp-GameText
 1691   .db TwoPlayerGameOver-GameText, OnePlayerGameOver-GameText
 1692   .db WarpZoneWelcome-GameText, WarpZoneWelcome-GameText
 1693 
 1694 WriteGameText:
 1695                pha                      ;save text number to stack
 1696                asl
 1697                tay                      ;multiply by 2 and use as offset
 1698                cpy #$04                 ;if set to do top status bar or world/lives display,
 1699                bcc LdGameText           ;branch to use current offset as-is
 1700                cpy #$08                 ;if set to do time-up or game over,
 1701                bcc Chk2Players          ;branch to check players
 1702                ldy #$08                 ;otherwise warp zone, therefore set offset
 1703 Chk2Players:   lda NumberOfPlayers      ;check for number of players
 1704                bne LdGameText           ;if there are two, use current offset to also print name
 1705                iny                      ;otherwise increment offset by one to not print name
 1706 LdGameText:    ldx GameTextOffsets,y    ;get offset to message we want to print
 1707                ldy #$00
 1708 GameTextLoop:  lda GameText,x           ;load message data
 1709                cmp #$ff                 ;check for terminator
 1710                beq EndGameText          ;branch to end text if found
 1711                sta VRAM_Buffer1,y       ;otherwise write data to buffer
 1712                inx                      ;and increment increment
 1713                iny
 1714                bne GameTextLoop         ;do this for 256 bytes if no terminator found
 1715 EndGameText:   lda #$00                 ;put null terminator at end
 1716                sta VRAM_Buffer1,y
 1717                pla                      ;pull original text number from stack
 1718                tax
 1719                cmp #$04                 ;are we printing warp zone?
 1720                bcs PrintWarpZoneNumbers
 1721                dex                      ;are we printing the world/lives display?
 1722                bne CheckPlayerName      ;if not, branch to check player's name
 1723                lda NumberofLives        ;otherwise, check number of lives
 1724                clc                      ;and increment by one for display
 1725                adc #$01
 1726                cmp #10                  ;more than 9 lives?
 1727                bcc PutLives
 1728                sbc #10                  ;if so, subtract 10 and put a crown tile
 1729                ldy #$9f                 ;next to the difference...strange things happen if
 1730                sty VRAM_Buffer1+7       ;the number of lives exceeds 19
 1731 PutLives:      sta VRAM_Buffer1+8
 1732                ldy WorldNumber          ;write world and level numbers (incremented for display)
 1733                iny                      ;to the buffer in the spaces surrounding the dash
 1734                sty VRAM_Buffer1+19
 1735                ldy LevelNumber
 1736                iny
 1737                sty VRAM_Buffer1+21      ;we're done here
 1738                rts
 1739 
 1740 CheckPlayerName:
 1741              lda NumberOfPlayers    ;check number of players
 1742              beq ExitChkName        ;if only 1 player, leave
 1743              lda CurrentPlayer      ;load current player
 1744              dex                    ;check to see if current message number is for time up
 1745              bne ChkLuigi
 1746              ldy OperMode           ;check for game over mode
 1747              cpy #GameOverModeValue
 1748              beq ChkLuigi
 1749              eor #%00000001         ;if not, must be time up, invert d0 to do other player
 1750 ChkLuigi:    lsr
 1751              bcc ExitChkName        ;if mario is current player, do not change the name
 1752              ldy #$04
 1753 NameLoop:    lda LuigiName,y        ;otherwise, replace "MARIO" with "LUIGI"
 1754              sta VRAM_Buffer1+3,y
 1755              dey
 1756              bpl NameLoop           ;do this until each letter is replaced
 1757 ExitChkName: rts
 1758 
 1759 PrintWarpZoneNumbers:
 1760              sbc #$04               ;subtract 4 and then shift to the left
 1761              asl                    ;twice to get proper warp zone number
 1762              asl                    ;offset
 1763              tax
 1764              ldy #$00
 1765 WarpNumLoop: lda WarpZoneNumbers,x  ;print warp zone numbers into the
 1766              sta VRAM_Buffer1+27,y  ;placeholders from earlier
 1767              inx
 1768              iny                    ;put a number in every fourth space
 1769              iny
 1770              iny
 1771              iny
 1772              cpy #$0c
 1773              bcc WarpNumLoop
 1774              lda #$2c               ;load new buffer pointer at end of message
 1775              jmp SetVRAMOffset
 1776 
 1777 ;-------------------------------------------------------------------------------------
 1778 
 1779 ResetSpritesAndScreenTimer:
 1780          lda ScreenTimer             ;check if screen timer has expired
 1781          bne NoReset                 ;if not, branch to leave
 1782          jsr MoveAllSpritesOffscreen ;otherwise reset sprites now
 1783 
 1784 ResetScreenTimer:
 1785          lda #$07                    ;reset timer again
 1786          sta ScreenTimer
 1787          inc ScreenRoutineTask       ;move onto next task
 1788 NoReset: rts
 1789 
 1790 ;-------------------------------------------------------------------------------------
 1791 ;$00 - temp vram buffer offset
 1792 ;$01 - temp metatile buffer offset
 1793 ;$02 - temp metatile graphics table offset
 1794 ;$03 - used to store attribute bits
 1795 ;$04 - used to determine attribute table row
 1796 ;$05 - used to determine attribute table column
 1797 ;$06 - metatile graphics table address low
 1798 ;$07 - metatile graphics table address high
 1799 
 1800 RenderAreaGraphics:
 1801             lda CurrentColumnPos         ;store LSB of where we're at
 1802             and #$01
 1803             sta $05
 1804             ldy VRAM_Buffer2_Offset      ;store vram buffer offset
 1805             sty $00
 1806             lda CurrentNTAddr_Low        ;get current name table address we're supposed to render
 1807             sta VRAM_Buffer2+1,y
 1808             lda CurrentNTAddr_High
 1809             sta VRAM_Buffer2,y
 1810             lda #$9a                     ;store length byte of 26 here with d7 set
 1811             sta VRAM_Buffer2+2,y         ;to increment by 32 (in columns)
 1812             lda #$00                     ;init attribute row
 1813             sta $04
 1814             tax
 1815 DrawMTLoop: stx $01                      ;store init value of 0 or incremented offset for buffer
 1816             lda MetatileBuffer,x         ;get first metatile number, and mask out all but 2 MSB
 1817             and #%11000000
 1818             sta $03                      ;store attribute table bits here
 1819             asl                          ;note that metatile format is:
 1820             rol                          ;%xx000000 - attribute table bits, 
 1821             rol                          ;%00xxxxxx - metatile number
 1822             tay                          ;rotate bits to d1-d0 and use as offset here
 1823             lda MetatileGraphics_Low,y   ;get address to graphics table from here
 1824             sta $06
 1825             lda MetatileGraphics_High,y
 1826             sta $07
 1827             lda MetatileBuffer,x         ;get metatile number again
 1828             asl                          ;multiply by 4 and use as tile offset
 1829             asl
 1830             sta $02
 1831             lda AreaParserTaskNum        ;get current task number for level processing and
 1832             and #%00000001               ;mask out all but LSB, then invert LSB, multiply by 2
 1833             eor #%00000001               ;to get the correct column position in the metatile,
 1834             asl                          ;then add to the tile offset so we can draw either side
 1835             adc $02                      ;of the metatiles
 1836             tay
 1837             ldx $00                      ;use vram buffer offset from before as X
 1838             lda ($06),y
 1839             sta VRAM_Buffer2+3,x         ;get first tile number (top left or top right) and store
 1840             iny
 1841             lda ($06),y                  ;now get the second (bottom left or bottom right) and store
 1842             sta VRAM_Buffer2+4,x
 1843             ldy $04                      ;get current attribute row
 1844             lda $05                      ;get LSB of current column where we're at, and
 1845             bne RightCheck               ;branch if set (clear = left attrib, set = right)
 1846             lda $01                      ;get current row we're rendering
 1847             lsr                          ;branch if LSB set (clear = top left, set = bottom left)
 1848             bcs LLeft
 1849             rol $03                      ;rotate attribute bits 3 to the left
 1850             rol $03                      ;thus in d1-d0, for upper left square
 1851             rol $03
 1852             jmp SetAttrib
 1853 RightCheck: lda $01                      ;get LSB of current row we're rendering
 1854             lsr                          ;branch if set (clear = top right, set = bottom right)
 1855             bcs NextMTRow
 1856             lsr $03                      ;shift attribute bits 4 to the right
 1857             lsr $03                      ;thus in d3-d2, for upper right square
 1858             lsr $03
 1859             lsr $03
 1860             jmp SetAttrib
 1861 LLeft:      lsr $03                      ;shift attribute bits 2 to the right
 1862             lsr $03                      ;thus in d5-d4 for lower left square
 1863 NextMTRow:  inc $04                      ;move onto next attribute row  
 1864 SetAttrib:  lda AttributeBuffer,y        ;get previously saved bits from before
 1865             ora $03                      ;if any, and put new bits, if any, onto
 1866             sta AttributeBuffer,y        ;the old, and store
 1867             inc $00                      ;increment vram buffer offset by 2
 1868             inc $00
 1869             ldx $01                      ;get current gfx buffer row, and check for
 1870             inx                          ;the bottom of the screen
 1871             cpx #$0d
 1872             bcc DrawMTLoop               ;if not there yet, loop back
 1873             ldy $00                      ;get current vram buffer offset, increment by 3
 1874             iny                          ;(for name table address and length bytes)
 1875             iny
 1876             iny
 1877             lda #$00
 1878             sta VRAM_Buffer2,y           ;put null terminator at end of data for name table
 1879             sty VRAM_Buffer2_Offset      ;store new buffer offset
 1880             inc CurrentNTAddr_Low        ;increment name table address low
 1881             lda CurrentNTAddr_Low        ;check current low byte
 1882             and #%00011111               ;if no wraparound, just skip this part
 1883             bne ExitDrawM
 1884             lda #$80                     ;if wraparound occurs, make sure low byte stays
 1885             sta CurrentNTAddr_Low        ;just under the status bar
 1886             lda CurrentNTAddr_High       ;and then invert d2 of the name table address high
 1887             eor #%00000100               ;to move onto the next appropriate name table
 1888             sta CurrentNTAddr_High
 1889 ExitDrawM:  jmp SetVRAMCtrl              ;jump to set buffer to $0341 and leave
 1890 
 1891 ;-------------------------------------------------------------------------------------
 1892 ;$00 - temp attribute table address high (big endian order this time!)
 1893 ;$01 - temp attribute table address low
 1894 
 1895 RenderAttributeTables:
 1896              lda CurrentNTAddr_Low    ;get low byte of next name table address
 1897              and #%00011111           ;to be written to, mask out all but 5 LSB,
 1898              sec                      ;subtract four 
 1899              sbc #$04
 1900              and #%00011111           ;mask out bits again and store
 1901              sta $01
 1902              lda CurrentNTAddr_High   ;get high byte and branch if borrow not set
 1903              bcs SetATHigh
 1904              eor #%00000100           ;otherwise invert d2
 1905 SetATHigh:   and #%00000100           ;mask out all other bits
 1906              ora #$23                 ;add $2300 to the high byte and store
 1907              sta $00
 1908              lda $01                  ;get low byte - 4, divide by 4, add offset for
 1909              lsr                      ;attribute table and store
 1910              lsr
 1911              adc #$c0                 ;we should now have the appropriate block of
 1912              sta $01                  ;attribute table in our temp address
 1913              ldx #$00
 1914              ldy VRAM_Buffer2_Offset  ;get buffer offset
 1915 AttribLoop:  lda $00
 1916              sta VRAM_Buffer2,y       ;store high byte of attribute table address
 1917              lda $01
 1918              clc                      ;get low byte, add 8 because we want to start
 1919              adc #$08                 ;below the status bar, and store
 1920              sta VRAM_Buffer2+1,y
 1921              sta $01                  ;also store in temp again
 1922              lda AttributeBuffer,x    ;fetch current attribute table byte and store
 1923              sta VRAM_Buffer2+3,y     ;in the buffer
 1924              lda #$01
 1925              sta VRAM_Buffer2+2,y     ;store length of 1 in buffer
 1926              lsr
 1927              sta AttributeBuffer,x    ;clear current byte in attribute buffer
 1928              iny                      ;increment buffer offset by 4 bytes
 1929              iny
 1930              iny
 1931              iny
 1932              inx                      ;increment attribute offset and check to see
 1933              cpx #$07                 ;if we're at the end yet
 1934              bcc AttribLoop
 1935              sta VRAM_Buffer2,y       ;put null terminator at the end
 1936              sty VRAM_Buffer2_Offset  ;store offset in case we want to do any more
 1937 SetVRAMCtrl: lda #$06
 1938              sta VRAM_Buffer_AddrCtrl ;set buffer to $0341 and leave
 1939              rts
 1940 
 1941 ;-------------------------------------------------------------------------------------
 1942 
 1943 ;$00 - used as temporary counter in ColorRotation
 1944 
 1945 ColorRotatePalette:
 1946        .db $27, $27, $27, $17, $07, $17
 1947 
 1948 BlankPalette:
 1949        .db $3f, $0c, $04, $ff, $ff, $ff, $ff, $00
 1950 
 1951 ;used based on area type
 1952 Palette3Data:
 1953        .db $0f, $07, $12, $0f 
 1954        .db $0f, $07, $17, $0f
 1955        .db $0f, $07, $17, $1c
 1956        .db $0f, $07, $17, $00
 1957 
 1958 ColorRotation:
 1959               lda FrameCounter         ;get frame counter
 1960               and #$07                 ;mask out all but three LSB
 1961               bne ExitColorRot         ;branch if not set to zero to do this every eighth frame
 1962               ldx VRAM_Buffer1_Offset  ;check vram buffer offset
 1963               cpx #$31
 1964               bcs ExitColorRot         ;if offset over 48 bytes, branch to leave
 1965               tay                      ;otherwise use frame counter's 3 LSB as offset here
 1966 GetBlankPal:  lda BlankPalette,y       ;get blank palette for palette 3
 1967               sta VRAM_Buffer1,x       ;store it in the vram buffer
 1968               inx                      ;increment offsets
 1969               iny
 1970               cpy #$08
 1971               bcc GetBlankPal          ;do this until all bytes are copied
 1972               ldx VRAM_Buffer1_Offset  ;get current vram buffer offset
 1973               lda #$03
 1974               sta $00                  ;set counter here
 1975               lda AreaType             ;get area type
 1976               asl                      ;multiply by 4 to get proper offset
 1977               asl
 1978               tay                      ;save as offset here
 1979 GetAreaPal:   lda Palette3Data,y       ;fetch palette to be written based on area type
 1980               sta VRAM_Buffer1+3,x     ;store it to overwrite blank palette in vram buffer
 1981               iny
 1982               inx
 1983               dec $00                  ;decrement counter
 1984               bpl GetAreaPal           ;do this until the palette is all copied
 1985               ldx VRAM_Buffer1_Offset  ;get current vram buffer offset
 1986               ldy ColorRotateOffset    ;get color cycling offset
 1987               lda ColorRotatePalette,y
 1988               sta VRAM_Buffer1+4,x     ;get and store current color in second slot of palette
 1989               lda VRAM_Buffer1_Offset
 1990               clc                      ;add seven bytes to vram buffer offset
 1991               adc #$07
 1992               sta VRAM_Buffer1_Offset
 1993               inc ColorRotateOffset    ;increment color cycling offset
 1994               lda ColorRotateOffset
 1995               cmp #$06                 ;check to see if it's still in range
 1996               bcc ExitColorRot         ;if so, branch to leave
 1997               lda #$00
 1998               sta ColorRotateOffset    ;otherwise, init to keep it in range
 1999 ExitColorRot: rts                      ;leave
 2000 
 2001 ;-------------------------------------------------------------------------------------
 2002 ;$00 - temp store for offset control bit
 2003 ;$01 - temp vram buffer offset
 2004 ;$02 - temp store for vertical high nybble in block buffer routine
 2005 ;$03 - temp adder for high byte of name table address
 2006 ;$04, $05 - name table address low/high
 2007 ;$06, $07 - block buffer address low/high
 2008 
 2009 BlockGfxData:
 2010        .db $45, $45, $47, $47
 2011        .db $47, $47, $47, $47
 2012        .db $57, $58, $59, $5a
 2013        .db $24, $24, $24, $24
 2014        .db $26, $26, $26, $26
 2015 
 2016 RemoveCoin_Axe:
 2017               ldy #$41                 ;set low byte so offset points to $0341
 2018               lda #$03                 ;load offset for default blank metatile
 2019               ldx AreaType             ;check area type
 2020               bne WriteBlankMT         ;if not water type, use offset
 2021               lda #$04                 ;otherwise load offset for blank metatile used in water
 2022 WriteBlankMT: jsr PutBlockMetatile     ;do a sub to write blank metatile to vram buffer
 2023               lda #$06
 2024               sta VRAM_Buffer_AddrCtrl ;set vram address controller to $0341 and leave
 2025               rts
 2026 
 2027 ReplaceBlockMetatile:
 2028        jsr WriteBlockMetatile    ;write metatile to vram buffer to replace block object
 2029        inc Block_ResidualCounter ;increment unused counter (residual code)
 2030        dec Block_RepFlag,x       ;decrement flag (residual code)
 2031        rts                       ;leave
 2032 
 2033 DestroyBlockMetatile:
 2034        lda #$00       ;force blank metatile if branched/jumped to this point
 2035 
 2036 WriteBlockMetatile:
 2037              ldy #$03                ;load offset for blank metatile
 2038              cmp #$00                ;check contents of A for blank metatile
 2039              beq UseBOffset          ;branch if found (unconditional if branched from 8a6b)
 2040              ldy #$00                ;load offset for brick metatile w/ line
 2041              cmp #$58
 2042              beq UseBOffset          ;use offset if metatile is brick with coins (w/ line)
 2043              cmp #$51
 2044              beq UseBOffset          ;use offset if metatile is breakable brick w/ line
 2045              iny                     ;increment offset for brick metatile w/o line
 2046              cmp #$5d
 2047              beq UseBOffset          ;use offset if metatile is brick with coins (w/o line)
 2048              cmp #$52
 2049              beq UseBOffset          ;use offset if metatile is breakable brick w/o line
 2050              iny                     ;if any other metatile, increment offset for empty block
 2051 UseBOffset:  tya                     ;put Y in A
 2052              ldy VRAM_Buffer1_Offset ;get vram buffer offset
 2053              iny                     ;move onto next byte
 2054              jsr PutBlockMetatile    ;get appropriate block data and write to vram buffer
 2055 MoveVOffset: dey                     ;decrement vram buffer offset
 2056              tya                     ;add 10 bytes to it
 2057              clc
 2058              adc #10
 2059              jmp SetVRAMOffset       ;branch to store as new vram buffer offset
 2060 
 2061 PutBlockMetatile:
 2062             stx $00               ;store control bit from SprDataOffset_Ctrl
 2063             sty $01               ;store vram buffer offset for next byte
 2064             asl
 2065             asl                   ;multiply A by four and use as X
 2066             tax
 2067             ldy #$20              ;load high byte for name table 0
 2068             lda $06               ;get low byte of block buffer pointer
 2069             cmp #$d0              ;check to see if we're on odd-page block buffer
 2070             bcc SaveHAdder        ;if not, use current high byte
 2071             ldy #$24              ;otherwise load high byte for name table 1
 2072 SaveHAdder: sty $03               ;save high byte here
 2073             and #$0f              ;mask out high nybble of block buffer pointer
 2074             asl                   ;multiply by 2 to get appropriate name table low byte
 2075             sta $04               ;and then store it here
 2076             lda #$00
 2077             sta $05               ;initialize temp high byte
 2078             lda $02               ;get vertical high nybble offset used in block buffer routine
 2079             clc
 2080             adc #$20              ;add 32 pixels for the status bar
 2081             asl
 2082             rol $05               ;shift and rotate d7 onto d0 and d6 into carry
 2083             asl
 2084             rol $05               ;shift and rotate d6 onto d0 and d5 into carry
 2085             adc $04               ;add low byte of name table and carry to vertical high nybble
 2086             sta $04               ;and store here
 2087             lda $05               ;get whatever was in d7 and d6 of vertical high nybble
 2088             adc #$00              ;add carry
 2089             clc
 2090             adc $03               ;then add high byte of name table
 2091             sta $05               ;store here
 2092             ldy $01               ;get vram buffer offset to be used
 2093 RemBridge:  lda BlockGfxData,x    ;write top left and top right
 2094             sta VRAM_Buffer1+2,y  ;tile numbers into first spot
 2095             lda BlockGfxData+1,x
 2096             sta VRAM_Buffer1+3,y
 2097             lda BlockGfxData+2,x  ;write bottom left and bottom
 2098             sta VRAM_Buffer1+7,y  ;right tiles numbers into
 2099             lda BlockGfxData+3,x  ;second spot
 2100             sta VRAM_Buffer1+8,y
 2101             lda $04
 2102             sta VRAM_Buffer1,y    ;write low byte of name table
 2103             clc                   ;into first slot as read
 2104             adc #$20              ;add 32 bytes to value
 2105             sta VRAM_Buffer1+5,y  ;write low byte of name table
 2106             lda $05               ;plus 32 bytes into second slot
 2107             sta VRAM_Buffer1-1,y  ;write high byte of name
 2108             sta VRAM_Buffer1+4,y  ;table address to both slots
 2109             lda #$02
 2110             sta VRAM_Buffer1+1,y  ;put length of 2 in
 2111             sta VRAM_Buffer1+6,y  ;both slots
 2112             lda #$00
 2113             sta VRAM_Buffer1+9,y  ;put null terminator at end
 2114             ldx $00               ;get offset control bit here
 2115             rts                   ;and leave
 2116 
 2117 ;-------------------------------------------------------------------------------------
 2118 ;METATILE GRAPHICS TABLE
 2119 
 2120 MetatileGraphics_Low:
 2121   .db <Palette0_MTiles, <Palette1_MTiles, <Palette2_MTiles, <Palette3_MTiles
 2122 
 2123 MetatileGraphics_High:
 2124   .db >Palette0_MTiles, >Palette1_MTiles, >Palette2_MTiles, >Palette3_MTiles
 2125 
 2126 Palette0_MTiles:
 2127   .db $24, $24, $24, $24 ;blank
 2128   .db $27, $27, $27, $27 ;black metatile
 2129   .db $24, $24, $24, $35 ;bush left
 2130   .db $36, $25, $37, $25 ;bush middle
 2131   .db $24, $38, $24, $24 ;bush right
 2132   .db $24, $30, $30, $26 ;mountain left
 2133   .db $26, $26, $34, $26 ;mountain left bottom/middle center
 2134   .db $24, $31, $24, $32 ;mountain middle top
 2135   .db $33, $26, $24, $33 ;mountain right
 2136   .db $34, $26, $26, $26 ;mountain right bottom
 2137   .db $26, $26, $26, $26 ;mountain middle bottom
 2138   .db $24, $c0, $24, $c0 ;bridge guardrail
 2139   .db $24, $7f, $7f, $24 ;chain
 2140   .db $b8, $ba, $b9, $bb ;tall tree top, top half
 2141   .db $b8, $bc, $b9, $bd ;short tree top
 2142   .db $ba, $bc, $bb, $bd ;tall tree top, bottom half
 2143   .db $60, $64, $61, $65 ;warp pipe end left, points up
 2144   .db $62, $66, $63, $67 ;warp pipe end right, points up
 2145   .db $60, $64, $61, $65 ;decoration pipe end left, points up
 2146   .db $62, $66, $63, $67 ;decoration pipe end right, points up
 2147   .db $68, $68, $69, $69 ;pipe shaft left
 2148   .db $26, $26, $6a, $6a ;pipe shaft right
 2149   .db $4b, $4c, $4d, $4e ;tree ledge left edge
 2150   .db $4d, $4f, $4d, $4f ;tree ledge middle
 2151   .db $4d, $4e, $50, $51 ;tree ledge right edge
 2152   .db $6b, $70, $2c, $2d ;mushroom left edge
 2153   .db $6c, $71, $6d, $72 ;mushroom middle
 2154   .db $6e, $73, $6f, $74 ;mushroom right edge
 2155   .db $86, $8a, $87, $8b ;sideways pipe end top
 2156   .db $88, $8c, $88, $8c ;sideways pipe shaft top
 2157   .db $89, $8d, $69, $69 ;sideways pipe joint top
 2158   .db $8e, $91, $8f, $92 ;sideways pipe end bottom
 2159   .db $26, $93, $26, $93 ;sideways pipe shaft bottom
 2160   .db $90, $94, $69, $69 ;sideways pipe joint bottom
 2161   .db $a4, $e9, $ea, $eb ;seaplant
 2162   .db $24, $24, $24, $24 ;blank, used on bricks or blocks that are hit
 2163   .db $24, $2f, $24, $3d ;flagpole ball
 2164   .db $a2, $a2, $a3, $a3 ;flagpole shaft
 2165   .db $24, $24, $24, $24 ;blank, used in conjunction with vines
 2166 
 2167 Palette1_MTiles:
 2168   .db $a2, $a2, $a3, $a3 ;vertical rope
 2169   .db $99, $24, $99, $24 ;horizontal rope
 2170   .db $24, $a2, $3e, $3f ;left pulley
 2171   .db $5b, $5c, $24, $a3 ;right pulley
 2172   .db $24, $24, $24, $24 ;blank used for balance rope
 2173   .db $9d, $47, $9e, $47 ;castle top
 2174   .db $47, $47, $27, $27 ;castle window left
 2175   .db $47, $47, $47, $47 ;castle brick wall
 2176   .db $27, $27, $47, $47 ;castle window right
 2177   .db $a9, $47, $aa, $47 ;castle top w/ brick
 2178   .db $9b, $27, $9c, $27 ;entrance top
 2179   .db $27, $27, $27, $27 ;entrance bottom
 2180   .db $52, $52, $52, $52 ;green ledge stump
 2181   .db $80, $a0, $81, $a1 ;fence
 2182   .db $be, $be, $bf, $bf ;tree trunk
 2183   .db $75, $ba, $76, $bb ;mushroom stump top
 2184   .db $ba, $ba, $bb, $bb ;mushroom stump bottom
 2185   .db $45, $47, $45, $47 ;breakable brick w/ line 
 2186   .db $47, $47, $47, $47 ;breakable brick 
 2187   .db $45, $47, $45, $47 ;breakable brick (not used)
 2188   .db $b4, $b6, $b5, $b7 ;cracked rock terrain
 2189   .db $45, $47, $45, $47 ;brick with line (power-up)
 2190   .db $45, $47, $45, $47 ;brick with line (vine)
 2191   .db $45, $47, $45, $47 ;brick with line (star)
 2192   .db $45, $47, $45, $47 ;brick with line (coins)
 2193   .db $45, $47, $45, $47 ;brick with line (1-up)
 2194   .db $47, $47, $47, $47 ;brick (power-up)
 2195   .db $47, $47, $47, $47 ;brick (vine)
 2196   .db $47, $47, $47, $47 ;brick (star)
 2197   .db $47, $47, $47, $47 ;brick (coins)
 2198   .db $47, $47, $47, $47 ;brick (1-up)
 2199   .db $24, $24, $24, $24 ;hidden block (1 coin)
 2200   .db $24, $24, $24, $24 ;hidden block (1-up)
 2201   .db $ab, $ac, $ad, $ae ;solid block (3-d block)
 2202   .db $5d, $5e, $5d, $5e ;solid block (white wall)
 2203   .db $c1, $24, $c1, $24 ;bridge
 2204   .db $c6, $c8, $c7, $c9 ;bullet bill cannon barrel
 2205   .db $ca, $cc, $cb, $cd ;bullet bill cannon top
 2206   .db $2a, $2a, $40, $40 ;bullet bill cannon bottom
 2207   .db $24, $24, $24, $24 ;blank used for jumpspring
 2208   .db $24, $47, $24, $47 ;half brick used for jumpspring
 2209   .db $82, $83, $84, $85 ;solid block (water level, green rock)
 2210   .db $24, $47, $24, $47 ;half brick (???)
 2211   .db $86, $8a, $87, $8b ;water pipe top
 2212   .db $8e, $91, $8f, $92 ;water pipe bottom
 2213   .db $24, $2f, $24, $3d ;flag ball (residual object)
 2214 
 2215 Palette2_MTiles:
 2216   .db $24, $24, $24, $35 ;cloud left
 2217   .db $36, $25, $37, $25 ;cloud middle
 2218   .db $24, $38, $24, $24 ;cloud right
 2219   .db $24, $24, $39, $24 ;cloud bottom left
 2220   .db $3a, $24, $3b, $24 ;cloud bottom middle
 2221   .db $3c, $24, $24, $24 ;cloud bottom right
 2222   .db $41, $26, $41, $26 ;water/lava top
 2223   .db $26, $26, $26, $26 ;water/lava
 2224   .db $b0, $b1, $b2, $b3 ;cloud level terrain
 2225   .db $77, $79, $77, $79 ;bowser's bridge
 2226       
 2227 Palette3_MTiles:
 2228   .db $53, $55, $54, $56 ;question block (coin)
 2229   .db $53, $55, $54, $56 ;question block (power-up)
 2230   .db $a5, $a7, $a6, $a8 ;coin
 2231   .db $c2, $c4, $c3, $c5 ;underwater coin
 2232   .db $57, $59, $58, $5a ;empty block
 2233   .db $7b, $7d, $7c, $7e ;axe
 2234 
 2235 ;-------------------------------------------------------------------------------------
 2236 ;VRAM BUFFER DATA FOR LOCATIONS IN PRG-ROM
 2237 
 2238 WaterPaletteData:
 2239   .db $3f, $00, $20
 2240   .db $0f, $15, $12, $25  
 2241   .db $0f, $3a, $1a, $0f
 2242   .db $0f, $30, $12, $0f
 2243   .db $0f, $27, $12, $0f
 2244   .db $22, $16, $27, $18
 2245   .db $0f, $10, $30, $27
 2246   .db $0f, $16, $30, $27
 2247   .db $0f, $0f, $30, $10
 2248   .db $00
 2249 
 2250 GroundPaletteData:
 2251   .db $3f, $00, $20
 2252   .db $0f, $29, $1a, $0f
 2253   .db $0f, $36, $17, $0f
 2254   .db $0f, $30, $21, $0f
 2255   .db $0f, $27, $17, $0f
 2256   .db $0f, $16, $27, $18
 2257   .db $0f, $1a, $30, $27
 2258   .db $0f, $16, $30, $27
 2259   .db $0f, $0f, $36, $17
 2260   .db $00
 2261 
 2262 UndergroundPaletteData:
 2263   .db $3f, $00, $20
 2264   .db $0f, $29, $1a, $09
 2265   .db $0f, $3c, $1c, $0f
 2266   .db $0f, $30, $21, $1c
 2267   .db $0f, $27, $17, $1c
 2268   .db $0f, $16, $27, $18
 2269   .db $0f, $1c, $36, $17
 2270   .db $0f, $16, $30, $27
 2271   .db $0f, $0c, $3c, $1c
 2272   .db $00
 2273 
 2274 CastlePaletteData:
 2275   .db $3f, $00, $20
 2276   .db $0f, $30, $10, $00
 2277   .db $0f, $30, $10, $00
 2278   .db $0f, $30, $16, $00
 2279   .db $0f, $27, $17, $00
 2280   .db $0f, $16, $27, $18
 2281   .db $0f, $1c, $36, $17
 2282   .db $0f, $16, $30, $27
 2283   .db $0f, $00, $30, $10
 2284   .db $00
 2285 
 2286 DaySnowPaletteData:
 2287   .db $3f, $00, $04
 2288   .db $22, $30, $00, $10
 2289   .db $00
 2290 
 2291 NightSnowPaletteData:
 2292   .db $3f, $00, $04
 2293   .db $0f, $30, $00, $10
 2294   .db $00
 2295 
 2296 MushroomPaletteData:
 2297   .db $3f, $00, $04
 2298   .db $22, $27, $16, $0f
 2299   .db $00
 2300 
 2301 BowserPaletteData:
 2302   .db $3f, $14, $04
 2303   .db $0f, $1a, $30, $27
 2304   .db $00
 2305 
 2306 MarioThanksMessage:
 2307 ;"THANK YOU MARIO!"
 2308   .db $25, $48, $10
 2309   .db $1d, $11, $0a, $17, $14, $24
 2310   .db $22, $18, $1e, $24
 2311   .db $16, $0a, $1b, $12, $18, $2b
 2312   .db $00
 2313 
 2314 LuigiThanksMessage:
 2315 ;"THANK YOU LUIGI!"
 2316   .db $25, $48, $10
 2317   .db $1d, $11, $0a, $17, $14, $24
 2318   .db $22, $18, $1e, $24
 2319   .db $15, $1e, $12, $10, $12, $2b
 2320   .db $00
 2321 
 2322 MushroomRetainerSaved:
 2323 ;"BUT OUR PRINCESS IS IN"
 2324   .db $25, $c5, $16
 2325   .db $0b, $1e, $1d, $24, $18, $1e, $1b, $24
 2326   .db $19, $1b, $12, $17, $0c, $0e, $1c, $1c, $24
 2327   .db $12, $1c, $24, $12, $17
 2328 ;"ANOTHER CASTLE!"
 2329   .db $26, $05, $0f
 2330   .db $0a, $17, $18, $1d, $11, $0e, $1b, $24
 2331   .db $0c, $0a, $1c, $1d, $15, $0e, $2b, $00
 2332 
 2333 PrincessSaved1:
 2334 ;"YOUR QUEST IS OVER."
 2335   .db $25, $a7, $13
 2336   .db $22, $18, $1e, $1b, $24
 2337   .db $1a, $1e, $0e, $1c, $1d, $24
 2338   .db $12, $1c, $24, $18, $1f, $0e, $1b, $af
 2339   .db $00
 2340 
 2341 PrincessSaved2:
 2342 ;"WE PRESENT YOU A NEW QUEST."
 2343   .db $25, $e3, $1b
 2344   .db $20, $0e, $24
 2345   .db $19, $1b, $0e, $1c, $0e, $17, $1d, $24
 2346   .db $22, $18, $1e, $24, $0a, $24, $17, $0e, $20, $24
 2347   .db $1a, $1e, $0e, $1c, $1d, $af
 2348   .db $00
 2349 
 2350 WorldSelectMessage1:
 2351 ;"PUSH BUTTON B"
 2352   .db $26, $4a, $0d
 2353   .db $19, $1e, $1c, $11, $24
 2354   .db $0b, $1e, $1d, $1d, $18, $17, $24, $0b
 2355   .db $00
 2356 
 2357 WorldSelectMessage2:
 2358 ;"TO SELECT A WORLD"
 2359   .db $26, $88, $11
 2360   .db $1d, $18, $24, $1c, $0e, $15, $0e, $0c, $1d, $24
 2361   .db $0a, $24, $20, $18, $1b, $15, $0d
 2362   .db $00
 2363 
 2364 ;-------------------------------------------------------------------------------------
 2365 ;$04 - address low to jump address
 2366 ;$05 - address high to jump address
 2367 ;$06 - jump address low
 2368 ;$07 - jump address high
 2369 
 2370 JumpEngine:
 2371        asl          ;shift bit from contents of A
 2372        tay
 2373        pla          ;pull saved return address from stack
 2374        sta $04      ;save to indirect
 2375        pla
 2376        sta $05
 2377        iny
 2378        lda ($04),y  ;load pointer from indirect
 2379        sta $06      ;note that if an RTS is performed in next routine
 2380        iny          ;it will return to the execution before the sub
 2381        lda ($04),y  ;that called this routine
 2382        sta $07
 2383        jmp ($06)    ;jump to the address we loaded
 2384 
 2385 ;-------------------------------------------------------------------------------------
 2386 
 2387 InitializeNameTables:
 2388               lda PPU_STATUS            ;reset flip-flop
 2389               lda Mirror_PPU_CTRL_REG1  ;load mirror of ppu reg $2000
 2390               ora #%00010000            ;set sprites for first 4k and background for second 4k
 2391               and #%11110000            ;clear rest of lower nybble, leave higher alone
 2392               jsr WritePPUReg1
 2393               lda #$24                  ;set vram address to start of name table 1
 2394               jsr WriteNTAddr
 2395               lda #$20                  ;and then set it to name table 0
 2396 WriteNTAddr:  sta PPU_ADDRESS
 2397               lda #$00
 2398               sta PPU_ADDRESS
 2399               ldx #$04                  ;clear name table with blank tile #24
 2400               ldy #$c0
 2401               lda #$24
 2402 InitNTLoop:   sta PPU_DATA              ;count out exactly 768 tiles
 2403               dey
 2404               bne InitNTLoop
 2405               dex
 2406               bne InitNTLoop
 2407               ldy #64                   ;now to clear the attribute table (with zero this time)
 2408               txa
 2409               sta VRAM_Buffer1_Offset   ;init vram buffer 1 offset
 2410               sta VRAM_Buffer1          ;init vram buffer 1
 2411 InitATLoop:   sta PPU_DATA
 2412               dey
 2413               bne InitATLoop
 2414               sta HorizontalScroll      ;reset scroll variables
 2415               sta VerticalScroll
 2416               jmp InitScroll            ;initialize scroll registers to zero
 2417 
 2418 ;-------------------------------------------------------------------------------------
 2419 ;$00 - temp joypad bit
 2420 
 2421 ReadJoypads: 
 2422               lda #$01               ;reset and clear strobe of joypad ports
 2423               sta JOYPAD_PORT
 2424               lsr
 2425               tax                    ;start with joypad 1's port
 2426               sta JOYPAD_PORT
 2427               jsr ReadPortBits
 2428               inx                    ;increment for joypad 2's port
 2429 ReadPortBits: ldy #$08
 2430 PortLoop:     pha                    ;push previous bit onto stack
 2431               lda JOYPAD_PORT,x      ;read current bit on joypad port
 2432               sta $00                ;check d1 and d0 of port output
 2433               lsr                    ;this is necessary on the old
 2434               ora $00                ;famicom systems in japan
 2435               lsr
 2436               pla                    ;read bits from stack
 2437               rol                    ;rotate bit from carry flag
 2438               dey
 2439               bne PortLoop           ;count down bits left
 2440               sta SavedJoypadBits,x  ;save controller status here always
 2441               pha
 2442               and #%00110000         ;check for select or start
 2443               and JoypadBitMask,x    ;if neither saved state nor current state
 2444               beq Save8Bits          ;have any of these two set, branch
 2445               pla
 2446               and #%11001111         ;otherwise store without select
 2447               sta SavedJoypadBits,x  ;or start bits and leave
 2448               rts
 2449 Save8Bits:    pla
 2450               sta JoypadBitMask,x    ;save with all bits in another place and leave
 2451               rts
 2452 
 2453 ;-------------------------------------------------------------------------------------
 2454 ;$00 - vram buffer address table low
 2455 ;$01 - vram buffer address table high
 2456 
 2457 WriteBufferToScreen:
 2458                sta PPU_ADDRESS           ;store high byte of vram address
 2459                iny
 2460                lda ($00),y               ;load next byte (second)
 2461                sta PPU_ADDRESS           ;store low byte of vram address
 2462                iny
 2463                lda ($00),y               ;load next byte (third)
 2464                asl                       ;shift to left and save in stack
 2465                pha
 2466                lda Mirror_PPU_CTRL_REG1  ;load mirror of $2000,
 2467                ora #%00000100            ;set ppu to increment by 32 by default
 2468                bcs SetupWrites           ;if d7 of third byte was clear, ppu will
 2469                and #%11111011            ;only increment by 1
 2470 SetupWrites:   jsr WritePPUReg1          ;write to register
 2471                pla                       ;pull from stack and shift to left again
 2472                asl
 2473                bcc GetLength             ;if d6 of third byte was clear, do not repeat byte
 2474                ora #%00000010            ;otherwise set d1 and increment Y
 2475                iny
 2476 GetLength:     lsr                       ;shift back to the right to get proper length
 2477                lsr                       ;note that d1 will now be in carry
 2478                tax
 2479 OutputToVRAM:  bcs RepeatByte            ;if carry set, repeat loading the same byte
 2480                iny                       ;otherwise increment Y to load next byte
 2481 RepeatByte:    lda ($00),y               ;load more data from buffer and write to vram
 2482                sta PPU_DATA
 2483                dex                       ;done writing?
 2484                bne OutputToVRAM
 2485                sec          
 2486                tya
 2487                adc $00                   ;add end length plus one to the indirect at $00
 2488                sta $00                   ;to allow this routine to read another set of updates
 2489                lda #$00
 2490                adc $01
 2491                sta $01
 2492                lda #$3f                  ;sets vram address to $3f00
 2493                sta PPU_ADDRESS
 2494                lda #$00
 2495                sta PPU_ADDRESS
 2496                sta PPU_ADDRESS           ;then reinitializes it for some reason
 2497                sta PPU_ADDRESS
 2498 UpdateScreen:  ldx PPU_STATUS            ;reset flip-flop
 2499                ldy #$00                  ;load first byte from indirect as a pointer
 2500                lda ($00),y  
 2501                bne WriteBufferToScreen   ;if byte is zero we have no further updates to make here
 2502 InitScroll:    sta PPU_SCROLL_REG        ;store contents of A into scroll registers
 2503                sta PPU_SCROLL_REG        ;and end whatever subroutine led us here
 2504                rts
 2505 
 2506 ;-------------------------------------------------------------------------------------
 2507 
 2508 WritePPUReg1:
 2509                sta PPU_CTRL_REG1         ;write contents of A to PPU register 1
 2510                sta Mirror_PPU_CTRL_REG1  ;and its mirror
 2511                rts
 2512 
 2513 ;-------------------------------------------------------------------------------------
 2514 ;$00 - used to store status bar nybbles
 2515 ;$02 - used as temp vram offset
 2516 ;$03 - used to store length of status bar number
 2517 
 2518 ;status bar name table offset and length data
 2519 StatusBarData:
 2520       .db $f0, $06 ; top score display on title screen
 2521       .db $62, $06 ; player score
 2522       .db $62, $06
 2523       .db $6d, $02 ; coin tally
 2524       .db $6d, $02
 2525       .db $7a, $03 ; game timer
 2526 
 2527 StatusBarOffset:
 2528       .db $06, $0c, $12, $18, $1e, $24
 2529 
 2530 PrintStatusBarNumbers:
 2531       sta $00            ;store player-specific offset
 2532       jsr OutputNumbers  ;use first nybble to print the coin display
 2533       lda $00            ;move high nybble to low
 2534       lsr                ;and print to score display
 2535       lsr
 2536       lsr
 2537       lsr
 2538 
 2539 OutputNumbers:
 2540              clc                      ;add 1 to low nybble
 2541              adc #$01
 2542              and #%00001111           ;mask out high nybble
 2543              cmp #$06
 2544              bcs ExitOutputN
 2545              pha                      ;save incremented value to stack for now and
 2546              asl                      ;shift to left and use as offset
 2547              tay
 2548              ldx VRAM_Buffer1_Offset  ;get current buffer pointer
 2549              lda #$20                 ;put at top of screen by default
 2550              cpy #$00                 ;are we writing top score on title screen?
 2551              bne SetupNums
 2552              lda #$22                 ;if so, put further down on the screen
 2553 SetupNums:   sta VRAM_Buffer1,x
 2554              lda StatusBarData,y      ;write low vram address and length of thing
 2555              sta VRAM_Buffer1+1,x     ;we're printing to the buffer
 2556              lda StatusBarData+1,y
 2557              sta VRAM_Buffer1+2,x
 2558              sta $03                  ;save length byte in counter
 2559              stx $02                  ;and buffer pointer elsewhere for now
 2560              pla                      ;pull original incremented value from stack
 2561              tax
 2562              lda StatusBarOffset,x    ;load offset to value we want to write
 2563              sec
 2564              sbc StatusBarData+1,y    ;subtract from length byte we read before
 2565              tay                      ;use value as offset to display digits
 2566              ldx $02
 2567 DigitPLoop:  lda DisplayDigits,y      ;write digits to the buffer
 2568              sta VRAM_Buffer1+3,x    
 2569              inx
 2570              iny
 2571              dec $03                  ;do this until all the digits are written
 2572              bne DigitPLoop
 2573              lda #$00                 ;put null terminator at end
 2574              sta VRAM_Buffer1+3,x
 2575              inx                      ;increment buffer pointer by 3
 2576              inx
 2577              inx
 2578              stx VRAM_Buffer1_Offset  ;store it in case we want to use it again
 2579 ExitOutputN: rts
 2580 
 2581 ;-------------------------------------------------------------------------------------
 2582 
 2583 DigitsMathRoutine:
 2584             lda OperMode              ;check mode of operation
 2585             cmp #TitleScreenModeValue
 2586             beq EraseDMods            ;if in title screen mode, branch to lock score
 2587             ldx #$05
 2588 AddModLoop: lda DigitModifier,x       ;load digit amount to increment
 2589             clc
 2590             adc DisplayDigits,y       ;add to current digit
 2591             bmi BorrowOne             ;if result is a negative number, branch to subtract
 2592             cmp #10
 2593             bcs CarryOne              ;if digit greater than $09, branch to add
 2594 StoreNewD:  sta DisplayDigits,y       ;store as new score or game timer digit
 2595             dey                       ;move onto next digits in score or game timer
 2596             dex                       ;and digit amounts to increment
 2597             bpl AddModLoop            ;loop back if we're not done yet
 2598 EraseDMods: lda #$00                  ;store zero here
 2599             ldx #$06                  ;start with the last digit
 2600 EraseMLoop: sta DigitModifier-1,x     ;initialize the digit amounts to increment
 2601             dex
 2602             bpl EraseMLoop            ;do this until they're all reset, then leave
 2603             rts
 2604 BorrowOne:  dec DigitModifier-1,x     ;decrement the previous digit, then put $09 in
 2605             lda #$09                  ;the game timer digit we're currently on to "borrow
 2606             bne StoreNewD             ;the one", then do an unconditional branch back
 2607 CarryOne:   sec                       ;subtract ten from our digit to make it a
 2608             sbc #10                   ;proper BCD number, then increment the digit
 2609             inc DigitModifier-1,x     ;preceding current digit to "carry the one" properly
 2610             jmp StoreNewD             ;go back to just after we branched here
 2611 
 2612 ;-------------------------------------------------------------------------------------
 2613 
 2614 UpdateTopScore:
 2615       ldx #$05          ;start with mario's score
 2616       jsr TopScoreCheck
 2617       ldx #$0b          ;now do luigi's score
 2618 
 2619 TopScoreCheck:
 2620               ldy #$05                 ;start with the lowest digit
 2621               sec           
 2622 GetScoreDiff: lda PlayerScoreDisplay,x ;subtract each player digit from each high score digit
 2623               sbc TopScoreDisplay,y    ;from lowest to highest, if any top score digit exceeds
 2624               dex                      ;any player digit, borrow will be set until a subsequent
 2625               dey                      ;subtraction clears it (player digit is higher than top)
 2626               bpl GetScoreDiff      
 2627               bcc NoTopSc              ;check to see if borrow is still set, if so, no new high score
 2628               inx                      ;increment X and Y once to the start of the score
 2629               iny
 2630 CopyScore:    lda PlayerScoreDisplay,x ;store player's score digits into high score memory area
 2631               sta TopScoreDisplay,y
 2632               inx
 2633               iny
 2634               cpy #$06                 ;do this until we have stored them all
 2635               bcc CopyScore
 2636 NoTopSc:      rts
 2637 
 2638 ;-------------------------------------------------------------------------------------
 2639 
 2640 DefaultSprOffsets:
 2641       .db $04, $30, $48, $60, $78, $90, $a8, $c0
 2642       .db $d8, $e8, $24, $f8, $fc, $28, $2c
 2643 
 2644 Sprite0Data:
 2645       .db $18, $ff, $23, $58
 2646 
 2647 ;-------------------------------------------------------------------------------------
 2648 
 2649 InitializeGame:
 2650              ldy #$6f              ;clear all memory as in initialization procedure,
 2651              jsr InitializeMemory  ;but this time, clear only as far as $076f
 2652              ldy #$1f
 2653 ClrSndLoop:  sta SoundMemory,y     ;clear out memory used
 2654              dey                   ;by the sound engines
 2655              bpl ClrSndLoop
 2656              lda #$18              ;set demo timer
 2657              sta DemoTimer
 2658              jsr LoadAreaPointer
 2659 
 2660 InitializeArea:
 2661                ldy #$4b                 ;clear all memory again, only as far as $074b
 2662                jsr InitializeMemory     ;this is only necessary if branching from
 2663                ldx #$21
 2664                lda #$00
 2665 ClrTimersLoop: sta Timers,x             ;clear out memory between
 2666                dex                      ;$0780 and $07a1
 2667                bpl ClrTimersLoop
 2668                lda HalfwayPage
 2669                ldy AltEntranceControl   ;if AltEntranceControl not set, use halfway page, if any found
 2670                beq StartPage
 2671                lda EntrancePage         ;otherwise use saved entry page number here
 2672 StartPage:     sta ScreenLeft_PageLoc   ;set as value here
 2673                sta CurrentPageLoc       ;also set as current page
 2674                sta BackloadingFlag      ;set flag here if halfway page or saved entry page number found
 2675                jsr GetScreenPosition    ;get pixel coordinates for screen borders
 2676                ldy #$20                 ;if on odd numbered page, use $2480 as start of rendering
 2677                and #%00000001           ;otherwise use $2080, this address used later as name table
 2678                beq SetInitNTHigh        ;address for rendering of game area
 2679                ldy #$24
 2680 SetInitNTHigh: sty CurrentNTAddr_High   ;store name table address
 2681                ldy #$80
 2682                sty CurrentNTAddr_Low
 2683                asl                      ;store LSB of page number in high nybble
 2684                asl                      ;of block buffer column position
 2685                asl
 2686                asl
 2687                sta BlockBufferColumnPos
 2688                dec AreaObjectLength     ;set area object lengths for all empty
 2689                dec AreaObjectLength+1
 2690                dec AreaObjectLength+2
 2691                lda #$0b                 ;set value for renderer to update 12 column sets
 2692                sta ColumnSets           ;12 column sets = 24 metatile columns = 1 1/2 screens
 2693                jsr GetAreaDataAddrs     ;get enemy and level addresses and load header
 2694                lda PrimaryHardMode      ;check to see if primary hard mode has been activated
 2695                bne SetSecHard           ;if so, activate the secondary no matter where we're at
 2696                lda WorldNumber          ;otherwise check world number
 2697                cmp #World5              ;if less than 5, do not activate secondary
 2698                bcc CheckHalfway
 2699                bne SetSecHard           ;if not equal to, then world > 5, thus activate
 2700                lda LevelNumber          ;otherwise, world 5, so check level number
 2701                cmp #Level3              ;if 1 or 2, do not set secondary hard mode flag
 2702                bcc CheckHalfway
 2703 SetSecHard:    inc SecondaryHardMode    ;set secondary hard mode flag for areas 5-3 and beyond
 2704 CheckHalfway:  lda HalfwayPage
 2705                beq DoneInitArea
 2706                lda #$02                 ;if halfway page set, overwrite start position from header
 2707                sta PlayerEntranceCtrl
 2708 DoneInitArea:  lda #Silence             ;silence music
 2709                sta AreaMusicQueue
 2710                lda #$01                 ;disable screen output
 2711                sta DisableScreenFlag
 2712                inc OperMode_Task        ;increment one of the modes
 2713                rts
 2714 
 2715 ;-------------------------------------------------------------------------------------
 2716 
 2717 PrimaryGameSetup:
 2718       lda #$01
 2719       sta FetchNewGameTimerFlag   ;set flag to load game timer from header
 2720       sta PlayerSize              ;set player's size to small
 2721       lda #$02
 2722       sta NumberofLives           ;give each player three lives
 2723       sta OffScr_NumberofLives
 2724 
 2725 SecondaryGameSetup:
 2726              lda #$00
 2727              sta DisableScreenFlag     ;enable screen output
 2728              tay
 2729 ClearVRLoop: sta VRAM_Buffer1-1,y      ;clear buffer at $0300-$03ff
 2730              iny
 2731              bne ClearVRLoop
 2732              sta GameTimerExpiredFlag  ;clear game timer exp flag
 2733              sta DisableIntermediate   ;clear skip lives display flag
 2734              sta BackloadingFlag       ;clear value here
 2735              lda #$ff
 2736              sta BalPlatformAlignment  ;initialize balance platform assignment flag
 2737              lda ScreenLeft_PageLoc    ;get left side page location
 2738              lsr Mirror_PPU_CTRL_REG1  ;shift LSB of ppu register #1 mirror out
 2739              and #$01                  ;mask out all but LSB of page location
 2740              ror                       ;rotate LSB of page location into carry then onto mirror
 2741              rol Mirror_PPU_CTRL_REG1  ;this is to set the proper PPU name table
 2742              jsr GetAreaMusic          ;load proper music into queue
 2743              lda #$38                  ;load sprite shuffle amounts to be used later
 2744              sta SprShuffleAmt+2
 2745              lda #$48
 2746              sta SprShuffleAmt+1
 2747              lda #$58
 2748              sta SprShuffleAmt
 2749              ldx #$0e                  ;load default OAM offsets into $06e4-$06f2
 2750 ShufAmtLoop: lda DefaultSprOffsets,x
 2751              sta SprDataOffset,x
 2752              dex                       ;do this until they're all set
 2753              bpl ShufAmtLoop
 2754              ldy #$03                  ;set up sprite #0
 2755 ISpr0Loop:   lda Sprite0Data,y
 2756              sta Sprite_Data,y
 2757              dey
 2758              bpl ISpr0Loop
 2759              jsr DoNothing2            ;these jsrs doesn't do anything useful
 2760              jsr DoNothing1
 2761              inc Sprite0HitDetectFlag  ;set sprite #0 check flag
 2762              inc OperMode_Task         ;increment to next task
 2763              rts
 2764 
 2765 ;-------------------------------------------------------------------------------------
 2766 
 2767 ;$06 - RAM address low
 2768 ;$07 - RAM address high
 2769 
 2770 InitializeMemory:
 2771               ldx #$07          ;set initial high byte to $0700-$07ff
 2772               lda #$00          ;set initial low byte to start of page (at $00 of page)
 2773               sta $06
 2774 InitPageLoop: stx $07
 2775 InitByteLoop: cpx #$01          ;check to see if we're on the stack ($0100-$01ff)
 2776               bne InitByte      ;if not, go ahead anyway
 2777               cpy #$60          ;otherwise, check to see if we're at $0160-$01ff
 2778               bcs SkipByte      ;if so, skip write
 2779 InitByte:     sta ($06),y       ;otherwise, initialize byte with current low byte in Y
 2780 SkipByte:     dey
 2781               cpy #$ff          ;do this until all bytes in page have been erased
 2782               bne InitByteLoop
 2783               dex               ;go onto the next page
 2784               bpl InitPageLoop  ;do this until all pages of memory have been erased
 2785               rts
 2786 
 2787 ;-------------------------------------------------------------------------------------
 2788 
 2789 MusicSelectData:
 2790       .db WaterMusic, GroundMusic, UndergroundMusic, CastleMusic
 2791       .db CloudMusic, PipeIntroMusic
 2792 
 2793 GetAreaMusic:
 2794              lda OperMode           ;if in title screen mode, leave
 2795              beq ExitGetM
 2796              lda AltEntranceControl ;check for specific alternate mode of entry
 2797              cmp #$02               ;if found, branch without checking starting position
 2798              beq ChkAreaType        ;from area object data header
 2799              ldy #$05               ;select music for pipe intro scene by default
 2800              lda PlayerEntranceCtrl ;check value from level header for certain values
 2801              cmp #$06
 2802              beq StoreMusic         ;load music for pipe intro scene if header
 2803              cmp #$07               ;start position either value $06 or $07
 2804              beq StoreMusic
 2805 ChkAreaType: ldy AreaType           ;load area type as offset for music bit
 2806              lda CloudTypeOverride
 2807              beq StoreMusic         ;check for cloud type override
 2808              ldy #$04               ;select music for cloud type level if found
 2809 StoreMusic:  lda MusicSelectData,y  ;otherwise select appropriate music for level type
 2810              sta AreaMusicQueue     ;store in queue and leave
 2811 ExitGetM:    rts
 2812 
 2813 ;-------------------------------------------------------------------------------------
 2814 
 2815 PlayerStarting_X_Pos:
 2816       .db $28, $18
 2817       .db $38, $28
 2818 
 2819 AltYPosOffset:
 2820       .db $08, $00
 2821 
 2822 PlayerStarting_Y_Pos:
 2823       .db $00, $20, $b0, $50, $00, $00, $b0, $b0
 2824       .db $f0
 2825 
 2826 PlayerBGPriorityData:
 2827       .db $00, $20, $00, $00, $00, $00, $00, $00
 2828 
 2829 GameTimerData:
 2830       .db $20 ;dummy byte, used as part of bg priority data
 2831       .db $04, $03, $02
 2832 
 2833 Entrance_GameTimerSetup:
 2834           lda ScreenLeft_PageLoc      ;set current page for area objects
 2835           sta Player_PageLoc          ;as page location for player
 2836           lda #$28                    ;store value here
 2837           sta VerticalForceDown       ;for fractional movement downwards if necessary
 2838           lda #$01                    ;set high byte of player position and
 2839           sta PlayerFacingDir         ;set facing direction so that player faces right
 2840           sta Player_Y_HighPos
 2841           lda #$00                    ;set player state to on the ground by default
 2842           sta Player_State
 2843           dec Player_CollisionBits    ;initialize player's collision bits
 2844           ldy #$00                    ;initialize halfway page
 2845           sty HalfwayPage      
 2846           lda AreaType                ;check area type
 2847           bne ChkStPos                ;if water type, set swimming flag, otherwise do not set
 2848           iny
 2849 ChkStPos: sty SwimmingFlag
 2850           ldx PlayerEntranceCtrl      ;get starting position loaded from header
 2851           ldy AltEntranceControl      ;check alternate mode of entry flag for 0 or 1
 2852           beq SetStPos
 2853           cpy #$01
 2854           beq SetStPos
 2855           ldx AltYPosOffset-2,y       ;if not 0 or 1, override $0710 with new offset in X
 2856 SetStPos: lda PlayerStarting_X_Pos,y  ;load appropriate horizontal position
 2857           sta Player_X_Position       ;and vertical positions for the player, using
 2858           lda PlayerStarting_Y_Pos,x  ;AltEntranceControl as offset for horizontal and either $0710
 2859           sta Player_Y_Position       ;or value that overwrote $0710 as offset for vertical
 2860           lda PlayerBGPriorityData,x
 2861           sta Player_SprAttrib        ;set player sprite attributes using offset in X
 2862           jsr GetPlayerColors         ;get appropriate player palette
 2863           ldy GameTimerSetting        ;get timer control value from header
 2864           beq ChkOverR                ;if set to zero, branch (do not use dummy byte for this)
 2865           lda FetchNewGameTimerFlag   ;do we need to set the game timer? if not, use 
 2866           beq ChkOverR                ;old game timer setting
 2867           lda GameTimerData,y         ;if game timer is set and game timer flag is also set,
 2868           sta GameTimerDisplay        ;use value of game timer control for first digit of game timer
 2869           lda #$01
 2870           sta GameTimerDisplay+2      ;set last digit of game timer to 1
 2871           lsr
 2872           sta GameTimerDisplay+1      ;set second digit of game timer
 2873           sta FetchNewGameTimerFlag   ;clear flag for game timer reset
 2874           sta StarInvincibleTimer     ;clear star mario timer
 2875 ChkOverR: ldy JoypadOverride          ;if controller bits not set, branch to skip this part
 2876           beq ChkSwimE
 2877           lda #$03                    ;set player state to climbing
 2878           sta Player_State
 2879           ldx #$00                    ;set offset for first slot, for block object
 2880           jsr InitBlock_XY_Pos
 2881           lda #$f0                    ;set vertical coordinate for block object
 2882           sta Block_Y_Position
 2883           ldx #$05                    ;set offset in X for last enemy object buffer slot
 2884           ldy #$00                    ;set offset in Y for object coordinates used earlier
 2885           jsr Setup_Vine              ;do a sub to grow vine
 2886 ChkSwimE: ldy AreaType                ;if level not water-type,
 2887           bne SetPESub                ;skip this subroutine
 2888           jsr SetupBubble             ;otherwise, execute sub to set up air bubbles
 2889 SetPESub: lda #$07                    ;set to run player entrance subroutine
 2890           sta GameEngineSubroutine    ;on the next frame of game engine
 2891           rts
 2892 
 2893 ;-------------------------------------------------------------------------------------
 2894 
 2895 ;page numbers are in order from -1 to -4
 2896 HalfwayPageNybbles:
 2897       .db $56, $40
 2898       .db $65, $70
 2899       .db $66, $40
 2900       .db $66, $40
 2901       .db $66, $40
 2902       .db $66, $60
 2903       .db $65, $70
 2904       .db $00, $00
 2905 
 2906 PlayerLoseLife:
 2907              inc DisableScreenFlag    ;disable screen and sprite 0 check
 2908              lda #$00
 2909              sta Sprite0HitDetectFlag
 2910              lda #Silence             ;silence music
 2911              sta EventMusicQueue
 2912              dec NumberofLives        ;take one life from player
 2913              bpl StillInGame          ;if player still has lives, branch
 2914              lda #$00
 2915              sta OperMode_Task        ;initialize mode task,
 2916              lda #GameOverModeValue   ;switch to game over mode
 2917              sta OperMode             ;and leave
 2918              rts
 2919 StillInGame: lda WorldNumber          ;multiply world number by 2 and use
 2920              asl                      ;as offset
 2921              tax
 2922              lda LevelNumber          ;if in area -3 or -4, increment
 2923              and #$02                 ;offset by one byte, otherwise
 2924              beq GetHalfway           ;leave offset alone
 2925              inx
 2926 GetHalfway:  ldy HalfwayPageNybbles,x ;get halfway page number with offset
 2927              lda LevelNumber          ;check area number's LSB
 2928              lsr
 2929              tya                      ;if in area -2 or -4, use lower nybble
 2930              bcs MaskHPNyb
 2931              lsr                      ;move higher nybble to lower if area
 2932              lsr                      ;number is -1 or -3
 2933              lsr
 2934              lsr
 2935 MaskHPNyb:   and #%00001111           ;mask out all but lower nybble
 2936              cmp ScreenLeft_PageLoc
 2937              beq SetHalfway           ;left side of screen must be at the halfway page,
 2938              bcc SetHalfway           ;otherwise player must start at the
 2939              lda #$00                 ;beginning of the level
 2940 SetHalfway:  sta HalfwayPage          ;store as halfway page for player
 2941              jsr TransposePlayers     ;switch players around if 2-player game
 2942              jmp ContinueGame         ;continue the game
 2943 
 2944 ;-------------------------------------------------------------------------------------
 2945 
 2946 GameOverMode:
 2947       lda OperMode_Task
 2948       jsr JumpEngine
 2949       
 2950       .dw SetupGameOver
 2951       .dw ScreenRoutines
 2952       .dw RunGameOver
 2953 
 2954 ;-------------------------------------------------------------------------------------
 2955 
 2956 SetupGameOver:
 2957       lda #$00                  ;reset screen routine task control for title screen, game,
 2958       sta ScreenRoutineTask     ;and game over modes
 2959       sta Sprite0HitDetectFlag  ;disable sprite 0 check
 2960       lda #GameOverMusic
 2961       sta EventMusicQueue       ;put game over music in secondary queue
 2962       inc DisableScreenFlag     ;disable screen output
 2963       inc OperMode_Task         ;set secondary mode to 1
 2964       rts
 2965 
 2966 ;-------------------------------------------------------------------------------------
 2967 
 2968 RunGameOver:
 2969       lda #$00              ;reenable screen
 2970       sta DisableScreenFlag
 2971       lda SavedJoypad1Bits  ;check controller for start pressed
 2972       and #Start_Button
 2973       bne TerminateGame
 2974       lda ScreenTimer       ;if not pressed, wait for
 2975       bne GameIsOn          ;screen timer to expire
 2976 TerminateGame:
 2977       lda #Silence          ;silence music
 2978       sta EventMusicQueue
 2979       jsr TransposePlayers  ;check if other player can keep
 2980       bcc ContinueGame      ;going, and do so if possible
 2981       lda WorldNumber       ;otherwise put world number of current
 2982       sta ContinueWorld     ;player into secret continue function variable
 2983       lda #$00
 2984       asl                   ;residual ASL instruction
 2985       sta OperMode_Task     ;reset all modes to title screen and
 2986       sta ScreenTimer       ;leave
 2987       sta OperMode
 2988       rts
 2989 
 2990 ContinueGame:
 2991            jsr LoadAreaPointer       ;update level pointer with
 2992            lda #$01                  ;actual world and area numbers, then
 2993            sta PlayerSize            ;reset player's size, status, and
 2994            inc FetchNewGameTimerFlag ;set game timer flag to reload
 2995            lda #$00                  ;game timer from header
 2996            sta TimerControl          ;also set flag for timers to count again
 2997            sta PlayerStatus
 2998            sta GameEngineSubroutine  ;reset task for game core
 2999            sta OperMode_Task         ;set modes and leave
 3000            lda #$01                  ;if in game over mode, switch back to
 3001            sta OperMode              ;game mode, because game is still on
 3002 GameIsOn:  rts
 3003 
 3004 TransposePlayers:
 3005            sec                       ;set carry flag by default to end game
 3006            lda NumberOfPlayers       ;if only a 1 player game, leave
 3007            beq ExTrans
 3008            lda OffScr_NumberofLives  ;does offscreen player have any lives left?
 3009            bmi ExTrans               ;branch if not
 3010            lda CurrentPlayer         ;invert bit to update
 3011            eor #%00000001            ;which player is on the screen
 3012            sta CurrentPlayer
 3013            ldx #$06
 3014 TransLoop: lda OnscreenPlayerInfo,x    ;transpose the information
 3015            pha                         ;of the onscreen player
 3016            lda OffscreenPlayerInfo,x   ;with that of the offscreen player
 3017            sta OnscreenPlayerInfo,x
 3018            pla
 3019            sta OffscreenPlayerInfo,x
 3020            dex
 3021            bpl TransLoop
 3022            clc            ;clear carry flag to get game going
 3023 ExTrans:   rts
 3024 
 3025 ;-------------------------------------------------------------------------------------
 3026 
 3027 DoNothing1:
 3028       lda #$ff       ;this is residual code, this value is
 3029       sta $06c9      ;not used anywhere in the program
 3030 DoNothing2:
 3031       rts
 3032 
 3033 ;-------------------------------------------------------------------------------------
 3034 
 3035 AreaParserTaskHandler:
 3036               ldy AreaParserTaskNum     ;check number of tasks here
 3037               bne DoAPTasks             ;if already set, go ahead
 3038               ldy #$08
 3039               sty AreaParserTaskNum     ;otherwise, set eight by default
 3040 DoAPTasks:    dey
 3041               tya
 3042               jsr AreaParserTasks
 3043               dec AreaParserTaskNum     ;if all tasks not complete do not
 3044               bne SkipATRender          ;render attribute table yet
 3045               jsr RenderAttributeTables
 3046 SkipATRender: rts
 3047 
 3048 AreaParserTasks:
 3049       jsr JumpEngine
 3050 
 3051       .dw IncrementColumnPos
 3052       .dw RenderAreaGraphics
 3053       .dw RenderAreaGraphics
 3054       .dw AreaParserCore
 3055       .dw IncrementColumnPos
 3056       .dw RenderAreaGraphics
 3057       .dw RenderAreaGraphics
 3058       .dw AreaParserCore
 3059 
 3060 ;-------------------------------------------------------------------------------------
 3061 
 3062 IncrementColumnPos:
 3063            inc CurrentColumnPos     ;increment column where we're at
 3064            lda CurrentColumnPos
 3065            and #%00001111           ;mask out higher nybble
 3066            bne NoColWrap
 3067            sta CurrentColumnPos     ;if no bits left set, wrap back to zero (0-f)
 3068            inc CurrentPageLoc       ;and increment page number where we're at
 3069 NoColWrap: inc BlockBufferColumnPos ;increment column offset where we're at
 3070            lda BlockBufferColumnPos
 3071            and #%00011111           ;mask out all but 5 LSB (0-1f)
 3072            sta BlockBufferColumnPos ;and save
 3073            rts
 3074 
 3075 ;-------------------------------------------------------------------------------------
 3076 ;$00 - used as counter, store for low nybble for background, ceiling byte for terrain
 3077 ;$01 - used to store floor byte for terrain
 3078 ;$07 - used to store terrain metatile
 3079 ;$06-$07 - used to store block buffer address
 3080 
 3081 BSceneDataOffsets:
 3082       .db $00, $30, $60 
 3083 
 3084 BackSceneryData:
 3085    .db $93, $00, $00, $11, $12, $12, $13, $00 ;clouds
 3086    .db $00, $51, $52, $53, $00, $00, $00, $00
 3087    .db $00, $00, $01, $02, $02, $03, $00, $00
 3088    .db $00, $00, $00, $00, $91, $92, $93, $00
 3089    .db $00, $00, $00, $51, $52, $53, $41, $42
 3090    .db $43, $00, $00, $00, $00, $00, $91, $92
 3091 
 3092    .db $97, $87, $88, $89, $99, $00, $00, $00 ;mountains and bushes
 3093    .db $11, $12, $13, $a4, $a5, $a5, $a5, $a6
 3094    .db $97, $98, $99, $01, $02, $03, $00, $a4
 3095    .db $a5, $a6, $00, $11, $12, $12, $12, $13
 3096    .db $00, $00, $00, $00, $01, $02, $02, $03
 3097    .db $00, $a4, $a5, $a5, $a6, $00, $00, $00
 3098 
 3099    .db $11, $12, $12, $13, $00, $00, $00, $00 ;trees and fences
 3100    .db $00, $00, $00, $9c, $00, $8b, $aa, $aa
 3101    .db $aa, $aa, $11, $12, $13, $8b, $00, $9c
 3102    .db $9c, $00, $00, $01, $02, $03, $11, $12
 3103    .db $12, $13, $00, $00, $00, $00, $aa, $aa
 3104    .db $9c, $aa, $00, $8b, $00, $01, $02, $03
 3105 
 3106 BackSceneryMetatiles:
 3107    .db $80, $83, $00 ;cloud left
 3108    .db $81, $84, $00 ;cloud middle
 3109    .db $82, $85, $00 ;cloud right
 3110    .db $02, $00, $00 ;bush left
 3111    .db $03, $00, $00 ;bush middle
 3112    .db $04, $00, $00 ;bush right
 3113    .db $00, $05, $06 ;mountain left
 3114    .db $07, $06, $0a ;mountain middle
 3115    .db $00, $08, $09 ;mountain right
 3116    .db $4d, $00, $00 ;fence
 3117    .db $0d, $0f, $4e ;tall tree
 3118    .db $0e, $4e, $4e ;short tree
 3119 
 3120 FSceneDataOffsets:
 3121       .db $00, $0d, $1a
 3122 
 3123 ForeSceneryData:
 3124    .db $86, $87, $87, $87, $87, $87, $87   ;in water
 3125    .db $87, $87, $87, $87, $69, $69
 3126 
 3127    .db $00, $00, $00, $00, $00, $45, $47   ;wall
 3128    .db $47, $47, $47, $47, $00, $00
 3129 
 3130    .db $00, $00, $00, $00, $00, $00, $00   ;over water
 3131    .db $00, $00, $00, $00, $86, $87
 3132 
 3133 TerrainMetatiles:
 3134       .db $69, $54, $52, $62
 3135 
 3136 TerrainRenderBits:
 3137       .db %00000000, %00000000 ;no ceiling or floor
 3138       .db %00000000, %00011000 ;no ceiling, floor 2
 3139       .db %00000001, %00011000 ;ceiling 1, floor 2
 3140       .db %00000111, %00011000 ;ceiling 3, floor 2
 3141       .db %00001111, %00011000 ;ceiling 4, floor 2
 3142       .db %11111111, %00011000 ;ceiling 8, floor 2
 3143       .db %00000001, %00011111 ;ceiling 1, floor 5
 3144       .db %00000111, %00011111 ;ceiling 3, floor 5
 3145       .db %00001111, %00011111 ;ceiling 4, floor 5
 3146       .db %10000001, %00011111 ;ceiling 1, floor 6
 3147       .db %00000001, %00000000 ;ceiling 1, no floor
 3148       .db %10001111, %00011111 ;ceiling 4, floor 6
 3149       .db %11110001, %00011111 ;ceiling 1, floor 9
 3150       .db %11111001, %00011000 ;ceiling 1, middle 5, floor 2
 3151       .db %11110001, %00011000 ;ceiling 1, middle 4, floor 2
 3152       .db %11111111, %00011111 ;completely solid top to bottom
 3153 
 3154 AreaParserCore:
 3155       lda BackloadingFlag       ;check to see if we are starting right of start
 3156       beq RenderSceneryTerrain  ;if not, go ahead and render background, foreground and terrain
 3157       jsr ProcessAreaData       ;otherwise skip ahead and load level data
 3158 
 3159 RenderSceneryTerrain:
 3160           ldx #$0c
 3161           lda #$00
 3162 ClrMTBuf: sta MetatileBuffer,x       ;clear out metatile buffer
 3163           dex
 3164           bpl ClrMTBuf
 3165           ldy BackgroundScenery      ;do we need to render the background scenery?
 3166           beq RendFore               ;if not, skip to check the foreground
 3167           lda CurrentPageLoc         ;otherwise check for every third page
 3168 ThirdP:   cmp #$03
 3169           bmi RendBack               ;if less than three we're there
 3170           sec
 3171           sbc #$03                   ;if 3 or more, subtract 3 and 
 3172           bpl ThirdP                 ;do an unconditional branch
 3173 RendBack: asl                        ;move results to higher nybble
 3174           asl
 3175           asl
 3176           asl
 3177           adc BSceneDataOffsets-1,y  ;add to it offset loaded from here
 3178           adc CurrentColumnPos       ;add to the result our current column position
 3179           tax
 3180           lda BackSceneryData,x      ;load data from sum of offsets
 3181           beq RendFore               ;if zero, no scenery for that part
 3182           pha
 3183           and #$0f                   ;save to stack and clear high nybble
 3184           sec
 3185           sbc #$01                   ;subtract one (because low nybble is $01-$0c)
 3186           sta $00                    ;save low nybble
 3187           asl                        ;multiply by three (shift to left and add result to old one)
 3188           adc $00                    ;note that since d7 was nulled, the carry flag is always clear
 3189           tax                        ;save as offset for background scenery metatile data
 3190           pla                        ;get high nybble from stack, move low
 3191           lsr
 3192           lsr
 3193           lsr
 3194           lsr
 3195           tay                        ;use as second offset (used to determine height)
 3196           lda #$03                   ;use previously saved memory location for counter
 3197           sta $00
 3198 SceLoop1: lda BackSceneryMetatiles,x ;load metatile data from offset of (lsb - 1) * 3
 3199           sta MetatileBuffer,y       ;store into buffer from offset of (msb / 16)
 3200           inx
 3201           iny
 3202           cpy #$0b                   ;if at this location, leave loop
 3203           beq RendFore
 3204           dec $00                    ;decrement until counter expires, barring exception
 3205           bne SceLoop1
 3206 RendFore: ldx ForegroundScenery      ;check for foreground data needed or not
 3207           beq RendTerr               ;if not, skip this part
 3208           ldy FSceneDataOffsets-1,x  ;load offset from location offset by header value, then
 3209           ldx #$00                   ;reinit X
 3210 SceLoop2: lda ForeSceneryData,y      ;load data until counter expires
 3211           beq NoFore                 ;do not store if zero found
 3212           sta MetatileBuffer,x
 3213 NoFore:   iny
 3214           inx
 3215           cpx #$0d                   ;store up to end of metatile buffer
 3216           bne SceLoop2
 3217 RendTerr: ldy AreaType               ;check world type for water level
 3218           bne TerMTile               ;if not water level, skip this part
 3219           lda WorldNumber            ;check world number, if not world number eight
 3220           cmp #World8                ;then skip this part
 3221           bne TerMTile
 3222           lda #$62                   ;if set as water level and world number eight,
 3223           jmp StoreMT                ;use castle wall metatile as terrain type
 3224 TerMTile: lda TerrainMetatiles,y     ;otherwise get appropriate metatile for area type
 3225           ldy CloudTypeOverride      ;check for cloud type override
 3226           beq StoreMT                ;if not set, keep value otherwise
 3227           lda #$88                   ;use cloud block terrain
 3228 StoreMT:  sta $07                    ;store value here
 3229           ldx #$00                   ;initialize X, use as metatile buffer offset
 3230           lda TerrainControl         ;use yet another value from the header
 3231           asl                        ;multiply by 2 and use as yet another offset
 3232           tay
 3233 TerrLoop: lda TerrainRenderBits,y    ;get one of the terrain rendering bit data
 3234           sta $00
 3235           iny                        ;increment Y and use as offset next time around
 3236           sty $01
 3237           lda CloudTypeOverride      ;skip if value here is zero
 3238           beq NoCloud2
 3239           cpx #$00                   ;otherwise, check if we're doing the ceiling byte
 3240           beq NoCloud2
 3241           lda $00                    ;if not, mask out all but d3
 3242           and #%00001000
 3243           sta $00
 3244 NoCloud2: ldy #$00                   ;start at beginning of bitmasks
 3245 TerrBChk: lda Bitmasks,y             ;load bitmask, then perform AND on contents of first byte
 3246           bit $00
 3247           beq NextTBit               ;if not set, skip this part (do not write terrain to buffer)
 3248           lda $07
 3249           sta MetatileBuffer,x       ;load terrain type metatile number and store into buffer here
 3250 NextTBit: inx                        ;continue until end of buffer
 3251           cpx #$0d
 3252           beq RendBBuf               ;if we're at the end, break out of this loop
 3253           lda AreaType               ;check world type for underground area
 3254           cmp #$02
 3255           bne EndUChk                ;if not underground, skip this part
 3256           cpx #$0b
 3257           bne EndUChk                ;if we're at the bottom of the screen, override
 3258           lda #$54                   ;old terrain type with ground level terrain type
 3259           sta $07
 3260 EndUChk:  iny                        ;increment bitmasks offset in Y
 3261           cpy #$08
 3262           bne TerrBChk               ;if not all bits checked, loop back    
 3263           ldy $01
 3264           bne TerrLoop               ;unconditional branch, use Y to load next byte
 3265 RendBBuf: jsr ProcessAreaData        ;do the area data loading routine now
 3266           lda BlockBufferColumnPos
 3267           jsr GetBlockBufferAddr     ;get block buffer address from where we're at
 3268           ldx #$00
 3269           ldy #$00                   ;init index regs and start at beginning of smaller buffer
 3270 ChkMTLow: sty $00
 3271           lda MetatileBuffer,x       ;load stored metatile number
 3272           and #%11000000             ;mask out all but 2 MSB
 3273           asl
 3274           rol                        ;make %xx000000 into %000000xx
 3275           rol
 3276           tay                        ;use as offset in Y
 3277           lda MetatileBuffer,x       ;reload original unmasked value here
 3278           cmp BlockBuffLowBounds,y   ;check for certain values depending on bits set
 3279           bcs StrBlock               ;if equal or greater, branch
 3280           lda #$00                   ;if less, init value before storing
 3281 StrBlock: ldy $00                    ;get offset for block buffer
 3282           sta ($06),y                ;store value into block buffer
 3283           tya
 3284           clc                        ;add 16 (move down one row) to offset
 3285           adc #$10
 3286           tay
 3287           inx                        ;increment column value
 3288           cpx #$0d
 3289           bcc ChkMTLow               ;continue until we pass last row, then leave
 3290           rts
 3291 
 3292 ;numbers lower than these with the same attribute bits
 3293 ;will not be stored in the block buffer
 3294 BlockBuffLowBounds:
 3295       .db $10, $51, $88, $c0
 3296 
 3297 ;-------------------------------------------------------------------------------------
 3298 ;$00 - used to store area object identifier
 3299 ;$07 - used as adder to find proper area object code
 3300 
 3301 ProcessAreaData:
 3302             ldx #$02                 ;start at the end of area object buffer
 3303 ProcADLoop: stx ObjectOffset
 3304             lda #$00                 ;reset flag
 3305             sta BehindAreaParserFlag
 3306             ldy AreaDataOffset       ;get offset of area data pointer
 3307             lda (AreaData),y         ;get first byte of area object
 3308             cmp #$fd                 ;if end-of-area, skip all this crap
 3309             beq RdyDecode
 3310             lda AreaObjectLength,x   ;check area object buffer flag
 3311             bpl RdyDecode            ;if buffer not negative, branch, otherwise
 3312             iny
 3313             lda (AreaData),y         ;get second byte of area object
 3314             asl                      ;check for page select bit (d7), branch if not set
 3315             bcc Chk1Row13
 3316             lda AreaObjectPageSel    ;check page select
 3317             bne Chk1Row13
 3318             inc AreaObjectPageSel    ;if not already set, set it now
 3319             inc AreaObjectPageLoc    ;and increment page location
 3320 Chk1Row13:  dey
 3321             lda (AreaData),y         ;reread first byte of level object
 3322             and #$0f                 ;mask out high nybble
 3323             cmp #$0d                 ;row 13?
 3324             bne Chk1Row14
 3325             iny                      ;if so, reread second byte of level object
 3326             lda (AreaData),y
 3327             dey                      ;decrement to get ready to read first byte
 3328             and #%01000000           ;check for d6 set (if not, object is page control)
 3329             bne CheckRear
 3330             lda AreaObjectPageSel    ;if page select is set, do not reread
 3331             bne CheckRear
 3332             iny                      ;if d6 not set, reread second byte
 3333             lda (AreaData),y
 3334             and #%00011111           ;mask out all but 5 LSB and store in page control
 3335             sta AreaObjectPageLoc
 3336             inc AreaObjectPageSel    ;increment page select
 3337             jmp NextAObj
 3338 Chk1Row14:  cmp #$0e                 ;row 14?
 3339             bne CheckRear
 3340             lda BackloadingFlag      ;check flag for saved page number and branch if set
 3341             bne RdyDecode            ;to render the object (otherwise bg might not look right)
 3342 CheckRear:  lda AreaObjectPageLoc    ;check to see if current page of level object is
 3343             cmp CurrentPageLoc       ;behind current page of renderer
 3344             bcc SetBehind            ;if so branch
 3345 RdyDecode:  jsr DecodeAreaData       ;do sub and do not turn on flag
 3346             jmp ChkLength
 3347 SetBehind:  inc BehindAreaParserFlag ;turn on flag if object is behind renderer
 3348 NextAObj:   jsr IncAreaObjOffset     ;increment buffer offset and move on
 3349 ChkLength:  ldx ObjectOffset         ;get buffer offset
 3350             lda AreaObjectLength,x   ;check object length for anything stored here
 3351             bmi ProcLoopb            ;if not, branch to handle loopback
 3352             dec AreaObjectLength,x   ;otherwise decrement length or get rid of it
 3353 ProcLoopb:  dex                      ;decrement buffer offset
 3354             bpl ProcADLoop           ;and loopback unless exceeded buffer
 3355             lda BehindAreaParserFlag ;check for flag set if objects were behind renderer
 3356             bne ProcessAreaData      ;branch if true to load more level data, otherwise
 3357             lda BackloadingFlag      ;check for flag set if starting right of page $00
 3358             bne ProcessAreaData      ;branch if true to load more level data, otherwise leave
 3359 EndAParse:  rts
 3360 
 3361 IncAreaObjOffset:
 3362       inc AreaDataOffset    ;increment offset of level pointer
 3363       inc AreaDataOffset
 3364       lda #$00              ;reset page select
 3365       sta AreaObjectPageSel
 3366       rts
 3367 
 3368 DecodeAreaData:
 3369           lda AreaObjectLength,x     ;check current buffer flag
 3370           bmi Chk1stB
 3371           ldy AreaObjOffsetBuffer,x  ;if not, get offset from buffer
 3372 Chk1stB:  ldx #$10                   ;load offset of 16 for special row 15
 3373           lda (AreaData),y           ;get first byte of level object again
 3374           cmp #$fd
 3375           beq EndAParse              ;if end of level, leave this routine
 3376           and #$0f                   ;otherwise, mask out low nybble
 3377           cmp #$0f                   ;row 15?
 3378           beq ChkRow14               ;if so, keep the offset of 16
 3379           ldx #$08                   ;otherwise load offset of 8 for special row 12
 3380           cmp #$0c                   ;row 12?
 3381           beq ChkRow14               ;if so, keep the offset value of 8
 3382           ldx #$00                   ;otherwise nullify value by default
 3383 ChkRow14: stx $07                    ;store whatever value we just loaded here
 3384           ldx ObjectOffset           ;get object offset again
 3385           cmp #$0e                   ;row 14?
 3386           bne ChkRow13
 3387           lda #$00                   ;if so, load offset with $00
 3388           sta $07
 3389           lda #$2e                   ;and load A with another value
 3390           bne NormObj                ;unconditional branch
 3391 ChkRow13: cmp #$0d                   ;row 13?
 3392           bne ChkSRows
 3393           lda #$22                   ;if so, load offset with 34
 3394           sta $07
 3395           iny                        ;get next byte
 3396           lda (AreaData),y
 3397           and #%01000000             ;mask out all but d6 (page control obj bit)
 3398           beq LeavePar               ;if d6 clear, branch to leave (we handled this earlier)
 3399           lda (AreaData),y           ;otherwise, get byte again
 3400           and #%01111111             ;mask out d7
 3401           cmp #$4b                   ;check for loop command in low nybble
 3402           bne Mask2MSB               ;(plus d6 set for object other than page control)
 3403           inc LoopCommand            ;if loop command, set loop command flag
 3404 Mask2MSB: and #%00111111             ;mask out d7 and d6
 3405           jmp NormObj                ;and jump
 3406 ChkSRows: cmp #$0c                   ;row 12-15?
 3407           bcs SpecObj
 3408           iny                        ;if not, get second byte of level object
 3409           lda (AreaData),y
 3410           and #%01110000             ;mask out all but d6-d4
 3411           bne LrgObj                 ;if any bits set, branch to handle large object
 3412           lda #$16
 3413           sta $07                    ;otherwise set offset of 24 for small object
 3414           lda (AreaData),y           ;reload second byte of level object
 3415           and #%00001111             ;mask out higher nybble and jump
 3416           jmp NormObj
 3417 LrgObj:   sta $00                    ;store value here (branch for large objects)
 3418           cmp #$70                   ;check for vertical pipe object
 3419           bne NotWPipe
 3420           lda (AreaData),y           ;if not, reload second byte
 3421           and #%00001000             ;mask out all but d3 (usage control bit)
 3422           beq NotWPipe               ;if d3 clear, branch to get original value
 3423           lda #$00                   ;otherwise, nullify value for warp pipe
 3424           sta $00
 3425 NotWPipe: lda $00                    ;get value and jump ahead
 3426           jmp MoveAOId
 3427 SpecObj:  iny                        ;branch here for rows 12-15
 3428           lda (AreaData),y
 3429           and #%01110000             ;get next byte and mask out all but d6-d4
 3430 MoveAOId: lsr                        ;move d6-d4 to lower nybble
 3431           lsr
 3432           lsr
 3433           lsr
 3434 NormObj:  sta $00                    ;store value here (branch for small objects and rows 13 and 14)
 3435           lda AreaObjectLength,x     ;is there something stored here already?
 3436           bpl RunAObj                ;if so, branch to do its particular sub
 3437           lda AreaObjectPageLoc      ;otherwise check to see if the object we've loaded is on the
 3438           cmp CurrentPageLoc         ;same page as the renderer, and if so, branch
 3439           beq InitRear
 3440           ldy AreaDataOffset         ;if not, get old offset of level pointer
 3441           lda (AreaData),y           ;and reload first byte
 3442           and #%00001111
 3443           cmp #$0e                   ;row 14?
 3444           bne LeavePar
 3445           lda BackloadingFlag        ;if so, check backloading flag
 3446           bne StrAObj                ;if set, branch to render object, else leave
 3447 LeavePar: rts
 3448 InitRear: lda BackloadingFlag        ;check backloading flag to see if it's been initialized
 3449           beq BackColC               ;branch to column-wise check
 3450           lda #$00                   ;if not, initialize both backloading and 
 3451           sta BackloadingFlag        ;behind-renderer flags and leave
 3452           sta BehindAreaParserFlag
 3453           sta ObjectOffset
 3454 LoopCmdE: rts
 3455 BackColC: ldy AreaDataOffset         ;get first byte again
 3456           lda (AreaData),y
 3457           and #%11110000             ;mask out low nybble and move high to low
 3458           lsr
 3459           lsr
 3460           lsr
 3461           lsr
 3462           cmp CurrentColumnPos       ;is this where we're at?
 3463           bne LeavePar               ;if not, branch to leave
 3464 StrAObj:  lda AreaDataOffset         ;if so, load area obj offset and store in buffer
 3465           sta AreaObjOffsetBuffer,x
 3466           jsr IncAreaObjOffset       ;do sub to increment to next object data
 3467 RunAObj:  lda $00                    ;get stored value and add offset to it
 3468           clc                        ;then use the jump engine with current contents of A
 3469           adc $07
 3470           jsr JumpEngine
 3471 
 3472 ;large objects (rows $00-$0b or 00-11, d6-d4 set)
 3473       .dw VerticalPipe         ;used by warp pipes
 3474       .dw AreaStyleObject
 3475       .dw RowOfBricks
 3476       .dw RowOfSolidBlocks
 3477       .dw RowOfCoins
 3478       .dw ColumnOfBricks
 3479       .dw ColumnOfSolidBlocks
 3480       .dw VerticalPipe         ;used by decoration pipes
 3481 
 3482 ;objects for special row $0c or 12
 3483       .dw Hole_Empty
 3484       .dw PulleyRopeObject
 3485       .dw Bridge_High
 3486       .dw Bridge_Middle
 3487       .dw Bridge_Low
 3488       .dw Hole_Water
 3489       .dw QuestionBlockRow_High
 3490       .dw QuestionBlockRow_Low
 3491 
 3492 ;objects for special row $0f or 15
 3493       .dw EndlessRope
 3494       .dw BalancePlatRope
 3495       .dw CastleObject
 3496       .dw StaircaseObject
 3497       .dw ExitPipe
 3498       .dw FlagBalls_Residual
 3499 
 3500 ;small objects (rows $00-$0b or 00-11, d6-d4 all clear)
 3501       .dw QuestionBlock     ;power-up
 3502       .dw QuestionBlock     ;coin
 3503       .dw QuestionBlock     ;hidden, coin
 3504       .dw Hidden1UpBlock    ;hidden, 1-up
 3505       .dw BrickWithItem     ;brick, power-up
 3506       .dw BrickWithItem     ;brick, vine
 3507       .dw BrickWithItem     ;brick, star
 3508       .dw BrickWithCoins    ;brick, coins
 3509       .dw BrickWithItem     ;brick, 1-up
 3510       .dw WaterPipe
 3511       .dw EmptyBlock
 3512       .dw Jumpspring
 3513 
 3514 ;objects for special row $0d or 13 (d6 set)
 3515       .dw IntroPipe
 3516       .dw FlagpoleObject
 3517       .dw AxeObj
 3518       .dw ChainObj
 3519       .dw CastleBridgeObj
 3520       .dw ScrollLockObject_Warp
 3521       .dw ScrollLockObject
 3522       .dw ScrollLockObject
 3523       .dw AreaFrenzy            ;flying cheep-cheeps 
 3524       .dw AreaFrenzy            ;bullet bills or swimming cheep-cheeps
 3525       .dw AreaFrenzy            ;stop frenzy
 3526       .dw LoopCmdE
 3527 
 3528 ;object for special row $0e or 14
 3529       .dw AlterAreaAttributes
 3530 
 3531 ;-------------------------------------------------------------------------------------
 3532 ;(these apply to all area object subroutines in this section unless otherwise stated)
 3533 ;$00 - used to store offset used to find object code
 3534 ;$07 - starts with adder from area parser, used to store row offset
 3535 
 3536 AlterAreaAttributes:
 3537          ldy AreaObjOffsetBuffer,x ;load offset for level object data saved in buffer
 3538          iny                       ;load second byte
 3539          lda (AreaData),y
 3540          pha                       ;save in stack for now
 3541          and #%01000000
 3542          bne Alter2                ;branch if d6 is set
 3543          pla
 3544          pha                       ;pull and push offset to copy to A
 3545          and #%00001111            ;mask out high nybble and store as
 3546          sta TerrainControl        ;new terrain height type bits
 3547          pla
 3548          and #%00110000            ;pull and mask out all but d5 and d4
 3549          lsr                       ;move bits to lower nybble and store
 3550          lsr                       ;as new background scenery bits
 3551          lsr
 3552          lsr
 3553          sta BackgroundScenery     ;then leave
 3554          rts
 3555 Alter2:  pla
 3556          and #%00000111            ;mask out all but 3 LSB
 3557          cmp #$04                  ;if four or greater, set color control bits
 3558          bcc SetFore               ;and nullify foreground scenery bits
 3559          sta BackgroundColorCtrl
 3560          lda #$00
 3561 SetFore: sta ForegroundScenery     ;otherwise set new foreground scenery bits
 3562          rts
 3563 
 3564 ;--------------------------------
 3565 
 3566 ScrollLockObject_Warp:
 3567          ldx #$04            ;load value of 4 for game text routine as default
 3568          lda WorldNumber     ;warp zone (4-3-2), then check world number
 3569          beq WarpNum
 3570          inx                 ;if world number > 1, increment for next warp zone (5)
 3571          ldy AreaType        ;check area type
 3572          dey
 3573          bne WarpNum         ;if ground area type, increment for last warp zone
 3574          inx                 ;(8-7-6) and move on
 3575 WarpNum: txa
 3576          sta WarpZoneControl ;store number here to be used by warp zone routine
 3577          jsr WriteGameText   ;print text and warp zone numbers
 3578          lda #PiranhaPlant
 3579          jsr KillEnemies     ;load identifier for piranha plants and do sub
 3580 
 3581 ScrollLockObject:
 3582       lda ScrollLock      ;invert scroll lock to turn it on
 3583       eor #%00000001
 3584       sta ScrollLock
 3585       rts
 3586 
 3587 ;--------------------------------
 3588 ;$00 - used to store enemy identifier in KillEnemies
 3589 
 3590 KillEnemies:
 3591            sta $00           ;store identifier here
 3592            lda #$00
 3593            ldx #$04          ;check for identifier in enemy object buffer
 3594 KillELoop: ldy Enemy_ID,x
 3595            cpy $00           ;if not found, branch
 3596            bne NoKillE
 3597            sta Enemy_Flag,x  ;if found, deactivate enemy object flag
 3598 NoKillE:   dex               ;do this until all slots are checked
 3599            bpl KillELoop
 3600            rts
 3601 
 3602 ;--------------------------------
 3603 
 3604 FrenzyIDData:
 3605       .db FlyCheepCheepFrenzy, BBill_CCheep_Frenzy, Stop_Frenzy
 3606 
 3607 AreaFrenzy:  ldx $00               ;use area object identifier bit as offset
 3608              lda FrenzyIDData-8,x  ;note that it starts at 8, thus weird address here
 3609              ldy #$05
 3610 FreCompLoop: dey                   ;check regular slots of enemy object buffer
 3611              bmi ExitAFrenzy       ;if all slots checked and enemy object not found, branch to store
 3612              cmp Enemy_ID,y    ;check for enemy object in buffer versus frenzy object
 3613              bne FreCompLoop
 3614              lda #$00              ;if enemy object already present, nullify queue and leave
 3615 ExitAFrenzy: sta EnemyFrenzyQueue  ;store enemy into frenzy queue
 3616              rts
 3617 
 3618 ;--------------------------------
 3619 ;$06 - used by MushroomLedge to store length
 3620 
 3621 AreaStyleObject:
 3622       lda AreaStyle        ;load level object style and jump to the right sub
 3623       jsr JumpEngine 
 3624       .dw TreeLedge        ;also used for cloud type levels
 3625       .dw MushroomLedge
 3626       .dw BulletBillCannon
 3627 
 3628 TreeLedge:
 3629           jsr GetLrgObjAttrib     ;get row and length of green ledge
 3630           lda AreaObjectLength,x  ;check length counter for expiration
 3631           beq EndTreeL   
 3632           bpl MidTreeL
 3633           tya
 3634           sta AreaObjectLength,x  ;store lower nybble into buffer flag as length of ledge
 3635           lda CurrentPageLoc
 3636           ora CurrentColumnPos    ;are we at the start of the level?
 3637           beq MidTreeL
 3638           lda #$16                ;render start of tree ledge
 3639           jmp NoUnder
 3640 MidTreeL: ldx $07
 3641           lda #$17                ;render middle of tree ledge
 3642           sta MetatileBuffer,x    ;note that this is also used if ledge position is
 3643           lda #$4c                ;at the start of level for continuous effect
 3644           jmp AllUnder            ;now render the part underneath
 3645 EndTreeL: lda #$18                ;render end of tree ledge
 3646           jmp NoUnder
 3647 
 3648 MushroomLedge:
 3649           jsr ChkLrgObjLength        ;get shroom dimensions
 3650           sty $06                    ;store length here for now
 3651           bcc EndMushL
 3652           lda AreaObjectLength,x     ;divide length by 2 and store elsewhere
 3653           lsr
 3654           sta MushroomLedgeHalfLen,x
 3655           lda #$19                   ;render start of mushroom
 3656           jmp NoUnder
 3657 EndMushL: lda #$1b                   ;if at the end, render end of mushroom
 3658           ldy AreaObjectLength,x
 3659           beq NoUnder
 3660           lda MushroomLedgeHalfLen,x ;get divided length and store where length
 3661           sta $06                    ;was stored originally
 3662           ldx $07
 3663           lda #$1a
 3664           sta MetatileBuffer,x       ;render middle of mushroom
 3665           cpy $06                    ;are we smack dab in the center?
 3666           bne MushLExit              ;if not, branch to leave
 3667           inx
 3668           lda #$4f
 3669           sta MetatileBuffer,x       ;render stem top of mushroom underneath the middle
 3670           lda #$50
 3671 AllUnder: inx
 3672           ldy #$0f                   ;set $0f to render all way down
 3673           jmp RenderUnderPart       ;now render the stem of mushroom
 3674 NoUnder:  ldx $07                    ;load row of ledge
 3675           ldy #$00                   ;set 0 for no bottom on this part
 3676           jmp RenderUnderPart
 3677 
 3678 ;--------------------------------
 3679 
 3680 ;tiles used by pulleys and rope object
 3681 PulleyRopeMetatiles:
 3682       .db $42, $41, $43
 3683 
 3684 PulleyRopeObject:
 3685            jsr ChkLrgObjLength       ;get length of pulley/rope object
 3686            ldy #$00                  ;initialize metatile offset
 3687            bcs RenderPul             ;if starting, render left pulley
 3688            iny
 3689            lda AreaObjectLength,x    ;if not at the end, render rope
 3690            bne RenderPul
 3691            iny                       ;otherwise render right pulley
 3692 RenderPul: lda PulleyRopeMetatiles,y
 3693            sta MetatileBuffer        ;render at the top of the screen
 3694 MushLExit: rts                       ;and leave
 3695 
 3696 ;--------------------------------
 3697 ;$06 - used to store upper limit of rows for CastleObject
 3698 
 3699 CastleMetatiles:
 3700       .db $00, $45, $45, $45, $00
 3701       .db $00, $48, $47, $46, $00
 3702       .db $45, $49, $49, $49, $45
 3703       .db $47, $47, $4a, $47, $47
 3704       .db $47, $47, $4b, $47, $47
 3705       .db $49, $49, $49, $49, $49
 3706       .db $47, $4a, $47, $4a, $47
 3707       .db $47, $4b, $47, $4b, $47
 3708       .db $47, $47, $47, $47, $47
 3709       .db $4a, $47, $4a, $47, $4a
 3710       .db $4b, $47, $4b, $47, $4b
 3711 
 3712 CastleObject:
 3713             jsr GetLrgObjAttrib      ;save lower nybble as starting row
 3714             sty $07                  ;if starting row is above $0a, game will crash!!!
 3715             ldy #$04
 3716             jsr ChkLrgObjFixedLength ;load length of castle if not already loaded
 3717             txa                  
 3718             pha                      ;save obj buffer offset to stack
 3719             ldy AreaObjectLength,x   ;use current length as offset for castle data
 3720             ldx $07                  ;begin at starting row
 3721             lda #$0b
 3722             sta $06                  ;load upper limit of number of rows to print
 3723 CRendLoop:  lda CastleMetatiles,y    ;load current byte using offset
 3724             sta MetatileBuffer,x
 3725             inx                      ;store in buffer and increment buffer offset
 3726             lda $06
 3727             beq ChkCFloor            ;have we reached upper limit yet?
 3728             iny                      ;if not, increment column-wise
 3729             iny                      ;to byte in next row
 3730             iny
 3731             iny
 3732             iny
 3733             dec $06                  ;move closer to upper limit
 3734 ChkCFloor:  cpx #$0b                 ;have we reached the row just before floor?
 3735             bne CRendLoop            ;if not, go back and do another row
 3736             pla
 3737             tax                      ;get obj buffer offset from before
 3738             lda CurrentPageLoc
 3739             beq ExitCastle           ;if we're at page 0, we do not need to do anything else
 3740             lda AreaObjectLength,x   ;check length
 3741             cmp #$01                 ;if length almost about to expire, put brick at floor
 3742             beq PlayerStop
 3743             ldy $07                  ;check starting row for tall castle ($00)
 3744             bne NotTall
 3745             cmp #$03                 ;if found, then check to see if we're at the second column
 3746             beq PlayerStop
 3747 NotTall:    cmp #$02                 ;if not tall castle, check to see if we're at the third column
 3748             bne ExitCastle           ;if we aren't and the castle is tall, don't create flag yet
 3749             jsr GetAreaObjXPosition  ;otherwise, obtain and save horizontal pixel coordinate
 3750             pha
 3751             jsr FindEmptyEnemySlot   ;find an empty place on the enemy object buffer
 3752             pla
 3753             sta Enemy_X_Position,x   ;then write horizontal coordinate for star flag
 3754             lda CurrentPageLoc
 3755             sta Enemy_PageLoc,x      ;set page location for star flag
 3756             lda #$01
 3757             sta Enemy_Y_HighPos,x    ;set vertical high byte
 3758             sta Enemy_Flag,x         ;set flag for buffer
 3759             lda #$90
 3760             sta Enemy_Y_Position,x   ;set vertical coordinate
 3761             lda #StarFlagObject      ;set star flag value in buffer itself
 3762             sta Enemy_ID,x
 3763             rts
 3764 PlayerStop: ldy #$52                 ;put brick at floor to stop player at end of level
 3765             sty MetatileBuffer+10    ;this is only done if we're on the second column
 3766 ExitCastle: rts
 3767 
 3768 ;--------------------------------
 3769 
 3770 WaterPipe:
 3771       jsr GetLrgObjAttrib     ;get row and lower nybble
 3772       ldy AreaObjectLength,x  ;get length (residual code, water pipe is 1 col thick)
 3773       ldx $07                 ;get row
 3774       lda #$6b
 3775       sta MetatileBuffer,x    ;draw something here and below it
 3776       lda #$6c
 3777       sta MetatileBuffer+1,x
 3778       rts
 3779 
 3780 ;--------------------------------
 3781 ;$05 - used to store length of vertical shaft in RenderSidewaysPipe
 3782 ;$06 - used to store leftover horizontal length in RenderSidewaysPipe
 3783 ; and vertical length in VerticalPipe and GetPipeHeight
 3784 
 3785 IntroPipe:
 3786                ldy #$03                 ;check if length set, if not set, set it
 3787                jsr ChkLrgObjFixedLength
 3788                ldy #$0a                 ;set fixed value and render the sideways part
 3789                jsr RenderSidewaysPipe
 3790                bcs NoBlankP             ;if carry flag set, not time to draw vertical pipe part
 3791                ldx #$06                 ;blank everything above the vertical pipe part
 3792 VPipeSectLoop: lda #$00                 ;all the way to the top of the screen
 3793                sta MetatileBuffer,x     ;because otherwise it will look like exit pipe
 3794                dex
 3795                bpl VPipeSectLoop
 3796                lda VerticalPipeData,y   ;draw the end of the vertical pipe part
 3797                sta MetatileBuffer+7
 3798 NoBlankP:      rts
 3799 
 3800 SidePipeShaftData:
 3801       .db $15, $14  ;used to control whether or not vertical pipe shaft
 3802       .db $00, $00  ;is drawn, and if so, controls the metatile number
 3803 SidePipeTopPart:
 3804       .db $15, $1e  ;top part of sideways part of pipe
 3805       .db $1d, $1c
 3806 SidePipeBottomPart: 
 3807       .db $15, $21  ;bottom part of sideways part of pipe
 3808       .db $20, $1f
 3809 
 3810 ExitPipe:
 3811       ldy #$03                 ;check if length set, if not set, set it
 3812       jsr ChkLrgObjFixedLength
 3813       jsr GetLrgObjAttrib      ;get vertical length, then plow on through RenderSidewaysPipe
 3814 
 3815 RenderSidewaysPipe:
 3816               dey                       ;decrement twice to make room for shaft at bottom
 3817               dey                       ;and store here for now as vertical length
 3818               sty $05
 3819               ldy AreaObjectLength,x    ;get length left over and store here
 3820               sty $06
 3821               ldx $05                   ;get vertical length plus one, use as buffer offset
 3822               inx
 3823               lda SidePipeShaftData,y   ;check for value $00 based on horizontal offset
 3824               cmp #$00
 3825               beq DrawSidePart          ;if found, do not draw the vertical pipe shaft
 3826               ldx #$00
 3827               ldy $05                   ;init buffer offset and get vertical length
 3828               jsr RenderUnderPart       ;and render vertical shaft using tile number in A
 3829               clc                       ;clear carry flag to be used by IntroPipe
 3830 DrawSidePart: ldy $06                   ;render side pipe part at the bottom
 3831               lda SidePipeTopPart,y
 3832               sta MetatileBuffer,x      ;note that the pipe parts are stored
 3833               lda SidePipeBottomPart,y  ;backwards horizontally
 3834               sta MetatileBuffer+1,x
 3835               rts
 3836 
 3837 VerticalPipeData:
 3838       .db $11, $10 ;used by pipes that lead somewhere
 3839       .db $15, $14
 3840       .db $13, $12 ;used by decoration pipes
 3841       .db $15, $14
 3842 
 3843 VerticalPipe:
 3844           jsr GetPipeHeight
 3845           lda $00                  ;check to see if value was nullified earlier
 3846           beq WarpPipe             ;(if d3, the usage control bit of second byte, was set)
 3847           iny
 3848           iny
 3849           iny
 3850           iny                      ;add four if usage control bit was not set
 3851 WarpPipe: tya                      ;save value in stack
 3852           pha
 3853           lda AreaNumber
 3854           ora WorldNumber          ;if at world 1-1, do not add piranha plant ever
 3855           beq DrawPipe
 3856           ldy AreaObjectLength,x   ;if on second column of pipe, branch
 3857           beq DrawPipe             ;(because we only need to do this once)
 3858           jsr FindEmptyEnemySlot   ;check for an empty moving data buffer space
 3859           bcs DrawPipe             ;if not found, too many enemies, thus skip
 3860           jsr GetAreaObjXPosition  ;get horizontal pixel coordinate
 3861           clc
 3862           adc #$08                 ;add eight to put the piranha plant in the center
 3863           sta Enemy_X_Position,x   ;store as enemy's horizontal coordinate
 3864           lda CurrentPageLoc       ;add carry to current page number
 3865           adc #$00
 3866           sta Enemy_PageLoc,x      ;store as enemy's page coordinate
 3867           lda #$01
 3868           sta Enemy_Y_HighPos,x
 3869           sta Enemy_Flag,x         ;activate enemy flag
 3870           jsr GetAreaObjYPosition  ;get piranha plant's vertical coordinate and store here
 3871           sta Enemy_Y_Position,x
 3872           lda #PiranhaPlant        ;write piranha plant's value into buffer
 3873           sta Enemy_ID,x
 3874           jsr InitPiranhaPlant
 3875 DrawPipe: pla                      ;get value saved earlier and use as Y
 3876           tay
 3877           ldx $07                  ;get buffer offset
 3878           lda VerticalPipeData,y   ;draw the appropriate pipe with the Y we loaded earlier
 3879           sta MetatileBuffer,x     ;render the top of the pipe
 3880           inx
 3881           lda VerticalPipeData+2,y ;render the rest of the pipe
 3882           ldy $06                  ;subtract one from length and render the part underneath
 3883           dey
 3884           jmp RenderUnderPart
 3885       
 3886 GetPipeHeight:
 3887       ldy #$01       ;check for length loaded, if not, load
 3888       jsr ChkLrgObjFixedLength ;pipe length of 2 (horizontal)
 3889       jsr GetLrgObjAttrib
 3890       tya            ;get saved lower nybble as height
 3891       and #$07       ;save only the three lower bits as
 3892       sta $06        ;vertical length, then load Y with
 3893       ldy AreaObjectLength,x    ;length left over
 3894       rts
 3895 
 3896 FindEmptyEnemySlot:
 3897               ldx #$00          ;start at first enemy slot
 3898 EmptyChkLoop: clc               ;clear carry flag by default
 3899               lda Enemy_Flag,x  ;check enemy buffer for nonzero
 3900               beq ExitEmptyChk  ;if zero, leave
 3901               inx
 3902               cpx #$05          ;if nonzero, check next value
 3903               bne EmptyChkLoop
 3904 ExitEmptyChk: rts               ;if all values nonzero, carry flag is set
 3905 
 3906 ;--------------------------------
 3907 
 3908 Hole_Water:
 3909       jsr ChkLrgObjLength   ;get low nybble and save as length
 3910       lda #$86              ;render waves
 3911       sta MetatileBuffer+10
 3912       ldx #$0b
 3913       ldy #$01              ;now render the water underneath
 3914       lda #$87
 3915       jmp RenderUnderPart
 3916 
 3917 ;--------------------------------
 3918 
 3919 QuestionBlockRow_High:
 3920       lda #$03    ;start on the fourth row
 3921       .db $2c     ;BIT instruction opcode
 3922 
 3923 QuestionBlockRow_Low:
 3924       lda #$07             ;start on the eighth row
 3925       pha                  ;save whatever row to the stack for now
 3926       jsr ChkLrgObjLength  ;get low nybble and save as length
 3927       pla
 3928       tax                  ;render question boxes with coins
 3929       lda #$c0
 3930       sta MetatileBuffer,x
 3931       rts
 3932 
 3933 ;--------------------------------
 3934 
 3935 Bridge_High:
 3936       lda #$06  ;start on the seventh row from top of screen
 3937       .db $2c   ;BIT instruction opcode
 3938 
 3939 Bridge_Middle:
 3940       lda #$07  ;start on the eighth row
 3941       .db $2c   ;BIT instruction opcode
 3942 
 3943 Bridge_Low:
 3944       lda #$09             ;start on the tenth row
 3945       pha                  ;save whatever row to the stack for now
 3946       jsr ChkLrgObjLength  ;get low nybble and save as length
 3947       pla
 3948       tax                  ;render bridge railing
 3949       lda #$0b
 3950       sta MetatileBuffer,x
 3951       inx
 3952       ldy #$00             ;now render the bridge itself
 3953       lda #$63
 3954       jmp RenderUnderPart
 3955 
 3956 ;--------------------------------
 3957 
 3958 FlagBalls_Residual:
 3959       jsr GetLrgObjAttrib  ;get low nybble from object byte
 3960       ldx #$02             ;render flag balls on third row from top
 3961       lda #$6d             ;of screen downwards based on low nybble
 3962       jmp RenderUnderPart
 3963 
 3964 ;--------------------------------
 3965 
 3966 FlagpoleObject:
 3967       lda #$24                 ;render flagpole ball on top
 3968       sta MetatileBuffer
 3969       ldx #$01                 ;now render the flagpole shaft
 3970       ldy #$08
 3971       lda #$25
 3972       jsr RenderUnderPart
 3973       lda #$61                 ;render solid block at the bottom
 3974       sta MetatileBuffer+10
 3975       jsr GetAreaObjXPosition
 3976       sec                      ;get pixel coordinate of where the flagpole is,
 3977       sbc #$08                 ;subtract eight pixels and use as horizontal
 3978       sta Enemy_X_Position+5   ;coordinate for the flag
 3979       lda CurrentPageLoc
 3980       sbc #$00                 ;subtract borrow from page location and use as
 3981       sta Enemy_PageLoc+5      ;page location for the flag
 3982       lda #$30
 3983       sta Enemy_Y_Position+5   ;set vertical coordinate for flag
 3984       lda #$b0
 3985       sta FlagpoleFNum_Y_Pos   ;set initial vertical coordinate for flagpole's floatey number
 3986       lda #FlagpoleFlagObject
 3987       sta Enemy_ID+5           ;set flag identifier, note that identifier and coordinates
 3988       inc Enemy_Flag+5         ;use last space in enemy object buffer
 3989       rts
 3990 
 3991 ;--------------------------------
 3992 
 3993 EndlessRope:
 3994       ldx #$00       ;render rope from the top to the bottom of screen
 3995       ldy #$0f
 3996       jmp DrawRope
 3997 
 3998 BalancePlatRope:
 3999           txa                 ;save object buffer offset for now
 4000           pha
 4001           ldx #$01            ;blank out all from second row to the bottom
 4002           ldy #$0f            ;with blank used for balance platform rope
 4003           lda #$44
 4004           jsr RenderUnderPart
 4005           pla                 ;get back object buffer offset
 4006           tax
 4007           jsr GetLrgObjAttrib ;get vertical length from lower nybble
 4008           ldx #$01
 4009 DrawRope: lda #$40            ;render the actual rope
 4010           jmp RenderUnderPart
 4011 
 4012 ;--------------------------------
 4013 
 4014 CoinMetatileData:
 4015       .db $c3, $c2, $c2, $c2
 4016 
 4017 RowOfCoins:
 4018       ldy AreaType            ;get area type
 4019       lda CoinMetatileData,y  ;load appropriate coin metatile
 4020       jmp GetRow
 4021 
 4022 ;--------------------------------
 4023 
 4024 C_ObjectRow:
 4025       .db $06, $07, $08
 4026 
 4027 C_ObjectMetatile:
 4028       .db $c5, $0c, $89
 4029 
 4030 CastleBridgeObj:
 4031       ldy #$0c                  ;load length of 13 columns
 4032       jsr ChkLrgObjFixedLength
 4033       jmp ChainObj
 4034 
 4035 AxeObj:
 4036       lda #$08                  ;load bowser's palette into sprite portion of palette
 4037       sta VRAM_Buffer_AddrCtrl
 4038 
 4039 ChainObj:
 4040       ldy $00                   ;get value loaded earlier from decoder
 4041       ldx C_ObjectRow-2,y       ;get appropriate row and metatile for object
 4042       lda C_ObjectMetatile-2,y
 4043       jmp ColObj
 4044 
 4045 EmptyBlock:
 4046         jsr GetLrgObjAttrib  ;get row location
 4047         ldx $07
 4048         lda #$c4
 4049 ColObj: ldy #$00             ;column length of 1
 4050         jmp RenderUnderPart
 4051 
 4052 ;--------------------------------
 4053 
 4054 SolidBlockMetatiles:
 4055       .db $69, $61, $61, $62
 4056 
 4057 BrickMetatiles:
 4058       .db $22, $51, $52, $52
 4059       .db $88 ;used only by row of bricks object
 4060 
 4061 RowOfBricks:
 4062             ldy AreaType           ;load area type obtained from area offset pointer
 4063             lda CloudTypeOverride  ;check for cloud type override
 4064             beq DrawBricks
 4065             ldy #$04               ;if cloud type, override area type
 4066 DrawBricks: lda BrickMetatiles,y   ;get appropriate metatile
 4067             jmp GetRow             ;and go render it
 4068 
 4069 RowOfSolidBlocks:
 4070          ldy AreaType               ;load area type obtained from area offset pointer
 4071          lda SolidBlockMetatiles,y  ;get metatile
 4072 GetRow:  pha                        ;store metatile here
 4073          jsr ChkLrgObjLength        ;get row number, load length
 4074 DrawRow: ldx $07
 4075          ldy #$00                   ;set vertical height of 1
 4076          pla
 4077          jmp RenderUnderPart        ;render object
 4078 
 4079 ColumnOfBricks:
 4080       ldy AreaType          ;load area type obtained from area offset
 4081       lda BrickMetatiles,y  ;get metatile (no cloud override as for row)
 4082       jmp GetRow2
 4083 
 4084 ColumnOfSolidBlocks:
 4085          ldy AreaType               ;load area type obtained from area offset
 4086          lda SolidBlockMetatiles,y  ;get metatile
 4087 GetRow2: pha                        ;save metatile to stack for now
 4088          jsr GetLrgObjAttrib        ;get length and row
 4089          pla                        ;restore metatile
 4090          ldx $07                    ;get starting row
 4091          jmp RenderUnderPart        ;now render the column
 4092 
 4093 ;--------------------------------
 4094 
 4095 BulletBillCannon:
 4096              jsr GetLrgObjAttrib      ;get row and length of bullet bill cannon
 4097              ldx $07                  ;start at first row
 4098              lda #$64                 ;render bullet bill cannon
 4099              sta MetatileBuffer,x
 4100              inx
 4101              dey                      ;done yet?
 4102              bmi SetupCannon
 4103              lda #$65                 ;if not, render middle part
 4104              sta MetatileBuffer,x
 4105              inx
 4106              dey                      ;done yet?
 4107              bmi SetupCannon
 4108              lda #$66                 ;if not, render bottom until length expires
 4109              jsr RenderUnderPart
 4110 SetupCannon: ldx Cannon_Offset        ;get offset for data used by cannons and whirlpools
 4111              jsr GetAreaObjYPosition  ;get proper vertical coordinate for cannon
 4112              sta Cannon_Y_Position,x  ;and store it here
 4113              lda CurrentPageLoc
 4114              sta Cannon_PageLoc,x     ;store page number for cannon here
 4115              jsr GetAreaObjXPosition  ;get proper horizontal coordinate for cannon
 4116              sta Cannon_X_Position,x  ;and store it here
 4117              inx
 4118              cpx #$06                 ;increment and check offset
 4119              bcc StrCOffset           ;if not yet reached sixth cannon, branch to save offset
 4120              ldx #$00                 ;otherwise initialize it
 4121 StrCOffset:  stx Cannon_Offset        ;save new offset and leave
 4122              rts
 4123 
 4124 ;--------------------------------
 4125 
 4126 StaircaseHeightData:
 4127       .db $07, $07, $06, $05, $04, $03, $02, $01, $00
 4128 
 4129 StaircaseRowData:
 4130       .db $03, $03, $04, $05, $06, $07, $08, $09, $0a
 4131 
 4132 StaircaseObject:
 4133            jsr ChkLrgObjLength       ;check and load length
 4134            bcc NextStair             ;if length already loaded, skip init part
 4135            lda #$09                  ;start past the end for the bottom
 4136            sta StaircaseControl      ;of the staircase
 4137 NextStair: dec StaircaseControl      ;move onto next step (or first if starting)
 4138            ldy StaircaseControl
 4139            ldx StaircaseRowData,y    ;get starting row and height to render
 4140            lda StaircaseHeightData,y
 4141            tay
 4142            lda #$61                  ;now render solid block staircase
 4143            jmp RenderUnderPart
 4144 
 4145 ;--------------------------------
 4146 
 4147 Jumpspring:
 4148       jsr GetLrgObjAttrib
 4149       jsr FindEmptyEnemySlot      ;find empty space in enemy object buffer
 4150       jsr GetAreaObjXPosition     ;get horizontal coordinate for jumpspring
 4151       sta Enemy_X_Position,x      ;and store
 4152       lda CurrentPageLoc          ;store page location of jumpspring
 4153       sta Enemy_PageLoc,x
 4154       jsr GetAreaObjYPosition     ;get vertical coordinate for jumpspring
 4155       sta Enemy_Y_Position,x      ;and store
 4156       sta Jumpspring_FixedYPos,x  ;store as permanent coordinate here
 4157       lda #JumpspringObject
 4158       sta Enemy_ID,x              ;write jumpspring object to enemy object buffer
 4159       ldy #$01
 4160       sty Enemy_Y_HighPos,x       ;store vertical high byte
 4161       inc Enemy_Flag,x            ;set flag for enemy object buffer
 4162       ldx $07
 4163       lda #$67                    ;draw metatiles in two rows where jumpspring is
 4164       sta MetatileBuffer,x
 4165       lda #$68
 4166       sta MetatileBuffer+1,x
 4167       rts
 4168 
 4169 ;--------------------------------
 4170 ;$07 - used to save ID of brick object
 4171 
 4172 Hidden1UpBlock:
 4173       lda Hidden1UpFlag  ;if flag not set, do not render object
 4174       beq ExitDecBlock
 4175       lda #$00           ;if set, init for the next one
 4176       sta Hidden1UpFlag
 4177       jmp BrickWithItem  ;jump to code shared with unbreakable bricks
 4178 
 4179 QuestionBlock:
 4180       jsr GetAreaObjectID ;get value from level decoder routine
 4181       jmp DrawQBlk        ;go to render it
 4182 
 4183 BrickWithCoins:
 4184       lda #$00                 ;initialize multi-coin timer flag
 4185       sta BrickCoinTimerFlag
 4186 
 4187 BrickWithItem:
 4188           jsr GetAreaObjectID         ;save area object ID
 4189           sty $07              
 4190           lda #$00                    ;load default adder for bricks with lines
 4191           ldy AreaType                ;check level type for ground level
 4192           dey
 4193           beq BWithL                  ;if ground type, do not start with 5
 4194           lda #$05                    ;otherwise use adder for bricks without lines
 4195 BWithL:   clc                         ;add object ID to adder
 4196           adc $07
 4197           tay                         ;use as offset for metatile
 4198 DrawQBlk: lda BrickQBlockMetatiles,y  ;get appropriate metatile for brick (question block
 4199           pha                         ;if branched to here from question block routine)
 4200           jsr GetLrgObjAttrib         ;get row from location byte
 4201           jmp DrawRow                 ;now render the object
 4202 
 4203 GetAreaObjectID:
 4204               lda $00    ;get value saved from area parser routine
 4205               sec
 4206               sbc #$00   ;possibly residual code
 4207               tay        ;save to Y
 4208 ExitDecBlock: rts
 4209 
 4210 ;--------------------------------
 4211 
 4212 HoleMetatiles:
 4213       .db $87, $00, $00, $00
 4214 
 4215 Hole_Empty:
 4216             jsr ChkLrgObjLength          ;get lower nybble and save as length
 4217             bcc NoWhirlP                 ;skip this part if length already loaded
 4218             lda AreaType                 ;check for water type level
 4219             bne NoWhirlP                 ;if not water type, skip this part
 4220             ldx Whirlpool_Offset         ;get offset for data used by cannons and whirlpools
 4221             jsr GetAreaObjXPosition      ;get proper vertical coordinate of where we're at
 4222             sec
 4223             sbc #$10                     ;subtract 16 pixels
 4224             sta Whirlpool_LeftExtent,x   ;store as left extent of whirlpool
 4225             lda CurrentPageLoc           ;get page location of where we're at
 4226             sbc #$00                     ;subtract borrow
 4227             sta Whirlpool_PageLoc,x      ;save as page location of whirlpool
 4228             iny
 4229             iny                          ;increment length by 2
 4230             tya
 4231             asl                          ;multiply by 16 to get size of whirlpool
 4232             asl                          ;note that whirlpool will always be
 4233             asl                          ;two blocks bigger than actual size of hole
 4234             asl                          ;and extend one block beyond each edge
 4235             sta Whirlpool_Length,x       ;save size of whirlpool here
 4236             inx
 4237             cpx #$05                     ;increment and check offset
 4238             bcc StrWOffset               ;if not yet reached fifth whirlpool, branch to save offset
 4239             ldx #$00                     ;otherwise initialize it
 4240 StrWOffset: stx Whirlpool_Offset         ;save new offset here
 4241 NoWhirlP:   ldx AreaType                 ;get appropriate metatile, then
 4242             lda HoleMetatiles,x          ;render the hole proper
 4243             ldx #$08
 4244             ldy #$0f                     ;start at ninth row and go to bottom, run RenderUnderPart
 4245 
 4246 ;--------------------------------
 4247 
 4248 RenderUnderPart:
 4249              sty AreaObjectHeight  ;store vertical length to render
 4250              ldy MetatileBuffer,x  ;check current spot to see if there's something
 4251              beq DrawThisRow       ;we need to keep, if nothing, go ahead
 4252              cpy #$17
 4253              beq WaitOneRow        ;if middle part (tree ledge), wait until next row
 4254              cpy #$1a
 4255              beq WaitOneRow        ;if middle part (mushroom ledge), wait until next row
 4256              cpy #$c0
 4257              beq DrawThisRow       ;if question block w/ coin, overwrite
 4258              cpy #$c0
 4259              bcs WaitOneRow        ;if any other metatile with palette 3, wait until next row
 4260              cpy #$54
 4261              bne DrawThisRow       ;if cracked rock terrain, overwrite
 4262              cmp #$50
 4263              beq WaitOneRow        ;if stem top of mushroom, wait until next row
 4264 DrawThisRow: sta MetatileBuffer,x  ;render contents of A from routine that called this
 4265 WaitOneRow:  inx
 4266              cpx #$0d              ;stop rendering if we're at the bottom of the screen
 4267              bcs ExitUPartR
 4268              ldy AreaObjectHeight  ;decrement, and stop rendering if there is no more length
 4269              dey
 4270              bpl RenderUnderPart
 4271 ExitUPartR:  rts
 4272 
 4273 ;--------------------------------
 4274 
 4275 ChkLrgObjLength:
 4276         jsr GetLrgObjAttrib     ;get row location and size (length if branched to from here)
 4277 
 4278 ChkLrgObjFixedLength:
 4279         lda AreaObjectLength,x  ;check for set length counter
 4280         clc                     ;clear carry flag for not just starting
 4281         bpl LenSet              ;if counter not set, load it, otherwise leave alone
 4282         tya                     ;save length into length counter
 4283         sta AreaObjectLength,x
 4284         sec                     ;set carry flag if just starting
 4285 LenSet: rts
 4286 
 4287 
 4288 GetLrgObjAttrib:
 4289       ldy AreaObjOffsetBuffer,x ;get offset saved from area obj decoding routine
 4290       lda (AreaData),y          ;get first byte of level object
 4291       and #%00001111
 4292       sta $07                   ;save row location
 4293       iny
 4294       lda (AreaData),y          ;get next byte, save lower nybble (length or height)
 4295       and #%00001111            ;as Y, then leave
 4296       tay
 4297       rts
 4298 
 4299 ;--------------------------------
 4300 
 4301 GetAreaObjXPosition:
 4302       lda CurrentColumnPos    ;multiply current offset where we're at by 16
 4303       asl                     ;to obtain horizontal pixel coordinate
 4304       asl
 4305       asl
 4306       asl
 4307       rts
 4308 
 4309 ;--------------------------------
 4310 
 4311 GetAreaObjYPosition:
 4312       lda $07  ;multiply value by 16
 4313       asl
 4314       asl      ;this will give us the proper vertical pixel coordinate
 4315       asl
 4316       asl
 4317       clc
 4318       adc #32  ;add 32 pixels for the status bar
 4319       rts
 4320 
 4321 ;-------------------------------------------------------------------------------------
 4322 ;$06-$07 - used to store block buffer address used as indirect
 4323 
 4324 BlockBufferAddr:
 4325       .db <Block_Buffer_1, <Block_Buffer_2
 4326       .db >Block_Buffer_1, >Block_Buffer_2
 4327 
 4328 GetBlockBufferAddr:
 4329       pha                      ;take value of A, save
 4330       lsr                      ;move high nybble to low
 4331       lsr
 4332       lsr
 4333       lsr
 4334       tay                      ;use nybble as pointer to high byte
 4335       lda BlockBufferAddr+2,y  ;of indirect here
 4336       sta $07
 4337       pla
 4338       and #%00001111           ;pull from stack, mask out high nybble
 4339       clc
 4340       adc BlockBufferAddr,y    ;add to low byte
 4341       sta $06                  ;store here and leave
 4342       rts
 4343 
 4344 ;-------------------------------------------------------------------------------------
 4345 
 4346 ;unused space
 4347       .db $ff, $ff
 4348 
 4349 ;-------------------------------------------------------------------------------------
 4350 
 4351 AreaDataOfsLoopback:
 4352       .db $12, $36, $0e, $0e, $0e, $32, $32, $32, $0a, $26, $40
 4353 
 4354 ;-------------------------------------------------------------------------------------
 4355 
 4356 LoadAreaPointer:
 4357              jsr FindAreaPointer  ;find it and store it here
 4358              sta AreaPointer
 4359 GetAreaType: and #%01100000       ;mask out all but d6 and d5
 4360              asl
 4361              rol
 4362              rol
 4363              rol                  ;make %0xx00000 into %000000xx
 4364              sta AreaType         ;save 2 MSB as area type
 4365              rts
 4366 
 4367 FindAreaPointer:
 4368       ldy WorldNumber        ;load offset from world variable
 4369       lda WorldAddrOffsets,y
 4370       clc                    ;add area number used to find data
 4371       adc AreaNumber
 4372       tay
 4373       lda AreaAddrOffsets,y  ;from there we have our area pointer
 4374       rts
 4375 
 4376 
 4377 GetAreaDataAddrs:
 4378             lda AreaPointer          ;use 2 MSB for Y
 4379             jsr GetAreaType
 4380             tay
 4381             lda AreaPointer          ;mask out all but 5 LSB
 4382             and #%00011111
 4383             sta AreaAddrsLOffset     ;save as low offset
 4384             lda EnemyAddrHOffsets,y  ;load base value with 2 altered MSB,
 4385             clc                      ;then add base value to 5 LSB, result
 4386             adc AreaAddrsLOffset     ;becomes offset for level data
 4387             tay
 4388             lda EnemyDataAddrLow,y   ;use offset to load pointer
 4389             sta EnemyDataLow
 4390             lda EnemyDataAddrHigh,y
 4391             sta EnemyDataHigh
 4392             ldy AreaType             ;use area type as offset
 4393             lda AreaDataHOffsets,y   ;do the same thing but with different base value
 4394             clc
 4395             adc AreaAddrsLOffset        
 4396             tay
 4397             lda AreaDataAddrLow,y    ;use this offset to load another pointer
 4398             sta AreaDataLow
 4399             lda AreaDataAddrHigh,y
 4400             sta AreaDataHigh
 4401             ldy #$00                 ;load first byte of header
 4402             lda (AreaData),y     
 4403             pha                      ;save it to the stack for now
 4404             and #%00000111           ;save 3 LSB for foreground scenery or bg color control
 4405             cmp #$04
 4406             bcc StoreFore
 4407             sta BackgroundColorCtrl  ;if 4 or greater, save value here as bg color control
 4408             lda #$00
 4409 StoreFore:  sta ForegroundScenery    ;if less, save value here as foreground scenery
 4410             pla                      ;pull byte from stack and push it back
 4411             pha
 4412             and #%00111000           ;save player entrance control bits
 4413             lsr                      ;shift bits over to LSBs
 4414             lsr
 4415             lsr
 4416             sta PlayerEntranceCtrl       ;save value here as player entrance control
 4417             pla                      ;pull byte again but do not push it back
 4418             and #%11000000           ;save 2 MSB for game timer setting
 4419             clc
 4420             rol                      ;rotate bits over to LSBs
 4421             rol
 4422             rol
 4423             sta GameTimerSetting     ;save value here as game timer setting
 4424             iny
 4425             lda (AreaData),y         ;load second byte of header
 4426             pha                      ;save to stack
 4427             and #%00001111           ;mask out all but lower nybble
 4428             sta TerrainControl
 4429             pla                      ;pull and push byte to copy it to A
 4430             pha
 4431             and #%00110000           ;save 2 MSB for background scenery type
 4432             lsr
 4433             lsr                      ;shift bits to LSBs
 4434             lsr
 4435             lsr
 4436             sta BackgroundScenery    ;save as background scenery
 4437             pla           
 4438             and #%11000000
 4439             clc
 4440             rol                      ;rotate bits over to LSBs
 4441             rol
 4442             rol
 4443             cmp #%00000011           ;if set to 3, store here
 4444             bne StoreStyle           ;and nullify other value
 4445             sta CloudTypeOverride    ;otherwise store value in other place
 4446             lda #$00
 4447 StoreStyle: sta AreaStyle
 4448             lda AreaDataLow          ;increment area data address by 2 bytes
 4449             clc
 4450             adc #$02
 4451             sta AreaDataLow
 4452             lda AreaDataHigh
 4453             adc #$00
 4454             sta AreaDataHigh
 4455             rts
 4456 
 4457 ;-------------------------------------------------------------------------------------
 4458 ;GAME LEVELS DATA
 4459 
 4460 WorldAddrOffsets:
 4461       .db World1Areas-AreaAddrOffsets, World2Areas-AreaAddrOffsets
 4462       .db World3Areas-AreaAddrOffsets, World4Areas-AreaAddrOffsets
 4463       .db World5Areas-AreaAddrOffsets, World6Areas-AreaAddrOffsets
 4464       .db World7Areas-AreaAddrOffsets, World8Areas-AreaAddrOffsets
 4465 
 4466 AreaAddrOffsets:
 4467 World1Areas: .db $25, $29, $c0, $26, $60
 4468 World2Areas: .db $28, $29, $01, $27, $62
 4469 World3Areas: .db $24, $35, $20, $63
 4470 World4Areas: .db $22, $29, $41, $2c, $61
 4471 World5Areas: .db $2a, $31, $26, $62
 4472 World6Areas: .db $2e, $23, $2d, $60
 4473 World7Areas: .db $33, $29, $01, $27, $64
 4474 World8Areas: .db $30, $32, $21, $65
 4475 
 4476 ;bonus area data offsets, included here for comparison purposes
 4477 ;underground bonus area  - c2
 4478 ;cloud area 1 (day)      - 2b
 4479 ;cloud area 2 (night)    - 34
 4480 ;water area (5-2/6-2)    - 00
 4481 ;water area (8-4)        - 02
 4482 ;warp zone area (4-2)    - 2f
 4483 
 4484 EnemyAddrHOffsets:
 4485       .db $1f, $06, $1c, $00
 4486 
 4487 EnemyDataAddrLow:
 4488       .db <E_CastleArea1, <E_CastleArea2, <E_CastleArea3, <E_CastleArea4, <E_CastleArea5, <E_CastleArea6
 4489       .db <E_GroundArea1, <E_GroundArea2, <E_GroundArea3, <E_GroundArea4, <E_GroundArea5, <E_GroundArea6
 4490       .db <E_GroundArea7, <E_GroundArea8, <E_GroundArea9, <E_GroundArea10, <E_GroundArea11, <E_GroundArea12
 4491       .db <E_GroundArea13, <E_GroundArea14, <E_GroundArea15, <E_GroundArea16, <E_GroundArea17, <E_GroundArea18
 4492       .db <E_GroundArea19, <E_GroundArea20, <E_GroundArea21, <E_GroundArea22, <E_UndergroundArea1
 4493       .db <E_UndergroundArea2, <E_UndergroundArea3, <E_WaterArea1, <E_WaterArea2, <E_WaterArea3
 4494 
 4495 EnemyDataAddrHigh:
 4496       .db >E_CastleArea1, >E_CastleArea2, >E_CastleArea3, >E_CastleArea4, >E_CastleArea5, >E_CastleArea6
 4497       .db >E_GroundArea1, >E_GroundArea2, >E_GroundArea3, >E_GroundArea4, >E_GroundArea5, >E_GroundArea6
 4498       .db >E_GroundArea7, >E_GroundArea8, >E_GroundArea9, >E_GroundArea10, >E_GroundArea11, >E_GroundArea12
 4499       .db >E_GroundArea13, >E_GroundArea14, >E_GroundArea15, >E_GroundArea16, >E_GroundArea17, >E_GroundArea18
 4500       .db >E_GroundArea19, >E_GroundArea20, >E_GroundArea21, >E_GroundArea22, >E_UndergroundArea1
 4501       .db >E_UndergroundArea2, >E_UndergroundArea3, >E_WaterArea1, >E_WaterArea2, >E_WaterArea3
 4502 
 4503 AreaDataHOffsets:
 4504       .db $00, $03, $19, $1c
 4505 
 4506 AreaDataAddrLow:
 4507       .db <L_WaterArea1, <L_WaterArea2, <L_WaterArea3, <L_GroundArea1, <L_GroundArea2, <L_GroundArea3
 4508       .db <L_GroundArea4, <L_GroundArea5, <L_GroundArea6, <L_GroundArea7, <L_GroundArea8, <L_GroundArea9
 4509       .db <L_GroundArea10, <L_GroundArea11, <L_GroundArea12, <L_GroundArea13, <L_GroundArea14, <L_GroundArea15
 4510       .db <L_GroundArea16, <L_GroundArea17, <L_GroundArea18, <L_GroundArea19, <L_GroundArea20, <L_GroundArea21
 4511       .db <L_GroundArea22, <L_UndergroundArea1, <L_UndergroundArea2, <L_UndergroundArea3, <L_CastleArea1
 4512       .db <L_CastleArea2, <L_CastleArea3, <L_CastleArea4, <L_CastleArea5, <L_CastleArea6
 4513 
 4514 AreaDataAddrHigh:
 4515       .db >L_WaterArea1, >L_WaterArea2, >L_WaterArea3, >L_GroundArea1, >L_GroundArea2, >L_GroundArea3
 4516       .db >L_GroundArea4, >L_GroundArea5, >L_GroundArea6, >L_GroundArea7, >L_GroundArea8, >L_GroundArea9
 4517       .db >L_GroundArea10, >L_GroundArea11, >L_GroundArea12, >L_GroundArea13, >L_GroundArea14, >L_GroundArea15
 4518       .db >L_GroundArea16, >L_GroundArea17, >L_GroundArea18, >L_GroundArea19, >L_GroundArea20, >L_GroundArea21
 4519       .db >L_GroundArea22, >L_UndergroundArea1, >L_UndergroundArea2, >L_UndergroundArea3, >L_CastleArea1
 4520       .db >L_CastleArea2, >L_CastleArea3, >L_CastleArea4, >L_CastleArea5, >L_CastleArea6
 4521 
 4522 ;ENEMY OBJECT DATA
 4523 
 4524 ;level 1-4/6-4
 4525 E_CastleArea1:
 4526       .db $76, $dd, $bb, $4c, $ea, $1d, $1b, $cc, $56, $5d
 4527       .db $16, $9d, $c6, $1d, $36, $9d, $c9, $1d, $04, $db
 4528       .db $49, $1d, $84, $1b, $c9, $5d, $88, $95, $0f, $08
 4529       .db $30, $4c, $78, $2d, $a6, $28, $90, $b5
 4530       .db $ff
 4531 
 4532 ;level 4-4
 4533 E_CastleArea2:
 4534       .db $0f, $03, $56, $1b, $c9, $1b, $0f, $07, $36, $1b
 4535       .db $aa, $1b, $48, $95, $0f, $0a, $2a, $1b, $5b, $0c
 4536       .db $78, $2d, $90, $b5
 4537       .db $ff
 4538 
 4539 ;level 2-4/5-4
 4540 E_CastleArea3:
 4541       .db $0b, $8c, $4b, $4c, $77, $5f, $eb, $0c, $bd, $db
 4542       .db $19, $9d, $75, $1d, $7d, $5b, $d9, $1d, $3d, $dd
 4543       .db $99, $1d, $26, $9d, $5a, $2b, $8a, $2c, $ca, $1b
 4544       .db $20, $95, $7b, $5c, $db, $4c, $1b, $cc, $3b, $cc
 4545       .db $78, $2d, $a6, $28, $90, $b5
 4546       .db $ff
 4547 
 4548 ;level 3-4
 4549 E_CastleArea4:
 4550       .db $0b, $8c, $3b, $1d, $8b, $1d, $ab, $0c, $db, $1d
 4551       .db $0f, $03, $65, $1d, $6b, $1b, $05, $9d, $0b, $1b
 4552       .db $05, $9b, $0b, $1d, $8b, $0c, $1b, $8c, $70, $15
 4553       .db $7b, $0c, $db, $0c, $0f, $08, $78, $2d, $a6, $28
 4554       .db $90, $b5
 4555       .db $ff
 4556 
 4557 ;level 7-4
 4558 E_CastleArea5:
 4559       .db $27, $a9, $4b, $0c, $68, $29, $0f, $06, $77, $1b
 4560       .db $0f, $0b, $60, $15, $4b, $8c, $78, $2d, $90, $b5
 4561       .db $ff
 4562 
 4563 ;level 8-4
 4564 E_CastleArea6:
 4565       .db $0f, $03, $8e, $65, $e1, $bb, $38, $6d, $a8, $3e, $e5, $e7
 4566       .db $0f, $08, $0b, $02, $2b, $02, $5e, $65, $e1, $bb, $0e
 4567       .db $db, $0e, $bb, $8e, $db, $0e, $fe, $65, $ec, $0f, $0d
 4568       .db $4e, $65, $e1, $0f, $0e, $4e, $02, $e0, $0f, $10, $fe, $e5, $e1
 4569       .db $1b, $85, $7b, $0c, $5b, $95, $78, $2d, $90, $b5
 4570       .db $ff
 4571 
 4572 ;level 3-3
 4573 E_GroundArea1:
 4574       .db $a5, $86, $e4, $28, $18, $a8, $45, $83, $69, $03
 4575       .db $c6, $29, $9b, $83, $16, $a4, $88, $24, $e9, $28
 4576       .db $05, $a8, $7b, $28, $24, $8f, $c8, $03, $e8, $03
 4577       .db $46, $a8, $85, $24, $c8, $24
 4578       .db $ff
 4579 
 4580 ;level 8-3
 4581 E_GroundArea2:
 4582       .db $eb, $8e, $0f, $03, $fb, $05, $17, $85, $db, $8e
 4583       .db $0f, $07, $57, $05, $7b, $05, $9b, $80, $2b, $85
 4584       .db $fb, $05, $0f, $0b, $1b, $05, $9b, $05
 4585       .db $ff
 4586 
 4587 ;level 4-1
 4588 E_GroundArea3:
 4589       .db $2e, $c2, $66, $e2, $11, $0f, $07, $02, $11, $0f, $0c
 4590       .db $12, $11
 4591       .db $ff
 4592 
 4593 ;level 6-2
 4594 E_GroundArea4:
 4595       .db $0e, $c2, $a8, $ab, $00, $bb, $8e, $6b, $82, $de, $00, $a0
 4596       .db $33, $86, $43, $06, $3e, $b4, $a0, $cb, $02, $0f, $07
 4597       .db $7e, $42, $a6, $83, $02, $0f, $0a, $3b, $02, $cb, $37
 4598       .db $0f, $0c, $e3, $0e
 4599       .db $ff
 4600 
 4601 ;level 3-1
 4602 E_GroundArea5:
 4603       .db $9b, $8e, $ca, $0e, $ee, $42, $44, $5b, $86, $80, $b8
 4604       .db $1b, $80, $50, $ba, $10, $b7, $5b, $00, $17, $85
 4605       .db $4b, $05, $fe, $34, $40, $b7, $86, $c6, $06, $5b, $80
 4606       .db $83, $00, $d0, $38, $5b, $8e, $8a, $0e, $a6, $00
 4607       .db $bb, $0e, $c5, $80, $f3, $00
 4608       .db $ff
 4609 
 4610 ;level 1-1
 4611 E_GroundArea6:
 4612       .db $1e, $c2, $00, $6b, $06, $8b, $86, $63, $b7, $0f, $05
 4613       .db $03, $06, $23, $06, $4b, $b7, $bb, $00, $5b, $b7
 4614       .db $fb, $37, $3b, $b7, $0f, $0b, $1b, $37
 4615       .db $ff
 4616 
 4617 ;level 1-3/5-3
 4618 E_GroundArea7:
 4619       .db $2b, $d7, $e3, $03, $c2, $86, $e2, $06, $76, $a5
 4620       .db $a3, $8f, $03, $86, $2b, $57, $68, $28, $e9, $28
 4621       .db $e5, $83, $24, $8f, $36, $a8, $5b, $03
 4622       .db $ff
 4623 
 4624 ;level 2-3/7-3
 4625 E_GroundArea8:
 4626       .db $0f, $02, $78, $40, $48, $ce, $f8, $c3, $f8, $c3
 4627       .db $0f, $07, $7b, $43, $c6, $d0, $0f, $8a, $c8, $50
 4628       .db $ff
 4629 
 4630 ;level 2-1
 4631 E_GroundArea9:
 4632       .db $85, $86, $0b, $80, $1b, $00, $db, $37, $77, $80
 4633       .db $eb, $37, $fe, $2b, $20, $2b, $80, $7b, $38, $ab, $b8
 4634       .db $77, $86, $fe, $42, $20, $49, $86, $8b, $06, $9b, $80
 4635       .db $7b, $8e, $5b, $b7, $9b, $0e, $bb, $0e, $9b, $80
 4636 ;end of data terminator here is also used by pipe intro area
 4637 E_GroundArea10:
 4638       .db $ff
 4639 
 4640 ;level 5-1
 4641 E_GroundArea11:
 4642       .db $0b, $80, $60, $38, $10, $b8, $c0, $3b, $db, $8e
 4643       .db $40, $b8, $f0, $38, $7b, $8e, $a0, $b8, $c0, $b8
 4644       .db $fb, $00, $a0, $b8, $30, $bb, $ee, $42, $88, $0f, $0b
 4645       .db $2b, $0e, $67, $0e
 4646       .db $ff
 4647 
 4648 ;cloud level used in levels 2-1 and 5-2
 4649 E_GroundArea12:
 4650       .db $0a, $aa, $0e, $28, $2a, $0e, $31, $88
 4651       .db $ff
 4652 
 4653 ;level 4-3
 4654 E_GroundArea13:
 4655       .db $c7, $83, $d7, $03, $42, $8f, $7a, $03, $05, $a4
 4656       .db $78, $24, $a6, $25, $e4, $25, $4b, $83, $e3, $03
 4657       .db $05, $a4, $89, $24, $b5, $24, $09, $a4, $65, $24
 4658       .db $c9, $24, $0f, $08, $85, $25
 4659       .db $ff
 4660 
 4661 ;level 6-3
 4662 E_GroundArea14:
 4663       .db $cd, $a5, $b5, $a8, $07, $a8, $76, $28, $cc, $25
 4664       .db $65, $a4, $a9, $24, $e5, $24, $19, $a4, $0f, $07
 4665       .db $95, $28, $e6, $24, $19, $a4, $d7, $29, $16, $a9
 4666       .db $58, $29, $97, $29
 4667       .db $ff
 4668 
 4669 ;level 6-1
 4670 E_GroundArea15:
 4671       .db $0f, $02, $02, $11, $0f, $07, $02, $11
 4672       .db $ff
 4673 
 4674 ;warp zone area used in level 4-2
 4675 E_GroundArea16:
 4676       .db $ff
 4677 
 4678 ;level 8-1
 4679 E_GroundArea17:
 4680       .db $2b, $82, $ab, $38, $de, $42, $e2, $1b, $b8, $eb
 4681       .db $3b, $db, $80, $8b, $b8, $1b, $82, $fb, $b8, $7b
 4682       .db $80, $fb, $3c, $5b, $bc, $7b, $b8, $1b, $8e, $cb
 4683       .db $0e, $1b, $8e, $0f, $0d, $2b, $3b, $bb, $b8, $eb, $82
 4684       .db $4b, $b8, $bb, $38, $3b, $b7, $bb, $02, $0f, $13
 4685       .db $1b, $00, $cb, $80, $6b, $bc
 4686       .db $ff
 4687 
 4688 ;level 5-2
 4689 E_GroundArea18:
 4690       .db $7b, $80, $ae, $00, $80, $8b, $8e, $e8, $05, $f9, $86 
 4691       .db $17, $86, $16, $85, $4e, $2b, $80, $ab, $8e, $87, $85
 4692       .db $c3, $05, $8b, $82, $9b, $02, $ab, $02, $bb, $86
 4693       .db $cb, $06, $d3, $03, $3b, $8e, $6b, $0e, $a7, $8e
 4694       .db $ff
 4695 
 4696 ;level 8-2
 4697 E_GroundArea19:
 4698       .db $29, $8e, $52, $11, $83, $0e, $0f, $03, $9b, $0e
 4699       .db $2b, $8e, $5b, $0e, $cb, $8e, $fb, $0e, $fb, $82
 4700       .db $9b, $82, $bb, $02, $fe, $42, $e8, $bb, $8e, $0f, $0a
 4701       .db $ab, $0e, $cb, $0e, $f9, $0e, $88, $86, $a6, $06
 4702       .db $db, $02, $b6, $8e
 4703       .db $ff
 4704 
 4705 ;level 7-1
 4706 E_GroundArea20:
 4707       .db $ab, $ce, $de, $42, $c0, $cb, $ce, $5b, $8e, $1b, $ce
 4708       .db $4b, $85, $67, $45, $0f, $07, $2b, $00, $7b, $85
 4709       .db $97, $05, $0f, $0a, $92, $02
 4710       .db $ff
 4711 
 4712 ;cloud level used in levels 3-1 and 6-2
 4713 E_GroundArea21:
 4714       .db $0a, $aa, $0e, $24, $4a, $1e, $23, $aa
 4715       .db $ff
 4716 
 4717 ;level 3-2
 4718 E_GroundArea22:
 4719       .db $1b, $80, $bb, $38, $4b, $bc, $eb, $3b, $0f, $04
 4720       .db $2b, $00, $ab, $38, $eb, $00, $cb, $8e, $fb, $80
 4721       .db $ab, $b8, $6b, $80, $fb, $3c, $9b, $bb, $5b, $bc
 4722       .db $fb, $00, $6b, $b8, $fb, $38
 4723       .db $ff
 4724 
 4725 ;level 1-2
 4726 E_UndergroundArea1:
 4727       .db $0b, $86, $1a, $06, $db, $06, $de, $c2, $02, $f0, $3b
 4728       .db $bb, $80, $eb, $06, $0b, $86, $93, $06, $f0, $39
 4729       .db $0f, $06, $60, $b8, $1b, $86, $a0, $b9, $b7, $27
 4730       .db $bd, $27, $2b, $83, $a1, $26, $a9, $26, $ee, $25, $0b
 4731       .db $27, $b4
 4732       .db $ff
 4733 
 4734 ;level 4-2
 4735 E_UndergroundArea2:
 4736       .db $0f, $02, $1e, $2f, $60, $e0, $3a, $a5, $a7, $db, $80
 4737       .db $3b, $82, $8b, $02, $fe, $42, $68, $70, $bb, $25, $a7
 4738       .db $2c, $27, $b2, $26, $b9, $26, $9b, $80, $a8, $82
 4739       .db $b5, $27, $bc, $27, $b0, $bb, $3b, $82, $87, $34
 4740       .db $ee, $25, $6b
 4741       .db $ff
 4742 
 4743 ;underground bonus rooms area used in many levels
 4744 E_UndergroundArea3:
 4745       .db $1e, $a5, $0a, $2e, $28, $27, $2e, $33, $c7, $0f, $03, $1e, $40, $07
 4746       .db $2e, $30, $e7, $0f, $05, $1e, $24, $44, $0f, $07, $1e, $22, $6a
 4747       .db $2e, $23, $ab, $0f, $09, $1e, $41, $68, $1e, $2a, $8a, $2e, $23, $a2
 4748       .db $2e, $32, $ea
 4749       .db $ff
 4750 
 4751 ;water area used in levels 5-2 and 6-2
 4752 E_WaterArea1:
 4753       .db $3b, $87, $66, $27, $cc, $27, $ee, $31, $87, $ee, $23, $a7
 4754       .db $3b, $87, $db, $07
 4755       .db $ff
 4756 
 4757 ;level 2-2/7-2
 4758 E_WaterArea2:
 4759       .db $0f, $01, $2e, $25, $2b, $2e, $25, $4b, $4e, $25, $cb, $6b, $07
 4760       .db $97, $47, $e9, $87, $47, $c7, $7a, $07, $d6, $c7
 4761       .db $78, $07, $38, $87, $ab, $47, $e3, $07, $9b, $87
 4762       .db $0f, $09, $68, $47, $db, $c7, $3b, $c7
 4763       .db $ff
 4764 
 4765 ;water area used in level 8-4
 4766 E_WaterArea3:
 4767       .db $47, $9b, $cb, $07, $fa, $1d, $86, $9b, $3a, $87
 4768       .db $56, $07, $88, $1b, $07, $9d, $2e, $65, $f0
 4769       .db $ff
 4770 
 4771 ;AREA OBJECT DATA
 4772 
 4773 ;level 1-4/6-4
 4774 L_CastleArea1:
 4775       .db $9b, $07
 4776       .db $05, $32, $06, $33, $07, $34, $ce, $03, $dc, $51
 4777       .db $ee, $07, $73, $e0, $74, $0a, $7e, $06, $9e, $0a
 4778       .db $ce, $06, $e4, $00, $e8, $0a, $fe, $0a, $2e, $89
 4779       .db $4e, $0b, $54, $0a, $14, $8a, $c4, $0a, $34, $8a
 4780       .db $7e, $06, $c7, $0a, $01, $e0, $02, $0a, $47, $0a
 4781       .db $81, $60, $82, $0a, $c7, $0a, $0e, $87, $7e, $02
 4782       .db $a7, $02, $b3, $02, $d7, $02, $e3, $02, $07, $82
 4783       .db $13, $02, $3e, $06, $7e, $02, $ae, $07, $fe, $0a
 4784       .db $0d, $c4, $cd, $43, $ce, $09, $de, $0b, $dd, $42
 4785       .db $fe, $02, $5d, $c7
 4786       .db $fd
 4787 
 4788 ;level 4-4
 4789 L_CastleArea2:
 4790       .db $5b, $07
 4791       .db $05, $32, $06, $33, $07, $34, $5e, $0a, $68, $64
 4792       .db $98, $64, $a8, $64, $ce, $06, $fe, $02, $0d, $01
 4793       .db $1e, $0e, $7e, $02, $94, $63, $b4, $63, $d4, $63
 4794       .db $f4, $63, $14, $e3, $2e, $0e, $5e, $02, $64, $35
 4795       .db $88, $72, $be, $0e, $0d, $04, $ae, $02, $ce, $08
 4796       .db $cd, $4b, $fe, $02, $0d, $05, $68, $31, $7e, $0a
 4797       .db $96, $31, $a9, $63, $a8, $33, $d5, $30, $ee, $02
 4798       .db $e6, $62, $f4, $61, $04, $b1, $08, $3f, $44, $33
 4799       .db $94, $63, $a4, $31, $e4, $31, $04, $bf, $08, $3f
 4800       .db $04, $bf, $08, $3f, $cd, $4b, $03, $e4, $0e, $03
 4801       .db $2e, $01, $7e, $06, $be, $02, $de, $06, $fe, $0a
 4802       .db $0d, $c4, $cd, $43, $ce, $09, $de, $0b, $dd, $42
 4803       .db $fe, $02, $5d, $c7
 4804       .db $fd
 4805 
 4806 ;level 2-4/5-4
 4807 L_CastleArea3:
 4808       .db $9b, $07
 4809       .db $05, $32, $06, $33, $07, $34, $fe, $00, $27, $b1
 4810       .db $65, $32, $75, $0a, $71, $00, $b7, $31, $08, $e4
 4811       .db $18, $64, $1e, $04, $57, $3b, $bb, $0a, $17, $8a
 4812       .db $27, $3a, $73, $0a, $7b, $0a, $d7, $0a, $e7, $3a
 4813       .db $3b, $8a, $97, $0a, $fe, $08, $24, $8a, $2e, $00
 4814       .db $3e, $40, $38, $64, $6f, $00, $9f, $00, $be, $43
 4815       .db $c8, $0a, $c9, $63, $ce, $07, $fe, $07, $2e, $81
 4816       .db $66, $42, $6a, $42, $79, $0a, $be, $00, $c8, $64
 4817       .db $f8, $64, $08, $e4, $2e, $07, $7e, $03, $9e, $07
 4818       .db $be, $03, $de, $07, $fe, $0a, $03, $a5, $0d, $44
 4819       .db $cd, $43, $ce, $09, $dd, $42, $de, $0b, $fe, $02
 4820       .db $5d, $c7
 4821       .db $fd
 4822 
 4823 ;level 3-4
 4824 L_CastleArea4:
 4825       .db $9b, $07
 4826       .db $05, $32, $06, $33, $07, $34, $fe, $06, $0c, $81
 4827       .db $39, $0a, $5c, $01, $89, $0a, $ac, $01, $d9, $0a
 4828       .db $fc, $01, $2e, $83, $a7, $01, $b7, $00, $c7, $01
 4829       .db $de, $0a, $fe, $02, $4e, $83, $5a, $32, $63, $0a
 4830       .db $69, $0a, $7e, $02, $ee, $03, $fa, $32, $03, $8a
 4831       .db $09, $0a, $1e, $02, $ee, $03, $fa, $32, $03, $8a
 4832       .db $09, $0a, $14, $42, $1e, $02, $7e, $0a, $9e, $07
 4833       .db $fe, $0a, $2e, $86, $5e, $0a, $8e, $06, $be, $0a
 4834       .db $ee, $07, $3e, $83, $5e, $07, $fe, $0a, $0d, $c4
 4835       .db $41, $52, $51, $52, $cd, $43, $ce, $09, $de, $0b
 4836       .db $dd, $42, $fe, $02, $5d, $c7
 4837       .db $fd
 4838 
 4839 ;level 7-4
 4840 L_CastleArea5:
 4841       .db $5b, $07
 4842       .db $05, $32, $06, $33, $07, $34, $fe, $0a, $ae, $86
 4843       .db $be, $07, $fe, $02, $0d, $02, $27, $32, $46, $61
 4844       .db $55, $62, $5e, $0e, $1e, $82, $68, $3c, $74, $3a
 4845       .db $7d, $4b, $5e, $8e, $7d, $4b, $7e, $82, $84, $62
 4846       .db $94, $61, $a4, $31, $bd, $4b, $ce, $06, $fe, $02
 4847       .db $0d, $06, $34, $31, $3e, $0a, $64, $32, $75, $0a
 4848       .db $7b, $61, $a4, $33, $ae, $02, $de, $0e, $3e, $82
 4849       .db $64, $32, $78, $32, $b4, $36, $c8, $36, $dd, $4b
 4850       .db $44, $b2, $58, $32, $94, $63, $a4, $3e, $ba, $30
 4851       .db $c9, $61, $ce, $06, $dd, $4b, $ce, $86, $dd, $4b
 4852       .db $fe, $02, $2e, $86, $5e, $02, $7e, $06, $fe, $02
 4853       .db $1e, $86, $3e, $02, $5e, $06, $7e, $02, $9e, $06
 4854       .db $fe, $0a, $0d, $c4, $cd, $43, $ce, $09, $de, $0b
 4855       .db $dd, $42, $fe, $02, $5d, $c7
 4856       .db $fd
 4857 
 4858 ;level 8-4
 4859 L_CastleArea6:
 4860       .db $5b, $06
 4861       .db $05, $32, $06, $33, $07, $34, $5e, $0a, $ae, $02
 4862       .db $0d, $01, $39, $73, $0d, $03, $39, $7b, $4d, $4b
 4863       .db $de, $06, $1e, $8a, $ae, $06, $c4, $33, $16, $fe
 4864       .db $a5, $77, $fe, $02, $fe, $82, $0d, $07, $39, $73
 4865       .db $a8, $74, $ed, $4b, $49, $fb, $e8, $74, $fe, $0a
 4866       .db $2e, $82, $67, $02, $84, $7a, $87, $31, $0d, $0b
 4867       .db $fe, $02, $0d, $0c, $39, $73, $5e, $06, $c6, $76
 4868       .db $45, $ff, $be, $0a, $dd, $48, $fe, $06, $3d, $cb
 4869       .db $46, $7e, $ad, $4a, $fe, $82, $39, $f3, $a9, $7b
 4870       .db $4e, $8a, $9e, $07, $fe, $0a, $0d, $c4, $cd, $43
 4871       .db $ce, $09, $de, $0b, $dd, $42, $fe, $02, $5d, $c7
 4872       .db $fd
 4873 
 4874 ;level 3-3
 4875 L_GroundArea1:
 4876       .db $94, $11
 4877       .db $0f, $26, $fe, $10, $28, $94, $65, $15, $eb, $12
 4878       .db $fa, $41, $4a, $96, $54, $40, $a4, $42, $b7, $13
 4879       .db $e9, $19, $f5, $15, $11, $80, $47, $42, $71, $13
 4880       .db $80, $41, $15, $92, $1b, $1f, $24, $40, $55, $12
 4881       .db $64, $40, $95, $12, $a4, $40, $d2, $12, $e1, $40
 4882       .db $13, $c0, $2c, $17, $2f, $12, $49, $13, $83, $40
 4883       .db $9f, $14, $a3, $40, $17, $92, $83, $13, $92, $41
 4884       .db $b9, $14, $c5, $12, $c8, $40, $d4, $40, $4b, $92
 4885       .db $78, $1b, $9c, $94, $9f, $11, $df, $14, $fe, $11
 4886       .db $7d, $c1, $9e, $42, $cf, $20
 4887       .db $fd
 4888 
 4889 ;level 8-3
 4890 L_GroundArea2:
 4891       .db $90, $b1
 4892       .db $0f, $26, $29, $91, $7e, $42, $fe, $40, $28, $92
 4893       .db $4e, $42, $2e, $c0, $57, $73, $c3, $25, $c7, $27
 4894       .db $23, $84, $33, $20, $5c, $01, $77, $63, $88, $62
 4895       .db $99, $61, $aa, $60, $bc, $01, $ee, $42, $4e, $c0
 4896       .db $69, $11, $7e, $42, $de, $40, $f8, $62, $0e, $c2
 4897       .db $ae, $40, $d7, $63, $e7, $63, $33, $a7, $37, $27
 4898       .db $43, $04, $cc, $01, $e7, $73, $0c, $81, $3e, $42
 4899       .db $0d, $0a, $5e, $40, $88, $72, $be, $42, $e7, $87
 4900       .db $fe, $40, $39, $e1, $4e, $00, $69, $60, $87, $60
 4901       .db $a5, $60, $c3, $31, $fe, $31, $6d, $c1, $be, $42
 4902       .db $ef, $20
 4903       .db $fd
 4904 
 4905 ;level 4-1
 4906 L_GroundArea3:
 4907       .db $52, $21
 4908       .db $0f, $20, $6e, $40, $58, $f2, $93, $01, $97, $00
 4909       .db $0c, $81, $97, $40, $a6, $41, $c7, $40, $0d, $04
 4910       .db $03, $01, $07, $01, $23, $01, $27, $01, $ec, $03
 4911       .db $ac, $f3, $c3, $03, $78, $e2, $94, $43, $47, $f3
 4912       .db $74, $43, $47, $fb, $74, $43, $2c, $f1, $4c, $63
 4913       .db $47, $00, $57, $21, $5c, $01, $7c, $72, $39, $f1
 4914       .db $ec, $02, $4c, $81, $d8, $62, $ec, $01, $0d, $0d
 4915       .db $0f, $38, $c7, $07, $ed, $4a, $1d, $c1, $5f, $26
 4916       .db $fd
 4917 
 4918 ;level 6-2
 4919 L_GroundArea4:
 4920       .db $54, $21
 4921       .db $0f, $26, $a7, $22, $37, $fb, $73, $20, $83, $07
 4922       .db $87, $02, $93, $20, $c7, $73, $04, $f1, $06, $31
 4923       .db $39, $71, $59, $71, $e7, $73, $37, $a0, $47, $04
 4924       .db $86, $7c, $e5, $71, $e7, $31, $33, $a4, $39, $71
 4925       .db $a9, $71, $d3, $23, $08, $f2, $13, $05, $27, $02
 4926       .db $49, $71, $75, $75, $e8, $72, $67, $f3, $99, $71
 4927       .db $e7, $20, $f4, $72, $f7, $31, $17, $a0, $33, $20
 4928       .db $39, $71, $73, $28, $bc, $05, $39, $f1, $79, $71
 4929       .db $a6, $21, $c3, $06, $d3, $20, $dc, $00, $fc, $00
 4930       .db $07, $a2, $13, $21, $5f, $32, $8c, $00, $98, $7a
 4931       .db $c7, $63, $d9, $61, $03, $a2, $07, $22, $74, $72
 4932       .db $77, $31, $e7, $73, $39, $f1, $58, $72, $77, $73
 4933       .db $d8, $72, $7f, $b1, $97, $73, $b6, $64, $c5, $65
 4934       .db $d4, $66, $e3, $67, $f3, $67, $8d, $c1, $cf, $26
 4935       .db $fd
 4936 
 4937 ;level 3-1
 4938 L_GroundArea5:
 4939       .db $52, $31
 4940       .db $0f, $20, $6e, $66, $07, $81, $36, $01, $66, $00
 4941       .db $a7, $22, $08, $f2, $67, $7b, $dc, $02, $98, $f2
 4942       .db $d7, $20, $39, $f1, $9f, $33, $dc, $27, $dc, $57
 4943       .db $23, $83, $57, $63, $6c, $51, $87, $63, $99, $61
 4944       .db $a3, $06, $b3, $21, $77, $f3, $f3, $21, $f7, $2a
 4945       .db $13, $81, $23, $22, $53, $00, $63, $22, $e9, $0b
 4946       .db $0c, $83, $13, $21, $16, $22, $33, $05, $8f, $35
 4947       .db $ec, $01, $63, $a0, $67, $20, $73, $01, $77, $01
 4948       .db $83, $20, $87, $20, $b3, $20, $b7, $20, $c3, $01
 4949       .db $c7, $00, $d3, $20, $d7, $20, $67, $a0, $77, $07
 4950       .db $87, $22, $e8, $62, $f5, $65, $1c, $82, $7f, $38
 4951       .db $8d, $c1, $cf, $26
 4952       .db $fd
 4953 
 4954 ;level 1-1
 4955 L_GroundArea6:
 4956       .db $50, $21
 4957       .db $07, $81, $47, $24, $57, $00, $63, $01, $77, $01
 4958       .db $c9, $71, $68, $f2, $e7, $73, $97, $fb, $06, $83
 4959       .db $5c, $01, $d7, $22, $e7, $00, $03, $a7, $6c, $02
 4960       .db $b3, $22, $e3, $01, $e7, $07, $47, $a0, $57, $06
 4961       .db $a7, $01, $d3, $00, $d7, $01, $07, $81, $67, $20
 4962       .db $93, $22, $03, $a3, $1c, $61, $17, $21, $6f, $33
 4963       .db $c7, $63, $d8, $62, $e9, $61, $fa, $60, $4f, $b3
 4964       .db $87, $63, $9c, $01, $b7, $63, $c8, $62, $d9, $61
 4965       .db $ea, $60, $39, $f1, $87, $21, $a7, $01, $b7, $20
 4966       .db $39, $f1, $5f, $38, $6d, $c1, $af, $26
 4967       .db $fd
 4968 
 4969 ;level 1-3/5-3
 4970 L_GroundArea7:
 4971       .db $90, $11
 4972       .db $0f, $26, $fe, $10, $2a, $93, $87, $17, $a3, $14
 4973       .db $b2, $42, $0a, $92, $19, $40, $36, $14, $50, $41
 4974       .db $82, $16, $2b, $93, $24, $41, $bb, $14, $b8, $00
 4975       .db $c2, $43, $c3, $13, $1b, $94, $67, $12, $c4, $15
 4976       .db $53, $c1, $d2, $41, $12, $c1, $29, $13, $85, $17
 4977       .db $1b, $92, $1a, $42, $47, $13, $83, $41, $a7, $13
 4978       .db $0e, $91, $a7, $63, $b7, $63, $c5, $65, $d5, $65
 4979       .db $dd, $4a, $e3, $67, $f3, $67, $8d, $c1, $ae, $42
 4980       .db $df, $20
 4981       .db $fd
 4982 
 4983 ;level 2-3/7-3
 4984 L_GroundArea8:
 4985       .db $90, $11
 4986       .db $0f, $26, $6e, $10, $8b, $17, $af, $32, $d8, $62
 4987       .db $e8, $62, $fc, $3f, $ad, $c8, $f8, $64, $0c, $be
 4988       .db $43, $43, $f8, $64, $0c, $bf, $73, $40, $84, $40
 4989       .db $93, $40, $a4, $40, $b3, $40, $f8, $64, $48, $e4
 4990       .db $5c, $39, $83, $40, $92, $41, $b3, $40, $f8, $64
 4991       .db $48, $e4, $5c, $39, $f8, $64, $13, $c2, $37, $65
 4992       .db $4c, $24, $63, $00, $97, $65, $c3, $42, $0b, $97
 4993       .db $ac, $32, $f8, $64, $0c, $be, $53, $45, $9d, $48
 4994       .db $f8, $64, $2a, $e2, $3c, $47, $56, $43, $ba, $62
 4995       .db $f8, $64, $0c, $b7, $88, $64, $bc, $31, $d4, $45
 4996       .db $fc, $31, $3c, $b1, $78, $64, $8c, $38, $0b, $9c
 4997       .db $1a, $33, $18, $61, $28, $61, $39, $60, $5d, $4a
 4998       .db $ee, $11, $0f, $b8, $1d, $c1, $3e, $42, $6f, $20
 4999       .db $fd
 5000 
 5001 ;level 2-1
 5002 L_GroundArea9:
 5003       .db $52, $31
 5004       .db $0f, $20, $6e, $40, $f7, $20, $07, $84, $17, $20
 5005       .db $4f, $34, $c3, $03, $c7, $02, $d3, $22, $27, $e3
 5006       .db $39, $61, $e7, $73, $5c, $e4, $57, $00, $6c, $73
 5007       .db $47, $a0, $53, $06, $63, $22, $a7, $73, $fc, $73
 5008       .db $13, $a1, $33, $05, $43, $21, $5c, $72, $c3, $23
 5009       .db $cc, $03, $77, $fb, $ac, $02, $39, $f1, $a7, $73
 5010       .db $d3, $04, $e8, $72, $e3, $22, $26, $f4, $bc, $02
 5011       .db $8c, $81, $a8, $62, $17, $87, $43, $24, $a7, $01
 5012       .db $c3, $04, $08, $f2, $97, $21, $a3, $02, $c9, $0b
 5013       .db $e1, $69, $f1, $69, $8d, $c1, $cf, $26
 5014       .db $fd
 5015 
 5016 ;pipe intro area
 5017 L_GroundArea10:
 5018       .db $38, $11
 5019       .db $0f, $26, $ad, $40, $3d, $c7
 5020       .db $fd
 5021 
 5022 ;level 5-1
 5023 L_GroundArea11:
 5024       .db $95, $b1
 5025       .db $0f, $26, $0d, $02, $c8, $72, $1c, $81, $38, $72
 5026       .db $0d, $05, $97, $34, $98, $62, $a3, $20, $b3, $06
 5027       .db $c3, $20, $cc, $03, $f9, $91, $2c, $81, $48, $62
 5028       .db $0d, $09, $37, $63, $47, $03, $57, $21, $8c, $02
 5029       .db $c5, $79, $c7, $31, $f9, $11, $39, $f1, $a9, $11
 5030       .db $6f, $b4, $d3, $65, $e3, $65, $7d, $c1, $bf, $26
 5031       .db $fd
 5032 
 5033 ;cloud level used in levels 2-1 and 5-2
 5034 L_GroundArea12:
 5035       .db $00, $c1
 5036       .db $4c, $00, $f4, $4f, $0d, $02, $02, $42, $43, $4f
 5037       .db $52, $c2, $de, $00, $5a, $c2, $4d, $c7
 5038       .db $fd
 5039 
 5040 ;level 4-3
 5041 L_GroundArea13:
 5042       .db $90, $51
 5043       .db $0f, $26, $ee, $10, $0b, $94, $33, $14, $42, $42
 5044       .db $77, $16, $86, $44, $02, $92, $4a, $16, $69, $42
 5045       .db $73, $14, $b0, $00, $c7, $12, $05, $c0, $1c, $17
 5046       .db $1f, $11, $36, $12, $8f, $14, $91, $40, $1b, $94
 5047       .db $35, $12, $34, $42, $60, $42, $61, $12, $87, $12
 5048       .db $96, $40, $a3, $14, $1c, $98, $1f, $11, $47, $12
 5049       .db $9f, $15, $cc, $15, $cf, $11, $05, $c0, $1f, $15
 5050       .db $39, $12, $7c, $16, $7f, $11, $82, $40, $98, $12
 5051       .db $df, $15, $16, $c4, $17, $14, $54, $12, $9b, $16
 5052       .db $28, $94, $ce, $01, $3d, $c1, $5e, $42, $8f, $20
 5053       .db $fd
 5054 
 5055 ;level 6-3
 5056 L_GroundArea14:
 5057       .db $97, $11
 5058       .db $0f, $26, $fe, $10, $2b, $92, $57, $12, $8b, $12
 5059       .db $c0, $41, $f7, $13, $5b, $92, $69, $0b, $bb, $12
 5060       .db $b2, $46, $19, $93, $71, $00, $17, $94, $7c, $14
 5061       .db $7f, $11, $93, $41, $bf, $15, $fc, $13, $ff, $11
 5062       .db $2f, $95, $50, $42, $51, $12, $58, $14, $a6, $12
 5063       .db $db, $12, $1b, $93, $46, $43, $7b, $12, $8d, $49
 5064       .db $b7, $14, $1b, $94, $49, $0b, $bb, $12, $fc, $13
 5065       .db $ff, $12, $03, $c1, $2f, $15, $43, $12, $4b, $13
 5066       .db $77, $13, $9d, $4a, $15, $c1, $a1, $41, $c3, $12
 5067       .db $fe, $01, $7d, $c1, $9e, $42, $cf, $20
 5068       .db $fd
 5069 
 5070 ;level 6-1
 5071 L_GroundArea15:
 5072       .db $52, $21
 5073       .db $0f, $20, $6e, $44, $0c, $f1, $4c, $01, $aa, $35
 5074       .db $d9, $34, $ee, $20, $08, $b3, $37, $32, $43, $04
 5075       .db $4e, $21, $53, $20, $7c, $01, $97, $21, $b7, $07
 5076       .db $9c, $81, $e7, $42, $5f, $b3, $97, $63, $ac, $02
 5077       .db $c5, $41, $49, $e0, $58, $61, $76, $64, $85, $65
 5078       .db $94, $66, $a4, $22, $a6, $03, $c8, $22, $dc, $02
 5079       .db $68, $f2, $96, $42, $13, $82, $17, $02, $af, $34
 5080       .db $f6, $21, $fc, $06, $26, $80, $2a, $24, $36, $01
 5081       .db $8c, $00, $ff, $35, $4e, $a0, $55, $21, $77, $20
 5082       .db $87, $07, $89, $22, $ae, $21, $4c, $82, $9f, $34
 5083       .db $ec, $01, $03, $e7, $13, $67, $8d, $4a, $ad, $41
 5084       .db $0f, $a6
 5085       .db $fd
 5086 
 5087 ;warp zone area used in level 4-2
 5088 L_GroundArea16:
 5089       .db $10, $51
 5090       .db $4c, $00, $c7, $12, $c6, $42, $03, $92, $02, $42
 5091       .db $29, $12, $63, $12, $62, $42, $69, $14, $a5, $12
 5092       .db $a4, $42, $e2, $14, $e1, $44, $f8, $16, $37, $c1
 5093       .db $8f, $38, $02, $bb, $28, $7a, $68, $7a, $a8, $7a
 5094       .db $e0, $6a, $f0, $6a, $6d, $c5
 5095       .db $fd
 5096 
 5097 ;level 8-1
 5098 L_GroundArea17:
 5099       .db $92, $31
 5100       .db $0f, $20, $6e, $40, $0d, $02, $37, $73, $ec, $00
 5101       .db $0c, $80, $3c, $00, $6c, $00, $9c, $00, $06, $c0
 5102       .db $c7, $73, $06, $83, $28, $72, $96, $40, $e7, $73
 5103       .db $26, $c0, $87, $7b, $d2, $41, $39, $f1, $c8, $f2
 5104       .db $97, $e3, $a3, $23, $e7, $02, $e3, $07, $f3, $22
 5105       .db $37, $e3, $9c, $00, $bc, $00, $ec, $00, $0c, $80
 5106       .db $3c, $00, $86, $21, $a6, $06, $b6, $24, $5c, $80
 5107       .db $7c, $00, $9c, $00, $29, $e1, $dc, $05, $f6, $41
 5108       .db $dc, $80, $e8, $72, $0c, $81, $27, $73, $4c, $01
 5109       .db $66, $74, $0d, $11, $3f, $35, $b6, $41, $2c, $82
 5110       .db $36, $40, $7c, $02, $86, $40, $f9, $61, $39, $e1
 5111       .db $ac, $04, $c6, $41, $0c, $83, $16, $41, $88, $f2
 5112       .db $39, $f1, $7c, $00, $89, $61, $9c, $00, $a7, $63
 5113       .db $bc, $00, $c5, $65, $dc, $00, $e3, $67, $f3, $67
 5114       .db $8d, $c1, $cf, $26
 5115       .db $fd
 5116 
 5117 ;level 5-2
 5118 L_GroundArea18:
 5119       .db $55, $b1
 5120       .db $0f, $26, $cf, $33, $07, $b2, $15, $11, $52, $42
 5121       .db $99, $0b, $ac, $02, $d3, $24, $d6, $42, $d7, $25
 5122       .db $23, $84, $cf, $33, $07, $e3, $19, $61, $78, $7a
 5123       .db $ef, $33, $2c, $81, $46, $64, $55, $65, $65, $65
 5124       .db $ec, $74, $47, $82, $53, $05, $63, $21, $62, $41
 5125       .db $96, $22, $9a, $41, $cc, $03, $b9, $91, $39, $f1
 5126       .db $63, $26, $67, $27, $d3, $06, $fc, $01, $18, $e2
 5127       .db $d9, $07, $e9, $04, $0c, $86, $37, $22, $93, $24
 5128       .db $87, $84, $ac, $02, $c2, $41, $c3, $23, $d9, $71
 5129       .db $fc, $01, $7f, $b1, $9c, $00, $a7, $63, $b6, $64
 5130       .db $cc, $00, $d4, $66, $e3, $67, $f3, $67, $8d, $c1
 5131       .db $cf, $26
 5132       .db $fd
 5133 
 5134 ;level 8-2
 5135 L_GroundArea19:
 5136       .db $50, $b1
 5137       .db $0f, $26, $fc, $00, $1f, $b3, $5c, $00, $65, $65
 5138       .db $74, $66, $83, $67, $93, $67, $dc, $73, $4c, $80
 5139       .db $b3, $20, $c9, $0b, $c3, $08, $d3, $2f, $dc, $00
 5140       .db $2c, $80, $4c, $00, $8c, $00, $d3, $2e, $ed, $4a
 5141       .db $fc, $00, $d7, $a1, $ec, $01, $4c, $80, $59, $11
 5142       .db $d8, $11, $da, $10, $37, $a0, $47, $04, $99, $11
 5143       .db $e7, $21, $3a, $90, $67, $20, $76, $10, $77, $60
 5144       .db $87, $07, $d8, $12, $39, $f1, $ac, $00, $e9, $71
 5145       .db $0c, $80, $2c, $00, $4c, $05, $c7, $7b, $39, $f1
 5146       .db $ec, $00, $f9, $11, $0c, $82, $6f, $34, $f8, $11
 5147       .db $fa, $10, $7f, $b2, $ac, $00, $b6, $64, $cc, $01
 5148       .db $e3, $67, $f3, $67, $8d, $c1, $cf, $26
 5149       .db $fd
 5150 
 5151 ;level 7-1
 5152 L_GroundArea20:
 5153       .db $52, $b1
 5154       .db $0f, $20, $6e, $45, $39, $91, $b3, $04, $c3, $21
 5155       .db $c8, $11, $ca, $10, $49, $91, $7c, $73, $e8, $12
 5156       .db $88, $91, $8a, $10, $e7, $21, $05, $91, $07, $30
 5157       .db $17, $07, $27, $20, $49, $11, $9c, $01, $c8, $72
 5158       .db $23, $a6, $27, $26, $d3, $03, $d8, $7a, $89, $91
 5159       .db $d8, $72, $39, $f1, $a9, $11, $09, $f1, $63, $24
 5160       .db $67, $24, $d8, $62, $28, $91, $2a, $10, $56, $21
 5161       .db $70, $04, $79, $0b, $8c, $00, $94, $21, $9f, $35
 5162       .db $2f, $b8, $3d, $c1, $7f, $26
 5163       .db $fd
 5164 
 5165 ;cloud level used in levels 3-1 and 6-2
 5166 L_GroundArea21:
 5167       .db $06, $c1
 5168       .db $4c, $00, $f4, $4f, $0d, $02, $06, $20, $24, $4f
 5169       .db $35, $a0, $36, $20, $53, $46, $d5, $20, $d6, $20
 5170       .db $34, $a1, $73, $49, $74, $20, $94, $20, $b4, $20
 5171       .db $d4, $20, $f4, $20, $2e, $80, $59, $42, $4d, $c7
 5172       .db $fd
 5173 
 5174 ;level 3-2
 5175 L_GroundArea22:
 5176       .db $96, $31
 5177       .db $0f, $26, $0d, $03, $1a, $60, $77, $42, $c4, $00
 5178       .db $c8, $62, $b9, $e1, $d3, $06, $d7, $07, $f9, $61
 5179       .db $0c, $81, $4e, $b1, $8e, $b1, $bc, $01, $e4, $50
 5180       .db $e9, $61, $0c, $81, $0d, $0a, $84, $43, $98, $72
 5181       .db $0d, $0c, $0f, $38, $1d, $c1, $5f, $26
 5182       .db $fd
 5183 
 5184 ;level 1-2
 5185 L_UndergroundArea1:
 5186       .db $48, $0f
 5187       .db $0e, $01, $5e, $02, $a7, $00, $bc, $73, $1a, $e0
 5188       .db $39, $61, $58, $62, $77, $63, $97, $63, $b8, $62
 5189       .db $d6, $07, $f8, $62, $19, $e1, $75, $52, $86, $40
 5190       .db $87, $50, $95, $52, $93, $43, $a5, $21, $c5, $52
 5191       .db $d6, $40, $d7, $20, $e5, $06, $e6, $51, $3e, $8d
 5192       .db $5e, $03, $67, $52, $77, $52, $7e, $02, $9e, $03
 5193       .db $a6, $43, $a7, $23, $de, $05, $fe, $02, $1e, $83
 5194       .db $33, $54, $46, $40, $47, $21, $56, $04, $5e, $02
 5195       .db $83, $54, $93, $52, $96, $07, $97, $50, $be, $03
 5196       .db $c7, $23, $fe, $02, $0c, $82, $43, $45, $45, $24
 5197       .db $46, $24, $90, $08, $95, $51, $78, $fa, $d7, $73
 5198       .db $39, $f1, $8c, $01, $a8, $52, $b8, $52, $cc, $01
 5199       .db $5f, $b3, $97, $63, $9e, $00, $0e, $81, $16, $24
 5200       .db $66, $04, $8e, $00, $fe, $01, $08, $d2, $0e, $06
 5201       .db $6f, $47, $9e, $0f, $0e, $82, $2d, $47, $28, $7a
 5202       .db $68, $7a, $a8, $7a, $ae, $01, $de, $0f, $6d, $c5
 5203       .db $fd
 5204 
 5205 ;level 4-2
 5206 L_UndergroundArea2:
 5207       .db $48, $0f
 5208       .db $0e, $01, $5e, $02, $bc, $01, $fc, $01, $2c, $82
 5209       .db $41, $52, $4e, $04, $67, $25, $68, $24, $69, $24
 5210       .db $ba, $42, $c7, $04, $de, $0b, $b2, $87, $fe, $02
 5211       .db $2c, $e1, $2c, $71, $67, $01, $77, $00, $87, $01
 5212       .db $8e, $00, $ee, $01, $f6, $02, $03, $85, $05, $02
 5213       .db $13, $21, $16, $02, $27, $02, $2e, $02, $88, $72
 5214       .db $c7, $20, $d7, $07, $e4, $76, $07, $a0, $17, $06
 5215       .db $48, $7a, $76, $20, $98, $72, $79, $e1, $88, $62
 5216       .db $9c, $01, $b7, $73, $dc, $01, $f8, $62, $fe, $01
 5217       .db $08, $e2, $0e, $00, $6e, $02, $73, $20, $77, $23
 5218       .db $83, $04, $93, $20, $ae, $00, $fe, $0a, $0e, $82
 5219       .db $39, $71, $a8, $72, $e7, $73, $0c, $81, $8f, $32
 5220       .db $ae, $00, $fe, $04, $04, $d1, $17, $04, $26, $49
 5221       .db $27, $29, $df, $33, $fe, $02, $44, $f6, $7c, $01
 5222       .db $8e, $06, $bf, $47, $ee, $0f, $4d, $c7, $0e, $82
 5223       .db $68, $7a, $ae, $01, $de, $0f, $6d, $c5
 5224       .db $fd
 5225 
 5226 ;underground bonus rooms area used in many levels
 5227 L_UndergroundArea3:
 5228       .db $48, $01
 5229       .db $0e, $01, $00, $5a, $3e, $06, $45, $46, $47, $46
 5230       .db $53, $44, $ae, $01, $df, $4a, $4d, $c7, $0e, $81
 5231       .db $00, $5a, $2e, $04, $37, $28, $3a, $48, $46, $47
 5232       .db $c7, $07, $ce, $0f, $df, $4a, $4d, $c7, $0e, $81
 5233       .db $00, $5a, $33, $53, $43, $51, $46, $40, $47, $50
 5234       .db $53, $04, $55, $40, $56, $50, $62, $43, $64, $40
 5235       .db $65, $50, $71, $41, $73, $51, $83, $51, $94, $40
 5236       .db $95, $50, $a3, $50, $a5, $40, $a6, $50, $b3, $51
 5237       .db $b6, $40, $b7, $50, $c3, $53, $df, $4a, $4d, $c7
 5238       .db $0e, $81, $00, $5a, $2e, $02, $36, $47, $37, $52
 5239       .db $3a, $49, $47, $25, $a7, $52, $d7, $04, $df, $4a
 5240       .db $4d, $c7, $0e, $81, $00, $5a, $3e, $02, $44, $51
 5241       .db $53, $44, $54, $44, $55, $24, $a1, $54, $ae, $01
 5242       .db $b4, $21, $df, $4a, $e5, $07, $4d, $c7
 5243       .db $fd
 5244 
 5245 ;water area used in levels 5-2 and 6-2
 5246 L_WaterArea1:
 5247       .db $41, $01
 5248       .db $b4, $34, $c8, $52, $f2, $51, $47, $d3, $6c, $03
 5249       .db $65, $49, $9e, $07, $be, $01, $cc, $03, $fe, $07
 5250       .db $0d, $c9, $1e, $01, $6c, $01, $62, $35, $63, $53
 5251       .db $8a, $41, $ac, $01, $b3, $53, $e9, $51, $26, $c3
 5252       .db $27, $33, $63, $43, $64, $33, $ba, $60, $c9, $61
 5253       .db $ce, $0b, $e5, $09, $ee, $0f, $7d, $ca, $7d, $47
 5254       .db $fd
 5255 
 5256 ;level 2-2/7-2
 5257 L_WaterArea2:
 5258       .db $41, $01
 5259       .db $b8, $52, $ea, $41, $27, $b2, $b3, $42, $16, $d4
 5260       .db $4a, $42, $a5, $51, $a7, $31, $27, $d3, $08, $e2
 5261       .db $16, $64, $2c, $04, $38, $42, $76, $64, $88, $62
 5262       .db $de, $07, $fe, $01, $0d, $c9, $23, $32, $31, $51
 5263       .db $98, $52, $0d, $c9, $59, $42, $63, $53, $67, $31
 5264       .db $14, $c2, $36, $31, $87, $53, $17, $e3, $29, $61
 5265       .db $30, $62, $3c, $08, $42, $37, $59, $40, $6a, $42
 5266       .db $99, $40, $c9, $61, $d7, $63, $39, $d1, $58, $52
 5267       .db $c3, $67, $d3, $31, $dc, $06, $f7, $42, $fa, $42
 5268       .db $23, $b1, $43, $67, $c3, $34, $c7, $34, $d1, $51
 5269       .db $43, $b3, $47, $33, $9a, $30, $a9, $61, $b8, $62
 5270       .db $be, $0b, $d5, $09, $de, $0f, $0d, $ca, $7d, $47
 5271       .db $fd
 5272 
 5273 ;water area used in level 8-4
 5274 L_WaterArea3:
 5275       .db $49, $0f
 5276       .db $1e, $01, $39, $73, $5e, $07, $ae, $0b, $1e, $82
 5277       .db $6e, $88, $9e, $02, $0d, $04, $2e, $0b, $45, $09
 5278       .db $4e, $0f, $ed, $47
 5279       .db $fd
 5280 
 5281 ;-------------------------------------------------------------------------------------
 5282 
 5283 ;unused space
 5284       .db $ff
 5285 
 5286 ;-------------------------------------------------------------------------------------
 5287 
 5288 ;indirect jump routine called when
 5289 ;$0770 is set to 1
 5290 GameMode:
 5291       lda OperMode_Task
 5292       jsr JumpEngine
 5293 
 5294       .dw InitializeArea
 5295       .dw ScreenRoutines
 5296       .dw SecondaryGameSetup
 5297       .dw GameCoreRoutine
 5298 
 5299 ;-------------------------------------------------------------------------------------
 5300 
 5301 GameCoreRoutine:
 5302       ldx CurrentPlayer          ;get which player is on the screen
 5303       lda SavedJoypadBits,x      ;use appropriate player's controller bits
 5304       sta SavedJoypadBits        ;as the master controller bits
 5305       jsr GameRoutines           ;execute one of many possible subs
 5306       lda OperMode_Task          ;check major task of operating mode
 5307       cmp #$03                   ;if we are supposed to be here,
 5308       bcs GameEngine             ;branch to the game engine itself
 5309       rts
 5310 
 5311 GameEngine:
 5312               jsr ProcFireball_Bubble    ;process fireballs and air bubbles
 5313               ldx #$00
 5314 ProcELoop:    stx ObjectOffset           ;put incremented offset in X as enemy object offset
 5315               jsr EnemiesAndLoopsCore    ;process enemy objects
 5316               jsr FloateyNumbersRoutine  ;process floatey numbers
 5317               inx
 5318               cpx #$06                   ;do these two subroutines until the whole buffer is done
 5319               bne ProcELoop
 5320               jsr GetPlayerOffscreenBits ;get offscreen bits for player object
 5321               jsr RelativePlayerPosition ;get relative coordinates for player object
 5322               jsr PlayerGfxHandler       ;draw the player
 5323               jsr BlockObjMT_Updater     ;replace block objects with metatiles if necessary
 5324               ldx #$01
 5325               stx ObjectOffset           ;set offset for second
 5326               jsr BlockObjectsCore       ;process second block object
 5327               dex
 5328               stx ObjectOffset           ;set offset for first
 5329               jsr BlockObjectsCore       ;process first block object
 5330               jsr MiscObjectsCore        ;process misc objects (hammer, jumping coins)
 5331               jsr ProcessCannons         ;process bullet bill cannons
 5332               jsr ProcessWhirlpools      ;process whirlpools
 5333               jsr FlagpoleRoutine        ;process the flagpole
 5334               jsr RunGameTimer           ;count down the game timer
 5335               jsr ColorRotation          ;cycle one of the background colors
 5336               lda Player_Y_HighPos
 5337               cmp #$02                   ;if player is below the screen, don't bother with the music
 5338               bpl NoChgMus
 5339               lda StarInvincibleTimer    ;if star mario invincibility timer at zero,
 5340               beq ClrPlrPal              ;skip this part
 5341               cmp #$04
 5342               bne NoChgMus               ;if not yet at a certain point, continue
 5343               lda IntervalTimerControl   ;if interval timer not yet expired,
 5344               bne NoChgMus               ;branch ahead, don't bother with the music
 5345               jsr GetAreaMusic           ;to re-attain appropriate level music
 5346 NoChgMus:     ldy StarInvincibleTimer    ;get invincibility timer
 5347               lda FrameCounter           ;get frame counter
 5348               cpy #$08                   ;if timer still above certain point,
 5349               bcs CycleTwo               ;branch to cycle player's palette quickly
 5350               lsr                        ;otherwise, divide by 8 to cycle every eighth frame
 5351               lsr
 5352 CycleTwo:     lsr                        ;if branched here, divide by 2 to cycle every other frame
 5353               jsr CyclePlayerPalette     ;do sub to cycle the palette (note: shares fire flower code)
 5354               jmp SaveAB                 ;then skip this sub to finish up the game engine
 5355 ClrPlrPal:    jsr ResetPalStar           ;do sub to clear player's palette bits in attributes
 5356 SaveAB:       lda A_B_Buttons            ;save current A and B button
 5357               sta PreviousA_B_Buttons    ;into temp variable to be used on next frame
 5358               lda #$00
 5359               sta Left_Right_Buttons     ;nullify left and right buttons temp variable
 5360 UpdScrollVar: lda VRAM_Buffer_AddrCtrl
 5361               cmp #$06                   ;if vram address controller set to 6 (one of two $0341s)
 5362               beq ExitEng                ;then branch to leave
 5363               lda AreaParserTaskNum      ;otherwise check number of tasks
 5364               bne RunParser
 5365               lda ScrollThirtyTwo        ;get horizontal scroll in 0-31 or $00-$20 range
 5366               cmp #$20                   ;check to see if exceeded $21
 5367               bmi ExitEng                ;branch to leave if not
 5368               lda ScrollThirtyTwo
 5369               sbc #$20                   ;otherwise subtract $20 to set appropriately
 5370               sta ScrollThirtyTwo        ;and store
 5371               lda #$00                   ;reset vram buffer offset used in conjunction with
 5372               sta VRAM_Buffer2_Offset    ;level graphics buffer at $0341-$035f
 5373 RunParser:    jsr AreaParserTaskHandler  ;update the name table with more level graphics
 5374 ExitEng:      rts                        ;and after all that, we're finally done!
 5375 
 5376 ;-------------------------------------------------------------------------------------
 5377 
 5378 ScrollHandler:
 5379             lda Player_X_Scroll       ;load value saved here
 5380             clc
 5381             adc Platform_X_Scroll     ;add value used by left/right platforms
 5382             sta Player_X_Scroll       ;save as new value here to impose force on scroll
 5383             lda ScrollLock            ;check scroll lock flag
 5384             bne InitScrlAmt           ;skip a bunch of code here if set
 5385             lda Player_Pos_ForScroll
 5386             cmp #$50                  ;check player's horizontal screen position
 5387             bcc InitScrlAmt           ;if less than 80 pixels to the right, branch
 5388             lda SideCollisionTimer    ;if timer related to player's side collision
 5389             bne InitScrlAmt           ;not expired, branch
 5390             ldy Player_X_Scroll       ;get value and decrement by one
 5391             dey                       ;if value originally set to zero or otherwise
 5392             bmi InitScrlAmt           ;negative for left movement, branch
 5393             iny
 5394             cpy #$02                  ;if value $01, branch and do not decrement
 5395             bcc ChkNearMid
 5396             dey                       ;otherwise decrement by one
 5397 ChkNearMid: lda Player_Pos_ForScroll
 5398             cmp #$70                  ;check player's horizontal screen position
 5399             bcc ScrollScreen          ;if less than 112 pixels to the right, branch
 5400             ldy Player_X_Scroll       ;otherwise get original value undecremented
 5401 
 5402 ScrollScreen:
 5403               tya
 5404               sta ScrollAmount          ;save value here
 5405               clc
 5406               adc ScrollThirtyTwo       ;add to value already set here
 5407               sta ScrollThirtyTwo       ;save as new value here
 5408               tya
 5409               clc
 5410               adc ScreenLeft_X_Pos      ;add to left side coordinate
 5411               sta ScreenLeft_X_Pos      ;save as new left side coordinate
 5412               sta HorizontalScroll      ;save here also
 5413               lda ScreenLeft_PageLoc
 5414               adc #$00                  ;add carry to page location for left
 5415               sta ScreenLeft_PageLoc    ;side of the screen
 5416               and #$01                  ;get LSB of page location
 5417               sta $00                   ;save as temp variable for PPU register 1 mirror
 5418               lda Mirror_PPU_CTRL_REG1  ;get PPU register 1 mirror
 5419               and #%11111110            ;save all bits except d0
 5420               ora $00                   ;get saved bit here and save in PPU register 1
 5421               sta Mirror_PPU_CTRL_REG1  ;mirror to be used to set name table later
 5422               jsr GetScreenPosition     ;figure out where the right side is
 5423               lda #$08
 5424               sta ScrollIntervalTimer   ;set scroll timer (residual, not used elsewhere)
 5425               jmp ChkPOffscr            ;skip this part
 5426 InitScrlAmt:  lda #$00
 5427               sta ScrollAmount          ;initialize value here
 5428 ChkPOffscr:   ldx #$00                  ;set X for player offset
 5429               jsr GetXOffscreenBits     ;get horizontal offscreen bits for player
 5430               sta $00                   ;save them here
 5431               ldy #$00                  ;load default offset (left side)
 5432               asl                       ;if d7 of offscreen bits are set,
 5433               bcs KeepOnscr             ;branch with default offset
 5434               iny                         ;otherwise use different offset (right side)
 5435               lda $00
 5436               and #%00100000              ;check offscreen bits for d5 set
 5437               beq InitPlatScrl            ;if not set, branch ahead of this part
 5438 KeepOnscr:    lda ScreenEdge_X_Pos,y      ;get left or right side coordinate based on offset
 5439               sec
 5440               sbc X_SubtracterData,y      ;subtract amount based on offset
 5441               sta Player_X_Position       ;store as player position to prevent movement further
 5442               lda ScreenEdge_PageLoc,y    ;get left or right page location based on offset
 5443               sbc #$00                    ;subtract borrow
 5444               sta Player_PageLoc          ;save as player's page location
 5445               lda Left_Right_Buttons      ;check saved controller bits
 5446               cmp OffscrJoypadBitsData,y  ;against bits based on offset
 5447               beq InitPlatScrl            ;if not equal, branch
 5448               lda #$00
 5449               sta Player_X_Speed          ;otherwise nullify horizontal speed of player
 5450 InitPlatScrl: lda #$00                    ;nullify platform force imposed on scroll
 5451               sta Platform_X_Scroll
 5452               rts
 5453 
 5454 X_SubtracterData:
 5455       .db $00, $10
 5456 
 5457 OffscrJoypadBitsData:
 5458       .db $01, $02
 5459 
 5460 ;-------------------------------------------------------------------------------------
 5461 
 5462 GetScreenPosition:
 5463       lda ScreenLeft_X_Pos    ;get coordinate of screen's left boundary
 5464       clc
 5465       adc #$ff                ;add 255 pixels
 5466       sta ScreenRight_X_Pos   ;store as coordinate of screen's right boundary
 5467       lda ScreenLeft_PageLoc  ;get page number where left boundary is
 5468       adc #$00                ;add carry from before
 5469       sta ScreenRight_PageLoc ;store as page number where right boundary is
 5470       rts
 5471 
 5472 ;-------------------------------------------------------------------------------------
 5473 
 5474 GameRoutines:
 5475       lda GameEngineSubroutine  ;run routine based on number (a few of these routines are   
 5476       jsr JumpEngine            ;merely placeholders as conditions for other routines)
 5477 
 5478       .dw Entrance_GameTimerSetup
 5479       .dw Vine_AutoClimb
 5480       .dw SideExitPipeEntry
 5481       .dw VerticalPipeEntry
 5482       .dw FlagpoleSlide
 5483       .dw PlayerEndLevel
 5484       .dw PlayerLoseLife
 5485       .dw PlayerEntrance
 5486       .dw PlayerCtrlRoutine
 5487       .dw PlayerChangeSize
 5488       .dw PlayerInjuryBlink
 5489       .dw PlayerDeath
 5490       .dw PlayerFireFlower
 5491 
 5492 ;-------------------------------------------------------------------------------------
 5493 
 5494 PlayerEntrance:
 5495             lda AltEntranceControl    ;check for mode of alternate entry
 5496             cmp #$02
 5497             beq EntrMode2             ;if found, branch to enter from pipe or with vine
 5498             lda #$00       
 5499             ldy Player_Y_Position     ;if vertical position above a certain
 5500             cpy #$30                  ;point, nullify controller bits and continue
 5501             bcc AutoControlPlayer     ;with player movement code, do not return
 5502             lda PlayerEntranceCtrl    ;check player entry bits from header
 5503             cmp #$06
 5504             beq ChkBehPipe            ;if set to 6 or 7, execute pipe intro code
 5505             cmp #$07                  ;otherwise branch to normal entry
 5506             bne PlayerRdy
 5507 ChkBehPipe: lda Player_SprAttrib      ;check for sprite attributes
 5508             bne IntroEntr             ;branch if found
 5509             lda #$01
 5510             jmp AutoControlPlayer     ;force player to walk to the right
 5511 IntroEntr:  jsr EnterSidePipe         ;execute sub to move player to the right
 5512             dec ChangeAreaTimer       ;decrement timer for change of area
 5513             bne ExitEntr              ;branch to exit if not yet expired
 5514             inc DisableIntermediate   ;set flag to skip world and lives display
 5515             jmp NextArea              ;jump to increment to next area and set modes
 5516 EntrMode2:  lda JoypadOverride        ;if controller override bits set here,
 5517             bne VineEntr              ;branch to enter with vine
 5518             lda #$ff                  ;otherwise, set value here then execute sub
 5519             jsr MovePlayerYAxis       ;to move player upwards (note $ff = -1)
 5520             lda Player_Y_Position     ;check to see if player is at a specific coordinate
 5521             cmp #$91                  ;if player risen to a certain point (this requires pipes
 5522             bcc PlayerRdy             ;to be at specific height to look/function right) branch
 5523             rts                       ;to the last part, otherwise leave
 5524 VineEntr:   lda VineHeight
 5525             cmp #$60                  ;check vine height
 5526             bne ExitEntr              ;if vine not yet reached maximum height, branch to leave
 5527             lda Player_Y_Position     ;get player's vertical coordinate
 5528             cmp #$99                  ;check player's vertical coordinate against preset value
 5529             ldy #$00                  ;load default values to be written to 
 5530             lda #$01                  ;this value moves player to the right off the vine
 5531             bcc OffVine               ;if vertical coordinate < preset value, use defaults
 5532             lda #$03
 5533             sta Player_State          ;otherwise set player state to climbing
 5534             iny                       ;increment value in Y
 5535             lda #$08                  ;set block in block buffer to cover hole, then 
 5536             sta Block_Buffer_1+$b4    ;use same value to force player to climb
 5537 OffVine:    sty DisableCollisionDet   ;set collision detection disable flag
 5538             jsr AutoControlPlayer     ;use contents of A to move player up or right, execute sub
 5539             lda Player_X_Position
 5540             cmp #$48                  ;check player's horizontal position
 5541             bcc ExitEntr              ;if not far enough to the right, branch to leave
 5542 PlayerRdy:  lda #$08                  ;set routine to be executed by game engine next frame
 5543             sta GameEngineSubroutine
 5544             lda #$01                  ;set to face player to the right
 5545             sta PlayerFacingDir
 5546             lsr                       ;init A
 5547             sta AltEntranceControl    ;init mode of entry
 5548             sta DisableCollisionDet   ;init collision detection disable flag
 5549             sta JoypadOverride        ;nullify controller override bits
 5550 ExitEntr:   rts                       ;leave!
 5551 
 5552 ;-------------------------------------------------------------------------------------
 5553 ;$07 - used to hold upper limit of high byte when player falls down hole
 5554 
 5555 AutoControlPlayer:
 5556       sta SavedJoypadBits         ;override controller bits with contents of A if executing here
 5557 
 5558 PlayerCtrlRoutine:
 5559             lda GameEngineSubroutine    ;check task here
 5560             cmp #$0b                    ;if certain value is set, branch to skip controller bit loading
 5561             beq SizeChk
 5562             lda AreaType                ;are we in a water type area?
 5563             bne SaveJoyp                ;if not, branch
 5564             ldy Player_Y_HighPos
 5565             dey                         ;if not in vertical area between
 5566             bne DisJoyp                 ;status bar and bottom, branch
 5567             lda Player_Y_Position
 5568             cmp #$d0                    ;if nearing the bottom of the screen or
 5569             bcc SaveJoyp                ;not in the vertical area between status bar or bottom,
 5570 DisJoyp:    lda #$00                    ;disable controller bits
 5571             sta SavedJoypadBits
 5572 SaveJoyp:   lda SavedJoypadBits         ;otherwise store A and B buttons in $0a
 5573             and #%11000000
 5574             sta A_B_Buttons
 5575             lda SavedJoypadBits         ;store left and right buttons in $0c
 5576             and #%00000011
 5577             sta Left_Right_Buttons
 5578             lda SavedJoypadBits         ;store up and down buttons in $0b
 5579             and #%00001100
 5580             sta Up_Down_Buttons
 5581             and #%00000100              ;check for pressing down
 5582             beq SizeChk                 ;if not, branch
 5583             lda Player_State            ;check player's state
 5584             bne SizeChk                 ;if not on the ground, branch
 5585             ldy Left_Right_Buttons      ;check left and right
 5586             beq SizeChk                 ;if neither pressed, branch
 5587             lda #$00
 5588             sta Left_Right_Buttons      ;if pressing down while on the ground,
 5589             sta Up_Down_Buttons         ;nullify directional bits
 5590 SizeChk:    jsr PlayerMovementSubs      ;run movement subroutines
 5591             ldy #$01                    ;is player small?
 5592             lda PlayerSize
 5593             bne ChkMoveDir
 5594             ldy #$00                    ;check for if crouching
 5595             lda CrouchingFlag
 5596             beq ChkMoveDir              ;if not, branch ahead
 5597             ldy #$02                    ;if big and crouching, load y with 2
 5598 ChkMoveDir: sty Player_BoundBoxCtrl     ;set contents of Y as player's bounding box size control
 5599             lda #$01                    ;set moving direction to right by default
 5600             ldy Player_X_Speed          ;check player's horizontal speed
 5601             beq PlayerSubs              ;if not moving at all horizontally, skip this part
 5602             bpl SetMoveDir              ;if moving to the right, use default moving direction
 5603             asl                         ;otherwise change to move to the left
 5604 SetMoveDir: sta Player_MovingDir        ;set moving direction
 5605 PlayerSubs: jsr ScrollHandler           ;move the screen if necessary
 5606             jsr GetPlayerOffscreenBits  ;get player's offscreen bits
 5607             jsr RelativePlayerPosition  ;get coordinates relative to the screen
 5608             ldx #$00                    ;set offset for player object
 5609             jsr BoundingBoxCore         ;get player's bounding box coordinates
 5610             jsr PlayerBGCollision       ;do collision detection and process
 5611             lda Player_Y_Position
 5612             cmp #$40                    ;check to see if player is higher than 64th pixel
 5613             bcc PlayerHole              ;if so, branch ahead
 5614             lda GameEngineSubroutine
 5615             cmp #$05                    ;if running end-of-level routine, branch ahead
 5616             beq PlayerHole
 5617             cmp #$07                    ;if running player entrance routine, branch ahead
 5618             beq PlayerHole
 5619             cmp #$04                    ;if running routines $00-$03, branch ahead
 5620             bcc PlayerHole
 5621             lda Player_SprAttrib
 5622             and #%11011111              ;otherwise nullify player's
 5623             sta Player_SprAttrib        ;background priority flag
 5624 PlayerHole: lda Player_Y_HighPos        ;check player's vertical high byte
 5625             cmp #$02                    ;for below the screen
 5626             bmi ExitCtrl                ;branch to leave if not that far down
 5627             ldx #$01
 5628             stx ScrollLock              ;set scroll lock
 5629             ldy #$04
 5630             sty $07                     ;set value here
 5631             ldx #$00                    ;use X as flag, and clear for cloud level
 5632             ldy GameTimerExpiredFlag    ;check game timer expiration flag
 5633             bne HoleDie                 ;if set, branch
 5634             ldy CloudTypeOverride       ;check for cloud type override
 5635             bne ChkHoleX                ;skip to last part if found
 5636 HoleDie:    inx                         ;set flag in X for player death
 5637             ldy GameEngineSubroutine
 5638             cpy #$0b                    ;check for some other routine running
 5639             beq ChkHoleX                ;if so, branch ahead
 5640             ldy DeathMusicLoaded        ;check value here
 5641             bne HoleBottom              ;if already set, branch to next part
 5642             iny
 5643             sty EventMusicQueue         ;otherwise play death music
 5644             sty DeathMusicLoaded        ;and set value here
 5645 HoleBottom: ldy #$06
 5646             sty $07                     ;change value here
 5647 ChkHoleX:   cmp $07                     ;compare vertical high byte with value set here
 5648             bmi ExitCtrl                ;if less, branch to leave
 5649             dex                         ;otherwise decrement flag in X
 5650             bmi CloudExit               ;if flag was clear, branch to set modes and other values
 5651             ldy EventMusicBuffer        ;check to see if music is still playing
 5652             bne ExitCtrl                ;branch to leave if so
 5653             lda #$06                    ;otherwise set to run lose life routine
 5654             sta GameEngineSubroutine    ;on next frame
 5655 ExitCtrl:   rts                         ;leave
 5656 
 5657 CloudExit:
 5658       lda #$00
 5659       sta JoypadOverride      ;clear controller override bits if any are set
 5660       jsr SetEntr             ;do sub to set secondary mode
 5661       inc AltEntranceControl  ;set mode of entry to 3
 5662       rts
 5663 
 5664 ;-------------------------------------------------------------------------------------
 5665 
 5666 Vine_AutoClimb:
 5667            lda Player_Y_HighPos   ;check to see whether player reached position
 5668            bne AutoClimb          ;above the status bar yet and if so, set modes
 5669            lda Player_Y_Position
 5670            cmp #$e4
 5671            bcc SetEntr
 5672 AutoClimb: lda #%00001000         ;set controller bits override to up
 5673            sta JoypadOverride
 5674            ldy #$03               ;set player state to climbing
 5675            sty Player_State
 5676            jmp AutoControlPlayer
 5677 SetEntr:   lda #$02               ;set starting position to override
 5678            sta AltEntranceControl
 5679            jmp ChgAreaMode        ;set modes
 5680 
 5681 ;-------------------------------------------------------------------------------------
 5682 
 5683 VerticalPipeEntry:
 5684       lda #$01             ;set 1 as movement amount
 5685       jsr MovePlayerYAxis  ;do sub to move player downwards
 5686       jsr ScrollHandler    ;do sub to scroll screen with saved force if necessary
 5687       ldy #$00             ;load default mode of entry
 5688       lda WarpZoneControl  ;check warp zone control variable/flag
 5689       bne ChgAreaPipe      ;if set, branch to use mode 0
 5690       iny
 5691       lda AreaType         ;check for castle level type
 5692       cmp #$03
 5693       bne ChgAreaPipe      ;if not castle type level, use mode 1
 5694       iny
 5695       jmp ChgAreaPipe      ;otherwise use mode 2
 5696 
 5697 MovePlayerYAxis:
 5698       clc
 5699       adc Player_Y_Position ;add contents of A to player position
 5700       sta Player_Y_Position
 5701       rts
 5702 
 5703 ;-------------------------------------------------------------------------------------
 5704 
 5705 SideExitPipeEntry:
 5706              jsr EnterSidePipe         ;execute sub to move player to the right
 5707              ldy #$02
 5708 ChgAreaPipe: dec ChangeAreaTimer       ;decrement timer for change of area
 5709              bne ExitCAPipe
 5710              sty AltEntranceControl    ;when timer expires set mode of alternate entry
 5711 ChgAreaMode: inc DisableScreenFlag     ;set flag to disable screen output
 5712              lda #$00
 5713              sta OperMode_Task         ;set secondary mode of operation
 5714              sta Sprite0HitDetectFlag  ;disable sprite 0 check
 5715 ExitCAPipe:  rts                       ;leave
 5716 
 5717 EnterSidePipe:
 5718            lda #$08               ;set player's horizontal speed
 5719            sta Player_X_Speed
 5720            ldy #$01               ;set controller right button by default
 5721            lda Player_X_Position  ;mask out higher nybble of player's
 5722            and #%00001111         ;horizontal position
 5723            bne RightPipe
 5724            sta Player_X_Speed     ;if lower nybble = 0, set as horizontal speed
 5725            tay                    ;and nullify controller bit override here
 5726 RightPipe: tya                    ;use contents of Y to
 5727            jsr AutoControlPlayer  ;execute player control routine with ctrl bits nulled
 5728            rts
 5729 
 5730 ;-------------------------------------------------------------------------------------
 5731 
 5732 PlayerChangeSize:
 5733              lda TimerControl    ;check master timer control
 5734              cmp #$f8            ;for specific moment in time
 5735              bne EndChgSize      ;branch if before or after that point
 5736              jmp InitChangeSize  ;otherwise run code to get growing/shrinking going
 5737 EndChgSize:  cmp #$c4            ;check again for another specific moment
 5738              bne ExitChgSize     ;and branch to leave if before or after that point
 5739              jsr DonePlayerTask  ;otherwise do sub to init timer control and set routine
 5740 ExitChgSize: rts                 ;and then leave
 5741 
 5742 ;-------------------------------------------------------------------------------------
 5743 
 5744 PlayerInjuryBlink:
 5745            lda TimerControl       ;check master timer control
 5746            cmp #$f0               ;for specific moment in time
 5747            bcs ExitBlink          ;branch if before that point
 5748            cmp #$c8               ;check again for another specific point
 5749            beq DonePlayerTask     ;branch if at that point, and not before or after
 5750            jmp PlayerCtrlRoutine  ;otherwise run player control routine
 5751 ExitBlink: bne ExitBoth           ;do unconditional branch to leave
 5752 
 5753 InitChangeSize:
 5754           ldy PlayerChangeSizeFlag  ;if growing/shrinking flag already set
 5755           bne ExitBoth              ;then branch to leave
 5756           sty PlayerAnimCtrl        ;otherwise initialize player's animation frame control
 5757           inc PlayerChangeSizeFlag  ;set growing/shrinking flag
 5758           lda PlayerSize
 5759           eor #$01                  ;invert player's size
 5760           sta PlayerSize
 5761 ExitBoth: rts                       ;leave
 5762 
 5763 ;-------------------------------------------------------------------------------------
 5764 ;$00 - used in CyclePlayerPalette to store current palette to cycle
 5765 
 5766 PlayerDeath:
 5767       lda TimerControl       ;check master timer control
 5768       cmp #$f0               ;for specific moment in time
 5769       bcs ExitDeath          ;branch to leave if before that point
 5770       jmp PlayerCtrlRoutine  ;otherwise run player control routine
 5771 
 5772 DonePlayerTask:
 5773       lda #$00
 5774       sta TimerControl          ;initialize master timer control to continue timers
 5775       lda #$08
 5776       sta GameEngineSubroutine  ;set player control routine to run next frame
 5777       rts                       ;leave
 5778 
 5779 PlayerFireFlower: 
 5780       lda TimerControl       ;check master timer control
 5781       cmp #$c0               ;for specific moment in time
 5782       beq ResetPalFireFlower ;branch if at moment, not before or after
 5783       lda FrameCounter       ;get frame counter
 5784       lsr
 5785       lsr                    ;divide by four to change every four frames
 5786 
 5787 CyclePlayerPalette:
 5788       and #$03              ;mask out all but d1-d0 (previously d3-d2)
 5789       sta $00               ;store result here to use as palette bits
 5790       lda Player_SprAttrib  ;get player attributes
 5791       and #%11111100        ;save any other bits but palette bits
 5792       ora $00               ;add palette bits
 5793       sta Player_SprAttrib  ;store as new player attributes
 5794       rts                   ;and leave
 5795 
 5796 ResetPalFireFlower:
 5797       jsr DonePlayerTask    ;do sub to init timer control and run player control routine
 5798 
 5799 ResetPalStar:
 5800       lda Player_SprAttrib  ;get player attributes
 5801       and #%11111100        ;mask out palette bits to force palette 0
 5802       sta Player_SprAttrib  ;store as new player attributes
 5803       rts                   ;and leave
 5804 
 5805 ExitDeath:
 5806       rts          ;leave from death routine
 5807 
 5808 ;-------------------------------------------------------------------------------------
 5809 
 5810 FlagpoleSlide:
 5811              lda Enemy_ID+5           ;check special use enemy slot
 5812              cmp #FlagpoleFlagObject  ;for flagpole flag object
 5813              bne NoFPObj              ;if not found, branch to something residual
 5814              lda FlagpoleSoundQueue   ;load flagpole sound
 5815              sta Square1SoundQueue    ;into square 1's sfx queue
 5816              lda #$00
 5817              sta FlagpoleSoundQueue   ;init flagpole sound queue
 5818              ldy Player_Y_Position
 5819              cpy #$9e                 ;check to see if player has slid down
 5820              bcs SlidePlayer          ;far enough, and if so, branch with no controller bits set
 5821              lda #$04                 ;otherwise force player to climb down (to slide)
 5822 SlidePlayer: jmp AutoControlPlayer    ;jump to player control routine
 5823 NoFPObj:     inc GameEngineSubroutine ;increment to next routine (this may
 5824              rts                      ;be residual code)
 5825 
 5826 ;-------------------------------------------------------------------------------------
 5827 
 5828 Hidden1UpCoinAmts:
 5829       .db $15, $23, $16, $1b, $17, $18, $23, $63
 5830 
 5831 PlayerEndLevel:
 5832           lda #$01                  ;force player to walk to the right
 5833           jsr AutoControlPlayer
 5834           lda Player_Y_Position     ;check player's vertical position
 5835           cmp #$ae
 5836           bcc ChkStop               ;if player is not yet off the flagpole, skip this part
 5837           lda ScrollLock            ;if scroll lock not set, branch ahead to next part
 5838           beq ChkStop               ;because we only need to do this part once
 5839           lda #EndOfLevelMusic
 5840           sta EventMusicQueue       ;load win level music in event music queue
 5841           lda #$00
 5842           sta ScrollLock            ;turn off scroll lock to skip this part later
 5843 ChkStop:  lda Player_CollisionBits  ;get player collision bits
 5844           lsr                       ;check for d0 set
 5845           bcs RdyNextA              ;if d0 set, skip to next part
 5846           lda StarFlagTaskControl   ;if star flag task control already set,
 5847           bne InCastle              ;go ahead with the rest of the code
 5848           inc StarFlagTaskControl   ;otherwise set task control now (this gets ball rolling!)
 5849 InCastle: lda #%00100000            ;set player's background priority bit to
 5850           sta Player_SprAttrib      ;give illusion of being inside the castle
 5851 RdyNextA: lda StarFlagTaskControl
 5852           cmp #$05                  ;if star flag task control not yet set
 5853           bne ExitNA                ;beyond last valid task number, branch to leave
 5854           inc LevelNumber           ;increment level number used for game logic
 5855           lda LevelNumber
 5856           cmp #$03                  ;check to see if we have yet reached level -4
 5857           bne NextArea              ;and skip this last part here if not
 5858           ldy WorldNumber           ;get world number as offset
 5859           lda CoinTallyFor1Ups      ;check third area coin tally for bonus 1-ups
 5860           cmp Hidden1UpCoinAmts,y   ;against minimum value, if player has not collected
 5861           bcc NextArea              ;at least this number of coins, leave flag clear
 5862           inc Hidden1UpFlag         ;otherwise set hidden 1-up box control flag
 5863 NextArea: inc AreaNumber            ;increment area number used for address loader
 5864           jsr LoadAreaPointer       ;get new level pointer
 5865           inc FetchNewGameTimerFlag ;set flag to load new game timer
 5866           jsr ChgAreaMode           ;do sub to set secondary mode, disable screen and sprite 0
 5867           sta HalfwayPage           ;reset halfway page to 0 (beginning)
 5868           lda #Silence
 5869           sta EventMusicQueue       ;silence music and leave
 5870 ExitNA:   rts
 5871 
 5872 ;-------------------------------------------------------------------------------------
 5873 
 5874 PlayerMovementSubs:
 5875            lda #$00                  ;set A to init crouch flag by default
 5876            ldy PlayerSize            ;is player small?
 5877            bne SetCrouch             ;if so, branch
 5878            lda Player_State          ;check state of player
 5879            bne ProcMove              ;if not on the ground, branch
 5880            lda Up_Down_Buttons       ;load controller bits for up and down
 5881            and #%00000100            ;single out bit for down button
 5882 SetCrouch: sta CrouchingFlag         ;store value in crouch flag
 5883 ProcMove:  jsr PlayerPhysicsSub      ;run sub related to jumping and swimming
 5884            lda PlayerChangeSizeFlag  ;if growing/shrinking flag set,
 5885            bne NoMoveSub             ;branch to leave
 5886            lda Player_State
 5887            cmp #$03                  ;get player state
 5888            beq MoveSubs              ;if climbing, branch ahead, leave timer unset
 5889            ldy #$18
 5890            sty ClimbSideTimer        ;otherwise reset timer now
 5891 MoveSubs:  jsr JumpEngine
 5892 
 5893       .dw OnGroundStateSub
 5894       .dw JumpSwimSub
 5895       .dw FallingSub
 5896       .dw ClimbingSub
 5897 
 5898 NoMoveSub: rts
 5899 
 5900 ;-------------------------------------------------------------------------------------
 5901 ;$00 - used by ClimbingSub to store high vertical adder
 5902 
 5903 OnGroundStateSub:
 5904          jsr GetPlayerAnimSpeed     ;do a sub to set animation frame timing
 5905          lda Left_Right_Buttons
 5906          beq GndMove                ;if left/right controller bits not set, skip instruction
 5907          sta PlayerFacingDir        ;otherwise set new facing direction
 5908 GndMove: jsr ImposeFriction         ;do a sub to impose friction on player's walk/run
 5909          jsr MovePlayerHorizontally ;do another sub to move player horizontally
 5910          sta Player_X_Scroll        ;set returned value as player's movement speed for scroll
 5911          rts
 5912 
 5913 ;--------------------------------
 5914 
 5915 FallingSub:
 5916       lda VerticalForceDown
 5917       sta VerticalForce      ;dump vertical movement force for falling into main one
 5918       jmp LRAir              ;movement force, then skip ahead to process left/right movement
 5919 
 5920 ;--------------------------------
 5921 
 5922 JumpSwimSub:
 5923           ldy Player_Y_Speed         ;if player's vertical speed zero
 5924           bpl DumpFall               ;or moving downwards, branch to falling
 5925           lda A_B_Buttons
 5926           and #A_Button              ;check to see if A button is being pressed
 5927           and PreviousA_B_Buttons    ;and was pressed in previous frame
 5928           bne ProcSwim               ;if so, branch elsewhere
 5929           lda JumpOrigin_Y_Position  ;get vertical position player jumped from
 5930           sec
 5931           sbc Player_Y_Position      ;subtract current from original vertical coordinate
 5932           cmp DiffToHaltJump         ;compare to value set here to see if player is in mid-jump
 5933           bcc ProcSwim               ;or just starting to jump, if just starting, skip ahead
 5934 DumpFall: lda VerticalForceDown      ;otherwise dump falling into main fractional
 5935           sta VerticalForce
 5936 ProcSwim: lda SwimmingFlag           ;if swimming flag not set,
 5937           beq LRAir                  ;branch ahead to last part
 5938           jsr GetPlayerAnimSpeed     ;do a sub to get animation frame timing
 5939           lda Player_Y_Position
 5940           cmp #$14                   ;check vertical position against preset value
 5941           bcs LRWater                ;if not yet reached a certain position, branch ahead
 5942           lda #$18
 5943           sta VerticalForce          ;otherwise set fractional
 5944 LRWater:  lda Left_Right_Buttons     ;check left/right controller bits (check for swimming)
 5945           beq LRAir                  ;if not pressing any, skip
 5946           sta PlayerFacingDir        ;otherwise set facing direction accordingly
 5947 LRAir:    lda Left_Right_Buttons     ;check left/right controller bits (check for jumping/falling)
 5948           beq JSMove                 ;if not pressing any, skip
 5949           jsr ImposeFriction         ;otherwise process horizontal movement
 5950 JSMove:   jsr MovePlayerHorizontally ;do a sub to move player horizontally
 5951           sta Player_X_Scroll        ;set player's speed here, to be used for scroll later
 5952           lda GameEngineSubroutine
 5953           cmp #$0b                   ;check for specific routine selected
 5954           bne ExitMov1               ;branch if not set to run
 5955           lda #$28
 5956           sta VerticalForce          ;otherwise set fractional
 5957 ExitMov1: jmp MovePlayerVertically   ;jump to move player vertically, then leave
 5958 
 5959 ;--------------------------------
 5960 
 5961 ClimbAdderLow:
 5962       .db $0e, $04, $fc, $f2
 5963 ClimbAdderHigh:
 5964       .db $00, $00, $ff, $ff
 5965 
 5966 ClimbingSub:
 5967              lda Player_YMF_Dummy
 5968              clc                      ;add movement force to dummy variable
 5969              adc Player_Y_MoveForce   ;save with carry
 5970              sta Player_YMF_Dummy
 5971              ldy #$00                 ;set default adder here
 5972              lda Player_Y_Speed       ;get player's vertical speed
 5973              bpl MoveOnVine           ;if not moving upwards, branch
 5974              dey                      ;otherwise set adder to $ff
 5975 MoveOnVine:  sty $00                  ;store adder here
 5976              adc Player_Y_Position    ;add carry to player's vertical position
 5977              sta Player_Y_Position    ;and store to move player up or down
 5978              lda Player_Y_HighPos
 5979              adc $00                  ;add carry to player's page location
 5980              sta Player_Y_HighPos     ;and store
 5981              lda Left_Right_Buttons   ;compare left/right controller bits
 5982              and Player_CollisionBits ;to collision flag
 5983              beq InitCSTimer          ;if not set, skip to end
 5984              ldy ClimbSideTimer       ;otherwise check timer 
 5985              bne ExitCSub             ;if timer not expired, branch to leave
 5986              ldy #$18
 5987              sty ClimbSideTimer       ;otherwise set timer now
 5988              ldx #$00                 ;set default offset here
 5989              ldy PlayerFacingDir      ;get facing direction
 5990              lsr                      ;move right button controller bit to carry
 5991              bcs ClimbFD              ;if controller right pressed, branch ahead
 5992              inx
 5993              inx                      ;otherwise increment offset by 2 bytes
 5994 ClimbFD:     dey                      ;check to see if facing right
 5995              beq CSetFDir             ;if so, branch, do not increment
 5996              inx                      ;otherwise increment by 1 byte
 5997 CSetFDir:    lda Player_X_Position
 5998              clc                      ;add or subtract from player's horizontal position
 5999              adc ClimbAdderLow,x      ;using value here as adder and X as offset
 6000              sta Player_X_Position
 6001              lda Player_PageLoc       ;add or subtract carry or borrow using value here
 6002              adc ClimbAdderHigh,x     ;from the player's page location
 6003              sta Player_PageLoc
 6004              lda Left_Right_Buttons   ;get left/right controller bits again
 6005              eor #%00000011           ;invert them and store them while player
 6006              sta PlayerFacingDir      ;is on vine to face player in opposite direction
 6007 ExitCSub:    rts                      ;then leave
 6008 InitCSTimer: sta ClimbSideTimer       ;initialize timer here
 6009              rts
 6010 
 6011 ;-------------------------------------------------------------------------------------
 6012 ;$00 - used to store offset to friction data
 6013 
 6014 JumpMForceData:
 6015       .db $20, $20, $1e, $28, $28, $0d, $04
 6016 
 6017 FallMForceData:
 6018       .db $70, $70, $60, $90, $90, $0a, $09
 6019 
 6020 PlayerYSpdData:
 6021       .db $fc, $fc, $fc, $fb, $fb, $fe, $ff
 6022 
 6023 InitMForceData:
 6024       .db $00, $00, $00, $00, $00, $80, $00
 6025 
 6026 MaxLeftXSpdData:
 6027       .db $d8, $e8, $f0
 6028 
 6029 MaxRightXSpdData:
 6030       .db $28, $18, $10
 6031       .db $0c ;used for pipe intros
 6032 
 6033 FrictionData:
 6034       .db $e4, $98, $d0
 6035 
 6036 Climb_Y_SpeedData:
 6037       .db $00, $ff, $01
 6038 
 6039 Climb_Y_MForceData:
 6040       .db $00, $20, $ff
 6041 
 6042 PlayerPhysicsSub:
 6043            lda Player_State          ;check player state
 6044            cmp #$03
 6045            bne CheckForJumping       ;if not climbing, branch
 6046            ldy #$00
 6047            lda Up_Down_Buttons       ;get controller bits for up/down
 6048            and Player_CollisionBits  ;check against player's collision detection bits
 6049            beq ProcClimb             ;if not pressing up or down, branch
 6050            iny
 6051            and #%00001000            ;check for pressing up
 6052            bne ProcClimb
 6053            iny
 6054 ProcClimb: ldx Climb_Y_MForceData,y  ;load value here
 6055            stx Player_Y_MoveForce    ;store as vertical movement force
 6056            lda #$08                  ;load default animation timing
 6057            ldx Climb_Y_SpeedData,y   ;load some other value here
 6058            stx Player_Y_Speed        ;store as vertical speed
 6059            bmi SetCAnim              ;if climbing down, use default animation timing value
 6060            lsr                       ;otherwise divide timer setting by 2
 6061 SetCAnim:  sta PlayerAnimTimerSet    ;store animation timer setting and leave
 6062            rts
 6063 
 6064 CheckForJumping:
 6065         lda JumpspringAnimCtrl    ;if jumpspring animating, 
 6066         bne NoJump                ;skip ahead to something else
 6067         lda A_B_Buttons           ;check for A button press
 6068         and #A_Button
 6069         beq NoJump                ;if not, branch to something else
 6070         and PreviousA_B_Buttons   ;if button not pressed in previous frame, branch
 6071         beq ProcJumping
 6072 NoJump: jmp X_Physics             ;otherwise, jump to something else
 6073 
 6074 ProcJumping:
 6075            lda Player_State           ;check player state
 6076            beq InitJS                 ;if on the ground, branch
 6077            lda SwimmingFlag           ;if swimming flag not set, jump to do something else
 6078            beq NoJump                 ;to prevent midair jumping, otherwise continue
 6079            lda JumpSwimTimer          ;if jump/swim timer nonzero, branch
 6080            bne InitJS
 6081            lda Player_Y_Speed         ;check player's vertical speed
 6082            bpl InitJS                 ;if player's vertical speed motionless or down, branch
 6083            jmp X_Physics              ;if timer at zero and player still rising, do not swim
 6084 InitJS:    lda #$20                   ;set jump/swim timer
 6085            sta JumpSwimTimer
 6086            ldy #$00                   ;initialize vertical force and dummy variable
 6087            sty Player_YMF_Dummy
 6088            sty Player_Y_MoveForce
 6089            lda Player_Y_HighPos       ;get vertical high and low bytes of jump origin
 6090            sta JumpOrigin_Y_HighPos   ;and store them next to each other here
 6091            lda Player_Y_Position
 6092            sta JumpOrigin_Y_Position
 6093            lda #$01                   ;set player state to jumping/swimming
 6094            sta Player_State
 6095            lda Player_XSpeedAbsolute  ;check value related to walking/running speed
 6096            cmp #$09
 6097            bcc ChkWtr                 ;branch if below certain values, increment Y
 6098            iny                        ;for each amount equal or exceeded
 6099            cmp #$10
 6100            bcc ChkWtr
 6101            iny
 6102            cmp #$19
 6103            bcc ChkWtr
 6104            iny
 6105            cmp #$1c
 6106            bcc ChkWtr                 ;note that for jumping, range is 0-4 for Y
 6107            iny
 6108 ChkWtr:    lda #$01                   ;set value here (apparently always set to 1)
 6109            sta DiffToHaltJump
 6110            lda SwimmingFlag           ;if swimming flag disabled, branch
 6111            beq GetYPhy
 6112            ldy #$05                   ;otherwise set Y to 5, range is 5-6
 6113            lda Whirlpool_Flag         ;if whirlpool flag not set, branch
 6114            beq GetYPhy
 6115            iny                        ;otherwise increment to 6
 6116 GetYPhy:   lda JumpMForceData,y       ;store appropriate jump/swim
 6117            sta VerticalForce          ;data here
 6118            lda FallMForceData,y
 6119            sta VerticalForceDown
 6120            lda InitMForceData,y
 6121            sta Player_Y_MoveForce
 6122            lda PlayerYSpdData,y
 6123            sta Player_Y_Speed
 6124            lda SwimmingFlag           ;if swimming flag disabled, branch
 6125            beq PJumpSnd
 6126            lda #Sfx_EnemyStomp        ;load swim/goomba stomp sound into
 6127            sta Square1SoundQueue      ;square 1's sfx queue
 6128            lda Player_Y_Position
 6129            cmp #$14                   ;check vertical low byte of player position
 6130            bcs X_Physics              ;if below a certain point, branch
 6131            lda #$00                   ;otherwise reset player's vertical speed
 6132            sta Player_Y_Speed         ;and jump to something else to keep player
 6133            jmp X_Physics              ;from swimming above water level
 6134 PJumpSnd:  lda #Sfx_BigJump           ;load big mario's jump sound by default
 6135            ldy PlayerSize             ;is mario big?
 6136            beq SJumpSnd
 6137            lda #Sfx_SmallJump         ;if not, load small mario's jump sound
 6138 SJumpSnd:  sta Square1SoundQueue      ;store appropriate jump sound in square 1 sfx queue
 6139 X_Physics: ldy #$00
 6140            sty $00                    ;init value here
 6141            lda Player_State           ;if mario is on the ground, branch
 6142            beq ProcPRun
 6143            lda Player_XSpeedAbsolute  ;check something that seems to be related
 6144            cmp #$19                   ;to mario's speed
 6145            bcs GetXPhy                ;if =>$19 branch here
 6146            bcc ChkRFast               ;if not branch elsewhere
 6147 ProcPRun:  iny                        ;if mario on the ground, increment Y
 6148            lda AreaType               ;check area type
 6149            beq ChkRFast               ;if water type, branch
 6150            dey                        ;decrement Y by default for non-water type area
 6151            lda Left_Right_Buttons     ;get left/right controller bits
 6152            cmp Player_MovingDir       ;check against moving direction
 6153            bne ChkRFast               ;if controller bits <> moving direction, skip this part
 6154            lda A_B_Buttons            ;check for b button pressed
 6155            and #B_Button
 6156            bne SetRTmr                ;if pressed, skip ahead to set timer
 6157            lda RunningTimer           ;check for running timer set
 6158            bne GetXPhy                ;if set, branch
 6159 ChkRFast:  iny                        ;if running timer not set or level type is water, 
 6160            inc $00                    ;increment Y again and temp variable in memory
 6161            lda RunningSpeed
 6162            bne FastXSp                ;if running speed set here, branch
 6163            lda Player_XSpeedAbsolute
 6164            cmp #$21                   ;otherwise check player's walking/running speed
 6165            bcc GetXPhy                ;if less than a certain amount, branch ahead
 6166 FastXSp:   inc $00                    ;if running speed set or speed => $21 increment $00
 6167            jmp GetXPhy                ;and jump ahead
 6168 SetRTmr:   lda #$0a                   ;if b button pressed, set running timer
 6169            sta RunningTimer
 6170 GetXPhy:   lda MaxLeftXSpdData,y      ;get maximum speed to the left
 6171            sta MaximumLeftSpeed
 6172            lda GameEngineSubroutine   ;check for specific routine running
 6173            cmp #$07                   ;(player entrance)
 6174            bne GetXPhy2               ;if not running, skip and use old value of Y
 6175            ldy #$03                   ;otherwise set Y to 3
 6176 GetXPhy2:  lda MaxRightXSpdData,y     ;get maximum speed to the right
 6177            sta MaximumRightSpeed
 6178            ldy $00                    ;get other value in memory
 6179            lda FrictionData,y         ;get value using value in memory as offset
 6180            sta FrictionAdderLow
 6181            lda #$00
 6182            sta FrictionAdderHigh      ;init something here
 6183            lda PlayerFacingDir
 6184            cmp Player_MovingDir       ;check facing direction against moving direction
 6185            beq ExitPhy                ;if the same, branch to leave
 6186            asl FrictionAdderLow       ;otherwise shift d7 of friction adder low into carry
 6187            rol FrictionAdderHigh      ;then rotate carry onto d0 of friction adder high
 6188 ExitPhy:   rts                        ;and then leave
 6189 
 6190 ;-------------------------------------------------------------------------------------
 6191 
 6192 PlayerAnimTmrData:
 6193       .db $02, $04, $07
 6194 
 6195 GetPlayerAnimSpeed:
 6196             ldy #$00                   ;initialize offset in Y
 6197             lda Player_XSpeedAbsolute  ;check player's walking/running speed
 6198             cmp #$1c                   ;against preset amount
 6199             bcs SetRunSpd              ;if greater than a certain amount, branch ahead
 6200             iny                        ;otherwise increment Y
 6201             cmp #$0e                   ;compare against lower amount
 6202             bcs ChkSkid                ;if greater than this but not greater than first, skip increment
 6203             iny                        ;otherwise increment Y again
 6204 ChkSkid:    lda SavedJoypadBits        ;get controller bits
 6205             and #%01111111             ;mask out A button
 6206             beq SetAnimSpd             ;if no other buttons pressed, branch ahead of all this
 6207             and #$03                   ;mask out all others except left and right
 6208             cmp Player_MovingDir       ;check against moving direction
 6209             bne ProcSkid               ;if left/right controller bits <> moving direction, branch
 6210             lda #$00                   ;otherwise set zero value here
 6211 SetRunSpd:  sta RunningSpeed           ;store zero or running speed here
 6212             jmp SetAnimSpd
 6213 ProcSkid:   lda Player_XSpeedAbsolute  ;check player's walking/running speed
 6214             cmp #$0b                   ;against one last amount
 6215             bcs SetAnimSpd             ;if greater than this amount, branch
 6216             lda PlayerFacingDir
 6217             sta Player_MovingDir       ;otherwise use facing direction to set moving direction
 6218             lda #$00
 6219             sta Player_X_Speed         ;nullify player's horizontal speed
 6220             sta Player_X_MoveForce     ;and dummy variable for player
 6221 SetAnimSpd: lda PlayerAnimTmrData,y    ;get animation timer setting using Y as offset
 6222             sta PlayerAnimTimerSet
 6223             rts
 6224 
 6225 ;-------------------------------------------------------------------------------------
 6226 
 6227 ImposeFriction:
 6228            and Player_CollisionBits  ;perform AND between left/right controller bits and collision flag
 6229            cmp #$00                  ;then compare to zero (this instruction is redundant)
 6230            bne JoypFrict             ;if any bits set, branch to next part
 6231            lda Player_X_Speed
 6232            beq SetAbsSpd             ;if player has no horizontal speed, branch ahead to last part
 6233            bpl RghtFrict             ;if player moving to the right, branch to slow
 6234            bmi LeftFrict             ;otherwise logic dictates player moving left, branch to slow
 6235 JoypFrict: lsr                       ;put right controller bit into carry
 6236            bcc RghtFrict             ;if left button pressed, carry = 0, thus branch
 6237 LeftFrict: lda Player_X_MoveForce    ;load value set here
 6238            clc
 6239            adc FrictionAdderLow      ;add to it another value set here
 6240            sta Player_X_MoveForce    ;store here
 6241            lda Player_X_Speed
 6242            adc FrictionAdderHigh     ;add value plus carry to horizontal speed
 6243            sta Player_X_Speed        ;set as new horizontal speed
 6244            cmp MaximumRightSpeed     ;compare against maximum value for right movement
 6245            bmi XSpdSign              ;if horizontal speed greater negatively, branch
 6246            lda MaximumRightSpeed     ;otherwise set preset value as horizontal speed
 6247            sta Player_X_Speed        ;thus slowing the player's left movement down
 6248            jmp SetAbsSpd             ;skip to the end
 6249 RghtFrict: lda Player_X_MoveForce    ;load value set here
 6250            sec
 6251            sbc FrictionAdderLow      ;subtract from it another value set here
 6252            sta Player_X_MoveForce    ;store here
 6253            lda Player_X_Speed
 6254            sbc FrictionAdderHigh     ;subtract value plus borrow from horizontal speed
 6255            sta Player_X_Speed        ;set as new horizontal speed
 6256            cmp MaximumLeftSpeed      ;compare against maximum value for left movement
 6257            bpl XSpdSign              ;if horizontal speed greater positively, branch
 6258            lda MaximumLeftSpeed      ;otherwise set preset value as horizontal speed
 6259            sta Player_X_Speed        ;thus slowing the player's right movement down
 6260 XSpdSign:  cmp #$00                  ;if player not moving or moving to the right,
 6261            bpl SetAbsSpd             ;branch and leave horizontal speed value unmodified
 6262            eor #$ff
 6263            clc                       ;otherwise get two's compliment to get absolute
 6264            adc #$01                  ;unsigned walking/running speed
 6265 SetAbsSpd: sta Player_XSpeedAbsolute ;store walking/running speed here and leave
 6266            rts
 6267 
 6268 ;-------------------------------------------------------------------------------------
 6269 ;$00 - used to store downward movement force in FireballObjCore
 6270 ;$02 - used to store maximum vertical speed in FireballObjCore
 6271 ;$07 - used to store pseudorandom bit in BubbleCheck
 6272 
 6273 ProcFireball_Bubble:
 6274       lda PlayerStatus           ;check player's status
 6275       cmp #$02
 6276       bcc ProcAirBubbles         ;if not fiery, branch
 6277       lda A_B_Buttons
 6278       and #B_Button              ;check for b button pressed
 6279       beq ProcFireballs          ;branch if not pressed
 6280       and PreviousA_B_Buttons
 6281       bne ProcFireballs          ;if button pressed in previous frame, branch
 6282       lda FireballCounter        ;load fireball counter
 6283       and #%00000001             ;get LSB and use as offset for buffer
 6284       tax
 6285       lda Fireball_State,x       ;load fireball state
 6286       bne ProcFireballs          ;if not inactive, branch
 6287       ldy Player_Y_HighPos       ;if player too high or too low, branch
 6288       dey
 6289       bne ProcFireballs
 6290       lda CrouchingFlag          ;if player crouching, branch
 6291       bne ProcFireballs
 6292       lda Player_State           ;if player's state = climbing, branch
 6293       cmp #$03
 6294       beq ProcFireballs
 6295       lda #Sfx_Fireball          ;play fireball sound effect
 6296       sta Square1SoundQueue
 6297       lda #$02                   ;load state
 6298       sta Fireball_State,x
 6299       ldy PlayerAnimTimerSet     ;copy animation frame timer setting
 6300       sty FireballThrowingTimer  ;into fireball throwing timer
 6301       dey
 6302       sty PlayerAnimTimer        ;decrement and store in player's animation timer
 6303       inc FireballCounter        ;increment fireball counter
 6304 
 6305 ProcFireballs:
 6306       ldx #$00
 6307       jsr FireballObjCore  ;process first fireball object
 6308       ldx #$01
 6309       jsr FireballObjCore  ;process second fireball object, then do air bubbles
 6310 
 6311 ProcAirBubbles:
 6312           lda AreaType                ;if not water type level, skip the rest of this
 6313           bne BublExit
 6314           ldx #$02                    ;otherwise load counter and use as offset
 6315 BublLoop: stx ObjectOffset            ;store offset
 6316           jsr BubbleCheck             ;check timers and coordinates, create air bubble
 6317           jsr RelativeBubblePosition  ;get relative coordinates
 6318           jsr GetBubbleOffscreenBits  ;get offscreen information
 6319           jsr DrawBubble              ;draw the air bubble
 6320           dex
 6321           bpl BublLoop                ;do this until all three are handled
 6322 BublExit: rts                         ;then leave
 6323 
 6324 FireballXSpdData:
 6325       .db $40, $c0
 6326 
 6327 FireballObjCore:
 6328          stx ObjectOffset             ;store offset as current object
 6329          lda Fireball_State,x         ;check for d7 = 1
 6330          asl
 6331          bcs FireballExplosion        ;if so, branch to get relative coordinates and draw explosion
 6332          ldy Fireball_State,x         ;if fireball inactive, branch to leave
 6333          beq NoFBall
 6334          dey                          ;if fireball state set to 1, skip this part and just run it
 6335          beq RunFB
 6336          lda Player_X_Position        ;get player's horizontal position
 6337          adc #$04                     ;add four pixels and store as fireball's horizontal position
 6338          sta Fireball_X_Position,x
 6339          lda Player_PageLoc           ;get player's page location
 6340          adc #$00                     ;add carry and store as fireball's page location
 6341          sta Fireball_PageLoc,x
 6342          lda Player_Y_Position        ;get player's vertical position and store
 6343          sta Fireball_Y_Position,x
 6344          lda #$01                     ;set high byte of vertical position
 6345          sta Fireball_Y_HighPos,x
 6346          ldy PlayerFacingDir          ;get player's facing direction
 6347          dey                          ;decrement to use as offset here
 6348          lda FireballXSpdData,y       ;set horizontal speed of fireball accordingly
 6349          sta Fireball_X_Speed,x
 6350          lda #$04                     ;set vertical speed of fireball
 6351          sta Fireball_Y_Speed,x
 6352          lda #$07
 6353          sta Fireball_BoundBoxCtrl,x  ;set bounding box size control for fireball
 6354          dec Fireball_State,x         ;decrement state to 1 to skip this part from now on
 6355 RunFB:   txa                          ;add 7 to offset to use
 6356          clc                          ;as fireball offset for next routines
 6357          adc #$07
 6358          tax
 6359          lda #$50                     ;set downward movement force here
 6360          sta $00
 6361          lda #$03                     ;set maximum speed here
 6362          sta $02
 6363          lda #$00
 6364          jsr ImposeGravity            ;do sub here to impose gravity on fireball and move vertically
 6365          jsr MoveObjectHorizontally   ;do another sub to move it horizontally
 6366          ldx ObjectOffset             ;return fireball offset to X
 6367          jsr RelativeFireballPosition ;get relative coordinates
 6368          jsr GetFireballOffscreenBits ;get offscreen information
 6369          jsr GetFireballBoundBox      ;get bounding box coordinates
 6370          jsr FireballBGCollision      ;do fireball to background collision detection
 6371          lda FBall_OffscreenBits      ;get fireball offscreen bits
 6372          and #%11001100               ;mask out certain bits
 6373          bne EraseFB                  ;if any bits still set, branch to kill fireball
 6374          jsr FireballEnemyCollision   ;do fireball to enemy collision detection and deal with collisions
 6375          jmp DrawFireball             ;draw fireball appropriately and leave
 6376 EraseFB: lda #$00                     ;erase fireball state
 6377          sta Fireball_State,x
 6378 NoFBall: rts                          ;leave
 6379 
 6380 FireballExplosion:
 6381       jsr RelativeFireballPosition
 6382       jmp DrawExplosion_Fireball
 6383 
 6384 BubbleCheck:
 6385       lda PseudoRandomBitReg+1,x  ;get part of LSFR
 6386       and #$01
 6387       sta $07                     ;store pseudorandom bit here
 6388       lda Bubble_Y_Position,x     ;get vertical coordinate for air bubble
 6389       cmp #$f8                    ;if offscreen coordinate not set,
 6390       bne MoveBubl                ;branch to move air bubble
 6391       lda AirBubbleTimer          ;if air bubble timer not expired,
 6392       bne ExitBubl                ;branch to leave, otherwise create new air bubble
 6393 
 6394 SetupBubble:
 6395           ldy #$00                 ;load default value here
 6396           lda PlayerFacingDir      ;get player's facing direction
 6397           lsr                      ;move d0 to carry
 6398           bcc PosBubl              ;branch to use default value if facing left
 6399           ldy #$08                 ;otherwise load alternate value here
 6400 PosBubl:  tya                      ;use value loaded as adder
 6401           adc Player_X_Position    ;add to player's horizontal position
 6402           sta Bubble_X_Position,x  ;save as horizontal position for airbubble
 6403           lda Player_PageLoc
 6404           adc #$00                 ;add carry to player's page location
 6405           sta Bubble_PageLoc,x     ;save as page location for airbubble
 6406           lda Player_Y_Position
 6407           clc                      ;add eight pixels to player's vertical position
 6408           adc #$08
 6409           sta Bubble_Y_Position,x  ;save as vertical position for air bubble
 6410           lda #$01
 6411           sta Bubble_Y_HighPos,x   ;set vertical high byte for air bubble
 6412           ldy $07                  ;get pseudorandom bit, use as offset
 6413           lda BubbleTimerData,y    ;get data for air bubble timer
 6414           sta AirBubbleTimer       ;set air bubble timer
 6415 MoveBubl: ldy $07                  ;get pseudorandom bit again, use as offset
 6416           lda Bubble_YMF_Dummy,x
 6417           sec                      ;subtract pseudorandom amount from dummy variable
 6418           sbc Bubble_MForceData,y
 6419           sta Bubble_YMF_Dummy,x   ;save dummy variable
 6420           lda Bubble_Y_Position,x
 6421           sbc #$00                 ;subtract borrow from airbubble's vertical coordinate
 6422           cmp #$20                 ;if below the status bar,
 6423           bcs Y_Bubl               ;branch to go ahead and use to move air bubble upwards
 6424           lda #$f8                 ;otherwise set offscreen coordinate
 6425 Y_Bubl:   sta Bubble_Y_Position,x  ;store as new vertical coordinate for air bubble
 6426 ExitBubl: rts                      ;leave
 6427 
 6428 Bubble_MForceData:
 6429       .db $ff, $50
 6430 
 6431 BubbleTimerData:
 6432       .db $40, $20
 6433 
 6434 ;-------------------------------------------------------------------------------------
 6435 
 6436 RunGameTimer:
 6437            lda OperMode               ;get primary mode of operation
 6438            beq ExGTimer               ;branch to leave if in title screen mode
 6439            lda GameEngineSubroutine
 6440            cmp #$08                   ;if routine number less than eight running,
 6441            bcc ExGTimer               ;branch to leave
 6442            cmp #$0b                   ;if running death routine,
 6443            beq ExGTimer               ;branch to leave
 6444            lda Player_Y_HighPos
 6445            cmp #$02                   ;if player below the screen,
 6446            bcs ExGTimer               ;branch to leave regardless of level type
 6447            lda GameTimerCtrlTimer     ;if game timer control not yet expired,
 6448            bne ExGTimer               ;branch to leave
 6449            lda GameTimerDisplay
 6450            ora GameTimerDisplay+1     ;otherwise check game timer digits
 6451            ora GameTimerDisplay+2
 6452            beq TimeUpOn               ;if game timer digits at 000, branch to time-up code
 6453            ldy GameTimerDisplay       ;otherwise check first digit
 6454            dey                        ;if first digit not on 1,
 6455            bne ResGTCtrl              ;branch to reset game timer control
 6456            lda GameTimerDisplay+1     ;otherwise check second and third digits
 6457            ora GameTimerDisplay+2
 6458            bne ResGTCtrl              ;if timer not at 100, branch to reset game timer control
 6459            lda #TimeRunningOutMusic
 6460            sta EventMusicQueue        ;otherwise load time running out music
 6461 ResGTCtrl: lda #$18                   ;reset game timer control
 6462            sta GameTimerCtrlTimer
 6463            ldy #$23                   ;set offset for last digit
 6464            lda #$ff                   ;set value to decrement game timer digit
 6465            sta DigitModifier+5
 6466            jsr DigitsMathRoutine      ;do sub to decrement game timer slowly
 6467            lda #$a4                   ;set status nybbles to update game timer display
 6468            jmp PrintStatusBarNumbers  ;do sub to update the display
 6469 TimeUpOn:  sta PlayerStatus           ;init player status (note A will always be zero here)
 6470            jsr ForceInjury            ;do sub to kill the player (note player is small here)
 6471            inc GameTimerExpiredFlag   ;set game timer expiration flag
 6472 ExGTimer:  rts                        ;leave
 6473 
 6474 ;-------------------------------------------------------------------------------------
 6475 
 6476 WarpZoneObject:
 6477       lda ScrollLock         ;check for scroll lock flag
 6478       beq ExGTimer           ;branch if not set to leave
 6479       lda Player_Y_Position  ;check to see if player's vertical coordinate has
 6480       and Player_Y_HighPos   ;same bits set as in vertical high byte (why?)
 6481       bne ExGTimer           ;if so, branch to leave
 6482       sta ScrollLock         ;otherwise nullify scroll lock flag
 6483       inc WarpZoneControl    ;increment warp zone flag to make warp pipes for warp zone
 6484       jmp EraseEnemyObject   ;kill this object
 6485 
 6486 ;-------------------------------------------------------------------------------------
 6487 ;$00 - used in WhirlpoolActivate to store whirlpool length / 2, page location of center of whirlpool
 6488 ;and also to store movement force exerted on player
 6489 ;$01 - used in ProcessWhirlpools to store page location of right extent of whirlpool
 6490 ;and in WhirlpoolActivate to store center of whirlpool
 6491 ;$02 - used in ProcessWhirlpools to store right extent of whirlpool and in
 6492 ;WhirlpoolActivate to store maximum vertical speed
 6493 
 6494 ProcessWhirlpools:
 6495         lda AreaType                ;check for water type level
 6496         bne ExitWh                  ;branch to leave if not found
 6497         sta Whirlpool_Flag          ;otherwise initialize whirlpool flag
 6498         lda TimerControl            ;if master timer control set,
 6499         bne ExitWh                  ;branch to leave
 6500         ldy #$04                    ;otherwise start with last whirlpool data
 6501 WhLoop: lda Whirlpool_LeftExtent,y  ;get left extent of whirlpool
 6502         clc
 6503         adc Whirlpool_Length,y      ;add length of whirlpool
 6504         sta $02                     ;store result as right extent here
 6505         lda Whirlpool_PageLoc,y     ;get page location
 6506         beq NextWh                  ;if none or page 0, branch to get next data
 6507         adc #$00                    ;add carry
 6508         sta $01                     ;store result as page location of right extent here
 6509         lda Player_X_Position       ;get player's horizontal position
 6510         sec
 6511         sbc Whirlpool_LeftExtent,y  ;subtract left extent
 6512         lda Player_PageLoc          ;get player's page location
 6513         sbc Whirlpool_PageLoc,y     ;subtract borrow
 6514         bmi NextWh                  ;if player too far left, branch to get next data
 6515         lda $02                     ;otherwise get right extent
 6516         sec
 6517         sbc Player_X_Position       ;subtract player's horizontal coordinate
 6518         lda $01                     ;get right extent's page location
 6519         sbc Player_PageLoc          ;subtract borrow
 6520         bpl WhirlpoolActivate       ;if player within right extent, branch to whirlpool code
 6521 NextWh: dey                         ;move onto next whirlpool data
 6522         bpl WhLoop                  ;do this until all whirlpools are checked
 6523 ExitWh: rts                         ;leave
 6524 
 6525 WhirlpoolActivate:
 6526         lda Whirlpool_Length,y      ;get length of whirlpool
 6527         lsr                         ;divide by 2
 6528         sta $00                     ;save here
 6529         lda Whirlpool_LeftExtent,y  ;get left extent of whirlpool
 6530         clc
 6531         adc $00                     ;add length divided by 2
 6532         sta $01                     ;save as center of whirlpool
 6533         lda Whirlpool_PageLoc,y     ;get page location
 6534         adc #$00                    ;add carry
 6535         sta $00                     ;save as page location of whirlpool center
 6536         lda FrameCounter            ;get frame counter
 6537         lsr                         ;shift d0 into carry (to run on every other frame)
 6538         bcc WhPull                  ;if d0 not set, branch to last part of code
 6539         lda $01                     ;get center
 6540         sec
 6541         sbc Player_X_Position       ;subtract player's horizontal coordinate
 6542         lda $00                     ;get page location of center
 6543         sbc Player_PageLoc          ;subtract borrow
 6544         bpl LeftWh                  ;if player to the left of center, branch
 6545         lda Player_X_Position       ;otherwise slowly pull player left, towards the center
 6546         sec
 6547         sbc #$01                    ;subtract one pixel
 6548         sta Player_X_Position       ;set player's new horizontal coordinate
 6549         lda Player_PageLoc
 6550         sbc #$00                    ;subtract borrow
 6551         jmp SetPWh                  ;jump to set player's new page location
 6552 LeftWh: lda Player_CollisionBits    ;get player's collision bits
 6553         lsr                         ;shift d0 into carry
 6554         bcc WhPull                  ;if d0 not set, branch
 6555         lda Player_X_Position       ;otherwise slowly pull player right, towards the center
 6556         clc
 6557         adc #$01                    ;add one pixel
 6558         sta Player_X_Position       ;set player's new horizontal coordinate
 6559         lda Player_PageLoc
 6560         adc #$00                    ;add carry
 6561 SetPWh: sta Player_PageLoc          ;set player's new page location
 6562 WhPull: lda #$10
 6563         sta $00                     ;set vertical movement force
 6564         lda #$01
 6565         sta Whirlpool_Flag          ;set whirlpool flag to be used later
 6566         sta $02                     ;also set maximum vertical speed
 6567         lsr
 6568         tax                         ;set X for player offset
 6569         jmp ImposeGravity           ;jump to put whirlpool effect on player vertically, do not return
 6570 
 6571 ;-------------------------------------------------------------------------------------
 6572 
 6573 FlagpoleScoreMods:
 6574       .db $05, $02, $08, $04, $01
 6575 
 6576 FlagpoleScoreDigits:
 6577       .db $03, $03, $04, $04, $04
 6578 
 6579 FlagpoleRoutine:
 6580            ldx #$05                  ;set enemy object offset
 6581            stx ObjectOffset          ;to special use slot
 6582            lda Enemy_ID,x
 6583            cmp #FlagpoleFlagObject   ;if flagpole flag not found,
 6584            bne ExitFlagP             ;branch to leave
 6585            lda GameEngineSubroutine
 6586            cmp #$04                  ;if flagpole slide routine not running,
 6587            bne SkipScore             ;branch to near the end of code
 6588            lda Player_State
 6589            cmp #$03                  ;if player state not climbing,
 6590            bne SkipScore             ;branch to near the end of code
 6591            lda Enemy_Y_Position,x    ;check flagpole flag's vertical coordinate
 6592            cmp #$aa                  ;if flagpole flag down to a certain point,
 6593            bcs GiveFPScr             ;branch to end the level
 6594            lda Player_Y_Position     ;check player's vertical coordinate
 6595            cmp #$a2                  ;if player down to a certain point,
 6596            bcs GiveFPScr             ;branch to end the level
 6597            lda Enemy_YMF_Dummy,x
 6598            adc #$ff                  ;add movement amount to dummy variable
 6599            sta Enemy_YMF_Dummy,x     ;save dummy variable
 6600            lda Enemy_Y_Position,x    ;get flag's vertical coordinate
 6601            adc #$01                  ;add 1 plus carry to move flag, and
 6602            sta Enemy_Y_Position,x    ;store vertical coordinate
 6603            lda FlagpoleFNum_YMFDummy
 6604            sec                       ;subtract movement amount from dummy variable
 6605            sbc #$ff
 6606            sta FlagpoleFNum_YMFDummy ;save dummy variable
 6607            lda FlagpoleFNum_Y_Pos
 6608            sbc #$01                  ;subtract one plus borrow to move floatey number,
 6609            sta FlagpoleFNum_Y_Pos    ;and store vertical coordinate here
 6610 SkipScore: jmp FPGfx                 ;jump to skip ahead and draw flag and floatey number
 6611 GiveFPScr: ldy FlagpoleScore         ;get score offset from earlier (when player touched flagpole)
 6612            lda FlagpoleScoreMods,y   ;get amount to award player points
 6613            ldx FlagpoleScoreDigits,y ;get digit with which to award points
 6614            sta DigitModifier,x       ;store in digit modifier
 6615            jsr AddToScore            ;do sub to award player points depending on height of collision
 6616            lda #$05
 6617            sta GameEngineSubroutine  ;set to run end-of-level subroutine on next frame
 6618 FPGfx:     jsr GetEnemyOffscreenBits ;get offscreen information
 6619            jsr RelativeEnemyPosition ;get relative coordinates
 6620            jsr FlagpoleGfxHandler    ;draw flagpole flag and floatey number
 6621 ExitFlagP: rts
 6622 
 6623 ;-------------------------------------------------------------------------------------
 6624 
 6625 Jumpspring_Y_PosData:
 6626       .db $08, $10, $08, $00
 6627 
 6628 JumpspringHandler:
 6629            jsr GetEnemyOffscreenBits   ;get offscreen information
 6630            lda TimerControl            ;check master timer control
 6631            bne DrawJSpr                ;branch to last section if set
 6632            lda JumpspringAnimCtrl      ;check jumpspring frame control
 6633            beq DrawJSpr                ;branch to last section if not set
 6634            tay
 6635            dey                         ;subtract one from frame control,
 6636            tya                         ;the only way a poor nmos 6502 can
 6637            and #%00000010              ;mask out all but d1, original value still in Y
 6638            bne DownJSpr                ;if set, branch to move player up
 6639            inc Player_Y_Position
 6640            inc Player_Y_Position       ;move player's vertical position down two pixels
 6641            jmp PosJSpr                 ;skip to next part
 6642 DownJSpr:  dec Player_Y_Position       ;move player's vertical position up two pixels
 6643            dec Player_Y_Position
 6644 PosJSpr:   lda Jumpspring_FixedYPos,x  ;get permanent vertical position
 6645            clc
 6646            adc Jumpspring_Y_PosData,y  ;add value using frame control as offset
 6647            sta Enemy_Y_Position,x      ;store as new vertical position
 6648            cpy #$01                    ;check frame control offset (second frame is $00)
 6649            bcc BounceJS                ;if offset not yet at third frame ($01), skip to next part
 6650            lda A_B_Buttons
 6651            and #A_Button               ;check saved controller bits for A button press
 6652            beq BounceJS                ;skip to next part if A not pressed
 6653            and PreviousA_B_Buttons     ;check for A button pressed in previous frame
 6654            bne BounceJS                ;skip to next part if so
 6655            lda #$f4
 6656            sta JumpspringForce         ;otherwise write new jumpspring force here
 6657 BounceJS:  cpy #$03                    ;check frame control offset again
 6658            bne DrawJSpr                ;skip to last part if not yet at fifth frame ($03)
 6659            lda JumpspringForce
 6660            sta Player_Y_Speed          ;store jumpspring force as player's new vertical speed
 6661            lda #$00
 6662            sta JumpspringAnimCtrl      ;initialize jumpspring frame control
 6663 DrawJSpr:  jsr RelativeEnemyPosition   ;get jumpspring's relative coordinates
 6664            jsr EnemyGfxHandler         ;draw jumpspring
 6665            jsr OffscreenBoundsCheck    ;check to see if we need to kill it
 6666            lda JumpspringAnimCtrl      ;if frame control at zero, don't bother
 6667            beq ExJSpring               ;trying to animate it, just leave
 6668            lda JumpspringTimer
 6669            bne ExJSpring               ;if jumpspring timer not expired yet, leave
 6670            lda #$04
 6671            sta JumpspringTimer         ;otherwise initialize jumpspring timer
 6672            inc JumpspringAnimCtrl      ;increment frame control to animate jumpspring
 6673 ExJSpring: rts                         ;leave
 6674 
 6675 ;-------------------------------------------------------------------------------------
 6676 
 6677 Setup_Vine:
 6678         lda #VineObject          ;load identifier for vine object
 6679         sta Enemy_ID,x           ;store in buffer
 6680         lda #$01
 6681         sta Enemy_Flag,x         ;set flag for enemy object buffer
 6682         lda Block_PageLoc,y
 6683         sta Enemy_PageLoc,x      ;copy page location from previous object
 6684         lda Block_X_Position,y
 6685         sta Enemy_X_Position,x   ;copy horizontal coordinate from previous object
 6686         lda Block_Y_Position,y
 6687         sta Enemy_Y_Position,x   ;copy vertical coordinate from previous object
 6688         ldy VineFlagOffset       ;load vine flag/offset to next available vine slot
 6689         bne NextVO               ;if set at all, don't bother to store vertical
 6690         sta VineStart_Y_Position ;otherwise store vertical coordinate here
 6691 NextVO: txa                      ;store object offset to next available vine slot
 6692         sta VineObjOffset,y      ;using vine flag as offset
 6693         inc VineFlagOffset       ;increment vine flag offset
 6694         lda #Sfx_GrowVine
 6695         sta Square2SoundQueue    ;load vine grow sound
 6696         rts
 6697 
 6698 ;-------------------------------------------------------------------------------------
 6699 ;$06-$07 - used as address to block buffer data
 6700 ;$02 - used as vertical high nybble of block buffer offset
 6701 
 6702 VineHeightData:
 6703       .db $30, $60
 6704 
 6705 VineObjectHandler:
 6706            cpx #$05                  ;check enemy offset for special use slot
 6707            bne ExitVH                ;if not in last slot, branch to leave
 6708            ldy VineFlagOffset
 6709            dey                       ;decrement vine flag in Y, use as offset
 6710            lda VineHeight
 6711            cmp VineHeightData,y      ;if vine has reached certain height,
 6712            beq RunVSubs              ;branch ahead to skip this part
 6713            lda FrameCounter          ;get frame counter
 6714            lsr                       ;shift d1 into carry
 6715            lsr
 6716            bcc RunVSubs              ;if d1 not set (2 frames every 4) skip this part
 6717            lda Enemy_Y_Position+5
 6718            sbc #$01                  ;subtract vertical position of vine
 6719            sta Enemy_Y_Position+5    ;one pixel every frame it's time
 6720            inc VineHeight            ;increment vine height
 6721 RunVSubs:  lda VineHeight            ;if vine still very small,
 6722            cmp #$08                  ;branch to leave
 6723            bcc ExitVH
 6724            jsr RelativeEnemyPosition ;get relative coordinates of vine,
 6725            jsr GetEnemyOffscreenBits ;and any offscreen bits
 6726            ldy #$00                  ;initialize offset used in draw vine sub
 6727 VDrawLoop: jsr DrawVine              ;draw vine
 6728            iny                       ;increment offset
 6729            cpy VineFlagOffset        ;if offset in Y and offset here
 6730            bne VDrawLoop             ;do not yet match, loop back to draw more vine
 6731            lda Enemy_OffscreenBits
 6732            and #%00001100            ;mask offscreen bits
 6733            beq WrCMTile              ;if none of the saved offscreen bits set, skip ahead
 6734            dey                       ;otherwise decrement Y to get proper offset again
 6735 KillVine:  ldx VineObjOffset,y       ;get enemy object offset for this vine object
 6736            jsr EraseEnemyObject      ;kill this vine object
 6737            dey                       ;decrement Y
 6738            bpl KillVine              ;if any vine objects left, loop back to kill it
 6739            sta VineFlagOffset        ;initialize vine flag/offset
 6740            sta VineHeight            ;initialize vine height
 6741 WrCMTile:  lda VineHeight            ;check vine height
 6742            cmp #$20                  ;if vine small (less than 32 pixels tall)
 6743            bcc ExitVH                ;then branch ahead to leave
 6744            ldx #$06                  ;set offset in X to last enemy slot
 6745            lda #$01                  ;set A to obtain horizontal in $04, but we don't care
 6746            ldy #$1b                  ;set Y to offset to get block at ($04, $10) of coordinates
 6747            jsr BlockBufferCollision  ;do a sub to get block buffer address set, return contents
 6748            ldy $02
 6749            cpy #$d0                  ;if vertical high nybble offset beyond extent of
 6750            bcs ExitVH                ;current block buffer, branch to leave, do not write
 6751            lda ($06),y               ;otherwise check contents of block buffer at 
 6752            bne ExitVH                ;current offset, if not empty, branch to leave
 6753            lda #$26
 6754            sta ($06),y               ;otherwise, write climbing metatile to block buffer
 6755 ExitVH:    ldx ObjectOffset          ;get enemy object offset and leave
 6756            rts
 6757 
 6758 ;-------------------------------------------------------------------------------------
 6759 
 6760 CannonBitmasks:
 6761       .db %00001111, %00000111
 6762 
 6763 ProcessCannons:
 6764            lda AreaType                ;get area type
 6765            beq ExCannon                ;if water type area, branch to leave
 6766            ldx #$02
 6767 ThreeSChk: stx ObjectOffset            ;start at third enemy slot
 6768            lda Enemy_Flag,x            ;check enemy buffer flag
 6769            bne Chk_BB                  ;if set, branch to check enemy
 6770            lda PseudoRandomBitReg+1,x  ;otherwise get part of LSFR
 6771            ldy SecondaryHardMode       ;get secondary hard mode flag, use as offset
 6772            and CannonBitmasks,y        ;mask out bits of LSFR as decided by flag
 6773            cmp #$06                    ;check to see if lower nybble is above certain value
 6774            bcs Chk_BB                  ;if so, branch to check enemy
 6775            tay                         ;transfer masked contents of LSFR to Y as pseudorandom offset
 6776            lda Cannon_PageLoc,y        ;get page location
 6777            beq Chk_BB                  ;if not set or on page 0, branch to check enemy
 6778            lda Cannon_Timer,y          ;get cannon timer
 6779            beq FireCannon              ;if expired, branch to fire cannon
 6780            sbc #$00                    ;otherwise subtract borrow (note carry will always be clear here)
 6781            sta Cannon_Timer,y          ;to count timer down
 6782            jmp Chk_BB                  ;then jump ahead to check enemy
 6783 
 6784 FireCannon:
 6785           lda TimerControl           ;if master timer control set,
 6786           bne Chk_BB                 ;branch to check enemy
 6787           lda #$0e                   ;otherwise we start creating one
 6788           sta Cannon_Timer,y         ;first, reset cannon timer
 6789           lda Cannon_PageLoc,y       ;get page location of cannon
 6790           sta Enemy_PageLoc,x        ;save as page location of bullet bill
 6791           lda Cannon_X_Position,y    ;get horizontal coordinate of cannon
 6792           sta Enemy_X_Position,x     ;save as horizontal coordinate of bullet bill
 6793           lda Cannon_Y_Position,y    ;get vertical coordinate of cannon
 6794           sec
 6795           sbc #$08                   ;subtract eight pixels (because enemies are 24 pixels tall)
 6796           sta Enemy_Y_Position,x     ;save as vertical coordinate of bullet bill
 6797           lda #$01
 6798           sta Enemy_Y_HighPos,x      ;set vertical high byte of bullet bill
 6799           sta Enemy_Flag,x           ;set buffer flag
 6800           lsr                        ;shift right once to init A
 6801           sta Enemy_State,x          ;then initialize enemy's state
 6802           lda #$09
 6803           sta Enemy_BoundBoxCtrl,x   ;set bounding box size control for bullet bill
 6804           lda #BulletBill_CannonVar
 6805           sta Enemy_ID,x             ;load identifier for bullet bill (cannon variant)
 6806           jmp Next3Slt               ;move onto next slot
 6807 Chk_BB:   lda Enemy_ID,x             ;check enemy identifier for bullet bill (cannon variant)
 6808           cmp #BulletBill_CannonVar
 6809           bne Next3Slt               ;if not found, branch to get next slot
 6810           jsr OffscreenBoundsCheck   ;otherwise, check to see if it went offscreen
 6811           lda Enemy_Flag,x           ;check enemy buffer flag
 6812           beq Next3Slt               ;if not set, branch to get next slot
 6813           jsr GetEnemyOffscreenBits  ;otherwise, get offscreen information
 6814           jsr BulletBillHandler      ;then do sub to handle bullet bill
 6815 Next3Slt: dex                        ;move onto next slot
 6816           bpl ThreeSChk              ;do this until first three slots are checked
 6817 ExCannon: rts                        ;then leave
 6818 
 6819 ;--------------------------------
 6820 
 6821 BulletBillXSpdData:
 6822       .db $18, $e8
 6823 
 6824 BulletBillHandler:
 6825            lda TimerControl          ;if master timer control set,
 6826            bne RunBBSubs             ;branch to run subroutines except movement sub
 6827            lda Enemy_State,x
 6828            bne ChkDSte               ;if bullet bill's state set, branch to check defeated state
 6829            lda Enemy_OffscreenBits   ;otherwise load offscreen bits
 6830            and #%00001100            ;mask out bits
 6831            cmp #%00001100            ;check to see if all bits are set
 6832            beq KillBB                ;if so, branch to kill this object
 6833            ldy #$01                  ;set to move right by default
 6834            jsr PlayerEnemyDiff       ;get horizontal difference between player and bullet bill
 6835            bmi SetupBB               ;if enemy to the left of player, branch
 6836            iny                       ;otherwise increment to move left
 6837 SetupBB:   sty Enemy_MovingDir,x     ;set bullet bill's moving direction
 6838            dey                       ;decrement to use as offset
 6839            lda BulletBillXSpdData,y  ;get horizontal speed based on moving direction
 6840            sta Enemy_X_Speed,x       ;and store it
 6841            lda $00                   ;get horizontal difference
 6842            adc #$28                  ;add 40 pixels
 6843            cmp #$50                  ;if less than a certain amount, player is too close
 6844            bcc KillBB                ;to cannon either on left or right side, thus branch
 6845            lda #$01
 6846            sta Enemy_State,x         ;otherwise set bullet bill's state
 6847            lda #$0a
 6848            sta EnemyFrameTimer,x     ;set enemy frame timer
 6849            lda #Sfx_Blast
 6850            sta Square2SoundQueue     ;play fireworks/gunfire sound
 6851 ChkDSte:   lda Enemy_State,x         ;check enemy state for d5 set
 6852            and #%00100000
 6853            beq BBFly                 ;if not set, skip to move horizontally
 6854            jsr MoveD_EnemyVertically ;otherwise do sub to move bullet bill vertically
 6855 BBFly:     jsr MoveEnemyHorizontally ;do sub to move bullet bill horizontally
 6856 RunBBSubs: jsr GetEnemyOffscreenBits ;get offscreen information
 6857            jsr RelativeEnemyPosition ;get relative coordinates
 6858            jsr GetEnemyBoundBox      ;get bounding box coordinates
 6859            jsr PlayerEnemyCollision  ;handle player to enemy collisions
 6860            jmp EnemyGfxHandler       ;draw the bullet bill and leave
 6861 KillBB:    jsr EraseEnemyObject      ;kill bullet bill and leave
 6862            rts
 6863 
 6864 ;-------------------------------------------------------------------------------------
 6865 
 6866 HammerEnemyOfsData:
 6867       .db $04, $04, $04, $05, $05, $05
 6868       .db $06, $06, $06
 6869 
 6870 HammerXSpdData:
 6871       .db $10, $f0
 6872 
 6873 SpawnHammerObj:
 6874           lda PseudoRandomBitReg+1 ;get pseudorandom bits from
 6875           and #%00000111           ;second part of LSFR
 6876           bne SetMOfs              ;if any bits are set, branch and use as offset
 6877           lda PseudoRandomBitReg+1
 6878           and #%00001000           ;get d3 from same part of LSFR
 6879 SetMOfs:  tay                      ;use either d3 or d2-d0 for offset here
 6880           lda Misc_State,y         ;if any values loaded in
 6881           bne NoHammer             ;$2a-$32 where offset is then leave with carry clear
 6882           ldx HammerEnemyOfsData,y ;get offset of enemy slot to check using Y as offset
 6883           lda Enemy_Flag,x         ;check enemy buffer flag at offset
 6884           bne NoHammer             ;if buffer flag set, branch to leave with carry clear
 6885           ldx ObjectOffset         ;get original enemy object offset
 6886           txa
 6887           sta HammerEnemyOffset,y  ;save here
 6888           lda #$90
 6889           sta Misc_State,y         ;save hammer's state here
 6890           lda #$07
 6891           sta Misc_BoundBoxCtrl,y  ;set something else entirely, here
 6892           sec                      ;return with carry set
 6893           rts
 6894 NoHammer: ldx ObjectOffset         ;get original enemy object offset
 6895           clc                      ;return with carry clear
 6896           rts
 6897 
 6898 ;--------------------------------
 6899 ;$00 - used to set downward force
 6900 ;$01 - used to set upward force (residual)
 6901 ;$02 - used to set maximum speed
 6902 
 6903 ProcHammerObj:
 6904           lda TimerControl           ;if master timer control set
 6905           bne RunHSubs               ;skip all of this code and go to last subs at the end
 6906           lda Misc_State,x           ;otherwise get hammer's state
 6907           and #%01111111             ;mask out d7
 6908           ldy HammerEnemyOffset,x    ;get enemy object offset that spawned this hammer
 6909           cmp #$02                   ;check hammer's state
 6910           beq SetHSpd                ;if currently at 2, branch
 6911           bcs SetHPos                ;if greater than 2, branch elsewhere
 6912           txa
 6913           clc                        ;add 13 bytes to use
 6914           adc #$0d                   ;proper misc object
 6915           tax                        ;return offset to X
 6916           lda #$10
 6917           sta $00                    ;set downward movement force
 6918           lda #$0f
 6919           sta $01                    ;set upward movement force (not used)
 6920           lda #$04
 6921           sta $02                    ;set maximum vertical speed
 6922           lda #$00                   ;set A to impose gravity on hammer
 6923           jsr ImposeGravity          ;do sub to impose gravity on hammer and move vertically
 6924           jsr MoveObjectHorizontally ;do sub to move it horizontally
 6925           ldx ObjectOffset           ;get original misc object offset
 6926           jmp RunAllH                ;branch to essential subroutines
 6927 SetHSpd:  lda #$fe
 6928           sta Misc_Y_Speed,x         ;set hammer's vertical speed
 6929           lda Enemy_State,y          ;get enemy object state
 6930           and #%11110111             ;mask out d3
 6931           sta Enemy_State,y          ;store new state
 6932           ldx Enemy_MovingDir,y      ;get enemy's moving direction
 6933           dex                        ;decrement to use as offset
 6934           lda HammerXSpdData,x       ;get proper speed to use based on moving direction
 6935           ldx ObjectOffset           ;reobtain hammer's buffer offset
 6936           sta Misc_X_Speed,x         ;set hammer's horizontal speed
 6937 SetHPos:  dec Misc_State,x           ;decrement hammer's state
 6938           lda Enemy_X_Position,y     ;get enemy's horizontal position
 6939           clc
 6940           adc #$02                   ;set position 2 pixels to the right
 6941           sta Misc_X_Position,x      ;store as hammer's horizontal position
 6942           lda Enemy_PageLoc,y        ;get enemy's page location
 6943           adc #$00                   ;add carry
 6944           sta Misc_PageLoc,x         ;store as hammer's page location
 6945           lda Enemy_Y_Position,y     ;get enemy's vertical position
 6946           sec
 6947           sbc #$0a                   ;move position 10 pixels upward
 6948           sta Misc_Y_Position,x      ;store as hammer's vertical position
 6949           lda #$01
 6950           sta Misc_Y_HighPos,x       ;set hammer's vertical high byte
 6951           bne RunHSubs               ;unconditional branch to skip first routine
 6952 RunAllH:  jsr PlayerHammerCollision  ;handle collisions
 6953 RunHSubs: jsr GetMiscOffscreenBits   ;get offscreen information
 6954           jsr RelativeMiscPosition   ;get relative coordinates
 6955           jsr GetMiscBoundBox        ;get bounding box coordinates
 6956           jsr DrawHammer             ;draw the hammer
 6957           rts                        ;and we are done here
 6958 
 6959 ;-------------------------------------------------------------------------------------
 6960 ;$02 - used to store vertical high nybble offset from block buffer routine
 6961 ;$06 - used to store low byte of block buffer address
 6962 
 6963 CoinBlock:
 6964       jsr FindEmptyMiscSlot   ;set offset for empty or last misc object buffer slot
 6965       lda Block_PageLoc,x     ;get page location of block object
 6966       sta Misc_PageLoc,y      ;store as page location of misc object
 6967       lda Block_X_Position,x  ;get horizontal coordinate of block object
 6968       ora #$05                ;add 5 pixels
 6969       sta Misc_X_Position,y   ;store as horizontal coordinate of misc object
 6970       lda Block_Y_Position,x  ;get vertical coordinate of block object
 6971       sbc #$10                ;subtract 16 pixels
 6972       sta Misc_Y_Position,y   ;store as vertical coordinate of misc object
 6973       jmp JCoinC              ;jump to rest of code as applies to this misc object
 6974 
 6975 SetupJumpCoin:
 6976         jsr FindEmptyMiscSlot  ;set offset for empty or last misc object buffer slot
 6977         lda Block_PageLoc2,x   ;get page location saved earlier
 6978         sta Misc_PageLoc,y     ;and save as page location for misc object
 6979         lda $06                ;get low byte of block buffer offset
 6980         asl
 6981         asl                    ;multiply by 16 to use lower nybble
 6982         asl
 6983         asl
 6984         ora #$05               ;add five pixels
 6985         sta Misc_X_Position,y  ;save as horizontal coordinate for misc object
 6986         lda $02                ;get vertical high nybble offset from earlier
 6987         adc #$20               ;add 32 pixels for the status bar
 6988         sta Misc_Y_Position,y  ;store as vertical coordinate
 6989 JCoinC: lda #$fb
 6990         sta Misc_Y_Speed,y     ;set vertical speed
 6991         lda #$01
 6992         sta Misc_Y_HighPos,y   ;set vertical high byte
 6993         sta Misc_State,y       ;set state for misc object
 6994         sta Square2SoundQueue  ;load coin grab sound
 6995         stx ObjectOffset       ;store current control bit as misc object offset 
 6996         jsr GiveOneCoin        ;update coin tally on the screen and coin amount variable
 6997         inc CoinTallyFor1Ups   ;increment coin tally used to activate 1-up block flag
 6998         rts
 6999 
 7000 FindEmptyMiscSlot:
 7001            ldy #$08                ;start at end of misc objects buffer
 7002 FMiscLoop: lda Misc_State,y        ;get misc object state
 7003            beq UseMiscS            ;branch if none found to use current offset
 7004            dey                     ;decrement offset
 7005            cpy #$05                ;do this for three slots
 7006            bne FMiscLoop           ;do this until all slots are checked
 7007            ldy #$08                ;if no empty slots found, use last slot
 7008 UseMiscS:  sty JumpCoinMiscOffset  ;store offset of misc object buffer here (residual)
 7009            rts
 7010 
 7011 ;-------------------------------------------------------------------------------------
 7012 
 7013 MiscObjectsCore:
 7014           ldx #$08          ;set at end of misc object buffer
 7015 MiscLoop: stx ObjectOffset  ;store misc object offset here
 7016           lda Misc_State,x  ;check misc object state
 7017           beq MiscLoopBack  ;branch to check next slot
 7018           asl               ;otherwise shift d7 into carry
 7019           bcc ProcJumpCoin  ;if d7 not set, jumping coin, thus skip to rest of code here
 7020           jsr ProcHammerObj ;otherwise go to process hammer,
 7021           jmp MiscLoopBack  ;then check next slot
 7022 
 7023 ;--------------------------------
 7024 ;$00 - used to set downward force
 7025 ;$01 - used to set upward force (residual)
 7026 ;$02 - used to set maximum speed
 7027 
 7028 ProcJumpCoin:
 7029            ldy Misc_State,x          ;check misc object state
 7030            dey                       ;decrement to see if it's set to 1
 7031            beq JCoinRun              ;if so, branch to handle jumping coin
 7032            inc Misc_State,x          ;otherwise increment state to either start off or as timer
 7033            lda Misc_X_Position,x     ;get horizontal coordinate for misc object
 7034            clc                       ;whether its jumping coin (state 0 only) or floatey number
 7035            adc ScrollAmount          ;add current scroll speed
 7036            sta Misc_X_Position,x     ;store as new horizontal coordinate
 7037            lda Misc_PageLoc,x        ;get page location
 7038            adc #$00                  ;add carry
 7039            sta Misc_PageLoc,x        ;store as new page location
 7040            lda Misc_State,x
 7041            cmp #$30                  ;check state of object for preset value
 7042            bne RunJCSubs             ;if not yet reached, branch to subroutines
 7043            lda #$00
 7044            sta Misc_State,x          ;otherwise nullify object state
 7045            jmp MiscLoopBack          ;and move onto next slot
 7046 JCoinRun:  txa             
 7047            clc                       ;add 13 bytes to offset for next subroutine
 7048            adc #$0d
 7049            tax
 7050            lda #$50                  ;set downward movement amount
 7051            sta $00
 7052            lda #$06                  ;set maximum vertical speed
 7053            sta $02
 7054            lsr                       ;divide by 2 and set
 7055            sta $01                   ;as upward movement amount (apparently residual)
 7056            lda #$00                  ;set A to impose gravity on jumping coin
 7057            jsr ImposeGravity         ;do sub to move coin vertically and impose gravity on it
 7058            ldx ObjectOffset          ;get original misc object offset
 7059            lda Misc_Y_Speed,x        ;check vertical speed
 7060            cmp #$05
 7061            bne RunJCSubs             ;if not moving downward fast enough, keep state as-is
 7062            inc Misc_State,x          ;otherwise increment state to change to floatey number
 7063 RunJCSubs: jsr RelativeMiscPosition  ;get relative coordinates
 7064            jsr GetMiscOffscreenBits  ;get offscreen information
 7065            jsr GetMiscBoundBox       ;get bounding box coordinates (why?)
 7066            jsr JCoinGfxHandler       ;draw the coin or floatey number
 7067 
 7068 MiscLoopBack: 
 7069            dex                       ;decrement misc object offset
 7070            bpl MiscLoop              ;loop back until all misc objects handled
 7071            rts                       ;then leave
 7072 
 7073 ;-------------------------------------------------------------------------------------
 7074 
 7075 CoinTallyOffsets:
 7076       .db $17, $1d
 7077 
 7078 ScoreOffsets:
 7079       .db $0b, $11
 7080 
 7081 StatusBarNybbles:
 7082       .db $02, $13
 7083 
 7084 GiveOneCoin:
 7085       lda #$01               ;set digit modifier to add 1 coin
 7086       sta DigitModifier+5    ;to the current player's coin tally
 7087       ldx CurrentPlayer      ;get current player on the screen
 7088       ldy CoinTallyOffsets,x ;get offset for player's coin tally
 7089       jsr DigitsMathRoutine  ;update the coin tally
 7090       inc CoinTally          ;increment onscreen player's coin amount
 7091       lda CoinTally
 7092       cmp #100               ;does player have 100 coins yet?
 7093       bne CoinPoints         ;if not, skip all of this
 7094       lda #$00
 7095       sta CoinTally          ;otherwise, reinitialize coin amount
 7096       inc NumberofLives      ;give the player an extra life
 7097       lda #Sfx_ExtraLife
 7098       sta Square2SoundQueue  ;play 1-up sound
 7099 
 7100 CoinPoints:
 7101       lda #$02               ;set digit modifier to award
 7102       sta DigitModifier+4    ;200 points to the player
 7103 
 7104 AddToScore:
 7105       ldx CurrentPlayer      ;get current player
 7106       ldy ScoreOffsets,x     ;get offset for player's score
 7107       jsr DigitsMathRoutine  ;update the score internally with value in digit modifier
 7108 
 7109 GetSBNybbles:
 7110       ldy CurrentPlayer      ;get current player
 7111       lda StatusBarNybbles,y ;get nybbles based on player, use to update score and coins
 7112 
 7113 UpdateNumber:
 7114         jsr PrintStatusBarNumbers ;print status bar numbers based on nybbles, whatever they be
 7115         ldy VRAM_Buffer1_Offset   
 7116         lda VRAM_Buffer1-6,y      ;check highest digit of score
 7117         bne NoZSup                ;if zero, overwrite with space tile for zero suppression
 7118         lda #$24
 7119         sta VRAM_Buffer1-6,y
 7120 NoZSup: ldx ObjectOffset          ;get enemy object buffer offset
 7121         rts
 7122 
 7123 ;-------------------------------------------------------------------------------------
 7124 
 7125 SetupPowerUp:
 7126            lda #PowerUpObject        ;load power-up identifier into
 7127            sta Enemy_ID+5            ;special use slot of enemy object buffer
 7128            lda Block_PageLoc,x       ;store page location of block object
 7129            sta Enemy_PageLoc+5       ;as page location of power-up object
 7130            lda Block_X_Position,x    ;store horizontal coordinate of block object
 7131            sta Enemy_X_Position+5    ;as horizontal coordinate of power-up object
 7132            lda #$01
 7133            sta Enemy_Y_HighPos+5     ;set vertical high byte of power-up object
 7134            lda Block_Y_Position,x    ;get vertical coordinate of block object
 7135            sec
 7136            sbc #$08                  ;subtract 8 pixels
 7137            sta Enemy_Y_Position+5    ;and use as vertical coordinate of power-up object
 7138 PwrUpJmp:  lda #$01                  ;this is a residual jump point in enemy object jump table
 7139            sta Enemy_State+5         ;set power-up object's state
 7140            sta Enemy_Flag+5          ;set buffer flag
 7141            lda #$03
 7142            sta Enemy_BoundBoxCtrl+5  ;set bounding box size control for power-up object
 7143            lda PowerUpType
 7144            cmp #$02                  ;check currently loaded power-up type
 7145            bcs PutBehind             ;if star or 1-up, branch ahead
 7146            lda PlayerStatus          ;otherwise check player's current status
 7147            cmp #$02
 7148            bcc StrType               ;if player not fiery, use status as power-up type
 7149            lsr                       ;otherwise shift right to force fire flower type
 7150 StrType:   sta PowerUpType           ;store type here
 7151 PutBehind: lda #%00100000
 7152            sta Enemy_SprAttrib+5     ;set background priority bit
 7153            lda #Sfx_GrowPowerUp
 7154            sta Square2SoundQueue     ;load power-up reveal sound and leave
 7155            rts
 7156 
 7157 ;-------------------------------------------------------------------------------------
 7158 
 7159 PowerUpObjHandler:
 7160          ldx #$05                   ;set object offset for last slot in enemy object buffer
 7161          stx ObjectOffset
 7162          lda Enemy_State+5          ;check power-up object's state
 7163          beq ExitPUp                ;if not set, branch to leave
 7164          asl                        ;shift to check if d7 was set in object state
 7165          bcc GrowThePowerUp         ;if not set, branch ahead to skip this part
 7166          lda TimerControl           ;if master timer control set,
 7167          bne RunPUSubs              ;branch ahead to enemy object routines
 7168          lda PowerUpType            ;check power-up type
 7169          beq ShroomM                ;if normal mushroom, branch ahead to move it
 7170          cmp #$03
 7171          beq ShroomM                ;if 1-up mushroom, branch ahead to move it
 7172          cmp #$02
 7173          bne RunPUSubs              ;if not star, branch elsewhere to skip movement
 7174          jsr MoveJumpingEnemy       ;otherwise impose gravity on star power-up and make it jump
 7175          jsr EnemyJump              ;note that green paratroopa shares the same code here 
 7176          jmp RunPUSubs              ;then jump to other power-up subroutines
 7177 ShroomM: jsr MoveNormalEnemy        ;do sub to make mushrooms move
 7178          jsr EnemyToBGCollisionDet  ;deal with collisions
 7179          jmp RunPUSubs              ;run the other subroutines
 7180 
 7181 GrowThePowerUp:
 7182            lda FrameCounter           ;get frame counter
 7183            and #$03                   ;mask out all but 2 LSB
 7184            bne ChkPUSte               ;if any bits set here, branch
 7185            dec Enemy_Y_Position+5     ;otherwise decrement vertical coordinate slowly
 7186            lda Enemy_State+5          ;load power-up object state
 7187            inc Enemy_State+5          ;increment state for next frame (to make power-up rise)
 7188            cmp #$11                   ;if power-up object state not yet past 16th pixel,
 7189            bcc ChkPUSte               ;branch ahead to last part here
 7190            lda #$10
 7191            sta Enemy_X_Speed,x        ;otherwise set horizontal speed
 7192            lda #%10000000
 7193            sta Enemy_State+5          ;and then set d7 in power-up object's state
 7194            asl                        ;shift once to init A
 7195            sta Enemy_SprAttrib+5      ;initialize background priority bit set here
 7196            rol                        ;rotate A to set right moving direction
 7197            sta Enemy_MovingDir,x      ;set moving direction
 7198 ChkPUSte:  lda Enemy_State+5          ;check power-up object's state
 7199            cmp #$06                   ;for if power-up has risen enough
 7200            bcc ExitPUp                ;if not, don't even bother running these routines
 7201 RunPUSubs: jsr RelativeEnemyPosition  ;get coordinates relative to screen
 7202            jsr GetEnemyOffscreenBits  ;get offscreen bits
 7203            jsr GetEnemyBoundBox       ;get bounding box coordinates
 7204            jsr DrawPowerUp            ;draw the power-up object
 7205            jsr PlayerEnemyCollision   ;check for collision with player
 7206            jsr OffscreenBoundsCheck   ;check to see if it went offscreen
 7207 ExitPUp:   rts                        ;and we're done
 7208 
 7209 ;-------------------------------------------------------------------------------------
 7210 ;These apply to all routines in this section unless otherwise noted:
 7211 ;$00 - used to store metatile from block buffer routine
 7212 ;$02 - used to store vertical high nybble offset from block buffer routine
 7213 ;$05 - used to store metatile stored in A at beginning of PlayerHeadCollision
 7214 ;$06-$07 - used as block buffer address indirect
 7215 
 7216 BlockYPosAdderData:
 7217       .db $04, $12
 7218 
 7219 PlayerHeadCollision:
 7220            pha                      ;store metatile number to stack
 7221            lda #$11                 ;load unbreakable block object state by default
 7222            ldx SprDataOffset_Ctrl   ;load offset control bit here
 7223            ldy PlayerSize           ;check player's size
 7224            bne DBlockSte            ;if small, branch
 7225            lda #$12                 ;otherwise load breakable block object state
 7226 DBlockSte: sta Block_State,x        ;store into block object buffer
 7227            jsr DestroyBlockMetatile ;store blank metatile in vram buffer to write to name table
 7228            ldx SprDataOffset_Ctrl   ;load offset control bit
 7229            lda $02                  ;get vertical high nybble offset used in block buffer routine
 7230            sta Block_Orig_YPos,x    ;set as vertical coordinate for block object
 7231            tay
 7232            lda $06                  ;get low byte of block buffer address used in same routine
 7233            sta Block_BBuf_Low,x     ;save as offset here to be used later
 7234            lda ($06),y              ;get contents of block buffer at old address at $06, $07
 7235            jsr BlockBumpedChk       ;do a sub to check which block player bumped head on
 7236            sta $00                  ;store metatile here
 7237            ldy PlayerSize           ;check player's size
 7238            bne ChkBrick             ;if small, use metatile itself as contents of A
 7239            tya                      ;otherwise init A (note: big = 0)
 7240 ChkBrick:  bcc PutMTileB            ;if no match was found in previous sub, skip ahead
 7241            ldy #$11                 ;otherwise load unbreakable state into block object buffer
 7242            sty Block_State,x        ;note this applies to both player sizes
 7243            lda #$c4                 ;load empty block metatile into A for now
 7244            ldy $00                  ;get metatile from before
 7245            cpy #$58                 ;is it brick with coins (with line)?
 7246            beq StartBTmr            ;if so, branch
 7247            cpy #$5d                 ;is it brick with coins (without line)?
 7248            bne PutMTileB            ;if not, branch ahead to store empty block metatile
 7249 StartBTmr: lda BrickCoinTimerFlag   ;check brick coin timer flag
 7250            bne ContBTmr             ;if set, timer expired or counting down, thus branch
 7251            lda #$0b
 7252            sta BrickCoinTimer       ;if not set, set brick coin timer
 7253            inc BrickCoinTimerFlag   ;and set flag linked to it
 7254 ContBTmr:  lda BrickCoinTimer       ;check brick coin timer
 7255            bne PutOldMT             ;if not yet expired, branch to use current metatile
 7256            ldy #$c4                 ;otherwise use empty block metatile
 7257 PutOldMT:  tya                      ;put metatile into A
 7258 PutMTileB: sta Block_Metatile,x     ;store whatever metatile be appropriate here
 7259            jsr InitBlock_XY_Pos     ;get block object horizontal coordinates saved
 7260            ldy $02                  ;get vertical high nybble offset
 7261            lda #$23
 7262            sta ($06),y              ;write blank metatile $23 to block buffer
 7263            lda #$10
 7264            sta BlockBounceTimer     ;set block bounce timer
 7265            pla                      ;pull original metatile from stack
 7266            sta $05                  ;and save here
 7267            ldy #$00                 ;set default offset
 7268            lda CrouchingFlag        ;is player crouching?
 7269            bne SmallBP              ;if so, branch to increment offset
 7270            lda PlayerSize           ;is player big?
 7271            beq BigBP                ;if so, branch to use default offset
 7272 SmallBP:   iny                      ;increment for small or big and crouching
 7273 BigBP:     lda Player_Y_Position    ;get player's vertical coordinate
 7274            clc
 7275            adc BlockYPosAdderData,y ;add value determined by size
 7276            and #$f0                 ;mask out low nybble to get 16-pixel correspondence
 7277            sta Block_Y_Position,x   ;save as vertical coordinate for block object
 7278            ldy Block_State,x        ;get block object state
 7279            cpy #$11
 7280            beq Unbreak              ;if set to value loaded for unbreakable, branch
 7281            jsr BrickShatter         ;execute code for breakable brick
 7282            jmp InvOBit              ;skip subroutine to do last part of code here
 7283 Unbreak:   jsr BumpBlock            ;execute code for unbreakable brick or question block
 7284 InvOBit:   lda SprDataOffset_Ctrl   ;invert control bit used by block objects
 7285            eor #$01                 ;and floatey numbers
 7286            sta SprDataOffset_Ctrl
 7287            rts                      ;leave!
 7288 
 7289 ;--------------------------------
 7290 
 7291 InitBlock_XY_Pos:
 7292       lda Player_X_Position   ;get player's horizontal coordinate
 7293       clc
 7294       adc #$08                ;add eight pixels
 7295       and #$f0                ;mask out low nybble to give 16-pixel correspondence
 7296       sta Block_X_Position,x  ;save as horizontal coordinate for block object
 7297       lda Player_PageLoc
 7298       adc #$00                ;add carry to page location of player
 7299       sta Block_PageLoc,x     ;save as page location of block object
 7300       sta Block_PageLoc2,x    ;save elsewhere to be used later
 7301       lda Player_Y_HighPos
 7302       sta Block_Y_HighPos,x   ;save vertical high byte of player into
 7303       rts                     ;vertical high byte of block object and leave
 7304 
 7305 ;--------------------------------
 7306 
 7307 BumpBlock:
 7308            jsr CheckTopOfBlock     ;check to see if there's a coin directly above this block
 7309            lda #Sfx_Bump
 7310            sta Square1SoundQueue   ;play bump sound
 7311            lda #$00
 7312            sta Block_X_Speed,x     ;initialize horizontal speed for block object
 7313            sta Block_Y_MoveForce,x ;init fractional movement force
 7314            sta Player_Y_Speed      ;init player's vertical speed
 7315            lda #$fe
 7316            sta Block_Y_Speed,x     ;set vertical speed for block object
 7317            lda $05                 ;get original metatile from stack
 7318            jsr BlockBumpedChk      ;do a sub to check which block player bumped head on
 7319            bcc ExitBlockChk        ;if no match was found, branch to leave
 7320            tya                     ;move block number to A
 7321            cmp #$09                ;if block number was within 0-8 range,
 7322            bcc BlockCode           ;branch to use current number
 7323            sbc #$05                ;otherwise subtract 5 for second set to get proper number
 7324 BlockCode: jsr JumpEngine          ;run appropriate subroutine depending on block number
 7325 
 7326       .dw MushFlowerBlock
 7327       .dw CoinBlock
 7328       .dw CoinBlock
 7329       .dw ExtraLifeMushBlock
 7330       .dw MushFlowerBlock
 7331       .dw VineBlock
 7332       .dw StarBlock
 7333       .dw CoinBlock
 7334       .dw ExtraLifeMushBlock
 7335 
 7336 ;--------------------------------
 7337 
 7338 MushFlowerBlock:
 7339       lda #$00       ;load mushroom/fire flower into power-up type
 7340       .db $2c        ;BIT instruction opcode
 7341 
 7342 StarBlock:
 7343       lda #$02       ;load star into power-up type
 7344       .db $2c        ;BIT instruction opcode
 7345 
 7346 ExtraLifeMushBlock:
 7347       lda #$03         ;load 1-up mushroom into power-up type
 7348       sta $39          ;store correct power-up type
 7349       jmp SetupPowerUp
 7350 
 7351 VineBlock:
 7352       ldx #$05                ;load last slot for enemy object buffer
 7353       ldy SprDataOffset_Ctrl  ;get control bit
 7354       jsr Setup_Vine          ;set up vine object
 7355 
 7356 ExitBlockChk:
 7357       rts                     ;leave
 7358 
 7359 ;--------------------------------
 7360 
 7361 BrickQBlockMetatiles:
 7362       .db $c1, $c0, $5f, $60 ;used by question blocks
 7363 
 7364       ;these two sets are functionally identical, but look different
 7365       .db $55, $56, $57, $58, $59 ;used by ground level types
 7366       .db $5a, $5b, $5c, $5d, $5e ;used by other level types
 7367 
 7368 BlockBumpedChk:
 7369              ldy #$0d                    ;start at end of metatile data
 7370 BumpChkLoop: cmp BrickQBlockMetatiles,y  ;check to see if current metatile matches
 7371              beq MatchBump               ;metatile found in block buffer, branch if so
 7372              dey                         ;otherwise move onto next metatile
 7373              bpl BumpChkLoop             ;do this until all metatiles are checked
 7374              clc                         ;if none match, return with carry clear
 7375 MatchBump:   rts                         ;note carry is set if found match
 7376 
 7377 ;--------------------------------
 7378 
 7379 BrickShatter:
 7380       jsr CheckTopOfBlock    ;check to see if there's a coin directly above this block
 7381       lda #Sfx_BrickShatter
 7382       sta Block_RepFlag,x    ;set flag for block object to immediately replace metatile
 7383       sta NoiseSoundQueue    ;load brick shatter sound
 7384       jsr SpawnBrickChunks   ;create brick chunk objects
 7385       lda #$fe
 7386       sta Player_Y_Speed     ;set vertical speed for player
 7387       lda #$05
 7388       sta DigitModifier+5    ;set digit modifier to give player 50 points
 7389       jsr AddToScore         ;do sub to update the score
 7390       ldx SprDataOffset_Ctrl ;load control bit and leave
 7391       rts
 7392 
 7393 ;--------------------------------
 7394 
 7395 CheckTopOfBlock:
 7396        ldx SprDataOffset_Ctrl  ;load control bit
 7397        ldy $02                 ;get vertical high nybble offset used in block buffer
 7398        beq TopEx               ;branch to leave if set to zero, because we're at the top
 7399        tya                     ;otherwise set to A
 7400        sec
 7401        sbc #$10                ;subtract $10 to move up one row in the block buffer
 7402        sta $02                 ;store as new vertical high nybble offset
 7403        tay 
 7404        lda ($06),y             ;get contents of block buffer in same column, one row up
 7405        cmp #$c2                ;is it a coin? (not underwater)
 7406        bne TopEx               ;if not, branch to leave
 7407        lda #$00
 7408        sta ($06),y             ;otherwise put blank metatile where coin was
 7409        jsr RemoveCoin_Axe      ;write blank metatile to vram buffer
 7410        ldx SprDataOffset_Ctrl  ;get control bit
 7411        jsr SetupJumpCoin       ;create jumping coin object and update coin variables
 7412 TopEx: rts                     ;leave!
 7413 
 7414 ;--------------------------------
 7415 
 7416 SpawnBrickChunks:
 7417       lda Block_X_Position,x     ;set horizontal coordinate of block object
 7418       sta Block_Orig_XPos,x      ;as original horizontal coordinate here
 7419       lda #$f0
 7420       sta Block_X_Speed,x        ;set horizontal speed for brick chunk objects
 7421       sta Block_X_Speed+2,x
 7422       lda #$fa
 7423       sta Block_Y_Speed,x        ;set vertical speed for one
 7424       lda #$fc
 7425       sta Block_Y_Speed+2,x      ;set lower vertical speed for the other
 7426       lda #$00
 7427       sta Block_Y_MoveForce,x    ;init fractional movement force for both
 7428       sta Block_Y_MoveForce+2,x
 7429       lda Block_PageLoc,x
 7430       sta Block_PageLoc+2,x      ;copy page location
 7431       lda Block_X_Position,x
 7432       sta Block_X_Position+2,x   ;copy horizontal coordinate
 7433       lda Block_Y_Position,x
 7434       clc                        ;add 8 pixels to vertical coordinate
 7435       adc #$08                   ;and save as vertical coordinate for one of them
 7436       sta Block_Y_Position+2,x
 7437       lda #$fa
 7438       sta Block_Y_Speed,x        ;set vertical speed...again??? (redundant)
 7439       rts
 7440 
 7441 ;-------------------------------------------------------------------------------------
 7442 
 7443 BlockObjectsCore:
 7444         lda Block_State,x           ;get state of block object
 7445         beq UpdSte                  ;if not set, branch to leave
 7446         and #$0f                    ;mask out high nybble
 7447         pha                         ;push to stack
 7448         tay                         ;put in Y for now
 7449         txa
 7450         clc
 7451         adc #$09                    ;add 9 bytes to offset (note two block objects are created
 7452         tax                         ;when using brick chunks, but only one offset for both)
 7453         dey                         ;decrement Y to check for solid block state
 7454         beq BouncingBlockHandler    ;branch if found, otherwise continue for brick chunks
 7455         jsr ImposeGravityBlock      ;do sub to impose gravity on one block object object
 7456         jsr MoveObjectHorizontally  ;do another sub to move horizontally
 7457         txa
 7458         clc                         ;move onto next block object
 7459         adc #$02
 7460         tax
 7461         jsr ImposeGravityBlock      ;do sub to impose gravity on other block object
 7462         jsr MoveObjectHorizontally  ;do another sub to move horizontally
 7463         ldx ObjectOffset            ;get block object offset used for both
 7464         jsr RelativeBlockPosition   ;get relative coordinates
 7465         jsr GetBlockOffscreenBits   ;get offscreen information
 7466         jsr DrawBrickChunks         ;draw the brick chunks
 7467         pla                         ;get lower nybble of saved state
 7468         ldy Block_Y_HighPos,x       ;check vertical high byte of block object
 7469         beq UpdSte                  ;if above the screen, branch to kill it
 7470         pha                         ;otherwise save state back into stack
 7471         lda #$f0
 7472         cmp Block_Y_Position+2,x    ;check to see if bottom block object went
 7473         bcs ChkTop                  ;to the bottom of the screen, and branch if not
 7474         sta Block_Y_Position+2,x    ;otherwise set offscreen coordinate
 7475 ChkTop: lda Block_Y_Position,x      ;get top block object's vertical coordinate
 7476         cmp #$f0                    ;see if it went to the bottom of the screen
 7477         pla                         ;pull block object state from stack
 7478         bcc UpdSte                  ;if not, branch to save state
 7479         bcs KillBlock               ;otherwise do unconditional branch to kill it
 7480 
 7481 BouncingBlockHandler:
 7482            jsr ImposeGravityBlock     ;do sub to impose gravity on block object
 7483            ldx ObjectOffset           ;get block object offset
 7484            jsr RelativeBlockPosition  ;get relative coordinates
 7485            jsr GetBlockOffscreenBits  ;get offscreen information
 7486            jsr DrawBlock              ;draw the block
 7487            lda Block_Y_Position,x     ;get vertical coordinate
 7488            and #$0f                   ;mask out high nybble
 7489            cmp #$05                   ;check to see if low nybble wrapped around
 7490            pla                        ;pull state from stack
 7491            bcs UpdSte                 ;if still above amount, not time to kill block yet, thus branch
 7492            lda #$01
 7493            sta Block_RepFlag,x        ;otherwise set flag to replace metatile
 7494 KillBlock: lda #$00                   ;if branched here, nullify object state
 7495 UpdSte:    sta Block_State,x          ;store contents of A in block object state
 7496            rts
 7497 
 7498 ;-------------------------------------------------------------------------------------
 7499 ;$02 - used to store offset to block buffer
 7500 ;$06-$07 - used to store block buffer address
 7501 
 7502 BlockObjMT_Updater:
 7503             ldx #$01                  ;set offset to start with second block object
 7504 UpdateLoop: stx ObjectOffset          ;set offset here
 7505             lda VRAM_Buffer1          ;if vram buffer already being used here,
 7506             bne NextBUpd              ;branch to move onto next block object
 7507             lda Block_RepFlag,x       ;if flag for block object already clear,
 7508             beq NextBUpd              ;branch to move onto next block object
 7509             lda Block_BBuf_Low,x      ;get low byte of block buffer
 7510             sta $06                   ;store into block buffer address
 7511             lda #$05
 7512             sta $07                   ;set high byte of block buffer address
 7513             lda Block_Orig_YPos,x     ;get original vertical coordinate of block object
 7514             sta $02                   ;store here and use as offset to block buffer
 7515             tay
 7516             lda Block_Metatile,x      ;get metatile to be written
 7517             sta ($06),y               ;write it to the block buffer
 7518             jsr ReplaceBlockMetatile  ;do sub to replace metatile where block object is
 7519             lda #$00
 7520             sta Block_RepFlag,x       ;clear block object flag
 7521 NextBUpd:   dex                       ;decrement block object offset
 7522             bpl UpdateLoop            ;do this until both block objects are dealt with
 7523             rts                       ;then leave
 7524 
 7525 ;-------------------------------------------------------------------------------------
 7526 ;$00 - used to store high nybble of horizontal speed as adder
 7527 ;$01 - used to store low nybble of horizontal speed
 7528 ;$02 - used to store adder to page location
 7529 
 7530 MoveEnemyHorizontally:
 7531       inx                         ;increment offset for enemy offset
 7532       jsr MoveObjectHorizontally  ;position object horizontally according to
 7533       ldx ObjectOffset            ;counters, return with saved value in A,
 7534       rts                         ;put enemy offset back in X and leave
 7535 
 7536 MovePlayerHorizontally:
 7537       lda JumpspringAnimCtrl  ;if jumpspring currently animating,
 7538       bne ExXMove             ;branch to leave
 7539       tax                     ;otherwise set zero for offset to use player's stuff
 7540 
 7541 MoveObjectHorizontally:
 7542           lda SprObject_X_Speed,x     ;get currently saved value (horizontal
 7543           asl                         ;speed, secondary counter, whatever)
 7544           asl                         ;and move low nybble to high
 7545           asl
 7546           asl
 7547           sta $01                     ;store result here
 7548           lda SprObject_X_Speed,x     ;get saved value again
 7549           lsr                         ;move high nybble to low
 7550           lsr
 7551           lsr
 7552           lsr
 7553           cmp #$08                    ;if < 8, branch, do not change
 7554           bcc SaveXSpd
 7555           ora #%11110000              ;otherwise alter high nybble
 7556 SaveXSpd: sta $00                     ;save result here
 7557           ldy #$00                    ;load default Y value here
 7558           cmp #$00                    ;if result positive, leave Y alone
 7559           bpl UseAdder
 7560           dey                         ;otherwise decrement Y
 7561 UseAdder: sty $02                     ;save Y here
 7562           lda SprObject_X_MoveForce,x ;get whatever number's here
 7563           clc
 7564           adc $01                     ;add low nybble moved to high
 7565           sta SprObject_X_MoveForce,x ;store result here
 7566           lda #$00                    ;init A
 7567           rol                         ;rotate carry into d0
 7568           pha                         ;push onto stack
 7569           ror                         ;rotate d0 back onto carry
 7570           lda SprObject_X_Position,x
 7571           adc $00                     ;add carry plus saved value (high nybble moved to low
 7572           sta SprObject_X_Position,x  ;plus $f0 if necessary) to object's horizontal position
 7573           lda SprObject_PageLoc,x
 7574           adc $02                     ;add carry plus other saved value to the
 7575           sta SprObject_PageLoc,x     ;object's page location and save
 7576           pla
 7577           clc                         ;pull old carry from stack and add
 7578           adc $00                     ;to high nybble moved to low
 7579 ExXMove:  rts                         ;and leave
 7580 
 7581 ;-------------------------------------------------------------------------------------
 7582 ;$00 - used for downward force
 7583 ;$01 - used for upward force
 7584 ;$02 - used for maximum vertical speed
 7585 
 7586 MovePlayerVertically:
 7587          ldx #$00                ;set X for player offset
 7588          lda TimerControl
 7589          bne NoJSChk             ;if master timer control set, branch ahead
 7590          lda JumpspringAnimCtrl  ;otherwise check to see if jumpspring is animating
 7591          bne ExXMove             ;branch to leave if so
 7592 NoJSChk: lda VerticalForce       ;dump vertical force 
 7593          sta $00
 7594          lda #$04                ;set maximum vertical speed here
 7595          jmp ImposeGravitySprObj ;then jump to move player vertically
 7596 
 7597 ;--------------------------------
 7598 
 7599 MoveD_EnemyVertically:
 7600       ldy #$3d           ;set quick movement amount downwards
 7601       lda Enemy_State,x  ;then check enemy state
 7602       cmp #$05           ;if not set to unique state for spiny's egg, go ahead
 7603       bne ContVMove      ;and use, otherwise set different movement amount, continue on
 7604 
 7605 MoveFallingPlatform:
 7606            ldy #$20       ;set movement amount
 7607 ContVMove: jmp SetHiMax   ;jump to skip the rest of this
 7608 
 7609 ;--------------------------------
 7610 
 7611 MoveRedPTroopaDown:
 7612       ldy #$00            ;set Y to move downwards
 7613       jmp MoveRedPTroopa  ;skip to movement routine
 7614 
 7615 MoveRedPTroopaUp:
 7616       ldy #$01            ;set Y to move upwards
 7617 
 7618 MoveRedPTroopa:
 7619       inx                 ;increment X for enemy offset
 7620       lda #$03
 7621       sta $00             ;set downward movement amount here
 7622       lda #$06
 7623       sta $01             ;set upward movement amount here
 7624       lda #$02
 7625       sta $02             ;set maximum speed here
 7626       tya                 ;set movement direction in A, and
 7627       jmp RedPTroopaGrav  ;jump to move this thing
 7628 
 7629 ;--------------------------------
 7630 
 7631 MoveDropPlatform:
 7632       ldy #$7f      ;set movement amount for drop platform
 7633       bne SetMdMax  ;skip ahead of other value set here
 7634 
 7635 MoveEnemySlowVert:
 7636           ldy #$0f         ;set movement amount for bowser/other objects
 7637 SetMdMax: lda #$02         ;set maximum speed in A
 7638           bne SetXMoveAmt  ;unconditional branch
 7639 
 7640 ;--------------------------------
 7641 
 7642 MoveJ_EnemyVertically:
 7643              ldy #$1c                ;set movement amount for podoboo/other objects
 7644 SetHiMax:    lda #$03                ;set maximum speed in A
 7645 SetXMoveAmt: sty $00                 ;set movement amount here
 7646              inx                     ;increment X for enemy offset
 7647              jsr ImposeGravitySprObj ;do a sub to move enemy object downwards
 7648              ldx ObjectOffset        ;get enemy object buffer offset and leave
 7649              rts
 7650 
 7651 ;--------------------------------
 7652 
 7653 MaxSpdBlockData:
 7654       .db $06, $08
 7655 
 7656 ResidualGravityCode:
 7657       ldy #$00       ;this part appears to be residual,
 7658       .db $2c        ;no code branches or jumps to it...
 7659 
 7660 ImposeGravityBlock:
 7661       ldy #$01       ;set offset for maximum speed
 7662       lda #$50       ;set movement amount here
 7663       sta $00
 7664       lda MaxSpdBlockData,y    ;get maximum speed
 7665 
 7666 ImposeGravitySprObj:
 7667       sta $02            ;set maximum speed here
 7668       lda #$00           ;set value to move downwards
 7669       jmp ImposeGravity  ;jump to the code that actually moves it
 7670 
 7671 ;--------------------------------
 7672 
 7673 MovePlatformDown:
 7674       lda #$00    ;save value to stack (if branching here, execute next
 7675       .db $2c     ;part as BIT instruction)
 7676 
 7677 MovePlatformUp:
 7678            lda #$01        ;save value to stack
 7679            pha
 7680            ldy Enemy_ID,x  ;get enemy object identifier
 7681            inx             ;increment offset for enemy object
 7682            lda #$05        ;load default value here
 7683            cpy #$29        ;residual comparison, object #29 never executes
 7684            bne SetDplSpd   ;this code, thus unconditional branch here
 7685            lda #$09        ;residual code
 7686 SetDplSpd: sta $00         ;save downward movement amount here
 7687            lda #$0a        ;save upward movement amount here
 7688            sta $01
 7689            lda #$03        ;save maximum vertical speed here
 7690            sta $02
 7691            pla             ;get value from stack
 7692            tay             ;use as Y, then move onto code shared by red koopa
 7693 
 7694 RedPTroopaGrav:
 7695       jsr ImposeGravity  ;do a sub to move object gradually
 7696       ldx ObjectOffset   ;get enemy object offset and leave
 7697       rts
 7698 
 7699 ;-------------------------------------------------------------------------------------
 7700 ;$00 - used for downward force
 7701 ;$01 - used for upward force
 7702 ;$07 - used as adder for vertical position
 7703 
 7704 ImposeGravity:
 7705          pha                          ;push value to stack
 7706          lda SprObject_YMF_Dummy,x
 7707          clc                          ;add value in movement force to contents of dummy variable
 7708          adc SprObject_Y_MoveForce,x
 7709          sta SprObject_YMF_Dummy,x
 7710          ldy #$00                     ;set Y to zero by default
 7711          lda SprObject_Y_Speed,x      ;get current vertical speed
 7712          bpl AlterYP                  ;if currently moving downwards, do not decrement Y
 7713          dey                          ;otherwise decrement Y
 7714 AlterYP: sty $07                      ;store Y here
 7715          adc SprObject_Y_Position,x   ;add vertical position to vertical speed plus carry
 7716          sta SprObject_Y_Position,x   ;store as new vertical position
 7717          lda SprObject_Y_HighPos,x
 7718          adc $07                      ;add carry plus contents of $07 to vertical high byte
 7719          sta SprObject_Y_HighPos,x    ;store as new vertical high byte
 7720          lda SprObject_Y_MoveForce,x
 7721          clc
 7722          adc $00                      ;add downward movement amount to contents of $0433
 7723          sta SprObject_Y_MoveForce,x
 7724          lda SprObject_Y_Speed,x      ;add carry to vertical speed and store
 7725          adc #$00
 7726          sta SprObject_Y_Speed,x
 7727          cmp $02                      ;compare to maximum speed
 7728          bmi ChkUpM                   ;if less than preset value, skip this part
 7729          lda SprObject_Y_MoveForce,x
 7730          cmp #$80                     ;if less positively than preset maximum, skip this part
 7731          bcc ChkUpM
 7732          lda $02
 7733          sta SprObject_Y_Speed,x      ;keep vertical speed within maximum value
 7734          lda #$00
 7735          sta SprObject_Y_MoveForce,x  ;clear fractional
 7736 ChkUpM:  pla                          ;get value from stack
 7737          beq ExVMove                  ;if set to zero, branch to leave
 7738          lda $02
 7739          eor #%11111111               ;otherwise get two's compliment of maximum speed
 7740          tay
 7741          iny
 7742          sty $07                      ;store two's compliment here
 7743          lda SprObject_Y_MoveForce,x
 7744          sec                          ;subtract upward movement amount from contents
 7745          sbc $01                      ;of movement force, note that $01 is twice as large as $00,
 7746          sta SprObject_Y_MoveForce,x  ;thus it effectively undoes add we did earlier
 7747          lda SprObject_Y_Speed,x
 7748          sbc #$00                     ;subtract borrow from vertical speed and store
 7749          sta SprObject_Y_Speed,x
 7750          cmp $07                      ;compare vertical speed to two's compliment
 7751          bpl ExVMove                  ;if less negatively than preset maximum, skip this part
 7752          lda SprObject_Y_MoveForce,x
 7753          cmp #$80                     ;check if fractional part is above certain amount,
 7754          bcs ExVMove                  ;and if so, branch to leave
 7755          lda $07
 7756          sta SprObject_Y_Speed,x      ;keep vertical speed within maximum value
 7757          lda #$ff
 7758          sta SprObject_Y_MoveForce,x  ;clear fractional
 7759 ExVMove: rts                          ;leave!
 7760 
 7761 ;-------------------------------------------------------------------------------------
 7762 
 7763 EnemiesAndLoopsCore:
 7764             lda Enemy_Flag,x         ;check data here for MSB set
 7765             pha                      ;save in stack
 7766             asl
 7767             bcs ChkBowserF           ;if MSB set in enemy flag, branch ahead of jumps
 7768             pla                      ;get from stack
 7769             beq ChkAreaTsk           ;if data zero, branch
 7770             jmp RunEnemyObjectsCore  ;otherwise, jump to run enemy subroutines
 7771 ChkAreaTsk: lda AreaParserTaskNum    ;check number of tasks to perform
 7772             and #$07
 7773             cmp #$07                 ;if at a specific task, jump and leave
 7774             beq ExitELCore
 7775             jmp ProcLoopCommand      ;otherwise, jump to process loop command/load enemies
 7776 ChkBowserF: pla                      ;get data from stack
 7777             and #%00001111           ;mask out high nybble
 7778             tay
 7779             lda Enemy_Flag,y         ;use as pointer and load same place with different offset
 7780             bne ExitELCore
 7781             sta Enemy_Flag,x         ;if second enemy flag not set, also clear first one
 7782 ExitELCore: rts
 7783 
 7784 ;--------------------------------
 7785 
 7786 ;loop command data
 7787 LoopCmdWorldNumber:
 7788       .db $03, $03, $06, $06, $06, $06, $06, $06, $07, $07, $07
 7789 
 7790 LoopCmdPageNumber:
 7791       .db $05, $09, $04, $05, $06, $08, $09, $0a, $06, $0b, $10
 7792 
 7793 LoopCmdYPosition:
 7794       .db $40, $b0, $b0, $80, $40, $40, $80, $40, $f0, $f0, $f0
 7795 
 7796 ExecGameLoopback:
 7797       lda Player_PageLoc        ;send player back four pages
 7798       sec
 7799       sbc #$04
 7800       sta Player_PageLoc
 7801       lda CurrentPageLoc        ;send current page back four pages
 7802       sec
 7803       sbc #$04
 7804       sta CurrentPageLoc
 7805       lda ScreenLeft_PageLoc    ;subtract four from page location
 7806       sec                       ;of screen's left border
 7807       sbc #$04
 7808       sta ScreenLeft_PageLoc
 7809       lda ScreenRight_PageLoc   ;do the same for the page location
 7810       sec                       ;of screen's right border
 7811       sbc #$04
 7812       sta ScreenRight_PageLoc
 7813       lda AreaObjectPageLoc     ;subtract four from page control
 7814       sec                       ;for area objects
 7815       sbc #$04
 7816       sta AreaObjectPageLoc
 7817       lda #$00                  ;initialize page select for both
 7818       sta EnemyObjectPageSel    ;area and enemy objects
 7819       sta AreaObjectPageSel
 7820       sta EnemyDataOffset       ;initialize enemy object data offset
 7821       sta EnemyObjectPageLoc    ;and enemy object page control
 7822       lda AreaDataOfsLoopback,y ;adjust area object offset based on
 7823       sta AreaDataOffset        ;which loop command we encountered
 7824       rts
 7825 
 7826 ProcLoopCommand:
 7827           lda LoopCommand           ;check if loop command was found
 7828           beq ChkEnemyFrenzy
 7829           lda CurrentColumnPos      ;check to see if we're still on the first page
 7830           bne ChkEnemyFrenzy        ;if not, do not loop yet
 7831           ldy #$0b                  ;start at the end of each set of loop data
 7832 FindLoop: dey
 7833           bmi ChkEnemyFrenzy        ;if all data is checked and not match, do not loop
 7834           lda WorldNumber           ;check to see if one of the world numbers
 7835           cmp LoopCmdWorldNumber,y  ;matches our current world number
 7836           bne FindLoop
 7837           lda CurrentPageLoc        ;check to see if one of the page numbers
 7838           cmp LoopCmdPageNumber,y   ;matches the page we're currently on
 7839           bne FindLoop
 7840           lda Player_Y_Position     ;check to see if the player is at the correct position
 7841           cmp LoopCmdYPosition,y    ;if not, branch to check for world 7
 7842           bne WrongChk
 7843           lda Player_State          ;check to see if the player is
 7844           cmp #$00                  ;on solid ground (i.e. not jumping or falling)
 7845           bne WrongChk              ;if not, player fails to pass loop, and loopback
 7846           lda WorldNumber           ;are we in world 7? (check performed on correct
 7847           cmp #World7               ;vertical position and on solid ground)
 7848           bne InitMLp               ;if not, initialize flags used there, otherwise
 7849           inc MultiLoopCorrectCntr  ;increment counter for correct progression
 7850 IncMLoop: inc MultiLoopPassCntr     ;increment master multi-part counter
 7851           lda MultiLoopPassCntr     ;have we done all three parts?
 7852           cmp #$03
 7853           bne InitLCmd              ;if not, skip this part
 7854           lda MultiLoopCorrectCntr  ;if so, have we done them all correctly?
 7855           cmp #$03
 7856           beq InitMLp               ;if so, branch past unnecessary check here
 7857           bne DoLpBack              ;unconditional branch if previous branch fails
 7858 WrongChk: lda WorldNumber           ;are we in world 7? (check performed on
 7859           cmp #World7               ;incorrect vertical position or not on solid ground)
 7860           beq IncMLoop
 7861 DoLpBack: jsr ExecGameLoopback      ;if player is not in right place, loop back
 7862           jsr KillAllEnemies
 7863 InitMLp:  lda #$00                  ;initialize counters used for multi-part loop commands
 7864           sta MultiLoopPassCntr
 7865           sta MultiLoopCorrectCntr
 7866 InitLCmd: lda #$00                  ;initialize loop command flag
 7867           sta LoopCommand
 7868 
 7869 ;--------------------------------
 7870 
 7871 ChkEnemyFrenzy:
 7872       lda EnemyFrenzyQueue  ;check for enemy object in frenzy queue
 7873       beq ProcessEnemyData  ;if not, skip this part
 7874       sta Enemy_ID,x        ;store as enemy object identifier here
 7875       lda #$01
 7876       sta Enemy_Flag,x      ;activate enemy object flag
 7877       lda #$00
 7878       sta Enemy_State,x     ;initialize state and frenzy queue
 7879       sta EnemyFrenzyQueue
 7880       jmp InitEnemyObject   ;and then jump to deal with this enemy
 7881 
 7882 ;--------------------------------
 7883 ;$06 - used to hold page location of extended right boundary
 7884 ;$07 - used to hold high nybble of position of extended right boundary
 7885 
 7886 ProcessEnemyData:
 7887         ldy EnemyDataOffset      ;get offset of enemy object data
 7888         lda (EnemyData),y        ;load first byte
 7889         cmp #$ff                 ;check for EOD terminator
 7890         bne CheckEndofBuffer
 7891         jmp CheckFrenzyBuffer    ;if found, jump to check frenzy buffer, otherwise
 7892 
 7893 CheckEndofBuffer:
 7894         and #%00001111           ;check for special row $0e
 7895         cmp #$0e
 7896         beq CheckRightBounds     ;if found, branch, otherwise
 7897         cpx #$05                 ;check for end of buffer
 7898         bcc CheckRightBounds     ;if not at end of buffer, branch
 7899         iny
 7900         lda (EnemyData),y        ;check for specific value here
 7901         and #%00111111           ;not sure what this was intended for, exactly
 7902         cmp #$2e                 ;this part is quite possibly residual code
 7903         beq CheckRightBounds     ;but it has the effect of keeping enemies out of
 7904         rts                      ;the sixth slot
 7905 
 7906 CheckRightBounds:
 7907         lda ScreenRight_X_Pos    ;add 48 to pixel coordinate of right boundary
 7908         clc
 7909         adc #$30
 7910         and #%11110000           ;store high nybble
 7911         sta $07
 7912         lda ScreenRight_PageLoc  ;add carry to page location of right boundary
 7913         adc #$00
 7914         sta $06                  ;store page location + carry
 7915         ldy EnemyDataOffset
 7916         iny
 7917         lda (EnemyData),y        ;if MSB of enemy object is clear, branch to check for row $0f
 7918         asl
 7919         bcc CheckPageCtrlRow
 7920         lda EnemyObjectPageSel   ;if page select already set, do not set again
 7921         bne CheckPageCtrlRow
 7922         inc EnemyObjectPageSel   ;otherwise, if MSB is set, set page select 
 7923         inc EnemyObjectPageLoc   ;and increment page control
 7924 
 7925 CheckPageCtrlRow:
 7926         dey
 7927         lda (EnemyData),y        ;reread first byte
 7928         and #$0f
 7929         cmp #$0f                 ;check for special row $0f
 7930         bne PositionEnemyObj     ;if not found, branch to position enemy object
 7931         lda EnemyObjectPageSel   ;if page select set,
 7932         bne PositionEnemyObj     ;branch without reading second byte
 7933         iny
 7934         lda (EnemyData),y        ;otherwise, get second byte, mask out 2 MSB
 7935         and #%00111111
 7936         sta EnemyObjectPageLoc   ;store as page control for enemy object data
 7937         inc EnemyDataOffset      ;increment enemy object data offset 2 bytes
 7938         inc EnemyDataOffset
 7939         inc EnemyObjectPageSel   ;set page select for enemy object data and 
 7940         jmp ProcLoopCommand      ;jump back to process loop commands again
 7941 
 7942 PositionEnemyObj:
 7943         lda EnemyObjectPageLoc   ;store page control as page location
 7944         sta Enemy_PageLoc,x      ;for enemy object
 7945         lda (EnemyData),y        ;get first byte of enemy object
 7946         and #%11110000
 7947         sta Enemy_X_Position,x   ;store column position
 7948         cmp ScreenRight_X_Pos    ;check column position against right boundary
 7949         lda Enemy_PageLoc,x      ;without subtracting, then subtract borrow
 7950         sbc ScreenRight_PageLoc  ;from page location
 7951         bcs CheckRightExtBounds  ;if enemy object beyond or at boundary, branch
 7952         lda (EnemyData),y
 7953         and #%00001111           ;check for special row $0e
 7954         cmp #$0e                 ;if found, jump elsewhere
 7955         beq ParseRow0e
 7956         jmp CheckThreeBytes      ;if not found, unconditional jump
 7957 
 7958 CheckRightExtBounds:
 7959         lda $07                  ;check right boundary + 48 against
 7960         cmp Enemy_X_Position,x   ;column position without subtracting,
 7961         lda $06                  ;then subtract borrow from page control temp
 7962         sbc Enemy_PageLoc,x      ;plus carry
 7963         bcc CheckFrenzyBuffer    ;if enemy object beyond extended boundary, branch
 7964         lda #$01                 ;store value in vertical high byte
 7965         sta Enemy_Y_HighPos,x
 7966         lda (EnemyData),y        ;get first byte again
 7967         asl                      ;multiply by four to get the vertical
 7968         asl                      ;coordinate
 7969         asl
 7970         asl
 7971         sta Enemy_Y_Position,x
 7972         cmp #$e0                 ;do one last check for special row $0e
 7973         beq ParseRow0e           ;(necessary if branched to $c1cb)
 7974         iny
 7975         lda (EnemyData),y        ;get second byte of object
 7976         and #%01000000           ;check to see if hard mode bit is set
 7977         beq CheckForEnemyGroup   ;if not, branch to check for group enemy objects
 7978         lda SecondaryHardMode    ;if set, check to see if secondary hard mode flag
 7979         beq Inc2B                ;is on, and if not, branch to skip this object completely
 7980 
 7981 CheckForEnemyGroup:
 7982         lda (EnemyData),y      ;get second byte and mask out 2 MSB
 7983         and #%00111111
 7984         cmp #$37               ;check for value below $37
 7985         bcc BuzzyBeetleMutate
 7986         cmp #$3f               ;if $37 or greater, check for value
 7987         bcc DoGroup            ;below $3f, branch if below $3f
 7988 
 7989 BuzzyBeetleMutate:
 7990         cmp #Goomba          ;if below $37, check for goomba
 7991         bne StrID            ;value ($3f or more always fails)
 7992         ldy PrimaryHardMode  ;check if primary hard mode flag is set
 7993         beq StrID            ;and if so, change goomba to buzzy beetle
 7994         lda #BuzzyBeetle
 7995 StrID:  sta Enemy_ID,x       ;store enemy object number into buffer
 7996         lda #$01
 7997         sta Enemy_Flag,x     ;set flag for enemy in buffer
 7998         jsr InitEnemyObject
 7999         lda Enemy_Flag,x     ;check to see if flag is set
 8000         bne Inc2B            ;if not, leave, otherwise branch
 8001         rts
 8002 
 8003 CheckFrenzyBuffer:
 8004         lda EnemyFrenzyBuffer    ;if enemy object stored in frenzy buffer
 8005         bne StrFre               ;then branch ahead to store in enemy object buffer
 8006         lda VineFlagOffset       ;otherwise check vine flag offset
 8007         cmp #$01
 8008         bne ExEPar               ;if other value <> 1, leave
 8009         lda #VineObject          ;otherwise put vine in enemy identifier
 8010 StrFre: sta Enemy_ID,x           ;store contents of frenzy buffer into enemy identifier value
 8011 
 8012 InitEnemyObject:
 8013         lda #$00                 ;initialize enemy state
 8014         sta Enemy_State,x
 8015         jsr CheckpointEnemyID    ;jump ahead to run jump engine and subroutines
 8016 ExEPar: rts                      ;then leave
 8017 
 8018 DoGroup:
 8019         jmp HandleGroupEnemies   ;handle enemy group objects
 8020 
 8021 ParseRow0e:
 8022         iny                      ;increment Y to load third byte of object
 8023         iny
 8024         lda (EnemyData),y
 8025         lsr                      ;move 3 MSB to the bottom, effectively
 8026         lsr                      ;making %xxx00000 into %00000xxx
 8027         lsr
 8028         lsr
 8029         lsr
 8030         cmp WorldNumber          ;is it the same world number as we're on?
 8031         bne NotUse               ;if not, do not use (this allows multiple uses
 8032         dey                      ;of the same area, like the underground bonus areas)
 8033         lda (EnemyData),y        ;otherwise, get second byte and use as offset
 8034         sta AreaPointer          ;to addresses for level and enemy object data
 8035         iny
 8036         lda (EnemyData),y        ;get third byte again, and this time mask out
 8037         and #%00011111           ;the 3 MSB from before, save as page number to be
 8038         sta EntrancePage         ;used upon entry to area, if area is entered
 8039 NotUse: jmp Inc3B
 8040 
 8041 CheckThreeBytes:
 8042         ldy EnemyDataOffset      ;load current offset for enemy object data
 8043         lda (EnemyData),y        ;get first byte
 8044         and #%00001111           ;check for special row $0e
 8045         cmp #$0e
 8046         bne Inc2B
 8047 Inc3B:  inc EnemyDataOffset      ;if row = $0e, increment three bytes
 8048 Inc2B:  inc EnemyDataOffset      ;otherwise increment two bytes
 8049         inc EnemyDataOffset
 8050         lda #$00                 ;init page select for enemy objects
 8051         sta EnemyObjectPageSel
 8052         ldx ObjectOffset         ;reload current offset in enemy buffers
 8053         rts                      ;and leave
 8054 
 8055 CheckpointEnemyID:
 8056         lda Enemy_ID,x
 8057         cmp #$15                     ;check enemy object identifier for $15 or greater
 8058         bcs InitEnemyRoutines        ;and branch straight to the jump engine if found
 8059         tay                          ;save identifier in Y register for now
 8060         lda Enemy_Y_Position,x
 8061         adc #$08                     ;add eight pixels to what will eventually be the
 8062         sta Enemy_Y_Position,x       ;enemy object's vertical coordinate ($00-$14 only)
 8063         lda #$01
 8064         sta EnemyOffscrBitsMasked,x  ;set offscreen masked bit
 8065         tya                          ;get identifier back and use as offset for jump engine
 8066 
 8067 InitEnemyRoutines:
 8068         jsr JumpEngine
 8069       
 8070 ;jump engine table for newly loaded enemy objects
 8071 
 8072       .dw InitNormalEnemy  ;for objects $00-$0f
 8073       .dw InitNormalEnemy
 8074       .dw InitNormalEnemy
 8075       .dw InitRedKoopa
 8076       .dw NoInitCode
 8077       .dw InitHammerBro
 8078       .dw InitGoomba
 8079       .dw InitBloober
 8080       .dw InitBulletBill
 8081       .dw NoInitCode
 8082       .dw InitCheepCheep
 8083       .dw InitCheepCheep
 8084       .dw InitPodoboo
 8085       .dw InitPiranhaPlant
 8086       .dw InitJumpGPTroopa
 8087       .dw InitRedPTroopa
 8088 
 8089       .dw InitHorizFlySwimEnemy  ;for objects $10-$1f
 8090       .dw InitLakitu
 8091       .dw InitEnemyFrenzy
 8092       .dw NoInitCode
 8093       .dw InitEnemyFrenzy
 8094       .dw InitEnemyFrenzy
 8095       .dw InitEnemyFrenzy
 8096       .dw InitEnemyFrenzy
 8097       .dw EndFrenzy
 8098       .dw NoInitCode
 8099       .dw NoInitCode
 8100       .dw InitShortFirebar
 8101       .dw InitShortFirebar
 8102       .dw InitShortFirebar
 8103       .dw InitShortFirebar
 8104       .dw InitLongFirebar
 8105 
 8106       .dw NoInitCode ;for objects $20-$2f
 8107       .dw NoInitCode
 8108       .dw NoInitCode
 8109       .dw NoInitCode
 8110       .dw InitBalPlatform
 8111       .dw InitVertPlatform
 8112       .dw LargeLiftUp
 8113       .dw LargeLiftDown
 8114       .dw InitHoriPlatform
 8115       .dw InitDropPlatform
 8116       .dw InitHoriPlatform
 8117       .dw PlatLiftUp
 8118       .dw PlatLiftDown
 8119       .dw InitBowser
 8120       .dw PwrUpJmp   ;possibly dummy value
 8121       .dw Setup_Vine
 8122 
 8123       .dw NoInitCode ;for objects $30-$36
 8124       .dw NoInitCode
 8125       .dw NoInitCode
 8126       .dw NoInitCode
 8127       .dw NoInitCode
 8128       .dw InitRetainerObj
 8129       .dw EndOfEnemyInitCode
 8130 
 8131 ;-------------------------------------------------------------------------------------
 8132 
 8133 NoInitCode:
 8134       rts               ;this executed when enemy object has no init code
 8135 
 8136 ;--------------------------------
 8137 
 8138 InitGoomba:
 8139       jsr InitNormalEnemy  ;set appropriate horizontal speed
 8140       jmp SmallBBox        ;set $09 as bounding box control, set other values
 8141 
 8142 ;--------------------------------
 8143 
 8144 InitPodoboo:
 8145       lda #$02                  ;set enemy position to below
 8146       sta Enemy_Y_HighPos,x     ;the bottom of the screen
 8147       sta Enemy_Y_Position,x
 8148       lsr
 8149       sta EnemyIntervalTimer,x  ;set timer for enemy
 8150       lsr
 8151       sta Enemy_State,x         ;initialize enemy state, then jump to use
 8152       jmp SmallBBox             ;$09 as bounding box size and set other things
 8153 
 8154 ;--------------------------------
 8155 
 8156 InitRetainerObj:
 8157       lda #$b8                ;set fixed vertical position for
 8158       sta Enemy_Y_Position,x  ;princess/mushroom retainer object
 8159       rts
 8160 
 8161 ;--------------------------------
 8162 
 8163 NormalXSpdData:
 8164       .db $f8, $f4
 8165 
 8166 InitNormalEnemy:
 8167          ldy #$01              ;load offset of 1 by default
 8168          lda PrimaryHardMode   ;check for primary hard mode flag set
 8169          bne GetESpd
 8170          dey                   ;if not set, decrement offset
 8171 GetESpd: lda NormalXSpdData,y  ;get appropriate horizontal speed
 8172 SetESpd: sta Enemy_X_Speed,x   ;store as speed for enemy object
 8173          jmp TallBBox          ;branch to set bounding box control and other data
 8174 
 8175 ;--------------------------------
 8176 
 8177 InitRedKoopa:
 8178       jsr InitNormalEnemy   ;load appropriate horizontal speed
 8179       lda #$01              ;set enemy state for red koopa troopa $03
 8180       sta Enemy_State,x
 8181       rts
 8182 
 8183 ;--------------------------------
 8184 
 8185 HBroWalkingTimerData:
 8186       .db $80, $50
 8187 
 8188 InitHammerBro:
 8189       lda #$00                    ;init horizontal speed and timer used by hammer bro
 8190       sta HammerThrowingTimer,x   ;apparently to time hammer throwing
 8191       sta Enemy_X_Speed,x
 8192       ldy SecondaryHardMode       ;get secondary hard mode flag
 8193       lda HBroWalkingTimerData,y
 8194       sta EnemyIntervalTimer,x    ;set value as delay for hammer bro to walk left
 8195       lda #$0b                    ;set specific value for bounding box size control
 8196       jmp SetBBox
 8197 
 8198 ;--------------------------------
 8199 
 8200 InitHorizFlySwimEnemy:
 8201       lda #$00        ;initialize horizontal speed
 8202       jmp SetESpd
 8203 
 8204 ;--------------------------------
 8205 
 8206 InitBloober:
 8207            lda #$00               ;initialize horizontal speed
 8208            sta BlooperMoveSpeed,x
 8209 SmallBBox: lda #$09               ;set specific bounding box size control
 8210            bne SetBBox            ;unconditional branch
 8211 
 8212 ;--------------------------------
 8213 
 8214 InitRedPTroopa:
 8215           ldy #$30                    ;load central position adder for 48 pixels down
 8216           lda Enemy_Y_Position,x      ;set vertical coordinate into location to
 8217           sta RedPTroopaOrigXPos,x    ;be used as original vertical coordinate
 8218           bpl GetCent                 ;if vertical coordinate < $80
 8219           ldy #$e0                    ;if => $80, load position adder for 32 pixels up
 8220 GetCent:  tya                         ;send central position adder to A
 8221           adc Enemy_Y_Position,x      ;add to current vertical coordinate
 8222           sta RedPTroopaCenterYPos,x  ;store as central vertical coordinate
 8223 TallBBox: lda #$03                    ;set specific bounding box size control
 8224 SetBBox:  sta Enemy_BoundBoxCtrl,x    ;set bounding box control here
 8225           lda #$02                    ;set moving direction for left
 8226           sta Enemy_MovingDir,x
 8227 InitVStf: lda #$00                    ;initialize vertical speed
 8228           sta Enemy_Y_Speed,x         ;and movement force
 8229           sta Enemy_Y_MoveForce,x
 8230           rts
 8231 
 8232 ;--------------------------------
 8233 
 8234 InitBulletBill:
 8235       lda #$02                  ;set moving direction for left
 8236       sta Enemy_MovingDir,x
 8237       lda #$09                  ;set bounding box control for $09
 8238       sta Enemy_BoundBoxCtrl,x
 8239       rts
 8240 
 8241 ;--------------------------------
 8242 
 8243 InitCheepCheep:
 8244       jsr SmallBBox              ;set vertical bounding box, speed, init others
 8245       lda PseudoRandomBitReg,x   ;check one portion of LSFR
 8246       and #%00010000             ;get d4 from it
 8247       sta CheepCheepMoveMFlag,x  ;save as movement flag of some sort
 8248       lda Enemy_Y_Position,x
 8249       sta CheepCheepOrigYPos,x   ;save original vertical coordinate here
 8250       rts
 8251 
 8252 ;--------------------------------
 8253 
 8254 InitLakitu:
 8255       lda EnemyFrenzyBuffer      ;check to see if an enemy is already in
 8256       bne KillLakitu             ;the frenzy buffer, and branch to kill lakitu if so
 8257 
 8258 SetupLakitu:
 8259       lda #$00                   ;erase counter for lakitu's reappearance
 8260       sta LakituReappearTimer
 8261       jsr InitHorizFlySwimEnemy  ;set $03 as bounding box, set other attributes
 8262       jmp TallBBox2              ;set $03 as bounding box again (not necessary) and leave
 8263 
 8264 KillLakitu:
 8265       jmp EraseEnemyObject
 8266 
 8267 ;--------------------------------
 8268 ;$01-$03 - used to hold pseudorandom difference adjusters
 8269 
 8270 PRDiffAdjustData:
 8271       .db $26, $2c, $32, $38
 8272       .db $20, $22, $24, $26
 8273       .db $13, $14, $15, $16
 8274 
 8275 LakituAndSpinyHandler:
 8276           lda FrenzyEnemyTimer    ;if timer here not expired, leave
 8277           bne ExLSHand
 8278           cpx #$05                ;if we are on the special use slot, leave
 8279           bcs ExLSHand
 8280           lda #$80                ;set timer
 8281           sta FrenzyEnemyTimer
 8282           ldy #$04                ;start with the last enemy slot
 8283 ChkLak:   lda Enemy_ID,y          ;check all enemy slots to see
 8284           cmp #Lakitu             ;if lakitu is on one of them
 8285           beq CreateSpiny         ;if so, branch out of this loop
 8286           dey                     ;otherwise check another slot
 8287           bpl ChkLak              ;loop until all slots are checked
 8288           inc LakituReappearTimer ;increment reappearance timer
 8289           lda LakituReappearTimer
 8290           cmp #$07                ;check to see if we're up to a certain value yet
 8291           bcc ExLSHand            ;if not, leave
 8292           ldx #$04                ;start with the last enemy slot again
 8293 ChkNoEn:  lda Enemy_Flag,x        ;check enemy buffer flag for non-active enemy slot
 8294           beq CreateL             ;branch out of loop if found
 8295           dex                     ;otherwise check next slot
 8296           bpl ChkNoEn             ;branch until all slots are checked
 8297           bmi RetEOfs             ;if no empty slots were found, branch to leave
 8298 CreateL:  lda #$00                ;initialize enemy state
 8299           sta Enemy_State,x
 8300           lda #Lakitu             ;create lakitu enemy object
 8301           sta Enemy_ID,x
 8302           jsr SetupLakitu         ;do a sub to set up lakitu
 8303           lda #$20
 8304           jsr PutAtRightExtent    ;finish setting up lakitu
 8305 RetEOfs:  ldx ObjectOffset        ;get enemy object buffer offset again and leave
 8306 ExLSHand: rts
 8307 
 8308 ;--------------------------------
 8309 
 8310 CreateSpiny:
 8311           lda Player_Y_Position      ;if player above a certain point, branch to leave
 8312           cmp #$2c
 8313           bcc ExLSHand
 8314           lda Enemy_State,y          ;if lakitu is not in normal state, branch to leave
 8315           bne ExLSHand
 8316           lda Enemy_PageLoc,y        ;store horizontal coordinates (high and low) of lakitu
 8317           sta Enemy_PageLoc,x        ;into the coordinates of the spiny we're going to create
 8318           lda Enemy_X_Position,y
 8319           sta Enemy_X_Position,x
 8320           lda #$01                   ;put spiny within vertical screen unit
 8321           sta Enemy_Y_HighPos,x
 8322           lda Enemy_Y_Position,y     ;put spiny eight pixels above where lakitu is
 8323           sec
 8324           sbc #$08
 8325           sta Enemy_Y_Position,x
 8326           lda PseudoRandomBitReg,x   ;get 2 LSB of LSFR and save to Y
 8327           and #%00000011
 8328           tay
 8329           ldx #$02
 8330 DifLoop:  lda PRDiffAdjustData,y     ;get three values and save them
 8331           sta $01,x                  ;to $01-$03
 8332           iny
 8333           iny                        ;increment Y four bytes for each value
 8334           iny
 8335           iny
 8336           dex                        ;decrement X for each one
 8337           bpl DifLoop                ;loop until all three are written
 8338           ldx ObjectOffset           ;get enemy object buffer offset
 8339           jsr PlayerLakituDiff       ;move enemy, change direction, get value - difference
 8340           ldy Player_X_Speed         ;check player's horizontal speed
 8341           cpy #$08
 8342           bcs SetSpSpd               ;if moving faster than a certain amount, branch elsewhere
 8343           tay                        ;otherwise save value in A to Y for now
 8344           lda PseudoRandomBitReg+1,x
 8345           and #%00000011             ;get one of the LSFR parts and save the 2 LSB
 8346           beq UsePosv                ;branch if neither bits are set
 8347           tya
 8348           eor #%11111111             ;otherwise get two's compliment of Y
 8349           tay
 8350           iny
 8351 UsePosv:  tya                        ;put value from A in Y back to A (they will be lost anyway)
 8352 SetSpSpd: jsr SmallBBox              ;set bounding box control, init attributes, lose contents of A
 8353           ldy #$02
 8354           sta Enemy_X_Speed,x        ;set horizontal speed to zero because previous contents
 8355           cmp #$00                   ;of A were lost...branch here will never be taken for
 8356           bmi SpinyRte               ;the same reason
 8357           dey
 8358 SpinyRte: sty Enemy_MovingDir,x      ;set moving direction to the right
 8359           lda #$fd
 8360           sta Enemy_Y_Speed,x        ;set vertical speed to move upwards
 8361           lda #$01
 8362           sta Enemy_Flag,x           ;enable enemy object by setting flag
 8363           lda #$05
 8364           sta Enemy_State,x          ;put spiny in egg state and leave
 8365 ChpChpEx: rts
 8366 
 8367 ;--------------------------------
 8368 
 8369 FirebarSpinSpdData:
 8370       .db $28, $38, $28, $38, $28
 8371 
 8372 FirebarSpinDirData:
 8373       .db $00, $00, $10, $10, $00
 8374 
 8375 InitLongFirebar:
 8376       jsr DuplicateEnemyObj       ;create enemy object for long firebar
 8377 
 8378 InitShortFirebar:
 8379       lda #$00                    ;initialize low byte of spin state
 8380       sta FirebarSpinState_Low,x
 8381       lda Enemy_ID,x              ;subtract $1b from enemy identifier
 8382       sec                         ;to get proper offset for firebar data
 8383       sbc #$1b
 8384       tay
 8385       lda FirebarSpinSpdData,y    ;get spinning speed of firebar
 8386       sta FirebarSpinSpeed,x
 8387       lda FirebarSpinDirData,y    ;get spinning direction of firebar
 8388       sta FirebarSpinDirection,x
 8389       lda Enemy_Y_Position,x
 8390       clc                         ;add four pixels to vertical coordinate
 8391       adc #$04
 8392       sta Enemy_Y_Position,x
 8393       lda Enemy_X_Position,x
 8394       clc                         ;add four pixels to horizontal coordinate
 8395       adc #$04
 8396       sta Enemy_X_Position,x
 8397       lda Enemy_PageLoc,x
 8398       adc #$00                    ;add carry to page location
 8399       sta Enemy_PageLoc,x
 8400       jmp TallBBox2               ;set bounding box control (not used) and leave
 8401 
 8402 ;--------------------------------
 8403 ;$00-$01 - used to hold pseudorandom bits
 8404 
 8405 FlyCCXPositionData:
 8406       .db $80, $30, $40, $80
 8407       .db $30, $50, $50, $70
 8408       .db $20, $40, $80, $a0
 8409       .db $70, $40, $90, $68
 8410 
 8411 FlyCCXSpeedData:
 8412       .db $0e, $05, $06, $0e
 8413       .db $1c, $20, $10, $0c
 8414       .db $1e, $22, $18, $14
 8415 
 8416 FlyCCTimerData:
 8417       .db $10, $60, $20, $48
 8418 
 8419 InitFlyingCheepCheep:
 8420          lda FrenzyEnemyTimer       ;if timer here not expired yet, branch to leave
 8421          bne ChpChpEx
 8422          jsr SmallBBox              ;jump to set bounding box size $09 and init other values
 8423          lda PseudoRandomBitReg+1,x
 8424          and #%00000011             ;set pseudorandom offset here
 8425          tay
 8426          lda FlyCCTimerData,y       ;load timer with pseudorandom offset
 8427          sta FrenzyEnemyTimer
 8428          ldy #$03                   ;load Y with default value
 8429          lda SecondaryHardMode
 8430          beq MaxCC                  ;if secondary hard mode flag not set, do not increment Y
 8431          iny                        ;otherwise, increment Y to allow as many as four onscreen
 8432 MaxCC:   sty $00                    ;store whatever pseudorandom bits are in Y
 8433          cpx $00                    ;compare enemy object buffer offset with Y
 8434          bcs ChpChpEx               ;if X => Y, branch to leave
 8435          lda PseudoRandomBitReg,x
 8436          and #%00000011             ;get last two bits of LSFR, first part
 8437          sta $00                    ;and store in two places
 8438          sta $01
 8439          lda #$fb                   ;set vertical speed for cheep-cheep
 8440          sta Enemy_Y_Speed,x
 8441          lda #$00                   ;load default value
 8442          ldy Player_X_Speed         ;check player's horizontal speed
 8443          beq GSeed                  ;if player not moving left or right, skip this part
 8444          lda #$04
 8445          cpy #$19                   ;if moving to the right but not very quickly,
 8446          bcc GSeed                  ;do not change A
 8447          asl                        ;otherwise, multiply A by 2
 8448 GSeed:   pha                        ;save to stack
 8449          clc
 8450          adc $00                    ;add to last two bits of LSFR we saved earlier
 8451          sta $00                    ;save it there
 8452          lda PseudoRandomBitReg+1,x
 8453          and #%00000011             ;if neither of the last two bits of second LSFR set,
 8454          beq RSeed                  ;skip this part and save contents of $00
 8455          lda PseudoRandomBitReg+2,x
 8456          and #%00001111             ;otherwise overwrite with lower nybble of
 8457          sta $00                    ;third LSFR part
 8458 RSeed:   pla                        ;get value from stack we saved earlier
 8459          clc
 8460          adc $01                    ;add to last two bits of LSFR we saved in other place
 8461          tay                        ;use as pseudorandom offset here
 8462          lda FlyCCXSpeedData,y      ;get horizontal speed using pseudorandom offset
 8463          sta Enemy_X_Speed,x
 8464          lda #$01                   ;set to move towards the right
 8465          sta Enemy_MovingDir,x
 8466          lda Player_X_Speed         ;if player moving left or right, branch ahead of this part
 8467          bne D2XPos1
 8468          ldy $00                    ;get first LSFR or third LSFR lower nybble
 8469          tya                        ;and check for d1 set
 8470          and #%00000010
 8471          beq D2XPos1                ;if d1 not set, branch
 8472          lda Enemy_X_Speed,x
 8473          eor #$ff                   ;if d1 set, change horizontal speed
 8474          clc                        ;into two's compliment, thus moving in the opposite
 8475          adc #$01                   ;direction
 8476          sta Enemy_X_Speed,x
 8477          inc Enemy_MovingDir,x      ;increment to move towards the left
 8478 D2XPos1: tya                        ;get first LSFR or third LSFR lower nybble again
 8479          and #%00000010
 8480          beq D2XPos2                ;check for d1 set again, branch again if not set
 8481          lda Player_X_Position      ;get player's horizontal position
 8482          clc
 8483          adc FlyCCXPositionData,y   ;if d1 set, add value obtained from pseudorandom offset
 8484          sta Enemy_X_Position,x     ;and save as enemy's horizontal position
 8485          lda Player_PageLoc         ;get player's page location
 8486          adc #$00                   ;add carry and jump past this part
 8487          jmp FinCCSt
 8488 D2XPos2: lda Player_X_Position      ;get player's horizontal position
 8489          sec
 8490          sbc FlyCCXPositionData,y   ;if d1 not set, subtract value obtained from pseudorandom
 8491          sta Enemy_X_Position,x     ;offset and save as enemy's horizontal position
 8492          lda Player_PageLoc         ;get player's page location
 8493          sbc #$00                   ;subtract borrow
 8494 FinCCSt: sta Enemy_PageLoc,x        ;save as enemy's page location
 8495          lda #$01
 8496          sta Enemy_Flag,x           ;set enemy's buffer flag
 8497          sta Enemy_Y_HighPos,x      ;set enemy's high vertical byte
 8498          lda #$f8
 8499          sta Enemy_Y_Position,x     ;put enemy below the screen, and we are done
 8500          rts
 8501 
 8502 ;--------------------------------
 8503 
 8504 InitBowser:
 8505       jsr DuplicateEnemyObj     ;jump to create another bowser object
 8506       stx BowserFront_Offset    ;save offset of first here
 8507       lda #$00
 8508       sta BowserBodyControls    ;initialize bowser's body controls
 8509       sta BridgeCollapseOffset  ;and bridge collapse offset
 8510       lda Enemy_X_Position,x
 8511       sta BowserOrigXPos        ;store original horizontal position here
 8512       lda #$df
 8513       sta BowserFireBreathTimer ;store something here
 8514       sta Enemy_MovingDir,x     ;and in moving direction
 8515       lda #$20
 8516       sta BowserFeetCounter     ;set bowser's feet timer and in enemy timer
 8517       sta EnemyFrameTimer,x
 8518       lda #$05
 8519       sta BowserHitPoints       ;give bowser 5 hit points
 8520       lsr
 8521       sta BowserMovementSpeed   ;set default movement speed here
 8522       rts
 8523 
 8524 ;--------------------------------
 8525 
 8526 DuplicateEnemyObj:
 8527         ldy #$ff                ;start at beginning of enemy slots
 8528 FSLoop: iny                     ;increment one slot
 8529         lda Enemy_Flag,y        ;check enemy buffer flag for empty slot
 8530         bne FSLoop              ;if set, branch and keep checking
 8531         sty DuplicateObj_Offset ;otherwise set offset here
 8532         txa                     ;transfer original enemy buffer offset
 8533         ora #%10000000          ;store with d7 set as flag in new enemy
 8534         sta Enemy_Flag,y        ;slot as well as enemy offset
 8535         lda Enemy_PageLoc,x
 8536         sta Enemy_PageLoc,y     ;copy page location and horizontal coordinates
 8537         lda Enemy_X_Position,x  ;from original enemy to new enemy
 8538         sta Enemy_X_Position,y
 8539         lda #$01
 8540         sta Enemy_Flag,x        ;set flag as normal for original enemy
 8541         sta Enemy_Y_HighPos,y   ;set high vertical byte for new enemy
 8542         lda Enemy_Y_Position,x
 8543         sta Enemy_Y_Position,y  ;copy vertical coordinate from original to new
 8544 FlmEx:  rts                     ;and then leave
 8545 
 8546 ;--------------------------------
 8547 
 8548 FlameYPosData:
 8549       .db $90, $80, $70, $90
 8550 
 8551 FlameYMFAdderData:
 8552       .db $ff, $01
 8553 
 8554 InitBowserFlame:
 8555         lda FrenzyEnemyTimer        ;if timer not expired yet, branch to leave
 8556         bne FlmEx
 8557         sta Enemy_Y_MoveForce,x     ;reset something here
 8558         lda NoiseSoundQueue
 8559         ora #Sfx_BowserFlame        ;load bowser's flame sound into queue
 8560         sta NoiseSoundQueue
 8561         ldy BowserFront_Offset      ;get bowser's buffer offset
 8562         lda Enemy_ID,y              ;check for bowser
 8563         cmp #Bowser
 8564         beq SpawnFromMouth          ;branch if found
 8565         jsr SetFlameTimer           ;get timer data based on flame counter
 8566         clc
 8567         adc #$20                    ;add 32 frames by default
 8568         ldy SecondaryHardMode
 8569         beq SetFrT                  ;if secondary mode flag not set, use as timer setting
 8570         sec
 8571         sbc #$10                    ;otherwise subtract 16 frames for secondary hard mode
 8572 SetFrT: sta FrenzyEnemyTimer        ;set timer accordingly
 8573         lda PseudoRandomBitReg,x
 8574         and #%00000011              ;get 2 LSB from first part of LSFR
 8575         sta BowserFlamePRandomOfs,x ;set here
 8576         tay                         ;use as offset
 8577         lda FlameYPosData,y         ;load vertical position based on pseudorandom offset
 8578 
 8579 PutAtRightExtent:
 8580       sta Enemy_Y_Position,x    ;set vertical position
 8581       lda ScreenRight_X_Pos
 8582       clc
 8583       adc #$20                  ;place enemy 32 pixels beyond right side of screen
 8584       sta Enemy_X_Position,x
 8585       lda ScreenRight_PageLoc
 8586       adc #$00                  ;add carry
 8587       sta Enemy_PageLoc,x
 8588       jmp FinishFlame           ;skip this part to finish setting values
 8589 
 8590 SpawnFromMouth:
 8591        lda Enemy_X_Position,y    ;get bowser's horizontal position
 8592        sec
 8593        sbc #$0e                  ;subtract 14 pixels
 8594        sta Enemy_X_Position,x    ;save as flame's horizontal position
 8595        lda Enemy_PageLoc,y
 8596        sta Enemy_PageLoc,x       ;copy page location from bowser to flame
 8597        lda Enemy_Y_Position,y
 8598        clc                       ;add 8 pixels to bowser's vertical position
 8599        adc #$08
 8600        sta Enemy_Y_Position,x    ;save as flame's vertical position
 8601        lda PseudoRandomBitReg,x
 8602        and #%00000011            ;get 2 LSB from first part of LSFR
 8603        sta Enemy_YMF_Dummy,x     ;save here
 8604        tay                       ;use as offset
 8605        lda FlameYPosData,y       ;get value here using bits as offset
 8606        ldy #$00                  ;load default offset
 8607        cmp Enemy_Y_Position,x    ;compare value to flame's current vertical position
 8608        bcc SetMF                 ;if less, do not increment offset
 8609        iny                       ;otherwise increment now
 8610 SetMF: lda FlameYMFAdderData,y   ;get value here and save
 8611        sta Enemy_Y_MoveForce,x   ;to vertical movement force
 8612        lda #$00
 8613        sta EnemyFrenzyBuffer     ;clear enemy frenzy buffer
 8614 
 8615 FinishFlame:
 8616       lda #$08                 ;set $08 for bounding box control
 8617       sta Enemy_BoundBoxCtrl,x
 8618       lda #$01                 ;set high byte of vertical and
 8619       sta Enemy_Y_HighPos,x    ;enemy buffer flag
 8620       sta Enemy_Flag,x
 8621       lsr
 8622       sta Enemy_X_MoveForce,x  ;initialize horizontal movement force, and
 8623       sta Enemy_State,x        ;enemy state
 8624       rts
 8625 
 8626 ;--------------------------------
 8627 
 8628 FireworksXPosData:
 8629       .db $00, $30, $60, $60, $00, $20
 8630 
 8631 FireworksYPosData:
 8632       .db $60, $40, $70, $40, $60, $30
 8633 
 8634 InitFireworks:
 8635           lda FrenzyEnemyTimer         ;if timer not expired yet, branch to leave
 8636           bne ExitFWk
 8637           lda #$20                     ;otherwise reset timer
 8638           sta FrenzyEnemyTimer
 8639           dec FireworksCounter         ;decrement for each explosion
 8640           ldy #$06                     ;start at last slot
 8641 StarFChk: dey
 8642           lda Enemy_ID,y               ;check for presence of star flag object
 8643           cmp #StarFlagObject          ;if there isn't a star flag object,
 8644           bne StarFChk                 ;routine goes into infinite loop = crash
 8645           lda Enemy_X_Position,y
 8646           sec                          ;get horizontal coordinate of star flag object, then
 8647           sbc #$30                     ;subtract 48 pixels from it and save to
 8648           pha                          ;the stack
 8649           lda Enemy_PageLoc,y
 8650           sbc #$00                     ;subtract the carry from the page location
 8651           sta $00                      ;of the star flag object
 8652           lda FireworksCounter         ;get fireworks counter
 8653           clc
 8654           adc Enemy_State,y            ;add state of star flag object (possibly not necessary)
 8655           tay                          ;use as offset
 8656           pla                          ;get saved horizontal coordinate of star flag - 48 pixels
 8657           clc
 8658           adc FireworksXPosData,y      ;add number based on offset of fireworks counter
 8659           sta Enemy_X_Position,x       ;store as the fireworks object horizontal coordinate
 8660           lda $00
 8661           adc #$00                     ;add carry and store as page location for
 8662           sta Enemy_PageLoc,x          ;the fireworks object
 8663           lda FireworksYPosData,y      ;get vertical position using same offset
 8664           sta Enemy_Y_Position,x       ;and store as vertical coordinate for fireworks object
 8665           lda #$01
 8666           sta Enemy_Y_HighPos,x        ;store in vertical high byte
 8667           sta Enemy_Flag,x             ;and activate enemy buffer flag
 8668           lsr
 8669           sta ExplosionGfxCounter,x    ;initialize explosion counter
 8670           lda #$08
 8671           sta ExplosionTimerCounter,x  ;set explosion timing counter
 8672 ExitFWk:  rts
 8673 
 8674 ;--------------------------------
 8675 
 8676 Bitmasks:
 8677       .db %00000001, %00000010, %00000100, %00001000, %00010000, %00100000, %01000000, %10000000
 8678 
 8679 Enemy17YPosData:
 8680       .db $40, $30, $90, $50, $20, $60, $a0, $70
 8681 
 8682 SwimCC_IDData:
 8683       .db $0a, $0b
 8684 
 8685 BulletBillCheepCheep:
 8686          lda FrenzyEnemyTimer      ;if timer not expired yet, branch to leave
 8687          bne ExF17
 8688          lda AreaType              ;are we in a water-type level?
 8689          bne DoBulletBills         ;if not, branch elsewhere
 8690          cpx #$03                  ;are we past third enemy slot?
 8691          bcs ExF17                 ;if so, branch to leave
 8692          ldy #$00                  ;load default offset
 8693          lda PseudoRandomBitReg,x
 8694          cmp #$aa                  ;check first part of LSFR against preset value
 8695          bcc ChkW2                 ;if less than preset, do not increment offset
 8696          iny                       ;otherwise increment
 8697 ChkW2:   lda WorldNumber           ;check world number
 8698          cmp #World2
 8699          beq Get17ID               ;if we're on world 2, do not increment offset
 8700          iny                       ;otherwise increment
 8701 Get17ID: tya
 8702          and #%00000001            ;mask out all but last bit of offset
 8703          tay
 8704          lda SwimCC_IDData,y       ;load identifier for cheep-cheeps
 8705 Set17ID: sta Enemy_ID,x            ;store whatever's in A as enemy identifier
 8706          lda BitMFilter
 8707          cmp #$ff                  ;if not all bits set, skip init part and compare bits
 8708          bne GetRBit
 8709          lda #$00                  ;initialize vertical position filter
 8710          sta BitMFilter
 8711 GetRBit: lda PseudoRandomBitReg,x  ;get first part of LSFR
 8712          and #%00000111            ;mask out all but 3 LSB
 8713 ChkRBit: tay                       ;use as offset
 8714          lda Bitmasks,y            ;load bitmask
 8715          bit BitMFilter            ;perform AND on filter without changing it
 8716          beq AddFBit
 8717          iny                       ;increment offset
 8718          tya
 8719          and #%00000111            ;mask out all but 3 LSB thus keeping it 0-7
 8720          jmp ChkRBit               ;do another check
 8721 AddFBit: ora BitMFilter            ;add bit to already set bits in filter
 8722          sta BitMFilter            ;and store
 8723          lda Enemy17YPosData,y     ;load vertical position using offset
 8724          jsr PutAtRightExtent      ;set vertical position and other values
 8725          sta Enemy_YMF_Dummy,x     ;initialize dummy variable
 8726          lda #$20                  ;set timer
 8727          sta FrenzyEnemyTimer
 8728          jmp CheckpointEnemyID     ;process our new enemy object
 8729 
 8730 DoBulletBills:
 8731           ldy #$ff                   ;start at beginning of enemy slots
 8732 BB_SLoop: iny                        ;move onto the next slot
 8733           cpy #$05                   ;branch to play sound if we've done all slots
 8734           bcs FireBulletBill
 8735           lda Enemy_Flag,y           ;if enemy buffer flag not set,
 8736           beq BB_SLoop               ;loop back and check another slot
 8737           lda Enemy_ID,y
 8738           cmp #BulletBill_FrenzyVar  ;check enemy identifier for
 8739           bne BB_SLoop               ;bullet bill object (frenzy variant)
 8740 ExF17:    rts                        ;if found, leave
 8741 
 8742 FireBulletBill:
 8743       lda Square2SoundQueue
 8744       ora #Sfx_Blast            ;play fireworks/gunfire sound
 8745       sta Square2SoundQueue
 8746       lda #BulletBill_FrenzyVar ;load identifier for bullet bill object
 8747       bne Set17ID               ;unconditional branch
 8748 
 8749 ;--------------------------------
 8750 ;$00 - used to store Y position of group enemies
 8751 ;$01 - used to store enemy ID
 8752 ;$02 - used to store page location of right side of screen
 8753 ;$03 - used to store X position of right side of screen
 8754 
 8755 HandleGroupEnemies:
 8756         ldy #$00                  ;load value for green koopa troopa
 8757         sec
 8758         sbc #$37                  ;subtract $37 from second byte read
 8759         pha                       ;save result in stack for now
 8760         cmp #$04                  ;was byte in $3b-$3e range?
 8761         bcs SnglID                ;if so, branch
 8762         pha                       ;save another copy to stack
 8763         ldy #Goomba               ;load value for goomba enemy
 8764         lda PrimaryHardMode       ;if primary hard mode flag not set,
 8765         beq PullID                ;branch, otherwise change to value
 8766         ldy #BuzzyBeetle          ;for buzzy beetle
 8767 PullID: pla                       ;get second copy from stack
 8768 SnglID: sty $01                   ;save enemy id here
 8769         ldy #$b0                  ;load default y coordinate
 8770         and #$02                  ;check to see if d1 was set
 8771         beq SetYGp                ;if so, move y coordinate up,
 8772         ldy #$70                  ;otherwise branch and use default
 8773 SetYGp: sty $00                   ;save y coordinate here
 8774         lda ScreenRight_PageLoc   ;get page number of right edge of screen
 8775         sta $02                   ;save here
 8776         lda ScreenRight_X_Pos     ;get pixel coordinate of right edge
 8777         sta $03                   ;save here
 8778         ldy #$02                  ;load two enemies by default
 8779         pla                       ;get first copy from stack
 8780         lsr                       ;check to see if d0 was set
 8781         bcc CntGrp                ;if not, use default value
 8782         iny                       ;otherwise increment to three enemies
 8783 CntGrp: sty NumberofGroupEnemies  ;save number of enemies here
 8784 GrLoop: ldx #$ff                  ;start at beginning of enemy buffers
 8785 GSltLp: inx                       ;increment and branch if past
 8786         cpx #$05                  ;end of buffers
 8787         bcs NextED
 8788         lda Enemy_Flag,x          ;check to see if enemy is already
 8789         bne GSltLp                ;stored in buffer, and branch if so
 8790         lda $01
 8791         sta Enemy_ID,x            ;store enemy object identifier
 8792         lda $02
 8793         sta Enemy_PageLoc,x       ;store page location for enemy object
 8794         lda $03
 8795         sta Enemy_X_Position,x    ;store x coordinate for enemy object
 8796         clc
 8797         adc #$18                  ;add 24 pixels for next enemy
 8798         sta $03
 8799         lda $02                   ;add carry to page location for
 8800         adc #$00                  ;next enemy
 8801         sta $02
 8802         lda $00                   ;store y coordinate for enemy object
 8803         sta Enemy_Y_Position,x
 8804         lda #$01                  ;activate flag for buffer, and
 8805         sta Enemy_Y_HighPos,x     ;put enemy within the screen vertically
 8806         sta Enemy_Flag,x
 8807         jsr CheckpointEnemyID     ;process each enemy object separately
 8808         dec NumberofGroupEnemies  ;do this until we run out of enemy objects
 8809         bne GrLoop
 8810 NextED: jmp Inc2B                 ;jump to increment data offset and leave
 8811 
 8812 ;--------------------------------
 8813 
 8814 InitPiranhaPlant:
 8815       lda #$01                     ;set initial speed
 8816       sta PiranhaPlant_Y_Speed,x
 8817       lsr
 8818       sta Enemy_State,x            ;initialize enemy state and what would normally
 8819       sta PiranhaPlant_MoveFlag,x  ;be used as vertical speed, but not in this case
 8820       lda Enemy_Y_Position,x
 8821       sta PiranhaPlantDownYPos,x   ;save original vertical coordinate here
 8822       sec
 8823       sbc #$18
 8824       sta PiranhaPlantUpYPos,x     ;save original vertical coordinate - 24 pixels here
 8825       lda #$09
 8826       jmp SetBBox2                 ;set specific value for bounding box control
 8827 
 8828 ;--------------------------------
 8829 
 8830 InitEnemyFrenzy:
 8831       lda Enemy_ID,x        ;load enemy identifier
 8832       sta EnemyFrenzyBuffer ;save in enemy frenzy buffer
 8833       sec
 8834       sbc #$12              ;subtract 12 and use as offset for jump engine
 8835       jsr JumpEngine
 8836 
 8837 ;frenzy object jump table
 8838       .dw LakituAndSpinyHandler
 8839       .dw NoFrenzyCode
 8840       .dw InitFlyingCheepCheep
 8841       .dw InitBowserFlame
 8842       .dw InitFireworks
 8843       .dw BulletBillCheepCheep
 8844 
 8845 ;--------------------------------
 8846 
 8847 NoFrenzyCode:
 8848       rts
 8849 
 8850 ;--------------------------------
 8851 
 8852 EndFrenzy:
 8853            ldy #$05               ;start at last slot
 8854 LakituChk: lda Enemy_ID,y         ;check enemy identifiers
 8855            cmp #Lakitu            ;for lakitu
 8856            bne NextFSlot
 8857            lda #$01               ;if found, set state
 8858            sta Enemy_State,y
 8859 NextFSlot: dey                    ;move onto the next slot
 8860            bpl LakituChk          ;do this until all slots are checked
 8861            lda #$00
 8862            sta EnemyFrenzyBuffer  ;empty enemy frenzy buffer
 8863            sta Enemy_Flag,x       ;disable enemy buffer flag for this object
 8864            rts
 8865 
 8866 ;--------------------------------
 8867 
 8868 InitJumpGPTroopa:
 8869            lda #$02                  ;set for movement to the left
 8870            sta Enemy_MovingDir,x
 8871            lda #$f8                  ;set horizontal speed
 8872            sta Enemy_X_Speed,x
 8873 TallBBox2: lda #$03                  ;set specific value for bounding box control
 8874 SetBBox2:  sta Enemy_BoundBoxCtrl,x  ;set bounding box control then leave
 8875            rts
 8876 
 8877 ;--------------------------------
 8878 
 8879 InitBalPlatform:
 8880         dec Enemy_Y_Position,x    ;raise vertical position by two pixels
 8881         dec Enemy_Y_Position,x
 8882         ldy SecondaryHardMode     ;if secondary hard mode flag not set,
 8883         bne AlignP                ;branch ahead
 8884         ldy #$02                  ;otherwise set value here
 8885         jsr PosPlatform           ;do a sub to add or subtract pixels
 8886 AlignP: ldy #$ff                  ;set default value here for now
 8887         lda BalPlatformAlignment  ;get current balance platform alignment
 8888         sta Enemy_State,x         ;set platform alignment to object state here
 8889         bpl SetBPA                ;if old alignment $ff, put $ff as alignment for negative
 8890         txa                       ;if old contents already $ff, put
 8891         tay                       ;object offset as alignment to make next positive
 8892 SetBPA: sty BalPlatformAlignment  ;store whatever value's in Y here
 8893         lda #$00
 8894         sta Enemy_MovingDir,x     ;init moving direction
 8895         tay                       ;init Y
 8896         jsr PosPlatform           ;do a sub to add 8 pixels, then run shared code here
 8897 
 8898 ;--------------------------------
 8899 
 8900 InitDropPlatform:
 8901       lda #$ff
 8902       sta PlatformCollisionFlag,x  ;set some value here
 8903       jmp CommonPlatCode           ;then jump ahead to execute more code
 8904 
 8905 ;--------------------------------
 8906 
 8907 InitHoriPlatform:
 8908       lda #$00
 8909       sta XMoveSecondaryCounter,x  ;init one of the moving counters
 8910       jmp CommonPlatCode           ;jump ahead to execute more code
 8911 
 8912 ;--------------------------------
 8913 
 8914 InitVertPlatform:
 8915        ldy #$40                    ;set default value here
 8916        lda Enemy_Y_Position,x      ;check vertical position
 8917        bpl SetYO                   ;if above a certain point, skip this part
 8918        eor #$ff
 8919        clc                         ;otherwise get two's compliment
 8920        adc #$01
 8921        ldy #$c0                    ;get alternate value to add to vertical position
 8922 SetYO: sta YPlatformTopYPos,x      ;save as top vertical position
 8923        tya
 8924        clc                         ;load value from earlier, add number of pixels 
 8925        adc Enemy_Y_Position,x      ;to vertical position
 8926        sta YPlatformCenterYPos,x   ;save result as central vertical position
 8927 
 8928 ;--------------------------------
 8929 
 8930 CommonPlatCode: 
 8931         jsr InitVStf              ;do a sub to init certain other values 
 8932 SPBBox: lda #$05                  ;set default bounding box size control
 8933         ldy AreaType
 8934         cpy #$03                  ;check for castle-type level
 8935         beq CasPBB                ;use default value if found
 8936         ldy SecondaryHardMode     ;otherwise check for secondary hard mode flag
 8937         bne CasPBB                ;if set, use default value
 8938         lda #$06                  ;use alternate value if not castle or secondary not set
 8939 CasPBB: sta Enemy_BoundBoxCtrl,x  ;set bounding box size control here and leave
 8940         rts
 8941 
 8942 ;--------------------------------
 8943 
 8944 LargeLiftUp:
 8945       jsr PlatLiftUp       ;execute code for platforms going up
 8946       jmp LargeLiftBBox    ;overwrite bounding box for large platforms
 8947 
 8948 LargeLiftDown:
 8949       jsr PlatLiftDown     ;execute code for platforms going down
 8950 
 8951 LargeLiftBBox:
 8952       jmp SPBBox           ;jump to overwrite bounding box size control
 8953 
 8954 ;--------------------------------
 8955 
 8956 PlatLiftUp:
 8957       lda #$10                 ;set movement amount here
 8958       sta Enemy_Y_MoveForce,x
 8959       lda #$ff                 ;set moving speed for platforms going up
 8960       sta Enemy_Y_Speed,x
 8961       jmp CommonSmallLift      ;skip ahead to part we should be executing
 8962 
 8963 ;--------------------------------
 8964 
 8965 PlatLiftDown:
 8966       lda #$f0                 ;set movement amount here
 8967       sta Enemy_Y_MoveForce,x
 8968       lda #$00                 ;set moving speed for platforms going down
 8969       sta Enemy_Y_Speed,x
 8970 
 8971 ;--------------------------------
 8972 
 8973 CommonSmallLift:
 8974       ldy #$01
 8975       jsr PosPlatform           ;do a sub to add 12 pixels due to preset value  
 8976       lda #$04
 8977       sta Enemy_BoundBoxCtrl,x  ;set bounding box control for small platforms
 8978       rts
 8979 
 8980 ;--------------------------------
 8981 
 8982 PlatPosDataLow:
 8983       .db $08,$0c,$f8
 8984 
 8985 PlatPosDataHigh:
 8986       .db $00,$00,$ff
 8987 
 8988 PosPlatform:
 8989       lda Enemy_X_Position,x  ;get horizontal coordinate
 8990       clc
 8991       adc PlatPosDataLow,y    ;add or subtract pixels depending on offset
 8992       sta Enemy_X_Position,x  ;store as new horizontal coordinate
 8993       lda Enemy_PageLoc,x
 8994       adc PlatPosDataHigh,y   ;add or subtract page location depending on offset
 8995       sta Enemy_PageLoc,x     ;store as new page location
 8996       rts                     ;and go back
 8997 
 8998 ;--------------------------------
 8999 
 9000 EndOfEnemyInitCode:
 9001       rts
 9002 
 9003 ;-------------------------------------------------------------------------------------
 9004 
 9005 RunEnemyObjectsCore:
 9006        ldx ObjectOffset  ;get offset for enemy object buffer
 9007        lda #$00          ;load value 0 for jump engine by default
 9008        ldy Enemy_ID,x
 9009        cpy #$15          ;if enemy object < $15, use default value
 9010        bcc JmpEO
 9011        tya               ;otherwise subtract $14 from the value and use
 9012        sbc #$14          ;as value for jump engine
 9013 JmpEO: jsr JumpEngine
 9014       
 9015       .dw RunNormalEnemies  ;for objects $00-$14
 9016 
 9017       .dw RunBowserFlame    ;for objects $15-$1f
 9018       .dw RunFireworks
 9019       .dw NoRunCode
 9020       .dw NoRunCode
 9021       .dw NoRunCode
 9022       .dw NoRunCode
 9023       .dw RunFirebarObj
 9024       .dw RunFirebarObj
 9025       .dw RunFirebarObj
 9026       .dw RunFirebarObj
 9027       .dw RunFirebarObj
 9028 
 9029       .dw RunFirebarObj     ;for objects $20-$2f
 9030       .dw RunFirebarObj
 9031       .dw RunFirebarObj
 9032       .dw NoRunCode
 9033       .dw RunLargePlatform
 9034       .dw RunLargePlatform
 9035       .dw RunLargePlatform
 9036       .dw RunLargePlatform
 9037       .dw RunLargePlatform
 9038       .dw RunLargePlatform
 9039       .dw RunLargePlatform
 9040       .dw RunSmallPlatform
 9041       .dw RunSmallPlatform
 9042       .dw RunBowser
 9043       .dw PowerUpObjHandler
 9044       .dw VineObjectHandler
 9045 
 9046       .dw NoRunCode         ;for objects $30-$35
 9047       .dw RunStarFlagObj
 9048       .dw JumpspringHandler
 9049       .dw NoRunCode
 9050       .dw WarpZoneObject
 9051       .dw RunRetainerObj
 9052 
 9053 ;--------------------------------
 9054 
 9055 NoRunCode:
 9056       rts
 9057 
 9058 ;--------------------------------
 9059 
 9060 RunRetainerObj:
 9061       jsr GetEnemyOffscreenBits
 9062       jsr RelativeEnemyPosition
 9063       jmp EnemyGfxHandler
 9064 
 9065 ;--------------------------------
 9066 
 9067 RunNormalEnemies:
 9068           lda #$00                  ;init sprite attributes
 9069           sta Enemy_SprAttrib,x
 9070           jsr GetEnemyOffscreenBits
 9071           jsr RelativeEnemyPosition
 9072           jsr EnemyGfxHandler
 9073           jsr GetEnemyBoundBox
 9074           jsr EnemyToBGCollisionDet
 9075           jsr EnemiesCollision
 9076           jsr PlayerEnemyCollision
 9077           ldy TimerControl          ;if master timer control set, skip to last routine
 9078           bne SkipMove
 9079           jsr EnemyMovementSubs
 9080 SkipMove: jmp OffscreenBoundsCheck
 9081 
 9082 EnemyMovementSubs:
 9083       lda Enemy_ID,x
 9084       jsr JumpEngine
 9085 
 9086       .dw MoveNormalEnemy      ;only objects $00-$14 use this table
 9087       .dw MoveNormalEnemy
 9088       .dw MoveNormalEnemy
 9089       .dw MoveNormalEnemy
 9090       .dw MoveNormalEnemy
 9091       .dw ProcHammerBro
 9092       .dw MoveNormalEnemy
 9093       .dw MoveBloober
 9094       .dw MoveBulletBill
 9095       .dw NoMoveCode
 9096       .dw MoveSwimmingCheepCheep
 9097       .dw MoveSwimmingCheepCheep
 9098       .dw MovePodoboo
 9099       .dw MovePiranhaPlant
 9100       .dw MoveJumpingEnemy
 9101       .dw ProcMoveRedPTroopa
 9102       .dw MoveFlyGreenPTroopa
 9103       .dw MoveLakitu
 9104       .dw MoveNormalEnemy
 9105       .dw NoMoveCode   ;dummy
 9106       .dw MoveFlyingCheepCheep
 9107 
 9108 ;--------------------------------
 9109 
 9110 NoMoveCode:
 9111       rts
 9112 
 9113 ;--------------------------------
 9114 
 9115 RunBowserFlame:
 9116       jsr ProcBowserFlame
 9117       jsr GetEnemyOffscreenBits
 9118       jsr RelativeEnemyPosition
 9119       jsr GetEnemyBoundBox
 9120       jsr PlayerEnemyCollision
 9121       jmp OffscreenBoundsCheck
 9122 
 9123 ;--------------------------------
 9124 
 9125 RunFirebarObj:
 9126       jsr ProcFirebar
 9127       jmp OffscreenBoundsCheck
 9128 
 9129 ;--------------------------------
 9130 
 9131 RunSmallPlatform:
 9132       jsr GetEnemyOffscreenBits
 9133       jsr RelativeEnemyPosition
 9134       jsr SmallPlatformBoundBox
 9135       jsr SmallPlatformCollision
 9136       jsr RelativeEnemyPosition
 9137       jsr DrawSmallPlatform
 9138       jsr MoveSmallPlatform
 9139       jmp OffscreenBoundsCheck
 9140 
 9141 ;--------------------------------
 9142 
 9143 RunLargePlatform:
 9144         jsr GetEnemyOffscreenBits
 9145         jsr RelativeEnemyPosition
 9146         jsr LargePlatformBoundBox
 9147         jsr LargePlatformCollision
 9148         lda TimerControl             ;if master timer control set,
 9149         bne SkipPT                   ;skip subroutine tree
 9150         jsr LargePlatformSubroutines
 9151 SkipPT: jsr RelativeEnemyPosition
 9152         jsr DrawLargePlatform
 9153         jmp OffscreenBoundsCheck
 9154 
 9155 ;--------------------------------
 9156 
 9157 LargePlatformSubroutines:
 9158       lda Enemy_ID,x  ;subtract $24 to get proper offset for jump table
 9159       sec
 9160       sbc #$24
 9161       jsr JumpEngine
 9162 
 9163       .dw BalancePlatform   ;table used by objects $24-$2a
 9164       .dw YMovingPlatform
 9165       .dw MoveLargeLiftPlat
 9166       .dw MoveLargeLiftPlat
 9167       .dw XMovingPlatform
 9168       .dw DropPlatform
 9169       .dw RightPlatform
 9170 
 9171 ;-------------------------------------------------------------------------------------
 9172 
 9173 EraseEnemyObject:
 9174       lda #$00                 ;clear all enemy object variables
 9175       sta Enemy_Flag,x
 9176       sta Enemy_ID,x
 9177       sta Enemy_State,x
 9178       sta FloateyNum_Control,x
 9179       sta EnemyIntervalTimer,x
 9180       sta ShellChainCounter,x
 9181       sta Enemy_SprAttrib,x
 9182       sta EnemyFrameTimer,x
 9183       rts
 9184 
 9185 ;-------------------------------------------------------------------------------------
 9186 
 9187 MovePodoboo:
 9188       lda EnemyIntervalTimer,x   ;check enemy timer
 9189       bne PdbM                   ;branch to move enemy if not expired
 9190       jsr InitPodoboo            ;otherwise set up podoboo again
 9191       lda PseudoRandomBitReg+1,x ;get part of LSFR
 9192       ora #%10000000             ;set d7
 9193       sta Enemy_Y_MoveForce,x    ;store as movement force
 9194       and #%00001111             ;mask out high nybble
 9195       ora #$06                   ;set for at least six intervals
 9196       sta EnemyIntervalTimer,x   ;store as new enemy timer
 9197       lda #$f9
 9198       sta Enemy_Y_Speed,x        ;set vertical speed to move podoboo upwards
 9199 PdbM: jmp MoveJ_EnemyVertically  ;branch to impose gravity on podoboo
 9200 
 9201 ;--------------------------------
 9202 ;$00 - used in HammerBroJumpCode as bitmask
 9203 
 9204 HammerThrowTmrData:
 9205       .db $30, $1c
 9206 
 9207 XSpeedAdderData:
 9208       .db $00, $e8, $00, $18
 9209 
 9210 RevivedXSpeed:
 9211       .db $08, $f8, $0c, $f4
 9212 
 9213 ProcHammerBro:
 9214        lda Enemy_State,x          ;check hammer bro's enemy state for d5 set
 9215        and #%00100000
 9216        beq ChkJH                  ;if not set, go ahead with code
 9217        jmp MoveDefeatedEnemy      ;otherwise jump to something else
 9218 ChkJH: lda HammerBroJumpTimer,x   ;check jump timer
 9219        beq HammerBroJumpCode      ;if expired, branch to jump
 9220        dec HammerBroJumpTimer,x   ;otherwise decrement jump timer
 9221        lda Enemy_OffscreenBits
 9222        and #%00001100             ;check offscreen bits
 9223        bne MoveHammerBroXDir      ;if hammer bro a little offscreen, skip to movement code
 9224        lda HammerThrowingTimer,x  ;check hammer throwing timer
 9225        bne DecHT                  ;if not expired, skip ahead, do not throw hammer
 9226        ldy SecondaryHardMode      ;otherwise get secondary hard mode flag
 9227        lda HammerThrowTmrData,y   ;get timer data using flag as offset
 9228        sta HammerThrowingTimer,x  ;set as new timer
 9229        jsr SpawnHammerObj         ;do a sub here to spawn hammer object
 9230        bcc DecHT                  ;if carry clear, hammer not spawned, skip to decrement timer
 9231        lda Enemy_State,x
 9232        ora #%00001000             ;set d3 in enemy state for hammer throw
 9233        sta Enemy_State,x
 9234        jmp MoveHammerBroXDir      ;jump to move hammer bro
 9235 DecHT: dec HammerThrowingTimer,x  ;decrement timer
 9236        jmp MoveHammerBroXDir      ;jump to move hammer bro
 9237 
 9238 HammerBroJumpLData:
 9239       .db $20, $37
 9240 
 9241 HammerBroJumpCode:
 9242        lda Enemy_State,x           ;get hammer bro's enemy state
 9243        and #%00000111              ;mask out all but 3 LSB
 9244        cmp #$01                    ;check for d0 set (for jumping)
 9245        beq MoveHammerBroXDir       ;if set, branch ahead to moving code
 9246        lda #$00                    ;load default value here
 9247        sta $00                     ;save into temp variable for now
 9248        ldy #$fa                    ;set default vertical speed
 9249        lda Enemy_Y_Position,x      ;check hammer bro's vertical coordinate
 9250        bmi SetHJ                   ;if on the bottom half of the screen, use current speed
 9251        ldy #$fd                    ;otherwise set alternate vertical speed
 9252        cmp #$70                    ;check to see if hammer bro is above the middle of screen
 9253        inc $00                     ;increment preset value to $01
 9254        bcc SetHJ                   ;if above the middle of the screen, use current speed and $01
 9255        dec $00                     ;otherwise return value to $00
 9256        lda PseudoRandomBitReg+1,x  ;get part of LSFR, mask out all but LSB
 9257        and #$01
 9258        bne SetHJ                   ;if d0 of LSFR set, branch and use current speed and $00
 9259        ldy #$fa                    ;otherwise reset to default vertical speed
 9260 SetHJ: sty Enemy_Y_Speed,x         ;set vertical speed for jumping
 9261        lda Enemy_State,x           ;set d0 in enemy state for jumping
 9262        ora #$01
 9263        sta Enemy_State,x
 9264        lda $00                     ;load preset value here to use as bitmask
 9265        and PseudoRandomBitReg+2,x  ;and do bit-wise comparison with part of LSFR
 9266        tay                         ;then use as offset
 9267        lda SecondaryHardMode       ;check secondary hard mode flag
 9268        bne HJump
 9269        tay                         ;if secondary hard mode flag clear, set offset to 0
 9270 HJump: lda HammerBroJumpLData,y    ;get jump length timer data using offset from before
 9271        sta EnemyFrameTimer,x       ;save in enemy timer
 9272        lda PseudoRandomBitReg+1,x
 9273        ora #%11000000              ;get contents of part of LSFR, set d7 and d6, then
 9274        sta HammerBroJumpTimer,x    ;store in jump timer
 9275 
 9276 MoveHammerBroXDir:
 9277          ldy #$fc                  ;move hammer bro a little to the left
 9278          lda FrameCounter
 9279          and #%01000000            ;change hammer bro's direction every 64 frames
 9280          bne Shimmy
 9281          ldy #$04                  ;if d6 set in counter, move him a little to the right
 9282 Shimmy:  sty Enemy_X_Speed,x       ;store horizontal speed
 9283          ldy #$01                  ;set to face right by default
 9284          jsr PlayerEnemyDiff       ;get horizontal difference between player and hammer bro
 9285          bmi SetShim               ;if enemy to the left of player, skip this part
 9286          iny                       ;set to face left
 9287          lda EnemyIntervalTimer,x  ;check walking timer
 9288          bne SetShim               ;if not yet expired, skip to set moving direction
 9289          lda #$f8
 9290          sta Enemy_X_Speed,x       ;otherwise, make the hammer bro walk left towards player
 9291 SetShim: sty Enemy_MovingDir,x     ;set moving direction
 9292 
 9293 MoveNormalEnemy:
 9294        ldy #$00                   ;init Y to leave horizontal movement as-is 
 9295        lda Enemy_State,x
 9296        and #%01000000             ;check enemy state for d6 set, if set skip
 9297        bne FallE                  ;to move enemy vertically, then horizontally if necessary
 9298        lda Enemy_State,x
 9299        asl                        ;check enemy state for d7 set
 9300        bcs SteadM                 ;if set, branch to move enemy horizontally
 9301        lda Enemy_State,x
 9302        and #%00100000             ;check enemy state for d5 set
 9303        bne MoveDefeatedEnemy      ;if set, branch to move defeated enemy object
 9304        lda Enemy_State,x
 9305        and #%00000111             ;check d2-d0 of enemy state for any set bits
 9306        beq SteadM                 ;if enemy in normal state, branch to move enemy horizontally
 9307        cmp #$05
 9308        beq FallE                  ;if enemy in state used by spiny's egg, go ahead here
 9309        cmp #$03
 9310        bcs ReviveStunned          ;if enemy in states $03 or $04, skip ahead to yet another part
 9311 FallE: jsr MoveD_EnemyVertically  ;do a sub here to move enemy downwards
 9312        ldy #$00
 9313        lda Enemy_State,x          ;check for enemy state $02
 9314        cmp #$02
 9315        beq MEHor                  ;if found, branch to move enemy horizontally
 9316        and #%01000000             ;check for d6 set
 9317        beq SteadM                 ;if not set, branch to something else
 9318        lda Enemy_ID,x
 9319        cmp #PowerUpObject         ;check for power-up object
 9320        beq SteadM
 9321        bne SlowM                  ;if any other object where d6 set, jump to set Y
 9322 MEHor: jmp MoveEnemyHorizontally  ;jump here to move enemy horizontally for <> $2e and d6 set
 9323 
 9324 SlowM:  ldy #$01                  ;if branched here, increment Y to slow horizontal movement
 9325 SteadM: lda Enemy_X_Speed,x       ;get current horizontal speed
 9326         pha                       ;save to stack
 9327         bpl AddHS                 ;if not moving or moving right, skip, leave Y alone
 9328         iny
 9329         iny                       ;otherwise increment Y to next data
 9330 AddHS:  clc
 9331         adc XSpeedAdderData,y     ;add value here to slow enemy down if necessary
 9332         sta Enemy_X_Speed,x       ;save as horizontal speed temporarily
 9333         jsr MoveEnemyHorizontally ;then do a sub to move horizontally
 9334         pla
 9335         sta Enemy_X_Speed,x       ;get old horizontal speed from stack and return to
 9336         rts                       ;original memory location, then leave
 9337 
 9338 ReviveStunned:
 9339          lda EnemyIntervalTimer,x  ;if enemy timer not expired yet,
 9340          bne ChkKillGoomba         ;skip ahead to something else
 9341          sta Enemy_State,x         ;otherwise initialize enemy state to normal
 9342          lda FrameCounter
 9343          and #$01                  ;get d0 of frame counter
 9344          tay                       ;use as Y and increment for movement direction
 9345          iny
 9346          sty Enemy_MovingDir,x     ;store as pseudorandom movement direction
 9347          dey                       ;decrement for use as pointer
 9348          lda PrimaryHardMode       ;check primary hard mode flag
 9349          beq SetRSpd               ;if not set, use pointer as-is
 9350          iny
 9351          iny                       ;otherwise increment 2 bytes to next data
 9352 SetRSpd: lda RevivedXSpeed,y       ;load and store new horizontal speed
 9353          sta Enemy_X_Speed,x       ;and leave
 9354          rts
 9355 
 9356 MoveDefeatedEnemy:
 9357       jsr MoveD_EnemyVertically      ;execute sub to move defeated enemy downwards
 9358       jmp MoveEnemyHorizontally      ;now move defeated enemy horizontally
 9359 
 9360 ChkKillGoomba:
 9361         cmp #$0e              ;check to see if enemy timer has reached
 9362         bne NKGmba            ;a certain point, and branch to leave if not
 9363         lda Enemy_ID,x
 9364         cmp #Goomba           ;check for goomba object
 9365         bne NKGmba            ;branch if not found
 9366         jsr EraseEnemyObject  ;otherwise, kill this goomba object
 9367 NKGmba: rts                   ;leave!
 9368 
 9369 ;--------------------------------
 9370 
 9371 MoveJumpingEnemy:
 9372       jsr MoveJ_EnemyVertically  ;do a sub to impose gravity on green paratroopa
 9373       jmp MoveEnemyHorizontally  ;jump to move enemy horizontally
 9374 
 9375 ;--------------------------------
 9376 
 9377 ProcMoveRedPTroopa:
 9378           lda Enemy_Y_Speed,x
 9379           ora Enemy_Y_MoveForce,x     ;check for any vertical force or speed
 9380           bne MoveRedPTUpOrDown       ;branch if any found
 9381           sta Enemy_YMF_Dummy,x       ;initialize something here
 9382           lda Enemy_Y_Position,x      ;check current vs. original vertical coordinate
 9383           cmp RedPTroopaOrigXPos,x
 9384           bcs MoveRedPTUpOrDown       ;if current => original, skip ahead to more code
 9385           lda FrameCounter            ;get frame counter
 9386           and #%00000111              ;mask out all but 3 LSB
 9387           bne NoIncPT                 ;if any bits set, branch to leave
 9388           inc Enemy_Y_Position,x      ;otherwise increment red paratroopa's vertical position
 9389 NoIncPT:  rts                         ;leave
 9390 
 9391 MoveRedPTUpOrDown:
 9392           lda Enemy_Y_Position,x      ;check current vs. central vertical coordinate
 9393           cmp RedPTroopaCenterYPos,x
 9394           bcc MovPTDwn                ;if current < central, jump to move downwards
 9395           jmp MoveRedPTroopaUp        ;otherwise jump to move upwards
 9396 MovPTDwn: jmp MoveRedPTroopaDown      ;move downwards
 9397 
 9398 ;--------------------------------
 9399 ;$00 - used to store adder for movement, also used as adder for platform
 9400 ;$01 - used to store maximum value for secondary counter
 9401 
 9402 MoveFlyGreenPTroopa:
 9403         jsr XMoveCntr_GreenPTroopa ;do sub to increment primary and secondary counters
 9404         jsr MoveWithXMCntrs        ;do sub to move green paratroopa accordingly, and horizontally
 9405         ldy #$01                   ;set Y to move green paratroopa down
 9406         lda FrameCounter
 9407         and #%00000011             ;check frame counter 2 LSB for any bits set
 9408         bne NoMGPT                 ;branch to leave if set to move up/down every fourth frame
 9409         lda FrameCounter
 9410         and #%01000000             ;check frame counter for d6 set
 9411         bne YSway                  ;branch to move green paratroopa down if set
 9412         ldy #$ff                   ;otherwise set Y to move green paratroopa up
 9413 YSway:  sty $00                    ;store adder here
 9414         lda Enemy_Y_Position,x
 9415         clc                        ;add or subtract from vertical position
 9416         adc $00                    ;to give green paratroopa a wavy flight
 9417         sta Enemy_Y_Position,x
 9418 NoMGPT: rts                        ;leave!
 9419 
 9420 XMoveCntr_GreenPTroopa:
 9421          lda #$13                    ;load preset maximum value for secondary counter
 9422 
 9423 XMoveCntr_Platform:
 9424          sta $01                     ;store value here
 9425          lda FrameCounter
 9426          and #%00000011              ;branch to leave if not on
 9427          bne NoIncXM                 ;every fourth frame
 9428          ldy XMoveSecondaryCounter,x ;get secondary counter
 9429          lda XMovePrimaryCounter,x   ;get primary counter
 9430          lsr
 9431          bcs DecSeXM                 ;if d0 of primary counter set, branch elsewhere
 9432          cpy $01                     ;compare secondary counter to preset maximum value
 9433          beq IncPXM                  ;if equal, branch ahead of this part
 9434          inc XMoveSecondaryCounter,x ;increment secondary counter and leave
 9435 NoIncXM: rts
 9436 IncPXM:  inc XMovePrimaryCounter,x   ;increment primary counter and leave
 9437          rts
 9438 DecSeXM: tya                         ;put secondary counter in A
 9439          beq IncPXM                  ;if secondary counter at zero, branch back
 9440          dec XMoveSecondaryCounter,x ;otherwise decrement secondary counter and leave
 9441          rts
 9442 
 9443 MoveWithXMCntrs:
 9444          lda XMoveSecondaryCounter,x  ;save secondary counter to stack
 9445          pha
 9446          ldy #$01                     ;set value here by default
 9447          lda XMovePrimaryCounter,x
 9448          and #%00000010               ;if d1 of primary counter is
 9449          bne XMRight                  ;set, branch ahead of this part here
 9450          lda XMoveSecondaryCounter,x
 9451          eor #$ff                     ;otherwise change secondary
 9452          clc                          ;counter to two's compliment
 9453          adc #$01
 9454          sta XMoveSecondaryCounter,x
 9455          ldy #$02                     ;load alternate value here
 9456 XMRight: sty Enemy_MovingDir,x        ;store as moving direction
 9457          jsr MoveEnemyHorizontally
 9458          sta $00                      ;save value obtained from sub here
 9459          pla                          ;get secondary counter from stack
 9460          sta XMoveSecondaryCounter,x  ;and return to original place
 9461          rts
 9462 
 9463 ;--------------------------------
 9464 
 9465 BlooberBitmasks:
 9466       .db %00111111, %00000011
 9467 
 9468 MoveBloober:
 9469         lda Enemy_State,x
 9470         and #%00100000             ;check enemy state for d5 set
 9471         bne MoveDefeatedBloober    ;branch if set to move defeated bloober
 9472         ldy SecondaryHardMode      ;use secondary hard mode flag as offset
 9473         lda PseudoRandomBitReg+1,x ;get LSFR
 9474         and BlooberBitmasks,y      ;mask out bits in LSFR using bitmask loaded with offset
 9475         bne BlooberSwim            ;if any bits set, skip ahead to make swim
 9476         txa
 9477         lsr                        ;check to see if on second or fourth slot (1 or 3)
 9478         bcc FBLeft                 ;if not, branch to figure out moving direction
 9479         ldy Player_MovingDir       ;otherwise, load player's moving direction and
 9480         bcs SBMDir                 ;do an unconditional branch to set
 9481 FBLeft: ldy #$02                   ;set left moving direction by default
 9482         jsr PlayerEnemyDiff        ;get horizontal difference between player and bloober
 9483         bpl SBMDir                 ;if enemy to the right of player, keep left
 9484         dey                        ;otherwise decrement to set right moving direction
 9485 SBMDir: sty Enemy_MovingDir,x      ;set moving direction of bloober, then continue on here
 9486 
 9487 BlooberSwim:
 9488        jsr ProcSwimmingB        ;execute sub to make bloober swim characteristically
 9489        lda Enemy_Y_Position,x   ;get vertical coordinate
 9490        sec
 9491        sbc Enemy_Y_MoveForce,x  ;subtract movement force
 9492        cmp #$20                 ;check to see if position is above edge of status bar
 9493        bcc SwimX                ;if so, don't do it
 9494        sta Enemy_Y_Position,x   ;otherwise, set new vertical position, make bloober swim
 9495 SwimX: ldy Enemy_MovingDir,x    ;check moving direction
 9496        dey
 9497        bne LeftSwim             ;if moving to the left, branch to second part
 9498        lda Enemy_X_Position,x
 9499        clc                      ;add movement speed to horizontal coordinate
 9500        adc BlooperMoveSpeed,x
 9501        sta Enemy_X_Position,x   ;store result as new horizontal coordinate
 9502        lda Enemy_PageLoc,x
 9503        adc #$00                 ;add carry to page location
 9504        sta Enemy_PageLoc,x      ;store as new page location and leave
 9505        rts
 9506 
 9507 LeftSwim:
 9508       lda Enemy_X_Position,x
 9509       sec                      ;subtract movement speed from horizontal coordinate
 9510       sbc BlooperMoveSpeed,x
 9511       sta Enemy_X_Position,x   ;store result as new horizontal coordinate
 9512       lda Enemy_PageLoc,x
 9513       sbc #$00                 ;subtract borrow from page location
 9514       sta Enemy_PageLoc,x      ;store as new page location and leave
 9515       rts
 9516 
 9517 MoveDefeatedBloober:
 9518       jmp MoveEnemySlowVert    ;jump to move defeated bloober downwards
 9519 
 9520 ProcSwimmingB:
 9521         lda BlooperMoveCounter,x  ;get enemy's movement counter
 9522         and #%00000010            ;check for d1 set
 9523         bne ChkForFloatdown       ;branch if set
 9524         lda FrameCounter
 9525         and #%00000111            ;get 3 LSB of frame counter
 9526         pha                       ;and save it to the stack
 9527         lda BlooperMoveCounter,x  ;get enemy's movement counter
 9528         lsr                       ;check for d0 set
 9529         bcs SlowSwim              ;branch if set
 9530         pla                       ;pull 3 LSB of frame counter from the stack
 9531         bne BSwimE                ;branch to leave, execute code only every eighth frame
 9532         lda Enemy_Y_MoveForce,x
 9533         clc                       ;add to movement force to speed up swim
 9534         adc #$01
 9535         sta Enemy_Y_MoveForce,x   ;set movement force
 9536         sta BlooperMoveSpeed,x    ;set as movement speed
 9537         cmp #$02
 9538         bne BSwimE                ;if certain horizontal speed, branch to leave
 9539         inc BlooperMoveCounter,x  ;otherwise increment movement counter
 9540 BSwimE: rts
 9541 
 9542 SlowSwim:
 9543        pla                      ;pull 3 LSB of frame counter from the stack
 9544        bne NoSSw                ;branch to leave, execute code only every eighth frame
 9545        lda Enemy_Y_MoveForce,x
 9546        sec                      ;subtract from movement force to slow swim
 9547        sbc #$01
 9548        sta Enemy_Y_MoveForce,x  ;set movement force
 9549        sta BlooperMoveSpeed,x   ;set as movement speed
 9550        bne NoSSw                ;if any speed, branch to leave
 9551        inc BlooperMoveCounter,x ;otherwise increment movement counter
 9552        lda #$02
 9553        sta EnemyIntervalTimer,x ;set enemy's timer
 9554 NoSSw: rts                      ;leave
 9555 
 9556 ChkForFloatdown:
 9557       lda EnemyIntervalTimer,x ;get enemy timer
 9558       beq ChkNearPlayer        ;branch if expired
 9559 
 9560 Floatdown:
 9561       lda FrameCounter        ;get frame counter
 9562       lsr                     ;check for d0 set
 9563       bcs NoFD                ;branch to leave on every other frame
 9564       inc Enemy_Y_Position,x  ;otherwise increment vertical coordinate
 9565 NoFD: rts                     ;leave
 9566 
 9567 ChkNearPlayer:
 9568       lda Enemy_Y_Position,x    ;get vertical coordinate
 9569       adc #$10                  ;add sixteen pixels
 9570       cmp Player_Y_Position     ;compare result with player's vertical coordinate
 9571       bcc Floatdown             ;if modified vertical less than player's, branch
 9572       lda #$00
 9573       sta BlooperMoveCounter,x  ;otherwise nullify movement counter
 9574       rts
 9575 
 9576 ;--------------------------------
 9577 
 9578 MoveBulletBill:
 9579          lda Enemy_State,x          ;check bullet bill's enemy object state for d5 set
 9580          and #%00100000
 9581          beq NotDefB                ;if not set, continue with movement code
 9582          jmp MoveJ_EnemyVertically  ;otherwise jump to move defeated bullet bill downwards
 9583 NotDefB: lda #$e8                   ;set bullet bill's horizontal speed
 9584          sta Enemy_X_Speed,x        ;and move it accordingly (note: this bullet bill
 9585          jmp MoveEnemyHorizontally  ;object occurs in frenzy object $17, not from cannons)
 9586 
 9587 ;--------------------------------
 9588 ;$02 - used to hold preset values
 9589 ;$03 - used to hold enemy state
 9590 
 9591 SwimCCXMoveData:
 9592       .db $40, $80
 9593       .db $04, $04 ;residual data, not used
 9594 
 9595 MoveSwimmingCheepCheep:
 9596         lda Enemy_State,x         ;check cheep-cheep's enemy object state
 9597         and #%00100000            ;for d5 set
 9598         beq CCSwim                ;if not set, continue with movement code
 9599         jmp MoveEnemySlowVert     ;otherwise jump to move defeated cheep-cheep downwards
 9600 CCSwim: sta $03                   ;save enemy state in $03
 9601         lda Enemy_ID,x            ;get enemy identifier
 9602         sec
 9603         sbc #$0a                  ;subtract ten for cheep-cheep identifiers
 9604         tay                       ;use as offset
 9605         lda SwimCCXMoveData,y     ;load value here
 9606         sta $02
 9607         lda Enemy_X_MoveForce,x   ;load horizontal force
 9608         sec
 9609         sbc $02                   ;subtract preset value from horizontal force
 9610         sta Enemy_X_MoveForce,x   ;store as new horizontal force
 9611         lda Enemy_X_Position,x    ;get horizontal coordinate
 9612         sbc #$00                  ;subtract borrow (thus moving it slowly)
 9613         sta Enemy_X_Position,x    ;and save as new horizontal coordinate
 9614         lda Enemy_PageLoc,x
 9615         sbc #$00                  ;subtract borrow again, this time from the
 9616         sta Enemy_PageLoc,x       ;page location, then save
 9617         lda #$20
 9618         sta $02                   ;save new value here
 9619         cpx #$02                  ;check enemy object offset
 9620         bcc ExSwCC                ;if in first or second slot, branch to leave
 9621         lda CheepCheepMoveMFlag,x ;check movement flag
 9622         cmp #$10                  ;if movement speed set to $00,
 9623         bcc CCSwimUpwards         ;branch to move upwards
 9624         lda Enemy_YMF_Dummy,x
 9625         clc
 9626         adc $02                   ;add preset value to dummy variable to get carry
 9627         sta Enemy_YMF_Dummy,x     ;and save dummy
 9628         lda Enemy_Y_Position,x    ;get vertical coordinate
 9629         adc $03                   ;add carry to it plus enemy state to slowly move it downwards
 9630         sta Enemy_Y_Position,x    ;save as new vertical coordinate
 9631         lda Enemy_Y_HighPos,x
 9632         adc #$00                  ;add carry to page location and
 9633         jmp ChkSwimYPos           ;jump to end of movement code
 9634 
 9635 CCSwimUpwards:
 9636         lda Enemy_YMF_Dummy,x
 9637         sec
 9638         sbc $02                   ;subtract preset value to dummy variable to get borrow
 9639         sta Enemy_YMF_Dummy,x     ;and save dummy
 9640         lda Enemy_Y_Position,x    ;get vertical coordinate
 9641         sbc $03                   ;subtract borrow to it plus enemy state to slowly move it upwards
 9642         sta Enemy_Y_Position,x    ;save as new vertical coordinate
 9643         lda Enemy_Y_HighPos,x
 9644         sbc #$00                  ;subtract borrow from page location
 9645 
 9646 ChkSwimYPos:
 9647         sta Enemy_Y_HighPos,x     ;save new page location here
 9648         ldy #$00                  ;load movement speed to upwards by default
 9649         lda Enemy_Y_Position,x    ;get vertical coordinate
 9650         sec
 9651         sbc CheepCheepOrigYPos,x  ;subtract original coordinate from current
 9652         bpl YPDiff                ;if result positive, skip to next part
 9653         ldy #$10                  ;otherwise load movement speed to downwards
 9654         eor #$ff
 9655         clc                       ;get two's compliment of result
 9656         adc #$01                  ;to obtain total difference of original vs. current
 9657 YPDiff: cmp #$0f                  ;if difference between original vs. current vertical
 9658         bcc ExSwCC                ;coordinates < 15 pixels, leave movement speed alone
 9659         tya
 9660         sta CheepCheepMoveMFlag,x ;otherwise change movement speed
 9661 ExSwCC: rts                       ;leave
 9662 
 9663 ;--------------------------------
 9664 ;$00 - used as counter for firebar parts
 9665 ;$01 - used for oscillated high byte of spin state or to hold horizontal adder
 9666 ;$02 - used for oscillated high byte of spin state or to hold vertical adder
 9667 ;$03 - used for mirror data
 9668 ;$04 - used to store player's sprite 1 X coordinate
 9669 ;$05 - used to evaluate mirror data
 9670 ;$06 - used to store either screen X coordinate or sprite data offset
 9671 ;$07 - used to store screen Y coordinate
 9672 ;$ed - used to hold maximum length of firebar
 9673 ;$ef - used to hold high byte of spinstate
 9674 
 9675 ;horizontal adder is at first byte + high byte of spinstate,
 9676 ;vertical adder is same + 8 bytes, two's compliment
 9677 ;if greater than $08 for proper oscillation
 9678 FirebarPosLookupTbl:
 9679       .db $00, $01, $03, $04, $05, $06, $07, $07, $08
 9680       .db $00, $03, $06, $09, $0b, $0d, $0e, $0f, $10
 9681       .db $00, $04, $09, $0d, $10, $13, $16, $17, $18
 9682       .db $00, $06, $0c, $12, $16, $1a, $1d, $1f, $20
 9683       .db $00, $07, $0f, $16, $1c, $21, $25, $27, $28
 9684       .db $00, $09, $12, $1b, $21, $27, $2c, $2f, $30
 9685       .db $00, $0b, $15, $1f, $27, $2e, $33, $37, $38
 9686       .db $00, $0c, $18, $24, $2d, $35, $3b, $3e, $40
 9687       .db $00, $0e, $1b, $28, $32, $3b, $42, $46, $48
 9688       .db $00, $0f, $1f, $2d, $38, $42, $4a, $4e, $50
 9689       .db $00, $11, $22, $31, $3e, $49, $51, $56, $58
 9690 
 9691 FirebarMirrorData:
 9692       .db $01, $03, $02, $00
 9693 
 9694 FirebarTblOffsets:
 9695       .db $00, $09, $12, $1b, $24, $2d
 9696       .db $36, $3f, $48, $51, $5a, $63
 9697 
 9698 FirebarYPos:
 9699       .db $0c, $18
 9700 
 9701 ProcFirebar:
 9702           jsr GetEnemyOffscreenBits   ;get offscreen information
 9703           lda Enemy_OffscreenBits     ;check for d3 set
 9704           and #%00001000              ;if so, branch to leave
 9705           bne SkipFBar
 9706           lda TimerControl            ;if master timer control set, branch
 9707           bne SusFbar                 ;ahead of this part
 9708           lda FirebarSpinSpeed,x      ;load spinning speed of firebar
 9709           jsr FirebarSpin             ;modify current spinstate
 9710           and #%00011111              ;mask out all but 5 LSB
 9711           sta FirebarSpinState_High,x ;and store as new high byte of spinstate
 9712 SusFbar:  lda FirebarSpinState_High,x ;get high byte of spinstate
 9713           ldy Enemy_ID,x              ;check enemy identifier
 9714           cpy #$1f
 9715           bcc SetupGFB                ;if < $1f (long firebar), branch
 9716           cmp #$08                    ;check high byte of spinstate
 9717           beq SkpFSte                 ;if eight, branch to change
 9718           cmp #$18
 9719           bne SetupGFB                ;if not at twenty-four branch to not change
 9720 SkpFSte:  clc
 9721           adc #$01                    ;add one to spinning thing to avoid horizontal state
 9722           sta FirebarSpinState_High,x
 9723 SetupGFB: sta $ef                     ;save high byte of spinning thing, modified or otherwise
 9724           jsr RelativeEnemyPosition   ;get relative coordinates to screen
 9725           jsr GetFirebarPosition      ;do a sub here (residual, too early to be used now)
 9726           ldy Enemy_SprDataOffset,x   ;get OAM data offset
 9727           lda Enemy_Rel_YPos          ;get relative vertical coordinate
 9728           sta Sprite_Y_Position,y     ;store as Y in OAM data
 9729           sta $07                     ;also save here
 9730           lda Enemy_Rel_XPos          ;get relative horizontal coordinate
 9731           sta Sprite_X_Position,y     ;store as X in OAM data
 9732           sta $06                     ;also save here
 9733           lda #$01
 9734           sta $00                     ;set $01 value here (not necessary)
 9735           jsr FirebarCollision        ;draw fireball part and do collision detection
 9736           ldy #$05                    ;load value for short firebars by default
 9737           lda Enemy_ID,x
 9738           cmp #$1f                    ;are we doing a long firebar?
 9739           bcc SetMFbar                ;no, branch then
 9740           ldy #$0b                    ;otherwise load value for long firebars
 9741 SetMFbar: sty $ed                     ;store maximum value for length of firebars
 9742           lda #$00
 9743           sta $00                     ;initialize counter here
 9744 DrawFbar: lda $ef                     ;load high byte of spinstate
 9745           jsr GetFirebarPosition      ;get fireball position data depending on firebar part
 9746           jsr DrawFirebar_Collision   ;position it properly, draw it and do collision detection
 9747           lda $00                     ;check which firebar part
 9748           cmp #$04
 9749           bne NextFbar
 9750           ldy DuplicateObj_Offset     ;if we arrive at fifth firebar part,
 9751           lda Enemy_SprDataOffset,y   ;get offset from long firebar and load OAM data offset
 9752           sta $06                     ;using long firebar offset, then store as new one here
 9753 NextFbar: inc $00                     ;move onto the next firebar part
 9754           lda $00
 9755           cmp $ed                     ;if we end up at the maximum part, go on and leave
 9756           bcc DrawFbar                ;otherwise go back and do another
 9757 SkipFBar: rts
 9758 
 9759 DrawFirebar_Collision:
 9760          lda $03                  ;store mirror data elsewhere
 9761          sta $05          
 9762          ldy $06                  ;load OAM data offset for firebar
 9763          lda $01                  ;load horizontal adder we got from position loader
 9764          lsr $05                  ;shift LSB of mirror data
 9765          bcs AddHA                ;if carry was set, skip this part
 9766          eor #$ff
 9767          adc #$01                 ;otherwise get two's compliment of horizontal adder
 9768 AddHA:   clc                      ;add horizontal coordinate relative to screen to
 9769          adc Enemy_Rel_XPos       ;horizontal adder, modified or otherwise
 9770          sta Sprite_X_Position,y  ;store as X coordinate here
 9771          sta $06                  ;store here for now, note offset is saved in Y still
 9772          cmp Enemy_Rel_XPos       ;compare X coordinate of sprite to original X of firebar
 9773          bcs SubtR1               ;if sprite coordinate => original coordinate, branch
 9774          lda Enemy_Rel_XPos
 9775          sec                      ;otherwise subtract sprite X from the
 9776          sbc $06                  ;original one and skip this part
 9777          jmp ChkFOfs
 9778 SubtR1:  sec                      ;subtract original X from the
 9779          sbc Enemy_Rel_XPos       ;current sprite X
 9780 ChkFOfs: cmp #$59                 ;if difference of coordinates within a certain range,
 9781          bcc VAHandl              ;continue by handling vertical adder
 9782          lda #$f8                 ;otherwise, load offscreen Y coordinate
 9783          bne SetVFbr              ;and unconditionally branch to move sprite offscreen
 9784 VAHandl: lda Enemy_Rel_YPos       ;if vertical relative coordinate offscreen,
 9785          cmp #$f8                 ;skip ahead of this part and write into sprite Y coordinate
 9786          beq SetVFbr
 9787          lda $02                  ;load vertical adder we got from position loader
 9788          lsr $05                  ;shift LSB of mirror data one more time
 9789          bcs AddVA                ;if carry was set, skip this part
 9790          eor #$ff
 9791          adc #$01                 ;otherwise get two's compliment of second part
 9792 AddVA:   clc                      ;add vertical coordinate relative to screen to 
 9793          adc Enemy_Rel_YPos       ;the second data, modified or otherwise
 9794 SetVFbr: sta Sprite_Y_Position,y  ;store as Y coordinate here
 9795          sta $07                  ;also store here for now
 9796 
 9797 FirebarCollision:
 9798          jsr DrawFirebar          ;run sub here to draw current tile of firebar
 9799          tya                      ;return OAM data offset and save
 9800          pha                      ;to the stack for now
 9801          lda StarInvincibleTimer  ;if star mario invincibility timer
 9802          ora TimerControl         ;or master timer controls set
 9803          bne NoColFB              ;then skip all of this
 9804          sta $05                  ;otherwise initialize counter
 9805          ldy Player_Y_HighPos
 9806          dey                      ;if player's vertical high byte offscreen,
 9807          bne NoColFB              ;skip all of this
 9808          ldy Player_Y_Position    ;get player's vertical position
 9809          lda PlayerSize           ;get player's size
 9810          bne AdjSm                ;if player small, branch to alter variables
 9811          lda CrouchingFlag
 9812          beq BigJp                ;if player big and not crouching, jump ahead
 9813 AdjSm:   inc $05                  ;if small or big but crouching, execute this part
 9814          inc $05                  ;first increment our counter twice (setting $02 as flag)
 9815          tya
 9816          clc                      ;then add 24 pixels to the player's
 9817          adc #$18                 ;vertical coordinate
 9818          tay
 9819 BigJp:   tya                      ;get vertical coordinate, altered or otherwise, from Y
 9820 FBCLoop: sec                      ;subtract vertical position of firebar
 9821          sbc $07                  ;from the vertical coordinate of the player
 9822          bpl ChkVFBD              ;if player lower on the screen than firebar, 
 9823          eor #$ff                 ;skip two's compliment part
 9824          clc                      ;otherwise get two's compliment
 9825          adc #$01
 9826 ChkVFBD: cmp #$08                 ;if difference => 8 pixels, skip ahead of this part
 9827          bcs Chk2Ofs
 9828          lda $06                  ;if firebar on far right on the screen, skip this,
 9829          cmp #$f0                 ;because, really, what's the point?
 9830          bcs Chk2Ofs
 9831          lda Sprite_X_Position+4  ;get OAM X coordinate for sprite #1
 9832          clc
 9833          adc #$04                 ;add four pixels
 9834          sta $04                  ;store here
 9835          sec                      ;subtract horizontal coordinate of firebar
 9836          sbc $06                  ;from the X coordinate of player's sprite 1
 9837          bpl ChkFBCl              ;if modded X coordinate to the right of firebar
 9838          eor #$ff                 ;skip two's compliment part
 9839          clc                      ;otherwise get two's compliment
 9840          adc #$01
 9841 ChkFBCl: cmp #$08                 ;if difference < 8 pixels, collision, thus branch
 9842          bcc ChgSDir              ;to process
 9843 Chk2Ofs: lda $05                  ;if value of $02 was set earlier for whatever reason,
 9844          cmp #$02                 ;branch to increment OAM offset and leave, no collision
 9845          beq NoColFB
 9846          ldy $05                  ;otherwise get temp here and use as offset
 9847          lda Player_Y_Position
 9848          clc
 9849          adc FirebarYPos,y        ;add value loaded with offset to player's vertical coordinate
 9850          inc $05                  ;then increment temp and jump back
 9851          jmp FBCLoop
 9852 ChgSDir: ldx #$01                 ;set movement direction by default
 9853          lda $04                  ;if OAM X coordinate of player's sprite 1
 9854          cmp $06                  ;is greater than horizontal coordinate of firebar
 9855          bcs SetSDir              ;then do not alter movement direction
 9856          inx                      ;otherwise increment it
 9857 SetSDir: stx Enemy_MovingDir      ;store movement direction here
 9858          ldx #$00
 9859          lda $00                  ;save value written to $00 to stack
 9860          pha
 9861          jsr InjurePlayer         ;perform sub to hurt or kill player
 9862          pla
 9863          sta $00                  ;get value of $00 from stack
 9864 NoColFB: pla                      ;get OAM data offset
 9865          clc                      ;add four to it and save
 9866          adc #$04
 9867          sta $06
 9868          ldx ObjectOffset         ;get enemy object buffer offset and leave
 9869          rts
 9870 
 9871 GetFirebarPosition:
 9872            pha                        ;save high byte of spinstate to the stack
 9873            and #%00001111             ;mask out low nybble
 9874            cmp #$09
 9875            bcc GetHAdder              ;if lower than $09, branch ahead
 9876            eor #%00001111             ;otherwise get two's compliment to oscillate
 9877            clc
 9878            adc #$01
 9879 GetHAdder: sta $01                    ;store result, modified or not, here
 9880            ldy $00                    ;load number of firebar ball where we're at
 9881            lda FirebarTblOffsets,y    ;load offset to firebar position data
 9882            clc
 9883            adc $01                    ;add oscillated high byte of spinstate
 9884            tay                        ;to offset here and use as new offset
 9885            lda FirebarPosLookupTbl,y  ;get data here and store as horizontal adder
 9886            sta $01
 9887            pla                        ;pull whatever was in A from the stack
 9888            pha                        ;save it again because we still need it
 9889            clc
 9890            adc #$08                   ;add eight this time, to get vertical adder
 9891            and #%00001111             ;mask out high nybble
 9892            cmp #$09                   ;if lower than $09, branch ahead
 9893            bcc GetVAdder
 9894            eor #%00001111             ;otherwise get two's compliment
 9895            clc
 9896            adc #$01
 9897 GetVAdder: sta $02                    ;store result here
 9898            ldy $00
 9899            lda FirebarTblOffsets,y    ;load offset to firebar position data again
 9900            clc
 9901            adc $02                    ;this time add value in $02 to offset here and use as offset
 9902            tay
 9903            lda FirebarPosLookupTbl,y  ;get data here and store as vertica adder
 9904            sta $02
 9905            pla                        ;pull out whatever was in A one last time
 9906            lsr                        ;divide by eight or shift three to the right
 9907            lsr
 9908            lsr
 9909            tay                        ;use as offset
 9910            lda FirebarMirrorData,y    ;load mirroring data here
 9911            sta $03                    ;store
 9912            rts
 9913 
 9914 ;--------------------------------
 9915 
 9916 PRandomSubtracter:
 9917       .db $f8, $a0, $70, $bd, $00
 9918 
 9919 FlyCCBPriority:
 9920       .db $20, $20, $20, $00, $00
 9921 
 9922 MoveFlyingCheepCheep:
 9923         lda Enemy_State,x          ;check cheep-cheep's enemy state
 9924         and #%00100000             ;for d5 set
 9925         beq FlyCC                  ;branch to continue code if not set
 9926         lda #$00
 9927         sta Enemy_SprAttrib,x      ;otherwise clear sprite attributes
 9928         jmp MoveJ_EnemyVertically  ;and jump to move defeated cheep-cheep downwards
 9929 FlyCC:  jsr MoveEnemyHorizontally  ;move cheep-cheep horizontally based on speed and force
 9930         ldy #$0d                   ;set vertical movement amount
 9931         lda #$05                   ;set maximum speed
 9932         jsr SetXMoveAmt            ;branch to impose gravity on flying cheep-cheep
 9933         lda Enemy_Y_MoveForce,x
 9934         lsr                        ;get vertical movement force and
 9935         lsr                        ;move high nybble to low
 9936         lsr
 9937         lsr
 9938         tay                        ;save as offset (note this tends to go into reach of code)
 9939         lda Enemy_Y_Position,x     ;get vertical position
 9940         sec                        ;subtract pseudorandom value based on offset from position
 9941         sbc PRandomSubtracter,y
 9942         bpl AddCCF                  ;if result within top half of screen, skip this part
 9943         eor #$ff
 9944         clc                        ;otherwise get two's compliment
 9945         adc #$01
 9946 AddCCF: cmp #$08                   ;if result or two's compliment greater than eight,
 9947         bcs BPGet                  ;skip to the end without changing movement force
 9948         lda Enemy_Y_MoveForce,x
 9949         clc
 9950         adc #$10                   ;otherwise add to it
 9951         sta Enemy_Y_MoveForce,x
 9952         lsr                        ;move high nybble to low again
 9953         lsr
 9954         lsr
 9955         lsr
 9956         tay
 9957 BPGet:  lda FlyCCBPriority,y       ;load bg priority data and store (this is very likely
 9958         sta Enemy_SprAttrib,x      ;broken or residual code, value is overwritten before
 9959         rts                        ;drawing it next frame), then leave
 9960 
 9961 ;--------------------------------
 9962 ;$00 - used to hold horizontal difference
 9963 ;$01-$03 - used to hold difference adjusters
 9964 
 9965 LakituDiffAdj:
 9966       .db $15, $30, $40
 9967 
 9968 MoveLakitu:
 9969          lda Enemy_State,x          ;check lakitu's enemy state
 9970          and #%00100000             ;for d5 set
 9971          beq ChkLS                  ;if not set, continue with code
 9972          jmp MoveD_EnemyVertically  ;otherwise jump to move defeated lakitu downwards
 9973 ChkLS:   lda Enemy_State,x          ;if lakitu's enemy state not set at all,
 9974          beq Fr12S                  ;go ahead and continue with code
 9975          lda #$00
 9976          sta LakituMoveDirection,x  ;otherwise initialize moving direction to move to left
 9977          sta EnemyFrenzyBuffer      ;initialize frenzy buffer
 9978          lda #$10
 9979          bne SetLSpd                ;load horizontal speed and do unconditional branch
 9980 Fr12S:   lda #Spiny
 9981          sta EnemyFrenzyBuffer      ;set spiny identifier in frenzy buffer
 9982          ldy #$02
 9983 LdLDa:   lda LakituDiffAdj,y        ;load values
 9984          sta $0001,y                ;store in zero page
 9985          dey
 9986          bpl LdLDa                  ;do this until all values are stired
 9987          jsr PlayerLakituDiff       ;execute sub to set speed and create spinys
 9988 SetLSpd: sta LakituMoveSpeed,x      ;set movement speed returned from sub
 9989          ldy #$01                   ;set moving direction to right by default
 9990          lda LakituMoveDirection,x
 9991          and #$01                   ;get LSB of moving direction
 9992          bne SetLMov                ;if set, branch to the end to use moving direction
 9993          lda LakituMoveSpeed,x
 9994          eor #$ff                   ;get two's compliment of moving speed
 9995          clc
 9996          adc #$01
 9997          sta LakituMoveSpeed,x      ;store as new moving speed
 9998          iny                        ;increment moving direction to left
 9999 SetLMov: sty Enemy_MovingDir,x      ;store moving direction
10000          jmp MoveEnemyHorizontally  ;move lakitu horizontally
10001 
10002 PlayerLakituDiff:
10003            ldy #$00                   ;set Y for default value
10004            jsr PlayerEnemyDiff        ;get horizontal difference between enemy and player
10005            bpl ChkLakDif              ;branch if enemy is to the right of the player
10006            iny                        ;increment Y for left of player
10007            lda $00
10008            eor #$ff                   ;get two's compliment of low byte of horizontal difference
10009            clc
10010            adc #$01                   ;store two's compliment as horizontal difference
10011            sta $00
10012 ChkLakDif: lda $00                    ;get low byte of horizontal difference
10013            cmp #$3c                   ;if within a certain distance of player, branch
10014            bcc ChkPSpeed
10015            lda #$3c                   ;otherwise set maximum distance
10016            sta $00
10017            lda Enemy_ID,x             ;check if lakitu is in our current enemy slot
10018            cmp #Lakitu
10019            bne ChkPSpeed              ;if not, branch elsewhere
10020            tya                        ;compare contents of Y, now in A
10021            cmp LakituMoveDirection,x  ;to what is being used as horizontal movement direction
10022            beq ChkPSpeed              ;if moving toward the player, branch, do not alter
10023            lda LakituMoveDirection,x  ;if moving to the left beyond maximum distance,
10024            beq SetLMovD               ;branch and alter without delay
10025            dec LakituMoveSpeed,x      ;decrement horizontal speed
10026            lda LakituMoveSpeed,x      ;if horizontal speed not yet at zero, branch to leave
10027            bne ExMoveLak
10028 SetLMovD:  tya                        ;set horizontal direction depending on horizontal
10029            sta LakituMoveDirection,x  ;difference between enemy and player if necessary
10030 ChkPSpeed: lda $00
10031            and #%00111100             ;mask out all but four bits in the middle
10032            lsr                        ;divide masked difference by four
10033            lsr
10034            sta $00                    ;store as new value
10035            ldy #$00                   ;init offset
10036            lda Player_X_Speed
10037            beq SubDifAdj              ;if player not moving horizontally, branch
10038            lda ScrollAmount
10039            beq SubDifAdj              ;if scroll speed not set, branch to same place
10040            iny                        ;otherwise increment offset
10041            lda Player_X_Speed
10042            cmp #$19                   ;if player not running, branch
10043            bcc ChkSpinyO
10044            lda ScrollAmount
10045            cmp #$02                   ;if scroll speed below a certain amount, branch
10046            bcc ChkSpinyO              ;to same place
10047            iny                        ;otherwise increment once more
10048 ChkSpinyO: lda Enemy_ID,x             ;check for spiny object
10049            cmp #Spiny
10050            bne ChkEmySpd              ;branch if not found
10051            lda Player_X_Speed         ;if player not moving, skip this part
10052            bne SubDifAdj
10053 ChkEmySpd: lda Enemy_Y_Speed,x        ;check vertical speed
10054            bne SubDifAdj              ;branch if nonzero
10055            ldy #$00                   ;otherwise reinit offset
10056 SubDifAdj: lda $0001,y                ;get one of three saved values from earlier
10057            ldy $00                    ;get saved horizontal difference
10058 SPixelLak: sec                        ;subtract one for each pixel of horizontal difference
10059            sbc #$01                   ;from one of three saved values
10060            dey
10061            bpl SPixelLak              ;branch until all pixels are subtracted, to adjust difference
10062 ExMoveLak: rts                        ;leave!!!
10063 
10064 ;-------------------------------------------------------------------------------------
10065 ;$04-$05 - used to store name table address in little endian order
10066 
10067 BridgeCollapseData:
10068       .db $1a ;axe
10069       .db $58 ;chain
10070       .db $98, $96, $94, $92, $90, $8e, $8c ;bridge
10071       .db $8a, $88, $86, $84, $82, $80
10072 
10073 BridgeCollapse:
10074        ldx BowserFront_Offset    ;get enemy offset for bowser
10075        lda Enemy_ID,x            ;check enemy object identifier for bowser
10076        cmp #Bowser               ;if not found, branch ahead,
10077        bne SetM2                 ;metatile removal not necessary
10078        stx ObjectOffset          ;store as enemy offset here
10079        lda Enemy_State,x         ;if bowser in normal state, skip all of this
10080        beq RemoveBridge
10081        and #%01000000            ;if bowser's state has d6 clear, skip to silence music
10082        beq SetM2
10083        lda Enemy_Y_Position,x    ;check bowser's vertical coordinate
10084        cmp #$e0                  ;if bowser not yet low enough, skip this part ahead
10085        bcc MoveD_Bowser
10086 SetM2: lda #Silence              ;silence music
10087        sta EventMusicQueue
10088        inc OperMode_Task         ;move onto next secondary mode in autoctrl mode
10089        jmp KillAllEnemies        ;jump to empty all enemy slots and then leave  
10090 
10091 MoveD_Bowser:
10092        jsr MoveEnemySlowVert     ;do a sub to move bowser downwards
10093        jmp BowserGfxHandler      ;jump to draw bowser's front and rear, then leave
10094 
10095 RemoveBridge:
10096          dec BowserFeetCounter     ;decrement timer to control bowser's feet
10097          bne NoBFall               ;if not expired, skip all of this
10098          lda #$04
10099          sta BowserFeetCounter     ;otherwise, set timer now
10100          lda BowserBodyControls
10101          eor #$01                  ;invert bit to control bowser's feet
10102          sta BowserBodyControls
10103          lda #$22                  ;put high byte of name table address here for now
10104          sta $05
10105          ldy BridgeCollapseOffset  ;get bridge collapse offset here
10106          lda BridgeCollapseData,y  ;load low byte of name table address and store here
10107          sta $04
10108          ldy VRAM_Buffer1_Offset   ;increment vram buffer offset
10109          iny
10110          ldx #$0c                  ;set offset for tile data for sub to draw blank metatile
10111          jsr RemBridge             ;do sub here to remove bowser's bridge metatiles
10112          ldx ObjectOffset          ;get enemy offset
10113          jsr MoveVOffset           ;set new vram buffer offset
10114          lda #Sfx_Blast            ;load the fireworks/gunfire sound into the square 2 sfx
10115          sta Square2SoundQueue     ;queue while at the same time loading the brick
10116          lda #Sfx_BrickShatter     ;shatter sound into the noise sfx queue thus
10117          sta NoiseSoundQueue       ;producing the unique sound of the bridge collapsing 
10118          inc BridgeCollapseOffset  ;increment bridge collapse offset
10119          lda BridgeCollapseOffset
10120          cmp #$0f                  ;if bridge collapse offset has not yet reached
10121          bne NoBFall               ;the end, go ahead and skip this part
10122          jsr InitVStf              ;initialize whatever vertical speed bowser has
10123          lda #%01000000
10124          sta Enemy_State,x         ;set bowser's state to one of defeated states (d6 set)
10125          lda #Sfx_BowserFall
10126          sta Square2SoundQueue     ;play bowser defeat sound
10127 NoBFall: jmp BowserGfxHandler      ;jump to code that draws bowser
10128 
10129 ;--------------------------------
10130 
10131 PRandomRange:
10132       .db $21, $41, $11, $31
10133 
10134 RunBowser:
10135       lda Enemy_State,x       ;if d5 in enemy state is not set
10136       and #%00100000          ;then branch elsewhere to run bowser
10137       beq BowserControl
10138       lda Enemy_Y_Position,x  ;otherwise check vertical position
10139       cmp #$e0                ;if above a certain point, branch to move defeated bowser
10140       bcc MoveD_Bowser        ;otherwise proceed to KillAllEnemies
10141 
10142 KillAllEnemies:
10143           ldx #$04              ;start with last enemy slot
10144 KillLoop: jsr EraseEnemyObject  ;branch to kill enemy objects
10145           dex                   ;move onto next enemy slot
10146           bpl KillLoop          ;do this until all slots are emptied
10147           sta EnemyFrenzyBuffer ;empty frenzy buffer
10148           ldx ObjectOffset      ;get enemy object offset and leave
10149           rts
10150 
10151 BowserControl:
10152            lda #$00
10153            sta EnemyFrenzyBuffer      ;empty frenzy buffer
10154            lda TimerControl           ;if master timer control not set,
10155            beq ChkMouth               ;skip jump and execute code here
10156            jmp SkipToFB               ;otherwise, jump over a bunch of code
10157 ChkMouth:  lda BowserBodyControls     ;check bowser's mouth
10158            bpl FeetTmr                ;if bit clear, go ahead with code here
10159            jmp HammerChk              ;otherwise skip a whole section starting here
10160 FeetTmr:   dec BowserFeetCounter      ;decrement timer to control bowser's feet
10161            bne ResetMDr               ;if not expired, skip this part
10162            lda #$20                   ;otherwise, reset timer
10163            sta BowserFeetCounter        
10164            lda BowserBodyControls     ;and invert bit used
10165            eor #%00000001             ;to control bowser's feet
10166            sta BowserBodyControls
10167 ResetMDr:  lda FrameCounter           ;check frame counter
10168            and #%00001111             ;if not on every sixteenth frame, skip
10169            bne B_FaceP                ;ahead to continue code
10170            lda #$02                   ;otherwise reset moving/facing direction every
10171            sta Enemy_MovingDir,x      ;sixteen frames
10172 B_FaceP:   lda EnemyFrameTimer,x      ;if timer set here expired,
10173            beq GetPRCmp               ;branch to next section
10174            jsr PlayerEnemyDiff        ;get horizontal difference between player and bowser,
10175            bpl GetPRCmp               ;and branch if bowser to the right of the player
10176            lda #$01
10177            sta Enemy_MovingDir,x      ;set bowser to move and face to the right
10178            lda #$02
10179            sta BowserMovementSpeed    ;set movement speed
10180            lda #$20
10181            sta EnemyFrameTimer,x      ;set timer here
10182            sta BowserFireBreathTimer  ;set timer used for bowser's flame
10183            lda Enemy_X_Position,x        
10184            cmp #$c8                   ;if bowser to the right past a certain point,
10185            bcs HammerChk              ;skip ahead to some other section
10186 GetPRCmp:  lda FrameCounter           ;get frame counter
10187            and #%00000011
10188            bne HammerChk              ;execute this code every fourth frame, otherwise branch
10189            lda Enemy_X_Position,x
10190            cmp BowserOrigXPos         ;if bowser not at original horizontal position,
10191            bne GetDToO                ;branch to skip this part
10192            lda PseudoRandomBitReg,x
10193            and #%00000011             ;get pseudorandom offset
10194            tay
10195            lda PRandomRange,y         ;load value using pseudorandom offset
10196            sta MaxRangeFromOrigin     ;and store here
10197 GetDToO:   lda Enemy_X_Position,x
10198            clc                        ;add movement speed to bowser's horizontal
10199            adc BowserMovementSpeed    ;coordinate and save as new horizontal position
10200            sta Enemy_X_Position,x
10201            ldy Enemy_MovingDir,x
10202            cpy #$01                   ;if bowser moving and facing to the right, skip ahead
10203            beq HammerChk
10204            ldy #$ff                   ;set default movement speed here (move left)
10205            sec                        ;get difference of current vs. original
10206            sbc BowserOrigXPos         ;horizontal position
10207            bpl CompDToO               ;if current position to the right of original, skip ahead
10208            eor #$ff
10209            clc                        ;get two's compliment
10210            adc #$01
10211            ldy #$01                   ;set alternate movement speed here (move right)
10212 CompDToO:  cmp MaxRangeFromOrigin     ;compare difference with pseudorandom value
10213            bcc HammerChk              ;if difference < pseudorandom value, leave speed alone
10214            sty BowserMovementSpeed    ;otherwise change bowser's movement speed
10215 HammerChk: lda EnemyFrameTimer,x      ;if timer set here not expired yet, skip ahead to
10216            bne MakeBJump              ;some other section of code
10217            jsr MoveEnemySlowVert      ;otherwise start by moving bowser downwards
10218            lda WorldNumber            ;check world number
10219            cmp #World6
10220            bcc SetHmrTmr              ;if world 1-5, skip this part (not time to throw hammers yet)
10221            lda FrameCounter
10222            and #%00000011             ;check to see if it's time to execute sub
10223            bne SetHmrTmr              ;if not, skip sub, otherwise
10224            jsr SpawnHammerObj         ;execute sub on every fourth frame to spawn misc object (hammer)
10225 SetHmrTmr: lda Enemy_Y_Position,x     ;get current vertical position
10226            cmp #$80                   ;if still above a certain point
10227            bcc ChkFireB               ;then skip to world number check for flames
10228            lda PseudoRandomBitReg,x
10229            and #%00000011             ;get pseudorandom offset
10230            tay
10231            lda PRandomRange,y         ;get value using pseudorandom offset
10232            sta EnemyFrameTimer,x      ;set for timer here
10233 SkipToFB:  jmp ChkFireB               ;jump to execute flames code
10234 MakeBJump: cmp #$01                   ;if timer not yet about to expire,
10235            bne ChkFireB               ;skip ahead to next part
10236            dec Enemy_Y_Position,x     ;otherwise decrement vertical coordinate
10237            jsr InitVStf               ;initialize movement amount
10238            lda #$fe
10239            sta Enemy_Y_Speed,x        ;set vertical speed to move bowser upwards
10240 ChkFireB:  lda WorldNumber            ;check world number here
10241            cmp #World8                ;world 8?
10242            beq SpawnFBr               ;if so, execute this part here
10243            cmp #World6                ;world 6-7?
10244            bcs BowserGfxHandler       ;if so, skip this part here
10245 SpawnFBr:  lda BowserFireBreathTimer  ;check timer here
10246            bne BowserGfxHandler       ;if not expired yet, skip all of this
10247            lda #$20
10248            sta BowserFireBreathTimer  ;set timer here
10249            lda BowserBodyControls
10250            eor #%10000000             ;invert bowser's mouth bit to open
10251            sta BowserBodyControls     ;and close bowser's mouth
10252            bmi ChkFireB               ;if bowser's mouth open, loop back
10253            jsr SetFlameTimer          ;get timing for bowser's flame
10254            ldy SecondaryHardMode
10255            beq SetFBTmr               ;if secondary hard mode flag not set, skip this
10256            sec
10257            sbc #$10                   ;otherwise subtract from value in A
10258 SetFBTmr:  sta BowserFireBreathTimer  ;set value as timer here
10259            lda #BowserFlame           ;put bowser's flame identifier
10260            sta EnemyFrenzyBuffer      ;in enemy frenzy buffer
10261 
10262 ;--------------------------------
10263 
10264 BowserGfxHandler:
10265           jsr ProcessBowserHalf    ;do a sub here to process bowser's front
10266           ldy #$10                 ;load default value here to position bowser's rear
10267           lda Enemy_MovingDir,x    ;check moving direction
10268           lsr
10269           bcc CopyFToR             ;if moving left, use default
10270           ldy #$f0                 ;otherwise load alternate positioning value here
10271 CopyFToR: tya                      ;move bowser's rear object position value to A
10272           clc
10273           adc Enemy_X_Position,x   ;add to bowser's front object horizontal coordinate
10274           ldy DuplicateObj_Offset  ;get bowser's rear object offset
10275           sta Enemy_X_Position,y   ;store A as bowser's rear horizontal coordinate
10276           lda Enemy_Y_Position,x
10277           clc                      ;add eight pixels to bowser's front object
10278           adc #$08                 ;vertical coordinate and store as vertical coordinate
10279           sta Enemy_Y_Position,y   ;for bowser's rear
10280           lda Enemy_State,x
10281           sta Enemy_State,y        ;copy enemy state directly from front to rear
10282           lda Enemy_MovingDir,x
10283           sta Enemy_MovingDir,y    ;copy moving direction also
10284           lda ObjectOffset         ;save enemy object offset of front to stack
10285           pha
10286           ldx DuplicateObj_Offset  ;put enemy object offset of rear as current
10287           stx ObjectOffset
10288           lda #Bowser              ;set bowser's enemy identifier
10289           sta Enemy_ID,x           ;store in bowser's rear object
10290           jsr ProcessBowserHalf    ;do a sub here to process bowser's rear
10291           pla
10292           sta ObjectOffset         ;get original enemy object offset
10293           tax
10294           lda #$00                 ;nullify bowser's front/rear graphics flag
10295           sta BowserGfxFlag
10296 ExBGfxH:  rts                      ;leave!
10297 
10298 ProcessBowserHalf:
10299       inc BowserGfxFlag         ;increment bowser's graphics flag, then run subroutines
10300       jsr RunRetainerObj        ;to get offscreen bits, relative position and draw bowser (finally!)
10301       lda Enemy_State,x
10302       bne ExBGfxH               ;if either enemy object not in normal state, branch to leave
10303       lda #$0a
10304       sta Enemy_BoundBoxCtrl,x  ;set bounding box size control
10305       jsr GetEnemyBoundBox      ;get bounding box coordinates
10306       jmp PlayerEnemyCollision  ;do player-to-enemy collision detection
10307 
10308 ;-------------------------------------------------------------------------------------
10309 ;$00 - used to hold movement force and tile number
10310 ;$01 - used to hold sprite attribute data
10311 
10312 FlameTimerData:
10313       .db $bf, $40, $bf, $bf, $bf, $40, $40, $bf
10314 
10315 SetFlameTimer:
10316       ldy BowserFlameTimerCtrl  ;load counter as offset
10317       inc BowserFlameTimerCtrl  ;increment
10318       lda BowserFlameTimerCtrl  ;mask out all but 3 LSB
10319       and #%00000111            ;to keep in range of 0-7
10320       sta BowserFlameTimerCtrl
10321       lda FlameTimerData,y      ;load value to be used then leave
10322 ExFl: rts
10323 
10324 ProcBowserFlame:
10325          lda TimerControl            ;if master timer control flag set,
10326          bne SetGfxF                 ;skip all of this
10327          lda #$40                    ;load default movement force
10328          ldy SecondaryHardMode
10329          beq SFlmX                   ;if secondary hard mode flag not set, use default
10330          lda #$60                    ;otherwise load alternate movement force to go faster
10331 SFlmX:   sta $00                     ;store value here
10332          lda Enemy_X_MoveForce,x
10333          sec                         ;subtract value from movement force
10334          sbc $00
10335          sta Enemy_X_MoveForce,x     ;save new value
10336          lda Enemy_X_Position,x
10337          sbc #$01                    ;subtract one from horizontal position to move
10338          sta Enemy_X_Position,x      ;to the left
10339          lda Enemy_PageLoc,x
10340          sbc #$00                    ;subtract borrow from page location
10341          sta Enemy_PageLoc,x
10342          ldy BowserFlamePRandomOfs,x ;get some value here and use as offset
10343          lda Enemy_Y_Position,x      ;load vertical coordinate
10344          cmp FlameYPosData,y         ;compare against coordinate data using $0417,x as offset
10345          beq SetGfxF                 ;if equal, branch and do not modify coordinate
10346          clc
10347          adc Enemy_Y_MoveForce,x     ;otherwise add value here to coordinate and store
10348          sta Enemy_Y_Position,x      ;as new vertical coordinate
10349 SetGfxF: jsr RelativeEnemyPosition   ;get new relative coordinates
10350          lda Enemy_State,x           ;if bowser's flame not in normal state,
10351          bne ExFl                    ;branch to leave
10352          lda #$51                    ;otherwise, continue
10353          sta $00                     ;write first tile number
10354          ldy #$02                    ;load attributes without vertical flip by default
10355          lda FrameCounter
10356          and #%00000010              ;invert vertical flip bit every 2 frames
10357          beq FlmeAt                  ;if d1 not set, write default value
10358          ldy #$82                    ;otherwise write value with vertical flip bit set
10359 FlmeAt:  sty $01                     ;set bowser's flame sprite attributes here
10360          ldy Enemy_SprDataOffset,x   ;get OAM data offset
10361          ldx #$00
10362 
10363 DrawFlameLoop:
10364          lda Enemy_Rel_YPos         ;get Y relative coordinate of current enemy object
10365          sta Sprite_Y_Position,y    ;write into Y coordinate of OAM data
10366          lda $00
10367          sta Sprite_Tilenumber,y    ;write current tile number into OAM data
10368          inc $00                    ;increment tile number to draw more bowser's flame
10369          lda $01
10370          sta Sprite_Attributes,y    ;write saved attributes into OAM data
10371          lda Enemy_Rel_XPos
10372          sta Sprite_X_Position,y    ;write X relative coordinate of current enemy object
10373          clc
10374          adc #$08
10375          sta Enemy_Rel_XPos         ;then add eight to it and store
10376          iny
10377          iny
10378          iny
10379          iny                        ;increment Y four times to move onto the next OAM
10380          inx                        ;move onto the next OAM, and branch if three
10381          cpx #$03                   ;have not yet been done
10382          bcc DrawFlameLoop
10383          ldx ObjectOffset           ;reload original enemy offset
10384          jsr GetEnemyOffscreenBits  ;get offscreen information
10385          ldy Enemy_SprDataOffset,x  ;get OAM data offset
10386          lda Enemy_OffscreenBits    ;get enemy object offscreen bits
10387          lsr                        ;move d0 to carry and result to stack
10388          pha
10389          bcc M3FOfs                 ;branch if carry not set
10390          lda #$f8                   ;otherwise move sprite offscreen, this part likely
10391          sta Sprite_Y_Position+12,y ;residual since flame is only made of three sprites
10392 M3FOfs:  pla                        ;get bits from stack
10393          lsr                        ;move d1 to carry and move bits back to stack
10394          pha
10395          bcc M2FOfs                 ;branch if carry not set again
10396          lda #$f8                   ;otherwise move third sprite offscreen
10397          sta Sprite_Y_Position+8,y
10398 M2FOfs:  pla                        ;get bits from stack again
10399          lsr                        ;move d2 to carry and move bits back to stack again
10400          pha
10401          bcc M1FOfs                 ;branch if carry not set yet again
10402          lda #$f8                   ;otherwise move second sprite offscreen
10403          sta Sprite_Y_Position+4,y
10404 M1FOfs:  pla                        ;get bits from stack one last time
10405          lsr                        ;move d3 to carry
10406          bcc ExFlmeD                ;branch if carry not set one last time
10407          lda #$f8
10408          sta Sprite_Y_Position,y    ;otherwise move first sprite offscreen
10409 ExFlmeD: rts                        ;leave
10410 
10411 ;--------------------------------
10412 
10413 RunFireworks:
10414            dec ExplosionTimerCounter,x ;decrement explosion timing counter here
10415            bne SetupExpl               ;if not expired, skip this part
10416            lda #$08
10417            sta ExplosionTimerCounter,x ;reset counter
10418            inc ExplosionGfxCounter,x   ;increment explosion graphics counter
10419            lda ExplosionGfxCounter,x
10420            cmp #$03                    ;check explosion graphics counter
10421            bcs FireworksSoundScore     ;if at a certain point, branch to kill this object
10422 SetupExpl: jsr RelativeEnemyPosition   ;get relative coordinates of explosion
10423            lda Enemy_Rel_YPos          ;copy relative coordinates
10424            sta Fireball_Rel_YPos       ;from the enemy object to the fireball object
10425            lda Enemy_Rel_XPos          ;first vertical, then horizontal
10426            sta Fireball_Rel_XPos
10427            ldy Enemy_SprDataOffset,x   ;get OAM data offset
10428            lda ExplosionGfxCounter,x   ;get explosion graphics counter
10429            jsr DrawExplosion_Fireworks ;do a sub to draw the explosion then leave
10430            rts
10431 
10432 FireworksSoundScore:
10433       lda #$00               ;disable enemy buffer flag
10434       sta Enemy_Flag,x
10435       lda #Sfx_Blast         ;play fireworks/gunfire sound
10436       sta Square2SoundQueue
10437       lda #$05               ;set part of score modifier for 500 points
10438       sta DigitModifier+4
10439       jmp EndAreaPoints     ;jump to award points accordingly then leave
10440 
10441 ;--------------------------------
10442 
10443 StarFlagYPosAdder:
10444       .db $00, $00, $08, $08
10445 
10446 StarFlagXPosAdder:
10447       .db $00, $08, $00, $08
10448 
10449 StarFlagTileData:
10450       .db $54, $55, $56, $57
10451 
10452 RunStarFlagObj:
10453       lda #$00                 ;initialize enemy frenzy buffer
10454       sta EnemyFrenzyBuffer
10455       lda StarFlagTaskControl  ;check star flag object task number here
10456       cmp #$05                 ;if greater than 5, branch to exit
10457       bcs StarFlagExit
10458       jsr JumpEngine           ;otherwise jump to appropriate sub
10459       
10460       .dw StarFlagExit
10461       .dw GameTimerFireworks
10462       .dw AwardGameTimerPoints
10463       .dw RaiseFlagSetoffFWorks
10464       .dw DelayToAreaEnd
10465 
10466 GameTimerFireworks:
10467         ldy #$05               ;set default state for star flag object
10468         lda GameTimerDisplay+2 ;get game timer's last digit
10469         cmp #$01
10470         beq SetFWC             ;if last digit of game timer set to 1, skip ahead
10471         ldy #$03               ;otherwise load new value for state
10472         cmp #$03
10473         beq SetFWC             ;if last digit of game timer set to 3, skip ahead
10474         ldy #$00               ;otherwise load one more potential value for state
10475         cmp #$06
10476         beq SetFWC             ;if last digit of game timer set to 6, skip ahead
10477         lda #$ff               ;otherwise set value for no fireworks
10478 SetFWC: sta FireworksCounter   ;set fireworks counter here
10479         sty Enemy_State,x      ;set whatever state we have in star flag object
10480 
10481 IncrementSFTask1:
10482       inc StarFlagTaskControl  ;increment star flag object task number
10483 
10484 StarFlagExit:
10485       rts                      ;leave
10486 
10487 AwardGameTimerPoints:
10488          lda GameTimerDisplay   ;check all game timer digits for any intervals left
10489          ora GameTimerDisplay+1
10490          ora GameTimerDisplay+2
10491          beq IncrementSFTask1   ;if no time left on game timer at all, branch to next task
10492          lda FrameCounter
10493          and #%00000100         ;check frame counter for d2 set (skip ahead
10494          beq NoTTick            ;for four frames every four frames) branch if not set
10495          lda #Sfx_TimerTick
10496          sta Square2SoundQueue  ;load timer tick sound
10497 NoTTick: ldy #$23               ;set offset here to subtract from game timer's last digit
10498          lda #$ff               ;set adder here to $ff, or -1, to subtract one
10499          sta DigitModifier+5    ;from the last digit of the game timer
10500          jsr DigitsMathRoutine  ;subtract digit
10501          lda #$05               ;set now to add 50 points
10502          sta DigitModifier+5    ;per game timer interval subtracted
10503 
10504 EndAreaPoints:
10505          ldy #$0b               ;load offset for mario's score by default
10506          lda CurrentPlayer      ;check player on the screen
10507          beq ELPGive            ;if mario, do not change
10508          ldy #$11               ;otherwise load offset for luigi's score
10509 ELPGive: jsr DigitsMathRoutine  ;award 50 points per game timer interval
10510          lda CurrentPlayer      ;get player on the screen (or 500 points per
10511          asl                    ;fireworks explosion if branched here from there)
10512          asl                    ;shift to high nybble
10513          asl
10514          asl
10515          ora #%00000100         ;add four to set nybble for game timer
10516          jmp UpdateNumber       ;jump to print the new score and game timer
10517 
10518 RaiseFlagSetoffFWorks:
10519          lda Enemy_Y_Position,x  ;check star flag's vertical position
10520          cmp #$72                ;against preset value
10521          bcc SetoffF             ;if star flag higher vertically, branch to other code
10522          dec Enemy_Y_Position,x  ;otherwise, raise star flag by one pixel
10523          jmp DrawStarFlag        ;and skip this part here
10524 SetoffF: lda FireworksCounter    ;check fireworks counter
10525          beq DrawFlagSetTimer    ;if no fireworks left to go off, skip this part
10526          bmi DrawFlagSetTimer    ;if no fireworks set to go off, skip this part
10527          lda #Fireworks
10528          sta EnemyFrenzyBuffer   ;otherwise set fireworks object in frenzy queue
10529 
10530 DrawStarFlag:
10531          jsr RelativeEnemyPosition  ;get relative coordinates of star flag
10532          ldy Enemy_SprDataOffset,x  ;get OAM data offset
10533          ldx #$03                   ;do four sprites
10534 DSFLoop: lda Enemy_Rel_YPos         ;get relative vertical coordinate
10535          clc
10536          adc StarFlagYPosAdder,x    ;add Y coordinate adder data
10537          sta Sprite_Y_Position,y    ;store as Y coordinate
10538          lda StarFlagTileData,x     ;get tile number
10539          sta Sprite_Tilenumber,y    ;store as tile number
10540          lda #$22                   ;set palette and background priority bits
10541          sta Sprite_Attributes,y    ;store as attributes
10542          lda Enemy_Rel_XPos         ;get relative horizontal coordinate
10543          clc
10544          adc StarFlagXPosAdder,x    ;add X coordinate adder data
10545          sta Sprite_X_Position,y    ;store as X coordinate
10546          iny
10547          iny                        ;increment OAM data offset four bytes
10548          iny                        ;for next sprite
10549          iny
10550          dex                        ;move onto next sprite
10551          bpl DSFLoop                ;do this until all sprites are done
10552          ldx ObjectOffset           ;get enemy object offset and leave
10553          rts
10554 
10555 DrawFlagSetTimer:
10556       jsr DrawStarFlag          ;do sub to draw star flag
10557       lda #$06
10558       sta EnemyIntervalTimer,x  ;set interval timer here
10559 
10560 IncrementSFTask2:
10561       inc StarFlagTaskControl   ;move onto next task
10562       rts
10563 
10564 DelayToAreaEnd:
10565       jsr DrawStarFlag          ;do sub to draw star flag
10566       lda EnemyIntervalTimer,x  ;if interval timer set in previous task
10567       bne StarFlagExit2         ;not yet expired, branch to leave
10568       lda EventMusicBuffer      ;if event music buffer empty,
10569       beq IncrementSFTask2      ;branch to increment task
10570 
10571 StarFlagExit2:
10572       rts                       ;otherwise leave
10573 
10574 ;--------------------------------
10575 ;$00 - used to store horizontal difference between player and piranha plant
10576 
10577 MovePiranhaPlant:
10578       lda Enemy_State,x           ;check enemy state
10579       bne PutinPipe               ;if set at all, branch to leave
10580       lda EnemyFrameTimer,x       ;check enemy's timer here
10581       bne PutinPipe               ;branch to end if not yet expired
10582       lda PiranhaPlant_MoveFlag,x ;check movement flag
10583       bne SetupToMovePPlant       ;if moving, skip to part ahead
10584       lda PiranhaPlant_Y_Speed,x  ;if currently rising, branch 
10585       bmi ReversePlantSpeed       ;to move enemy upwards out of pipe
10586       jsr PlayerEnemyDiff         ;get horizontal difference between player and
10587       bpl ChkPlayerNearPipe       ;piranha plant, and branch if enemy to right of player
10588       lda $00                     ;otherwise get saved horizontal difference
10589       eor #$ff
10590       clc                         ;and change to two's compliment
10591       adc #$01
10592       sta $00                     ;save as new horizontal difference
10593 
10594 ChkPlayerNearPipe:
10595       lda $00                     ;get saved horizontal difference
10596       cmp #$21
10597       bcc PutinPipe               ;if player within a certain distance, branch to leave
10598 
10599 ReversePlantSpeed:
10600       lda PiranhaPlant_Y_Speed,x  ;get vertical speed
10601       eor #$ff
10602       clc                         ;change to two's compliment
10603       adc #$01
10604       sta PiranhaPlant_Y_Speed,x  ;save as new vertical speed
10605       inc PiranhaPlant_MoveFlag,x ;increment to set movement flag
10606 
10607 SetupToMovePPlant:
10608       lda PiranhaPlantDownYPos,x  ;get original vertical coordinate (lowest point)
10609       ldy PiranhaPlant_Y_Speed,x  ;get vertical speed
10610       bpl RiseFallPiranhaPlant    ;branch if moving downwards
10611       lda PiranhaPlantUpYPos,x    ;otherwise get other vertical coordinate (highest point)
10612 
10613 RiseFallPiranhaPlant:
10614       sta $00                     ;save vertical coordinate here
10615       lda FrameCounter            ;get frame counter
10616       lsr
10617       bcc PutinPipe               ;branch to leave if d0 set (execute code every other frame)
10618       lda TimerControl            ;get master timer control
10619       bne PutinPipe               ;branch to leave if set (likely not necessary)
10620       lda Enemy_Y_Position,x      ;get current vertical coordinate
10621       clc
10622       adc PiranhaPlant_Y_Speed,x  ;add vertical speed to move up or down
10623       sta Enemy_Y_Position,x      ;save as new vertical coordinate
10624       cmp $00                     ;compare against low or high coordinate
10625       bne PutinPipe               ;branch to leave if not yet reached
10626       lda #$00
10627       sta PiranhaPlant_MoveFlag,x ;otherwise clear movement flag
10628       lda #$40
10629       sta EnemyFrameTimer,x       ;set timer to delay piranha plant movement
10630 
10631 PutinPipe:
10632       lda #%00100000              ;set background priority bit in sprite
10633       sta Enemy_SprAttrib,x       ;attributes to give illusion of being inside pipe
10634       rts                         ;then leave
10635 
10636 ;-------------------------------------------------------------------------------------
10637 ;$07 - spinning speed
10638 
10639 FirebarSpin:
10640       sta $07                     ;save spinning speed here
10641       lda FirebarSpinDirection,x  ;check spinning direction
10642       bne SpinCounterClockwise    ;if moving counter-clockwise, branch to other part
10643       ldy #$18                    ;possibly residual ldy
10644       lda FirebarSpinState_Low,x
10645       clc                         ;add spinning speed to what would normally be
10646       adc $07                     ;the horizontal speed
10647       sta FirebarSpinState_Low,x
10648       lda FirebarSpinState_High,x ;add carry to what would normally be the vertical speed
10649       adc #$00
10650       rts
10651 
10652 SpinCounterClockwise:
10653       ldy #$08                    ;possibly residual ldy
10654       lda FirebarSpinState_Low,x
10655       sec                         ;subtract spinning speed to what would normally be
10656       sbc $07                     ;the horizontal speed
10657       sta FirebarSpinState_Low,x
10658       lda FirebarSpinState_High,x ;add carry to what would normally be the vertical speed
10659       sbc #$00
10660       rts
10661 
10662 ;-------------------------------------------------------------------------------------
10663 ;$00 - used to hold collision flag, Y movement force + 5 or low byte of name table for rope
10664 ;$01 - used to hold high byte of name table for rope
10665 ;$02 - used to hold page location of rope
10666 
10667 BalancePlatform:
10668        lda Enemy_Y_HighPos,x       ;check high byte of vertical position
10669        cmp #$03
10670        bne DoBPl
10671        jmp EraseEnemyObject        ;if far below screen, kill the object
10672 DoBPl: lda Enemy_State,x           ;get object's state (set to $ff or other platform offset)
10673        bpl CheckBalPlatform        ;if doing other balance platform, branch to leave
10674        rts
10675 
10676 CheckBalPlatform:
10677        tay                         ;save offset from state as Y
10678        lda PlatformCollisionFlag,x ;get collision flag of platform
10679        sta $00                     ;store here
10680        lda Enemy_MovingDir,x       ;get moving direction
10681        beq ChkForFall
10682        jmp PlatformFall            ;if set, jump here
10683 
10684 ChkForFall:
10685        lda #$2d                    ;check if platform is above a certain point
10686        cmp Enemy_Y_Position,x
10687        bcc ChkOtherForFall         ;if not, branch elsewhere
10688        cpy $00                     ;if collision flag is set to same value as
10689        beq MakePlatformFall        ;enemy state, branch to make platforms fall
10690        clc
10691        adc #$02                    ;otherwise add 2 pixels to vertical position
10692        sta Enemy_Y_Position,x      ;of current platform and branch elsewhere
10693        jmp StopPlatforms           ;to make platforms stop
10694 
10695 MakePlatformFall:
10696        jmp InitPlatformFall        ;make platforms fall
10697 
10698 ChkOtherForFall:
10699        cmp Enemy_Y_Position,y      ;check if other platform is above a certain point
10700        bcc ChkToMoveBalPlat        ;if not, branch elsewhere
10701        cpx $00                     ;if collision flag is set to same value as
10702        beq MakePlatformFall        ;enemy state, branch to make platforms fall
10703        clc
10704        adc #$02                    ;otherwise add 2 pixels to vertical position
10705        sta Enemy_Y_Position,y      ;of other platform and branch elsewhere
10706        jmp StopPlatforms           ;jump to stop movement and do not return
10707 
10708 ChkToMoveBalPlat:
10709         lda Enemy_Y_Position,x      ;save vertical position to stack
10710         pha
10711         lda PlatformCollisionFlag,x ;get collision flag
10712         bpl ColFlg                  ;branch if collision
10713         lda Enemy_Y_MoveForce,x
10714         clc                         ;add $05 to contents of moveforce, whatever they be
10715         adc #$05
10716         sta $00                     ;store here
10717         lda Enemy_Y_Speed,x
10718         adc #$00                    ;add carry to vertical speed
10719         bmi PlatDn                  ;branch if moving downwards
10720         bne PlatUp                  ;branch elsewhere if moving upwards
10721         lda $00
10722         cmp #$0b                    ;check if there's still a little force left
10723         bcc PlatSt                  ;if not enough, branch to stop movement
10724         bcs PlatUp                  ;otherwise keep branch to move upwards
10725 ColFlg: cmp ObjectOffset            ;if collision flag matches
10726         beq PlatDn                  ;current enemy object offset, branch
10727 PlatUp: jsr MovePlatformUp          ;do a sub to move upwards
10728         jmp DoOtherPlatform         ;jump ahead to remaining code
10729 PlatSt: jsr StopPlatforms           ;do a sub to stop movement
10730         jmp DoOtherPlatform         ;jump ahead to remaining code
10731 PlatDn: jsr MovePlatformDown        ;do a sub to move downwards
10732 
10733 DoOtherPlatform:
10734        ldy Enemy_State,x           ;get offset of other platform
10735        pla                         ;get old vertical coordinate from stack
10736        sec
10737        sbc Enemy_Y_Position,x      ;get difference of old vs. new coordinate
10738        clc
10739        adc Enemy_Y_Position,y      ;add difference to vertical coordinate of other
10740        sta Enemy_Y_Position,y      ;platform to move it in the opposite direction
10741        lda PlatformCollisionFlag,x ;if no collision, skip this part here
10742        bmi DrawEraseRope
10743        tax                         ;put offset which collision occurred here
10744        jsr PositionPlayerOnVPlat   ;and use it to position player accordingly
10745 
10746 DrawEraseRope:
10747          ldy ObjectOffset            ;get enemy object offset
10748          lda Enemy_Y_Speed,y         ;check to see if current platform is
10749          ora Enemy_Y_MoveForce,y     ;moving at all
10750          beq ExitRp                  ;if not, skip all of this and branch to leave
10751          ldx VRAM_Buffer1_Offset     ;get vram buffer offset
10752          cpx #$20                    ;if offset beyond a certain point, go ahead
10753          bcs ExitRp                  ;and skip this, branch to leave
10754          lda Enemy_Y_Speed,y
10755          pha                         ;save two copies of vertical speed to stack
10756          pha
10757          jsr SetupPlatformRope       ;do a sub to figure out where to put new bg tiles
10758          lda $01                     ;write name table address to vram buffer
10759          sta VRAM_Buffer1,x          ;first the high byte, then the low
10760          lda $00
10761          sta VRAM_Buffer1+1,x
10762          lda #$02                    ;set length for 2 bytes
10763          sta VRAM_Buffer1+2,x
10764          lda Enemy_Y_Speed,y         ;if platform moving upwards, branch 
10765          bmi EraseR1                 ;to do something else
10766          lda #$a2
10767          sta VRAM_Buffer1+3,x        ;otherwise put tile numbers for left
10768          lda #$a3                    ;and right sides of rope in vram buffer
10769          sta VRAM_Buffer1+4,x
10770          jmp OtherRope               ;jump to skip this part
10771 EraseR1: lda #$24                    ;put blank tiles in vram buffer
10772          sta VRAM_Buffer1+3,x        ;to erase rope
10773          sta VRAM_Buffer1+4,x
10774 
10775 OtherRope:
10776          lda Enemy_State,y           ;get offset of other platform from state
10777          tay                         ;use as Y here
10778          pla                         ;pull second copy of vertical speed from stack
10779          eor #$ff                    ;invert bits to reverse speed
10780          jsr SetupPlatformRope       ;do sub again to figure out where to put bg tiles  
10781          lda $01                     ;write name table address to vram buffer
10782          sta VRAM_Buffer1+5,x        ;this time we're doing putting tiles for
10783          lda $00                     ;the other platform
10784          sta VRAM_Buffer1+6,x
10785          lda #$02
10786          sta VRAM_Buffer1+7,x        ;set length again for 2 bytes
10787          pla                         ;pull first copy of vertical speed from stack
10788          bpl EraseR2                 ;if moving upwards (note inversion earlier), skip this
10789          lda #$a2
10790          sta VRAM_Buffer1+8,x        ;otherwise put tile numbers for left
10791          lda #$a3                    ;and right sides of rope in vram
10792          sta VRAM_Buffer1+9,x        ;transfer buffer
10793          jmp EndRp                   ;jump to skip this part
10794 EraseR2: lda #$24                    ;put blank tiles in vram buffer
10795          sta VRAM_Buffer1+8,x        ;to erase rope
10796          sta VRAM_Buffer1+9,x
10797 EndRp:   lda #$00                    ;put null terminator at the end
10798          sta VRAM_Buffer1+10,x
10799          lda VRAM_Buffer1_Offset     ;add ten bytes to the vram buffer offset
10800          clc                         ;and store
10801          adc #10
10802          sta VRAM_Buffer1_Offset
10803 ExitRp:  ldx ObjectOffset            ;get enemy object buffer offset and leave
10804          rts
10805 
10806 SetupPlatformRope:
10807         pha                     ;save second/third copy to stack
10808         lda Enemy_X_Position,y  ;get horizontal coordinate
10809         clc
10810         adc #$08                ;add eight pixels
10811         ldx SecondaryHardMode   ;if secondary hard mode flag set,
10812         bne GetLRp              ;use coordinate as-is
10813         clc
10814         adc #$10                ;otherwise add sixteen more pixels
10815 GetLRp: pha                     ;save modified horizontal coordinate to stack
10816         lda Enemy_PageLoc,y
10817         adc #$00                ;add carry to page location
10818         sta $02                 ;and save here
10819         pla                     ;pull modified horizontal coordinate
10820         and #%11110000          ;from the stack, mask out low nybble
10821         lsr                     ;and shift three bits to the right
10822         lsr
10823         lsr
10824         sta $00                 ;store result here as part of name table low byte
10825         ldx Enemy_Y_Position,y  ;get vertical coordinate
10826         pla                     ;get second/third copy of vertical speed from stack
10827         bpl GetHRp              ;skip this part if moving downwards or not at all
10828         txa
10829         clc
10830         adc #$08                ;add eight to vertical coordinate and
10831         tax                     ;save as X
10832 GetHRp: txa                     ;move vertical coordinate to A
10833         ldx VRAM_Buffer1_Offset ;get vram buffer offset
10834         asl
10835         rol                     ;rotate d7 to d0 and d6 into carry
10836         pha                     ;save modified vertical coordinate to stack
10837         rol                     ;rotate carry to d0, thus d7 and d6 are at 2 LSB
10838         and #%00000011          ;mask out all bits but d7 and d6, then set
10839         ora #%00100000          ;d5 to get appropriate high byte of name table
10840         sta $01                 ;address, then store
10841         lda $02                 ;get saved page location from earlier
10842         and #$01                ;mask out all but LSB
10843         asl
10844         asl                     ;shift twice to the left and save with the
10845         ora $01                 ;rest of the bits of the high byte, to get
10846         sta $01                 ;the proper name table and the right place on it
10847         pla                     ;get modified vertical coordinate from stack
10848         and #%11100000          ;mask out low nybble and LSB of high nybble
10849         clc
10850         adc $00                 ;add to horizontal part saved here
10851         sta $00                 ;save as name table low byte
10852         lda Enemy_Y_Position,y
10853         cmp #$e8                ;if vertical position not below the
10854         bcc ExPRp               ;bottom of the screen, we're done, branch to leave
10855         lda $00
10856         and #%10111111          ;mask out d6 of low byte of name table address
10857         sta $00
10858 ExPRp:  rts                     ;leave!
10859 
10860 InitPlatformFall:
10861       tya                        ;move offset of other platform from Y to X
10862       tax
10863       jsr GetEnemyOffscreenBits  ;get offscreen bits
10864       lda #$06
10865       jsr SetupFloateyNumber     ;award 1000 points to player
10866       lda Player_Rel_XPos
10867       sta FloateyNum_X_Pos,x     ;put floatey number coordinates where player is
10868       lda Player_Y_Position
10869       sta FloateyNum_Y_Pos,x
10870       lda #$01                   ;set moving direction as flag for
10871       sta Enemy_MovingDir,x      ;falling platforms
10872 
10873 StopPlatforms:
10874       jsr InitVStf             ;initialize vertical speed and low byte
10875       sta Enemy_Y_Speed,y      ;for both platforms and leave
10876       sta Enemy_Y_MoveForce,y
10877       rts
10878 
10879 PlatformFall:
10880       tya                         ;save offset for other platform to stack
10881       pha
10882       jsr MoveFallingPlatform     ;make current platform fall
10883       pla
10884       tax                         ;pull offset from stack and save to X
10885       jsr MoveFallingPlatform     ;make other platform fall
10886       ldx ObjectOffset
10887       lda PlatformCollisionFlag,x ;if player not standing on either platform,
10888       bmi ExPF                    ;skip this part
10889       tax                         ;transfer collision flag offset as offset to X
10890       jsr PositionPlayerOnVPlat   ;and position player appropriately
10891 ExPF: ldx ObjectOffset            ;get enemy object buffer offset and leave
10892       rts
10893 
10894 ;--------------------------------
10895 
10896 YMovingPlatform:
10897         lda Enemy_Y_Speed,x          ;if platform moving up or down, skip ahead to
10898         ora Enemy_Y_MoveForce,x      ;check on other position
10899         bne ChkYCenterPos
10900         sta Enemy_YMF_Dummy,x        ;initialize dummy variable
10901         lda Enemy_Y_Position,x
10902         cmp YPlatformTopYPos,x       ;if current vertical position => top position, branch
10903         bcs ChkYCenterPos            ;ahead of all this
10904         lda FrameCounter
10905         and #%00000111               ;check for every eighth frame
10906         bne SkipIY
10907         inc Enemy_Y_Position,x       ;increase vertical position every eighth frame
10908 SkipIY: jmp ChkYPCollision           ;skip ahead to last part
10909 
10910 ChkYCenterPos:
10911         lda Enemy_Y_Position,x       ;if current vertical position < central position, branch
10912         cmp YPlatformCenterYPos,x    ;to slow ascent/move downwards
10913         bcc YMDown
10914         jsr MovePlatformUp           ;otherwise start slowing descent/moving upwards
10915         jmp ChkYPCollision
10916 YMDown: jsr MovePlatformDown         ;start slowing ascent/moving downwards
10917 
10918 ChkYPCollision:
10919        lda PlatformCollisionFlag,x  ;if collision flag not set here, branch
10920        bmi ExYPl                    ;to leave
10921        jsr PositionPlayerOnVPlat    ;otherwise position player appropriately
10922 ExYPl: rts                          ;leave
10923 
10924 ;--------------------------------
10925 ;$00 - used as adder to position player hotizontally
10926 
10927 XMovingPlatform:
10928       lda #$0e                     ;load preset maximum value for secondary counter
10929       jsr XMoveCntr_Platform       ;do a sub to increment counters for movement
10930       jsr MoveWithXMCntrs          ;do a sub to move platform accordingly, and return value
10931       lda PlatformCollisionFlag,x  ;if no collision with player,
10932       bmi ExXMP                    ;branch ahead to leave
10933 
10934 PositionPlayerOnHPlat:
10935          lda Player_X_Position
10936          clc                       ;add saved value from second subroutine to
10937          adc $00                   ;current player's position to position
10938          sta Player_X_Position     ;player accordingly in horizontal position
10939          lda Player_PageLoc        ;get player's page location
10940          ldy $00                   ;check to see if saved value here is positive or negative
10941          bmi PPHSubt               ;if negative, branch to subtract
10942          adc #$00                  ;otherwise add carry to page location
10943          jmp SetPVar               ;jump to skip subtraction
10944 PPHSubt: sbc #$00                  ;subtract borrow from page location
10945 SetPVar: sta Player_PageLoc        ;save result to player's page location
10946          sty Platform_X_Scroll     ;put saved value from second sub here to be used later
10947          jsr PositionPlayerOnVPlat ;position player vertically and appropriately
10948 ExXMP:   rts                       ;and we are done here
10949 
10950 ;--------------------------------
10951 
10952 DropPlatform:
10953        lda PlatformCollisionFlag,x  ;if no collision between platform and player
10954        bmi ExDPl                    ;occurred, just leave without moving anything
10955        jsr MoveDropPlatform         ;otherwise do a sub to move platform down very quickly
10956        jsr PositionPlayerOnVPlat    ;do a sub to position player appropriately
10957 ExDPl: rts                          ;leave
10958 
10959 ;--------------------------------
10960 ;$00 - residual value from sub
10961 
10962 RightPlatform:
10963        jsr MoveEnemyHorizontally     ;move platform with current horizontal speed, if any
10964        sta $00                       ;store saved value here (residual code)
10965        lda PlatformCollisionFlag,x   ;check collision flag, if no collision between player
10966        bmi ExRPl                     ;and platform, branch ahead, leave speed unaltered
10967        lda #$10
10968        sta Enemy_X_Speed,x           ;otherwise set new speed (gets moving if motionless)
10969        jsr PositionPlayerOnHPlat     ;use saved value from earlier sub to position player
10970 ExRPl: rts                           ;then leave
10971 
10972 ;--------------------------------
10973 
10974 MoveLargeLiftPlat:
10975       jsr MoveLiftPlatforms  ;execute common to all large and small lift platforms
10976       jmp ChkYPCollision     ;branch to position player correctly
10977 
10978 MoveSmallPlatform:
10979       jsr MoveLiftPlatforms      ;execute common to all large and small lift platforms
10980       jmp ChkSmallPlatCollision  ;branch to position player correctly
10981 
10982 MoveLiftPlatforms:
10983       lda TimerControl         ;if master timer control set, skip all of this
10984       bne ExLiftP              ;and branch to leave
10985       lda Enemy_YMF_Dummy,x
10986       clc                      ;add contents of movement amount to whatever's here
10987       adc Enemy_Y_MoveForce,x
10988       sta Enemy_YMF_Dummy,x
10989       lda Enemy_Y_Position,x   ;add whatever vertical speed is set to current
10990       adc Enemy_Y_Speed,x      ;vertical position plus carry to move up or down
10991       sta Enemy_Y_Position,x   ;and then leave
10992       rts
10993 
10994 ChkSmallPlatCollision:
10995          lda PlatformCollisionFlag,x ;get bounding box counter saved in collision flag
10996          beq ExLiftP                 ;if none found, leave player position alone
10997          jsr PositionPlayerOnS_Plat  ;use to position player correctly
10998 ExLiftP: rts                         ;then leave
10999 
11000 ;-------------------------------------------------------------------------------------
11001 ;$00 - page location of extended left boundary
11002 ;$01 - extended left boundary position
11003 ;$02 - page location of extended right boundary
11004 ;$03 - extended right boundary position
11005 
11006 OffscreenBoundsCheck:
11007           lda Enemy_ID,x          ;check for cheep-cheep object
11008           cmp #FlyingCheepCheep   ;branch to leave if found
11009           beq ExScrnBd
11010           lda ScreenLeft_X_Pos    ;get horizontal coordinate for left side of screen
11011           ldy Enemy_ID,x
11012           cpy #HammerBro          ;check for hammer bro object
11013           beq LimitB
11014           cpy #PiranhaPlant       ;check for piranha plant object
11015           bne ExtendLB            ;these two will be erased sooner than others if too far left
11016 LimitB:   adc #$38                ;add 56 pixels to coordinate if hammer bro or piranha plant
11017 ExtendLB: sbc #$48                ;subtract 72 pixels regardless of enemy object
11018           sta $01                 ;store result here
11019           lda ScreenLeft_PageLoc
11020           sbc #$00                ;subtract borrow from page location of left side
11021           sta $00                 ;store result here
11022           lda ScreenRight_X_Pos   ;add 72 pixels to the right side horizontal coordinate
11023           adc #$48
11024           sta $03                 ;store result here
11025           lda ScreenRight_PageLoc     
11026           adc #$00                ;then add the carry to the page location
11027           sta $02                 ;and store result here
11028           lda Enemy_X_Position,x  ;compare horizontal coordinate of the enemy object
11029           cmp $01                 ;to modified horizontal left edge coordinate to get carry
11030           lda Enemy_PageLoc,x
11031           sbc $00                 ;then subtract it from the page coordinate of the enemy object
11032           bmi TooFar              ;if enemy object is too far left, branch to erase it
11033           lda Enemy_X_Position,x  ;compare horizontal coordinate of the enemy object
11034           cmp $03                 ;to modified horizontal right edge coordinate to get carry
11035           lda Enemy_PageLoc,x
11036           sbc $02                 ;then subtract it from the page coordinate of the enemy object
11037           bmi ExScrnBd            ;if enemy object is on the screen, leave, do not erase enemy
11038           lda Enemy_State,x       ;if at this point, enemy is offscreen to the right, so check
11039           cmp #HammerBro          ;if in state used by spiny's egg, do not erase
11040           beq ExScrnBd
11041           cpy #PiranhaPlant       ;if piranha plant, do not erase
11042           beq ExScrnBd
11043           cpy #FlagpoleFlagObject ;if flagpole flag, do not erase
11044           beq ExScrnBd
11045           cpy #StarFlagObject     ;if star flag, do not erase
11046           beq ExScrnBd
11047           cpy #JumpspringObject   ;if jumpspring, do not erase
11048           beq ExScrnBd            ;erase all others too far to the right
11049 TooFar:   jsr EraseEnemyObject    ;erase object if necessary
11050 ExScrnBd: rts                     ;leave
11051 
11052 ;-------------------------------------------------------------------------------------
11053 
11054 ;some unused space
11055       .db $ff, $ff, $ff
11056 
11057 ;-------------------------------------------------------------------------------------
11058 ;$01 - enemy buffer offset
11059 
11060 FireballEnemyCollision:
11061       lda Fireball_State,x  ;check to see if fireball state is set at all
11062       beq ExitFBallEnemy    ;branch to leave if not
11063       asl
11064       bcs ExitFBallEnemy    ;branch to leave also if d7 in state is set
11065       lda FrameCounter
11066       lsr                   ;get LSB of frame counter
11067       bcs ExitFBallEnemy    ;branch to leave if set (do routine every other frame)
11068       txa
11069       asl                   ;multiply fireball offset by four
11070       asl
11071       clc
11072       adc #$1c              ;then add $1c or 28 bytes to it
11073       tay                   ;to use fireball's bounding box coordinates 
11074       ldx #$04
11075 
11076 FireballEnemyCDLoop:
11077            stx $01                     ;store enemy object offset here
11078            tya
11079            pha                         ;push fireball offset to the stack
11080            lda Enemy_State,x
11081            and #%00100000              ;check to see if d5 is set in enemy state
11082            bne NoFToECol               ;if so, skip to next enemy slot
11083            lda Enemy_Flag,x            ;check to see if buffer flag is set
11084            beq NoFToECol               ;if not, skip to next enemy slot
11085            lda Enemy_ID,x              ;check enemy identifier
11086            cmp #$24
11087            bcc GoombaDie               ;if < $24, branch to check further
11088            cmp #$2b
11089            bcc NoFToECol               ;if in range $24-$2a, skip to next enemy slot
11090 GoombaDie: cmp #Goomba                 ;check for goomba identifier
11091            bne NotGoomba               ;if not found, continue with code
11092            lda Enemy_State,x           ;otherwise check for defeated state
11093            cmp #$02                    ;if stomped or otherwise defeated,
11094            bcs NoFToECol               ;skip to next enemy slot
11095 NotGoomba: lda EnemyOffscrBitsMasked,x ;if any masked offscreen bits set,
11096            bne NoFToECol               ;skip to next enemy slot
11097            txa
11098            asl                         ;otherwise multiply enemy offset by four
11099            asl
11100            clc
11101            adc #$04                    ;add 4 bytes to it
11102            tax                         ;to use enemy's bounding box coordinates
11103            jsr SprObjectCollisionCore  ;do fireball-to-enemy collision detection
11104            ldx ObjectOffset            ;return fireball's original offset
11105            bcc NoFToECol               ;if carry clear, no collision, thus do next enemy slot
11106            lda #%10000000
11107            sta Fireball_State,x        ;set d7 in enemy state
11108            ldx $01                     ;get enemy offset
11109            jsr HandleEnemyFBallCol     ;jump to handle fireball to enemy collision
11110 NoFToECol: pla                         ;pull fireball offset from stack
11111            tay                         ;put it in Y
11112            ldx $01                     ;get enemy object offset
11113            dex                         ;decrement it
11114            bpl FireballEnemyCDLoop     ;loop back until collision detection done on all enemies
11115 
11116 ExitFBallEnemy:
11117       ldx ObjectOffset                 ;get original fireball offset and leave
11118       rts
11119 
11120 BowserIdentities:
11121       .db Goomba, GreenKoopa, BuzzyBeetle, Spiny, Lakitu, Bloober, HammerBro, Bowser
11122 
11123 HandleEnemyFBallCol:
11124       jsr RelativeEnemyPosition  ;get relative coordinate of enemy
11125       ldx $01                    ;get current enemy object offset
11126       lda Enemy_Flag,x           ;check buffer flag for d7 set
11127       bpl ChkBuzzyBeetle         ;branch if not set to continue
11128       and #%00001111             ;otherwise mask out high nybble and
11129       tax                        ;use low nybble as enemy offset
11130       lda Enemy_ID,x
11131       cmp #Bowser                ;check enemy identifier for bowser
11132       beq HurtBowser             ;branch if found
11133       ldx $01                    ;otherwise retrieve current enemy offset
11134 
11135 ChkBuzzyBeetle:
11136       lda Enemy_ID,x
11137       cmp #BuzzyBeetle           ;check for buzzy beetle
11138       beq ExHCF                  ;branch if found to leave (buzzy beetles fireproof)
11139       cmp #Bowser                ;check for bowser one more time (necessary if d7 of flag was clear)
11140       bne ChkOtherEnemies        ;if not found, branch to check other enemies
11141 
11142 HurtBowser:
11143           dec BowserHitPoints        ;decrement bowser's hit points
11144           bne ExHCF                  ;if bowser still has hit points, branch to leave
11145           jsr InitVStf               ;otherwise do sub to init vertical speed and movement force
11146           sta Enemy_X_Speed,x        ;initialize horizontal speed
11147           sta EnemyFrenzyBuffer      ;init enemy frenzy buffer
11148           lda #$fe
11149           sta Enemy_Y_Speed,x        ;set vertical speed to make defeated bowser jump a little
11150           ldy WorldNumber            ;use world number as offset
11151           lda BowserIdentities,y     ;get enemy identifier to replace bowser with
11152           sta Enemy_ID,x             ;set as new enemy identifier
11153           lda #$20                   ;set A to use starting value for state
11154           cpy #$03                   ;check to see if using offset of 3 or more
11155           bcs SetDBSte               ;branch if so
11156           ora #$03                   ;otherwise add 3 to enemy state
11157 SetDBSte: sta Enemy_State,x          ;set defeated enemy state
11158           lda #Sfx_BowserFall
11159           sta Square2SoundQueue      ;load bowser defeat sound
11160           ldx $01                    ;get enemy offset
11161           lda #$09                   ;award 5000 points to player for defeating bowser
11162           bne EnemySmackScore        ;unconditional branch to award points
11163 
11164 ChkOtherEnemies:
11165       cmp #BulletBill_FrenzyVar
11166       beq ExHCF                 ;branch to leave if bullet bill (frenzy variant) 
11167       cmp #Podoboo       
11168       beq ExHCF                 ;branch to leave if podoboo
11169       cmp #$15       
11170       bcs ExHCF                 ;branch to leave if identifier => $15
11171 
11172 ShellOrBlockDefeat:
11173       lda Enemy_ID,x            ;check for piranha plant
11174       cmp #PiranhaPlant
11175       bne StnE                  ;branch if not found
11176       lda Enemy_Y_Position,x
11177       adc #$18                  ;add 24 pixels to enemy object's vertical position
11178       sta Enemy_Y_Position,x
11179 StnE: jsr ChkToStunEnemies      ;do yet another sub
11180       lda Enemy_State,x
11181       and #%00011111            ;mask out 2 MSB of enemy object's state
11182       ora #%00100000            ;set d5 to defeat enemy and save as new state
11183       sta Enemy_State,x
11184       lda #$02                  ;award 200 points by default
11185       ldy Enemy_ID,x            ;check for hammer bro
11186       cpy #HammerBro
11187       bne GoombaPoints          ;branch if not found
11188       lda #$06                  ;award 1000 points for hammer bro
11189 
11190 GoombaPoints:
11191       cpy #Goomba               ;check for goomba
11192       bne EnemySmackScore       ;branch if not found
11193       lda #$01                  ;award 100 points for goomba
11194 
11195 EnemySmackScore:
11196        jsr SetupFloateyNumber   ;update necessary score variables
11197        lda #Sfx_EnemySmack      ;play smack enemy sound
11198        sta Square1SoundQueue
11199 ExHCF: rts                      ;and now let's leave
11200 
11201 ;-------------------------------------------------------------------------------------
11202 
11203 PlayerHammerCollision:
11204         lda FrameCounter          ;get frame counter
11205         lsr                       ;shift d0 into carry
11206         bcc ExPHC                 ;branch to leave if d0 not set to execute every other frame
11207         lda TimerControl          ;if either master timer control
11208         ora Misc_OffscreenBits    ;or any offscreen bits for hammer are set,
11209         bne ExPHC                 ;branch to leave
11210         txa
11211         asl                       ;multiply misc object offset by four
11212         asl
11213         clc
11214         adc #$24                  ;add 36 or $24 bytes to get proper offset
11215         tay                       ;for misc object bounding box coordinates
11216         jsr PlayerCollisionCore   ;do player-to-hammer collision detection
11217         ldx ObjectOffset          ;get misc object offset
11218         bcc ClHCol                ;if no collision, then branch
11219         lda Misc_Collision_Flag,x ;otherwise read collision flag
11220         bne ExPHC                 ;if collision flag already set, branch to leave
11221         lda #$01
11222         sta Misc_Collision_Flag,x ;otherwise set collision flag now
11223         lda Misc_X_Speed,x
11224         eor #$ff                  ;get two's compliment of
11225         clc                       ;hammer's horizontal speed
11226         adc #$01
11227         sta Misc_X_Speed,x        ;set to send hammer flying the opposite direction
11228         lda StarInvincibleTimer   ;if star mario invincibility timer set,
11229         bne ExPHC                 ;branch to leave
11230         jmp InjurePlayer          ;otherwise jump to hurt player, do not return
11231 ClHCol: lda #$00                  ;clear collision flag
11232         sta Misc_Collision_Flag,x
11233 ExPHC:  rts
11234 
11235 ;-------------------------------------------------------------------------------------
11236 
11237 HandlePowerUpCollision:
11238       jsr EraseEnemyObject    ;erase the power-up object
11239       lda #$06
11240       jsr SetupFloateyNumber  ;award 1000 points to player by default
11241       lda #Sfx_PowerUpGrab
11242       sta Square2SoundQueue   ;play the power-up sound
11243       lda PowerUpType         ;check power-up type
11244       cmp #$02
11245       bcc Shroom_Flower_PUp   ;if mushroom or fire flower, branch
11246       cmp #$03
11247       beq SetFor1Up           ;if 1-up mushroom, branch
11248       lda #$23                ;otherwise set star mario invincibility
11249       sta StarInvincibleTimer ;timer, and load the star mario music
11250       lda #StarPowerMusic     ;into the area music queue, then leave
11251       sta AreaMusicQueue
11252       rts
11253 
11254 Shroom_Flower_PUp:
11255       lda PlayerStatus    ;if player status = small, branch
11256       beq UpToSuper
11257       cmp #$01            ;if player status not super, leave
11258       bne NoPUp
11259       ldx ObjectOffset    ;get enemy offset, not necessary
11260       lda #$02            ;set player status to fiery
11261       sta PlayerStatus
11262       jsr GetPlayerColors ;run sub to change colors of player
11263       ldx ObjectOffset    ;get enemy offset again, and again not necessary
11264       lda #$0c            ;set value to be used by subroutine tree (fiery)
11265       jmp UpToFiery       ;jump to set values accordingly
11266 
11267 SetFor1Up:
11268       lda #$0b                 ;change 1000 points into 1-up instead
11269       sta FloateyNum_Control,x ;and then leave
11270       rts
11271 
11272 UpToSuper:
11273        lda #$01         ;set player status to super
11274        sta PlayerStatus
11275        lda #$09         ;set value to be used by subroutine tree (super)
11276 
11277 UpToFiery:
11278        ldy #$00         ;set value to be used as new player state
11279        jsr SetPRout     ;set values to stop certain things in motion
11280 NoPUp: rts
11281 
11282 ;--------------------------------
11283 
11284 ResidualXSpdData:
11285       .db $18, $e8
11286 
11287 KickedShellXSpdData:
11288       .db $30, $d0
11289 
11290 DemotedKoopaXSpdData:
11291       .db $08, $f8
11292 
11293 PlayerEnemyCollision:
11294          lda FrameCounter            ;check counter for d0 set
11295          lsr
11296          bcs NoPUp                   ;if set, branch to leave
11297          jsr CheckPlayerVertical     ;if player object is completely offscreen or
11298          bcs NoPECol                 ;if down past 224th pixel row, branch to leave
11299          lda EnemyOffscrBitsMasked,x ;if current enemy is offscreen by any amount,
11300          bne NoPECol                 ;go ahead and branch to leave
11301          lda GameEngineSubroutine
11302          cmp #$08                    ;if not set to run player control routine
11303          bne NoPECol                 ;on next frame, branch to leave
11304          lda Enemy_State,x
11305          and #%00100000              ;if enemy state has d5 set, branch to leave
11306          bne NoPECol
11307          jsr GetEnemyBoundBoxOfs     ;get bounding box offset for current enemy object
11308          jsr PlayerCollisionCore     ;do collision detection on player vs. enemy
11309          ldx ObjectOffset            ;get enemy object buffer offset
11310          bcs CheckForPUpCollision    ;if collision, branch past this part here
11311          lda Enemy_CollisionBits,x
11312          and #%11111110              ;otherwise, clear d0 of current enemy object's
11313          sta Enemy_CollisionBits,x   ;collision bit
11314 NoPECol: rts
11315 
11316 CheckForPUpCollision:
11317        ldy Enemy_ID,x
11318        cpy #PowerUpObject            ;check for power-up object
11319        bne EColl                     ;if not found, branch to next part
11320        jmp HandlePowerUpCollision    ;otherwise, unconditional jump backwards
11321 EColl: lda StarInvincibleTimer       ;if star mario invincibility timer expired,
11322        beq HandlePECollisions        ;perform task here, otherwise kill enemy like
11323        jmp ShellOrBlockDefeat        ;hit with a shell, or from beneath
11324 
11325 KickedShellPtsData:
11326       .db $0a, $06, $04
11327 
11328 HandlePECollisions:
11329        lda Enemy_CollisionBits,x    ;check enemy collision bits for d0 set
11330        and #%00000001               ;or for being offscreen at all
11331        ora EnemyOffscrBitsMasked,x
11332        bne ExPEC                    ;branch to leave if either is true
11333        lda #$01
11334        ora Enemy_CollisionBits,x    ;otherwise set d0 now
11335        sta Enemy_CollisionBits,x
11336        cpy #Spiny                   ;branch if spiny
11337        beq ChkForPlayerInjury
11338        cpy #PiranhaPlant            ;branch if piranha plant
11339        beq InjurePlayer
11340        cpy #Podoboo                 ;branch if podoboo
11341        beq InjurePlayer
11342        cpy #BulletBill_CannonVar    ;branch if bullet bill
11343        beq ChkForPlayerInjury
11344        cpy #$15                     ;branch if object => $15
11345        bcs InjurePlayer
11346        lda AreaType                 ;branch if water type level
11347        beq InjurePlayer
11348        lda Enemy_State,x            ;branch if d7 of enemy state was set
11349        asl
11350        bcs ChkForPlayerInjury
11351        lda Enemy_State,x            ;mask out all but 3 LSB of enemy state
11352        and #%00000111
11353        cmp #$02                     ;branch if enemy is in normal or falling state
11354        bcc ChkForPlayerInjury
11355        lda Enemy_ID,x               ;branch to leave if goomba in defeated state
11356        cmp #Goomba
11357        beq ExPEC
11358        lda #Sfx_EnemySmack          ;play smack enemy sound
11359        sta Square1SoundQueue
11360        lda Enemy_State,x            ;set d7 in enemy state, thus become moving shell
11361        ora #%10000000
11362        sta Enemy_State,x
11363        jsr EnemyFacePlayer          ;set moving direction and get offset
11364        lda KickedShellXSpdData,y    ;load and set horizontal speed data with offset
11365        sta Enemy_X_Speed,x
11366        lda #$03                     ;add three to whatever the stomp counter contains
11367        clc                          ;to give points for kicking the shell
11368        adc StompChainCounter
11369        ldy EnemyIntervalTimer,x     ;check shell enemy's timer
11370        cpy #$03                     ;if above a certain point, branch using the points
11371        bcs KSPts                    ;data obtained from the stomp counter + 3
11372        lda KickedShellPtsData,y     ;otherwise, set points based on proximity to timer expiration
11373 KSPts: jsr SetupFloateyNumber       ;set values for floatey number now
11374 ExPEC: rts                          ;leave!!!
11375 
11376 ChkForPlayerInjury:
11377           lda Player_Y_Speed     ;check player's vertical speed
11378           bmi ChkInj             ;perform procedure below if player moving upwards
11379           bne EnemyStomped       ;or not at all, and branch elsewhere if moving downwards
11380 ChkInj:   lda Enemy_ID,x         ;branch if enemy object < $07
11381           cmp #Bloober
11382           bcc ChkETmrs
11383           lda Player_Y_Position  ;add 12 pixels to player's vertical position
11384           clc
11385           adc #$0c
11386           cmp Enemy_Y_Position,x ;compare modified player's position to enemy's position
11387           bcc EnemyStomped       ;branch if this player's position above (less than) enemy's
11388 ChkETmrs: lda StompTimer         ;check stomp timer
11389           bne EnemyStomped       ;branch if set
11390           lda InjuryTimer        ;check to see if injured invincibility timer still
11391           bne ExInjColRoutines   ;counting down, and branch elsewhere to leave if so
11392           lda Player_Rel_XPos
11393           cmp Enemy_Rel_XPos     ;if player's relative position to the left of enemy's
11394           bcc TInjE              ;relative position, branch here
11395           jmp ChkEnemyFaceRight  ;otherwise do a jump here
11396 TInjE:    lda Enemy_MovingDir,x  ;if enemy moving towards the left,
11397           cmp #$01               ;branch, otherwise do a jump here
11398           bne InjurePlayer       ;to turn the enemy around
11399           jmp LInj
11400 
11401 InjurePlayer:
11402       lda InjuryTimer          ;check again to see if injured invincibility timer is
11403       bne ExInjColRoutines     ;at zero, and branch to leave if so
11404 
11405 ForceInjury:
11406           ldx PlayerStatus          ;check player's status
11407           beq KillPlayer            ;branch if small
11408           sta PlayerStatus          ;otherwise set player's status to small
11409           lda #$08
11410           sta InjuryTimer           ;set injured invincibility timer
11411           asl
11412           sta Square1SoundQueue     ;play pipedown/injury sound
11413           jsr GetPlayerColors       ;change player's palette if necessary
11414           lda #$0a                  ;set subroutine to run on next frame
11415 SetKRout: ldy #$01                  ;set new player state
11416 SetPRout: sta GameEngineSubroutine  ;load new value to run subroutine on next frame
11417           sty Player_State          ;store new player state
11418           ldy #$ff
11419           sty TimerControl          ;set master timer control flag to halt timers
11420           iny
11421           sty ScrollAmount          ;initialize scroll speed
11422 
11423 ExInjColRoutines:
11424       ldx ObjectOffset              ;get enemy offset and leave
11425       rts
11426 
11427 KillPlayer:
11428       stx Player_X_Speed   ;halt player's horizontal movement by initializing speed
11429       inx
11430       stx EventMusicQueue  ;set event music queue to death music
11431       lda #$fc
11432       sta Player_Y_Speed   ;set new vertical speed
11433       lda #$0b             ;set subroutine to run on next frame
11434       bne SetKRout         ;branch to set player's state and other things
11435 
11436 StompedEnemyPtsData:
11437       .db $02, $06, $05, $06
11438 
11439 EnemyStomped:
11440       lda Enemy_ID,x             ;check for spiny, branch to hurt player
11441       cmp #Spiny                 ;if found
11442       beq InjurePlayer
11443       lda #Sfx_EnemyStomp        ;otherwise play stomp/swim sound
11444       sta Square1SoundQueue
11445       lda Enemy_ID,x
11446       ldy #$00                   ;initialize points data offset for stomped enemies
11447       cmp #FlyingCheepCheep      ;branch for cheep-cheep
11448       beq EnemyStompedPts
11449       cmp #BulletBill_FrenzyVar  ;branch for either bullet bill object
11450       beq EnemyStompedPts
11451       cmp #BulletBill_CannonVar
11452       beq EnemyStompedPts
11453       cmp #Podoboo               ;branch for podoboo (this branch is logically impossible
11454       beq EnemyStompedPts        ;for cpu to take due to earlier checking of podoboo)
11455       iny                        ;increment points data offset
11456       cmp #HammerBro             ;branch for hammer bro
11457       beq EnemyStompedPts
11458       iny                        ;increment points data offset
11459       cmp #Lakitu                ;branch for lakitu
11460       beq EnemyStompedPts
11461       iny                        ;increment points data offset
11462       cmp #Bloober               ;branch if NOT bloober
11463       bne ChkForDemoteKoopa
11464 
11465 EnemyStompedPts:
11466       lda StompedEnemyPtsData,y  ;load points data using offset in Y
11467       jsr SetupFloateyNumber     ;run sub to set floatey number controls
11468       lda Enemy_MovingDir,x
11469       pha                        ;save enemy movement direction to stack
11470       jsr SetStun                ;run sub to kill enemy
11471       pla
11472       sta Enemy_MovingDir,x      ;return enemy movement direction from stack
11473       lda #%00100000
11474       sta Enemy_State,x          ;set d5 in enemy state
11475       jsr InitVStf               ;nullify vertical speed, physics-related thing,
11476       sta Enemy_X_Speed,x        ;and horizontal speed
11477       lda #$fd                   ;set player's vertical speed, to give bounce
11478       sta Player_Y_Speed
11479       rts
11480 
11481 ChkForDemoteKoopa:
11482       cmp #$09                   ;branch elsewhere if enemy object < $09
11483       bcc HandleStompedShellE
11484       and #%00000001             ;demote koopa paratroopas to ordinary troopas
11485       sta Enemy_ID,x
11486       ldy #$00                   ;return enemy to normal state
11487       sty Enemy_State,x
11488       lda #$03                   ;award 400 points to the player
11489       jsr SetupFloateyNumber
11490       jsr InitVStf               ;nullify physics-related thing and vertical speed
11491       jsr EnemyFacePlayer        ;turn enemy around if necessary
11492       lda DemotedKoopaXSpdData,y
11493       sta Enemy_X_Speed,x        ;set appropriate moving speed based on direction
11494       jmp SBnce                  ;then move onto something else
11495 
11496 RevivalRateData:
11497       .db $10, $0b
11498 
11499 HandleStompedShellE:
11500        lda #$04                   ;set defeated state for enemy
11501        sta Enemy_State,x
11502        inc StompChainCounter      ;increment the stomp counter
11503        lda StompChainCounter      ;add whatever is in the stomp counter
11504        clc                        ;to whatever is in the stomp timer
11505        adc StompTimer
11506        jsr SetupFloateyNumber     ;award points accordingly
11507        inc StompTimer             ;increment stomp timer of some sort
11508        ldy PrimaryHardMode        ;check primary hard mode flag
11509        lda RevivalRateData,y      ;load timer setting according to flag
11510        sta EnemyIntervalTimer,x   ;set as enemy timer to revive stomped enemy
11511 SBnce: lda #$fc                   ;set player's vertical speed for bounce
11512        sta Player_Y_Speed         ;and then leave!!!
11513        rts
11514 
11515 ChkEnemyFaceRight:
11516        lda Enemy_MovingDir,x ;check to see if enemy is moving to the right
11517        cmp #$01
11518        bne LInj              ;if not, branch
11519        jmp InjurePlayer      ;otherwise go back to hurt player
11520 LInj:  jsr EnemyTurnAround   ;turn the enemy around, if necessary
11521        jmp InjurePlayer      ;go back to hurt player
11522 
11523 
11524 EnemyFacePlayer:
11525        ldy #$01               ;set to move right by default
11526        jsr PlayerEnemyDiff    ;get horizontal difference between player and enemy
11527        bpl SFcRt              ;if enemy is to the right of player, do not increment
11528        iny                    ;otherwise, increment to set to move to the left
11529 SFcRt: sty Enemy_MovingDir,x  ;set moving direction here
11530        dey                    ;then decrement to use as a proper offset
11531        rts
11532 
11533 SetupFloateyNumber:
11534        sta FloateyNum_Control,x ;set number of points control for floatey numbers
11535        lda #$30
11536        sta FloateyNum_Timer,x   ;set timer for floatey numbers
11537        lda Enemy_Y_Position,x
11538        sta FloateyNum_Y_Pos,x   ;set vertical coordinate
11539        lda Enemy_Rel_XPos
11540        sta FloateyNum_X_Pos,x   ;set horizontal coordinate and leave
11541 ExSFN: rts
11542 
11543 ;-------------------------------------------------------------------------------------
11544 ;$01 - used to hold enemy offset for second enemy
11545 
11546 SetBitsMask:
11547       .db %10000000, %01000000, %00100000, %00010000, %00001000, %00000100, %00000010
11548 
11549 ClearBitsMask:
11550       .db %01111111, %10111111, %11011111, %11101111, %11110111, %11111011, %11111101
11551 
11552 EnemiesCollision:
11553         lda FrameCounter            ;check counter for d0 set
11554         lsr
11555         bcc ExSFN                   ;if d0 not set, leave
11556         lda AreaType
11557         beq ExSFN                   ;if water area type, leave
11558         lda Enemy_ID,x
11559         cmp #$15                    ;if enemy object => $15, branch to leave
11560         bcs ExitECRoutine
11561         cmp #Lakitu                 ;if lakitu, branch to leave
11562         beq ExitECRoutine
11563         cmp #PiranhaPlant           ;if piranha plant, branch to leave
11564         beq ExitECRoutine
11565         lda EnemyOffscrBitsMasked,x ;if masked offscreen bits nonzero, branch to leave
11566         bne ExitECRoutine
11567         jsr GetEnemyBoundBoxOfs     ;otherwise, do sub, get appropriate bounding box offset for
11568         dex                         ;first enemy we're going to compare, then decrement for second
11569         bmi ExitECRoutine           ;branch to leave if there are no other enemies
11570 ECLoop: stx $01                     ;save enemy object buffer offset for second enemy here
11571         tya                         ;save first enemy's bounding box offset to stack
11572         pha
11573         lda Enemy_Flag,x            ;check enemy object enable flag
11574         beq ReadyNextEnemy          ;branch if flag not set
11575         lda Enemy_ID,x
11576         cmp #$15                    ;check for enemy object => $15
11577         bcs ReadyNextEnemy          ;branch if true
11578         cmp #Lakitu
11579         beq ReadyNextEnemy          ;branch if enemy object is lakitu
11580         cmp #PiranhaPlant
11581         beq ReadyNextEnemy          ;branch if enemy object is piranha plant
11582         lda EnemyOffscrBitsMasked,x
11583         bne ReadyNextEnemy          ;branch if masked offscreen bits set
11584         txa                         ;get second enemy object's bounding box offset
11585         asl                         ;multiply by four, then add four
11586         asl
11587         clc
11588         adc #$04
11589         tax                         ;use as new contents of X
11590         jsr SprObjectCollisionCore  ;do collision detection using the two enemies here
11591         ldx ObjectOffset            ;use first enemy offset for X
11592         ldy $01                     ;use second enemy offset for Y
11593         bcc NoEnemyCollision        ;if carry clear, no collision, branch ahead of this
11594         lda Enemy_State,x
11595         ora Enemy_State,y           ;check both enemy states for d7 set
11596         and #%10000000
11597         bne YesEC                   ;branch if at least one of them is set
11598         lda Enemy_CollisionBits,y   ;load first enemy's collision-related bits
11599         and SetBitsMask,x           ;check to see if bit connected to second enemy is
11600         bne ReadyNextEnemy          ;already set, and move onto next enemy slot if set
11601         lda Enemy_CollisionBits,y
11602         ora SetBitsMask,x           ;if the bit is not set, set it now
11603         sta Enemy_CollisionBits,y
11604 YesEC:  jsr ProcEnemyCollisions     ;react according to the nature of collision
11605         jmp ReadyNextEnemy          ;move onto next enemy slot
11606 
11607 NoEnemyCollision:
11608       lda Enemy_CollisionBits,y     ;load first enemy's collision-related bits
11609       and ClearBitsMask,x           ;clear bit connected to second enemy
11610       sta Enemy_CollisionBits,y     ;then move onto next enemy slot
11611 
11612 ReadyNextEnemy:
11613       pla              ;get first enemy's bounding box offset from the stack
11614       tay              ;use as Y again
11615       ldx $01          ;get and decrement second enemy's object buffer offset
11616       dex
11617       bpl ECLoop       ;loop until all enemy slots have been checked
11618 
11619 ExitECRoutine:
11620       ldx ObjectOffset ;get enemy object buffer offset
11621       rts              ;leave
11622 
11623 ProcEnemyCollisions:
11624       lda Enemy_State,y        ;check both enemy states for d5 set
11625       ora Enemy_State,x
11626       and #%00100000           ;if d5 is set in either state, or both, branch
11627       bne ExitProcessEColl     ;to leave and do nothing else at this point
11628       lda Enemy_State,x
11629       cmp #$06                 ;if second enemy state < $06, branch elsewhere
11630       bcc ProcSecondEnemyColl
11631       lda Enemy_ID,x           ;check second enemy identifier for hammer bro
11632       cmp #HammerBro           ;if hammer bro found in alt state, branch to leave
11633       beq ExitProcessEColl
11634       lda Enemy_State,y        ;check first enemy state for d7 set
11635       asl
11636       bcc ShellCollisions      ;branch if d7 is clear
11637       lda #$06
11638       jsr SetupFloateyNumber   ;award 1000 points for killing enemy
11639       jsr ShellOrBlockDefeat   ;then kill enemy, then load
11640       ldy $01                  ;original offset of second enemy
11641 
11642 ShellCollisions:
11643       tya                      ;move Y to X
11644       tax
11645       jsr ShellOrBlockDefeat   ;kill second enemy
11646       ldx ObjectOffset
11647       lda ShellChainCounter,x  ;get chain counter for shell
11648       clc
11649       adc #$04                 ;add four to get appropriate point offset
11650       ldx $01
11651       jsr SetupFloateyNumber   ;award appropriate number of points for second enemy
11652       ldx ObjectOffset         ;load original offset of first enemy
11653       inc ShellChainCounter,x  ;increment chain counter for additional enemies
11654 
11655 ExitProcessEColl:
11656       rts                      ;leave!!!
11657 
11658 ProcSecondEnemyColl:
11659       lda Enemy_State,y        ;if first enemy state < $06, branch elsewhere
11660       cmp #$06
11661       bcc MoveEOfs
11662       lda Enemy_ID,y           ;check first enemy identifier for hammer bro
11663       cmp #HammerBro           ;if hammer bro found in alt state, branch to leave
11664       beq ExitProcessEColl
11665       jsr ShellOrBlockDefeat   ;otherwise, kill first enemy
11666       ldy $01
11667       lda ShellChainCounter,y  ;get chain counter for shell
11668       clc
11669       adc #$04                 ;add four to get appropriate point offset
11670       ldx ObjectOffset
11671       jsr SetupFloateyNumber   ;award appropriate number of points for first enemy
11672       ldx $01                  ;load original offset of second enemy
11673       inc ShellChainCounter,x  ;increment chain counter for additional enemies
11674       rts                      ;leave!!!
11675 
11676 MoveEOfs:
11677       tya                      ;move Y ($01) to X
11678       tax
11679       jsr EnemyTurnAround      ;do the sub here using value from $01
11680       ldx ObjectOffset         ;then do it again using value from $08
11681 
11682 EnemyTurnAround:
11683        lda Enemy_ID,x           ;check for specific enemies
11684        cmp #PiranhaPlant
11685        beq ExTA                 ;if piranha plant, leave
11686        cmp #Lakitu
11687        beq ExTA                 ;if lakitu, leave
11688        cmp #HammerBro
11689        beq ExTA                 ;if hammer bro, leave
11690        cmp #Spiny
11691        beq RXSpd                ;if spiny, turn it around
11692        cmp #GreenParatroopaJump
11693        beq RXSpd                ;if green paratroopa, turn it around
11694        cmp #$07
11695        bcs ExTA                 ;if any OTHER enemy object => $07, leave
11696 RXSpd: lda Enemy_X_Speed,x      ;load horizontal speed
11697        eor #$ff                 ;get two's compliment for horizontal speed
11698        tay
11699        iny
11700        sty Enemy_X_Speed,x      ;store as new horizontal speed
11701        lda Enemy_MovingDir,x
11702        eor #%00000011           ;invert moving direction and store, then leave
11703        sta Enemy_MovingDir,x    ;thus effectively turning the enemy around
11704 ExTA:  rts                      ;leave!!!
11705 
11706 ;-------------------------------------------------------------------------------------
11707 ;$00 - vertical position of platform
11708 
11709 LargePlatformCollision:
11710        lda #$ff                     ;save value here
11711        sta PlatformCollisionFlag,x
11712        lda TimerControl             ;check master timer control
11713        bne ExLPC                    ;if set, branch to leave
11714        lda Enemy_State,x            ;if d7 set in object state,
11715        bmi ExLPC                    ;branch to leave
11716        lda Enemy_ID,x
11717        cmp #$24                     ;check enemy object identifier for
11718        bne ChkForPlayerC_LargeP     ;balance platform, branch if not found
11719        lda Enemy_State,x
11720        tax                          ;set state as enemy offset here
11721        jsr ChkForPlayerC_LargeP     ;perform code with state offset, then original offset, in X
11722 
11723 ChkForPlayerC_LargeP:
11724        jsr CheckPlayerVertical      ;figure out if player is below a certain point
11725        bcs ExLPC                    ;or offscreen, branch to leave if true
11726        txa
11727        jsr GetEnemyBoundBoxOfsArg   ;get bounding box offset in Y
11728        lda Enemy_Y_Position,x       ;store vertical coordinate in
11729        sta $00                      ;temp variable for now
11730        txa                          ;send offset we're on to the stack
11731        pha
11732        jsr PlayerCollisionCore      ;do player-to-platform collision detection
11733        pla                          ;retrieve offset from the stack
11734        tax
11735        bcc ExLPC                    ;if no collision, branch to leave
11736        jsr ProcLPlatCollisions      ;otherwise collision, perform sub
11737 ExLPC: ldx ObjectOffset             ;get enemy object buffer offset and leave
11738        rts
11739 
11740 ;--------------------------------
11741 ;$00 - counter for bounding boxes
11742 
11743 SmallPlatformCollision:
11744       lda TimerControl             ;if master timer control set,
11745       bne ExSPC                    ;branch to leave
11746       sta PlatformCollisionFlag,x  ;otherwise initialize collision flag
11747       jsr CheckPlayerVertical      ;do a sub to see if player is below a certain point
11748       bcs ExSPC                    ;or entirely offscreen, and branch to leave if true
11749       lda #$02
11750       sta $00                      ;load counter here for 2 bounding boxes
11751 
11752 ChkSmallPlatLoop:
11753       ldx ObjectOffset           ;get enemy object offset
11754       jsr GetEnemyBoundBoxOfs    ;get bounding box offset in Y
11755       and #%00000010             ;if d1 of offscreen lower nybble bits was set
11756       bne ExSPC                  ;then branch to leave
11757       lda BoundingBox_UL_YPos,y  ;check top of platform's bounding box for being
11758       cmp #$20                   ;above a specific point
11759       bcc MoveBoundBox           ;if so, branch, don't do collision detection
11760       jsr PlayerCollisionCore    ;otherwise, perform player-to-platform collision detection
11761       bcs ProcSPlatCollisions    ;skip ahead if collision
11762 
11763 MoveBoundBox:
11764        lda BoundingBox_UL_YPos,y  ;move bounding box vertical coordinates
11765        clc                        ;128 pixels downwards
11766        adc #$80
11767        sta BoundingBox_UL_YPos,y
11768        lda BoundingBox_DR_YPos,y
11769        clc
11770        adc #$80
11771        sta BoundingBox_DR_YPos,y
11772        dec $00                    ;decrement counter we set earlier
11773        bne ChkSmallPlatLoop       ;loop back until both bounding boxes are checked
11774 ExSPC: ldx ObjectOffset           ;get enemy object buffer offset, then leave
11775        rts
11776 
11777 ;--------------------------------
11778 
11779 ProcSPlatCollisions:
11780       ldx ObjectOffset             ;return enemy object buffer offset to X, then continue
11781 
11782 ProcLPlatCollisions:
11783       lda BoundingBox_DR_YPos,y    ;get difference by subtracting the top
11784       sec                          ;of the player's bounding box from the bottom
11785       sbc BoundingBox_UL_YPos      ;of the platform's bounding box
11786       cmp #$04                     ;if difference too large or negative,
11787       bcs ChkForTopCollision       ;branch, do not alter vertical speed of player
11788       lda Player_Y_Speed           ;check to see if player's vertical speed is moving down
11789       bpl ChkForTopCollision       ;if so, don't mess with it
11790       lda #$01                     ;otherwise, set vertical
11791       sta Player_Y_Speed           ;speed of player to kill jump
11792 
11793 ChkForTopCollision:
11794       lda BoundingBox_DR_YPos      ;get difference by subtracting the top
11795       sec                          ;of the platform's bounding box from the bottom
11796       sbc BoundingBox_UL_YPos,y    ;of the player's bounding box
11797       cmp #$06
11798       bcs PlatformSideCollisions   ;if difference not close enough, skip all of this
11799       lda Player_Y_Speed
11800       bmi PlatformSideCollisions   ;if player's vertical speed moving upwards, skip this
11801       lda $00                      ;get saved bounding box counter from earlier
11802       ldy Enemy_ID,x
11803       cpy #$2b                     ;if either of the two small platform objects are found,
11804       beq SetCollisionFlag         ;regardless of which one, branch to use bounding box counter
11805       cpy #$2c                     ;as contents of collision flag
11806       beq SetCollisionFlag
11807       txa                          ;otherwise use enemy object buffer offset
11808 
11809 SetCollisionFlag:
11810       ldx ObjectOffset             ;get enemy object buffer offset
11811       sta PlatformCollisionFlag,x  ;save either bounding box counter or enemy offset here
11812       lda #$00
11813       sta Player_State             ;set player state to normal then leave
11814       rts
11815 
11816 PlatformSideCollisions:
11817          lda #$01                   ;set value here to indicate possible horizontal
11818          sta $00                    ;collision on left side of platform
11819          lda BoundingBox_DR_XPos    ;get difference by subtracting platform's left edge
11820          sec                        ;from player's right edge
11821          sbc BoundingBox_UL_XPos,y
11822          cmp #$08                   ;if difference close enough, skip all of this
11823          bcc SideC
11824          inc $00                    ;otherwise increment value set here for right side collision
11825          lda BoundingBox_DR_XPos,y  ;get difference by subtracting player's left edge
11826          clc                        ;from platform's right edge
11827          sbc BoundingBox_UL_XPos
11828          cmp #$09                   ;if difference not close enough, skip subroutine
11829          bcs NoSideC                ;and instead branch to leave (no collision)
11830 SideC:   jsr ImpedePlayerMove       ;deal with horizontal collision
11831 NoSideC: ldx ObjectOffset           ;return with enemy object buffer offset
11832          rts
11833 
11834 ;-------------------------------------------------------------------------------------
11835 
11836 PlayerPosSPlatData:
11837       .db $80, $00
11838 
11839 PositionPlayerOnS_Plat:
11840       tay                        ;use bounding box counter saved in collision flag
11841       lda Enemy_Y_Position,x     ;for offset
11842       clc                        ;add positioning data using offset to the vertical
11843       adc PlayerPosSPlatData-1,y ;coordinate
11844       .db $2c                    ;BIT instruction opcode
11845 
11846 PositionPlayerOnVPlat:
11847          lda Enemy_Y_Position,x    ;get vertical coordinate
11848          ldy GameEngineSubroutine
11849          cpy #$0b                  ;if certain routine being executed on this frame,
11850          beq ExPlPos               ;skip all of this
11851          ldy Enemy_Y_HighPos,x
11852          cpy #$01                  ;if vertical high byte offscreen, skip this
11853          bne ExPlPos
11854          sec                       ;subtract 32 pixels from vertical coordinate
11855          sbc #$20                  ;for the player object's height
11856          sta Player_Y_Position     ;save as player's new vertical coordinate
11857          tya
11858          sbc #$00                  ;subtract borrow and store as player's
11859          sta Player_Y_HighPos      ;new vertical high byte
11860          lda #$00
11861          sta Player_Y_Speed        ;initialize vertical speed and low byte of force
11862          sta Player_Y_MoveForce    ;and then leave
11863 ExPlPos: rts
11864 
11865 ;-------------------------------------------------------------------------------------
11866 
11867 CheckPlayerVertical:
11868        lda Player_OffscreenBits  ;if player object is completely offscreen
11869        cmp #$f0                  ;vertically, leave this routine
11870        bcs ExCPV
11871        ldy Player_Y_HighPos      ;if player high vertical byte is not
11872        dey                       ;within the screen, leave this routine
11873        bne ExCPV
11874        lda Player_Y_Position     ;if on the screen, check to see how far down
11875        cmp #$d0                  ;the player is vertically
11876 ExCPV: rts
11877 
11878 ;-------------------------------------------------------------------------------------
11879 
11880 GetEnemyBoundBoxOfs:
11881       lda ObjectOffset         ;get enemy object buffer offset
11882 
11883 GetEnemyBoundBoxOfsArg:
11884       asl                      ;multiply A by four, then add four
11885       asl                      ;to skip player's bounding box
11886       clc
11887       adc #$04
11888       tay                      ;send to Y
11889       lda Enemy_OffscreenBits  ;get offscreen bits for enemy object
11890       and #%00001111           ;save low nybble
11891       cmp #%00001111           ;check for all bits set
11892       rts
11893 
11894 ;-------------------------------------------------------------------------------------
11895 ;$00-$01 - used to hold many values, essentially temp variables
11896 ;$04 - holds lower nybble of vertical coordinate from block buffer routine
11897 ;$eb - used to hold block buffer adder
11898 
11899 PlayerBGUpperExtent:
11900       .db $20, $10
11901 
11902 PlayerBGCollision:
11903           lda DisableCollisionDet   ;if collision detection disabled flag set,
11904           bne ExPBGCol              ;branch to leave
11905           lda GameEngineSubroutine
11906           cmp #$0b                  ;if running routine #11 or $0b
11907           beq ExPBGCol              ;branch to leave
11908           cmp #$04
11909           bcc ExPBGCol              ;if running routines $00-$03 branch to leave
11910           lda #$01                  ;load default player state for swimming
11911           ldy SwimmingFlag          ;if swimming flag set,
11912           bne SetPSte               ;branch ahead to set default state
11913           lda Player_State          ;if player in normal state,
11914           beq SetFallS              ;branch to set default state for falling
11915           cmp #$03
11916           bne ChkOnScr              ;if in any other state besides climbing, skip to next part
11917 SetFallS: lda #$02                  ;load default player state for falling
11918 SetPSte:  sta Player_State          ;set whatever player state is appropriate
11919 ChkOnScr: lda Player_Y_HighPos
11920           cmp #$01                  ;check player's vertical high byte for still on the screen
11921           bne ExPBGCol              ;branch to leave if not
11922           lda #$ff
11923           sta Player_CollisionBits  ;initialize player's collision flag
11924           lda Player_Y_Position
11925           cmp #$cf                  ;check player's vertical coordinate
11926           bcc ChkCollSize           ;if not too close to the bottom of screen, continue
11927 ExPBGCol: rts                       ;otherwise leave
11928 
11929 ChkCollSize:
11930          ldy #$02                    ;load default offset
11931          lda CrouchingFlag
11932          bne GBBAdr                  ;if player crouching, skip ahead
11933          lda PlayerSize
11934          bne GBBAdr                  ;if player small, skip ahead
11935          dey                         ;otherwise decrement offset for big player not crouching
11936          lda SwimmingFlag
11937          bne GBBAdr                  ;if swimming flag set, skip ahead
11938          dey                         ;otherwise decrement offset
11939 GBBAdr:  lda BlockBufferAdderData,y  ;get value using offset
11940          sta $eb                     ;store value here
11941          tay                         ;put value into Y, as offset for block buffer routine
11942          ldx PlayerSize              ;get player's size as offset
11943          lda CrouchingFlag
11944          beq HeadChk                 ;if player not crouching, branch ahead
11945          inx                         ;otherwise increment size as offset
11946 HeadChk: lda Player_Y_Position       ;get player's vertical coordinate
11947          cmp PlayerBGUpperExtent,x   ;compare with upper extent value based on offset
11948          bcc DoFootCheck             ;if player is too high, skip this part
11949          jsr BlockBufferColli_Head   ;do player-to-bg collision detection on top of
11950          beq DoFootCheck             ;player, and branch if nothing above player's head
11951          jsr CheckForCoinMTiles      ;check to see if player touched coin with their head
11952          bcs AwardTouchedCoin        ;if so, branch to some other part of code
11953          ldy Player_Y_Speed          ;check player's vertical speed
11954          bpl DoFootCheck             ;if player not moving upwards, branch elsewhere
11955          ldy $04                     ;check lower nybble of vertical coordinate returned
11956          cpy #$04                    ;from collision detection routine
11957          bcc DoFootCheck             ;if low nybble < 4, branch
11958          jsr CheckForSolidMTiles     ;check to see what player's head bumped on
11959          bcs SolidOrClimb            ;if player collided with solid metatile, branch
11960          ldy AreaType                ;otherwise check area type
11961          beq NYSpd                   ;if water level, branch ahead
11962          ldy BlockBounceTimer        ;if block bounce timer not expired,
11963          bne NYSpd                   ;branch ahead, do not process collision
11964          jsr PlayerHeadCollision     ;otherwise do a sub to process collision
11965          jmp DoFootCheck             ;jump ahead to skip these other parts here
11966 
11967 SolidOrClimb:
11968        cmp #$26               ;if climbing metatile,
11969        beq NYSpd              ;branch ahead and do not play sound
11970        lda #Sfx_Bump
11971        sta Square1SoundQueue  ;otherwise load bump sound
11972 NYSpd: lda #$01               ;set player's vertical speed to nullify
11973        sta Player_Y_Speed     ;jump or swim
11974 
11975 DoFootCheck:
11976       ldy $eb                    ;get block buffer adder offset
11977       lda Player_Y_Position
11978       cmp #$cf                   ;check to see how low player is
11979       bcs DoPlayerSideCheck      ;if player is too far down on screen, skip all of this
11980       jsr BlockBufferColli_Feet  ;do player-to-bg collision detection on bottom left of player
11981       jsr CheckForCoinMTiles     ;check to see if player touched coin with their left foot
11982       bcs AwardTouchedCoin       ;if so, branch to some other part of code
11983       pha                        ;save bottom left metatile to stack
11984       jsr BlockBufferColli_Feet  ;do player-to-bg collision detection on bottom right of player
11985       sta $00                    ;save bottom right metatile here
11986       pla
11987       sta $01                    ;pull bottom left metatile and save here
11988       bne ChkFootMTile           ;if anything here, skip this part
11989       lda $00                    ;otherwise check for anything in bottom right metatile
11990       beq DoPlayerSideCheck      ;and skip ahead if not
11991       jsr CheckForCoinMTiles     ;check to see if player touched coin with their right foot
11992       bcc ChkFootMTile           ;if not, skip unconditional jump and continue code
11993 
11994 AwardTouchedCoin:
11995       jmp HandleCoinMetatile     ;follow the code to erase coin and award to player 1 coin
11996 
11997 ChkFootMTile:
11998           jsr CheckForClimbMTiles    ;check to see if player landed on climbable metatiles
11999           bcs DoPlayerSideCheck      ;if so, branch
12000           ldy Player_Y_Speed         ;check player's vertical speed
12001           bmi DoPlayerSideCheck      ;if player moving upwards, branch
12002           cmp #$c5
12003           bne ContChk                ;if player did not touch axe, skip ahead
12004           jmp HandleAxeMetatile      ;otherwise jump to set modes of operation
12005 ContChk:  jsr ChkInvisibleMTiles     ;do sub to check for hidden coin or 1-up blocks
12006           beq DoPlayerSideCheck      ;if either found, branch
12007           ldy JumpspringAnimCtrl     ;if jumpspring animating right now,
12008           bne InitSteP               ;branch ahead
12009           ldy $04                    ;check lower nybble of vertical coordinate returned
12010           cpy #$05                   ;from collision detection routine
12011           bcc LandPlyr               ;if lower nybble < 5, branch
12012           lda Player_MovingDir
12013           sta $00                    ;use player's moving direction as temp variable
12014           jmp ImpedePlayerMove       ;jump to impede player's movement in that direction
12015 LandPlyr: jsr ChkForLandJumpSpring   ;do sub to check for jumpspring metatiles and deal with it
12016           lda #$f0
12017           and Player_Y_Position      ;mask out lower nybble of player's vertical position
12018           sta Player_Y_Position      ;and store as new vertical position to land player properly
12019           jsr HandlePipeEntry        ;do sub to process potential pipe entry
12020           lda #$00
12021           sta Player_Y_Speed         ;initialize vertical speed and fractional
12022           sta Player_Y_MoveForce     ;movement force to stop player's vertical movement
12023           sta StompChainCounter      ;initialize enemy stomp counter
12024 InitSteP: lda #$00
12025           sta Player_State           ;set player's state to normal
12026 
12027 DoPlayerSideCheck:
12028       ldy $eb       ;get block buffer adder offset
12029       iny
12030       iny           ;increment offset 2 bytes to use adders for side collisions
12031       lda #$02      ;set value here to be used as counter
12032       sta $00
12033 
12034 SideCheckLoop:
12035        iny                       ;move onto the next one
12036        sty $eb                   ;store it
12037        lda Player_Y_Position
12038        cmp #$20                  ;check player's vertical position
12039        bcc BHalf                 ;if player is in status bar area, branch ahead to skip this part
12040        cmp #$e4
12041        bcs ExSCH                 ;branch to leave if player is too far down
12042        jsr BlockBufferColli_Side ;do player-to-bg collision detection on one half of player
12043        beq BHalf                 ;branch ahead if nothing found
12044        cmp #$1c                  ;otherwise check for pipe metatiles
12045        beq BHalf                 ;if collided with sideways pipe (top), branch ahead
12046        cmp #$6b
12047        beq BHalf                 ;if collided with water pipe (top), branch ahead
12048        jsr CheckForClimbMTiles   ;do sub to see if player bumped into anything climbable
12049        bcc CheckSideMTiles       ;if not, branch to alternate section of code
12050 BHalf: ldy $eb                   ;load block adder offset
12051        iny                       ;increment it
12052        lda Player_Y_Position     ;get player's vertical position
12053        cmp #$08
12054        bcc ExSCH                 ;if too high, branch to leave
12055        cmp #$d0
12056        bcs ExSCH                 ;if too low, branch to leave
12057        jsr BlockBufferColli_Side ;do player-to-bg collision detection on other half of player
12058        bne CheckSideMTiles       ;if something found, branch
12059        dec $00                   ;otherwise decrement counter
12060        bne SideCheckLoop         ;run code until both sides of player are checked
12061 ExSCH: rts                       ;leave
12062 
12063 CheckSideMTiles:
12064           jsr ChkInvisibleMTiles     ;check for hidden or coin 1-up blocks
12065           beq ExCSM                  ;branch to leave if either found
12066           jsr CheckForClimbMTiles    ;check for climbable metatiles
12067           bcc ContSChk               ;if not found, skip and continue with code
12068           jmp HandleClimbing         ;otherwise jump to handle climbing
12069 ContSChk: jsr CheckForCoinMTiles     ;check to see if player touched coin
12070           bcs HandleCoinMetatile     ;if so, execute code to erase coin and award to player 1 coin
12071           jsr ChkJumpspringMetatiles ;check for jumpspring metatiles
12072           bcc ChkPBtm                ;if not found, branch ahead to continue cude
12073           lda JumpspringAnimCtrl     ;otherwise check jumpspring animation control
12074           bne ExCSM                  ;branch to leave if set
12075           jmp StopPlayerMove         ;otherwise jump to impede player's movement
12076 ChkPBtm:  ldy Player_State           ;get player's state
12077           cpy #$00                   ;check for player's state set to normal
12078           bne StopPlayerMove         ;if not, branch to impede player's movement
12079           ldy PlayerFacingDir        ;get player's facing direction
12080           dey
12081           bne StopPlayerMove         ;if facing left, branch to impede movement
12082           cmp #$6c                   ;otherwise check for pipe metatiles
12083           beq PipeDwnS               ;if collided with sideways pipe (bottom), branch
12084           cmp #$1f                   ;if collided with water pipe (bottom), continue
12085           bne StopPlayerMove         ;otherwise branch to impede player's movement
12086 PipeDwnS: lda Player_SprAttrib       ;check player's attributes
12087           bne PlyrPipe               ;if already set, branch, do not play sound again
12088           ldy #Sfx_PipeDown_Injury
12089           sty Square1SoundQueue      ;otherwise load pipedown/injury sound
12090 PlyrPipe: ora #%00100000
12091           sta Player_SprAttrib       ;set background priority bit in player attributes
12092           lda Player_X_Position
12093           and #%00001111             ;get lower nybble of player's horizontal coordinate
12094           beq ChkGERtn               ;if at zero, branch ahead to skip this part
12095           ldy #$00                   ;set default offset for timer setting data
12096           lda ScreenLeft_PageLoc     ;load page location for left side of screen
12097           beq SetCATmr               ;if at page zero, use default offset
12098           iny                        ;otherwise increment offset
12099 SetCATmr: lda AreaChangeTimerData,y  ;set timer for change of area as appropriate
12100           sta ChangeAreaTimer
12101 ChkGERtn: lda GameEngineSubroutine   ;get number of game engine routine running
12102           cmp #$07
12103           beq ExCSM                  ;if running player entrance routine or
12104           cmp #$08                   ;player control routine, go ahead and branch to leave
12105           bne ExCSM
12106           lda #$02
12107           sta GameEngineSubroutine   ;otherwise set sideways pipe entry routine to run
12108           rts                        ;and leave
12109 
12110 ;--------------------------------
12111 ;$02 - high nybble of vertical coordinate from block buffer
12112 ;$04 - low nybble of horizontal coordinate from block buffer
12113 ;$06-$07 - block buffer address
12114 
12115 StopPlayerMove:
12116        jsr ImpedePlayerMove      ;stop player's movement
12117 ExCSM: rts                       ;leave
12118       
12119 AreaChangeTimerData:
12120       .db $a0, $34
12121 
12122 HandleCoinMetatile:
12123       jsr ErACM             ;do sub to erase coin metatile from block buffer
12124       inc CoinTallyFor1Ups  ;increment coin tally used for 1-up blocks
12125       jmp GiveOneCoin       ;update coin amount and tally on the screen
12126 
12127 HandleAxeMetatile:
12128        lda #$00
12129        sta OperMode_Task   ;reset secondary mode
12130        lda #$02
12131        sta OperMode        ;set primary mode to autoctrl mode
12132        lda #$18
12133        sta Player_X_Speed  ;set horizontal speed and continue to erase axe metatile
12134 ErACM: ldy $02             ;load vertical high nybble offset for block buffer
12135        lda #$00            ;load blank metatile
12136        sta ($06),y         ;store to remove old contents from block buffer
12137        jmp RemoveCoin_Axe  ;update the screen accordingly
12138 
12139 ;--------------------------------
12140 ;$02 - high nybble of vertical coordinate from block buffer
12141 ;$04 - low nybble of horizontal coordinate from block buffer
12142 ;$06-$07 - block buffer address
12143 
12144 ClimbXPosAdder:
12145       .db $f9, $07
12146 
12147 ClimbPLocAdder:
12148       .db $ff, $00
12149 
12150 FlagpoleYPosData:
12151       .db $18, $22, $50, $68, $90
12152 
12153 HandleClimbing:
12154       ldy $04            ;check low nybble of horizontal coordinate returned from
12155       cpy #$06           ;collision detection routine against certain values, this
12156       bcc ExHC           ;makes actual physical part of vine or flagpole thinner
12157       cpy #$0a           ;than 16 pixels
12158       bcc ChkForFlagpole
12159 ExHC: rts                ;leave if too far left or too far right
12160 
12161 ChkForFlagpole:
12162       cmp #$24               ;check climbing metatiles
12163       beq FlagpoleCollision  ;branch if flagpole ball found
12164       cmp #$25
12165       bne VineCollision      ;branch to alternate code if flagpole shaft not found
12166 
12167 FlagpoleCollision:
12168       lda GameEngineSubroutine
12169       cmp #$05                  ;check for end-of-level routine running
12170       beq PutPlayerOnVine       ;if running, branch to end of climbing code
12171       lda #$01
12172       sta PlayerFacingDir       ;set player's facing direction to right
12173       inc ScrollLock            ;set scroll lock flag
12174       lda GameEngineSubroutine
12175       cmp #$04                  ;check for flagpole slide routine running
12176       beq RunFR                 ;if running, branch to end of flagpole code here
12177       lda #BulletBill_CannonVar ;load identifier for bullet bills (cannon variant)
12178       jsr KillEnemies           ;get rid of them
12179       lda #Silence
12180       sta EventMusicQueue       ;silence music
12181       lsr
12182       sta FlagpoleSoundQueue    ;load flagpole sound into flagpole sound queue
12183       ldx #$04                  ;start at end of vertical coordinate data
12184       lda Player_Y_Position
12185       sta FlagpoleCollisionYPos ;store player's vertical coordinate here to be used later
12186 
12187 ChkFlagpoleYPosLoop:
12188        cmp FlagpoleYPosData,x    ;compare with current vertical coordinate data
12189        bcs MtchF                 ;if player's => current, branch to use current offset
12190        dex                       ;otherwise decrement offset to use 
12191        bne ChkFlagpoleYPosLoop   ;do this until all data is checked (use last one if all checked)
12192 MtchF: stx FlagpoleScore         ;store offset here to be used later
12193 RunFR: lda #$04
12194        sta GameEngineSubroutine  ;set value to run flagpole slide routine
12195        jmp PutPlayerOnVine       ;jump to end of climbing code
12196 
12197 VineCollision:
12198       cmp #$26                  ;check for climbing metatile used on vines
12199       bne PutPlayerOnVine
12200       lda Player_Y_Position     ;check player's vertical coordinate
12201       cmp #$20                  ;for being in status bar area
12202       bcs PutPlayerOnVine       ;branch if not that far up
12203       lda #$01
12204       sta GameEngineSubroutine  ;otherwise set to run autoclimb routine next frame
12205 
12206 PutPlayerOnVine:
12207          lda #$03                ;set player state to climbing
12208          sta Player_State
12209          lda #$00                ;nullify player's horizontal speed
12210          sta Player_X_Speed      ;and fractional horizontal movement force
12211          sta Player_X_MoveForce
12212          lda Player_X_Position   ;get player's horizontal coordinate
12213          sec
12214          sbc ScreenLeft_X_Pos    ;subtract from left side horizontal coordinate
12215          cmp #$10
12216          bcs SetVXPl             ;if 16 or more pixels difference, do not alter facing direction
12217          lda #$02
12218          sta PlayerFacingDir     ;otherwise force player to face left
12219 SetVXPl: ldy PlayerFacingDir     ;get current facing direction, use as offset
12220          lda $06                 ;get low byte of block buffer address
12221          asl
12222          asl                     ;move low nybble to high
12223          asl
12224          asl
12225          clc
12226          adc ClimbXPosAdder-1,y  ;add pixels depending on facing direction
12227          sta Player_X_Position   ;store as player's horizontal coordinate
12228          lda $06                 ;get low byte of block buffer address again
12229          bne ExPVne              ;if not zero, branch
12230          lda ScreenRight_PageLoc ;load page location of right side of screen
12231          clc
12232          adc ClimbPLocAdder-1,y  ;add depending on facing location
12233          sta Player_PageLoc      ;store as player's page location
12234 ExPVne:  rts                     ;finally, we're done!
12235 
12236 ;--------------------------------
12237 
12238 ChkInvisibleMTiles:
12239          cmp #$5f       ;check for hidden coin block
12240          beq ExCInvT    ;branch to leave if found
12241          cmp #$60       ;check for hidden 1-up block
12242 ExCInvT: rts            ;leave with zero flag set if either found
12243 
12244 ;--------------------------------
12245 ;$00-$01 - used to hold bottom right and bottom left metatiles (in that order)
12246 ;$00 - used as flag by ImpedePlayerMove to restrict specific movement
12247 
12248 ChkForLandJumpSpring:
12249         jsr ChkJumpspringMetatiles  ;do sub to check if player landed on jumpspring
12250         bcc ExCJSp                  ;if carry not set, jumpspring not found, therefore leave
12251         lda #$70
12252         sta VerticalForce           ;otherwise set vertical movement force for player
12253         lda #$f9
12254         sta JumpspringForce         ;set default jumpspring force
12255         lda #$03
12256         sta JumpspringTimer         ;set jumpspring timer to be used later
12257         lsr
12258         sta JumpspringAnimCtrl      ;set jumpspring animation control to start animating
12259 ExCJSp: rts                         ;and leave
12260 
12261 ChkJumpspringMetatiles:
12262          cmp #$67      ;check for top jumpspring metatile
12263          beq JSFnd     ;branch to set carry if found
12264          cmp #$68      ;check for bottom jumpspring metatile
12265          clc           ;clear carry flag
12266          bne NoJSFnd   ;branch to use cleared carry if not found
12267 JSFnd:   sec           ;set carry if found
12268 NoJSFnd: rts           ;leave
12269 
12270 HandlePipeEntry:
12271          lda Up_Down_Buttons       ;check saved controller bits from earlier
12272          and #%00000100            ;for pressing down
12273          beq ExPipeE               ;if not pressing down, branch to leave
12274          lda $00
12275          cmp #$11                  ;check right foot metatile for warp pipe right metatile
12276          bne ExPipeE               ;branch to leave if not found
12277          lda $01
12278          cmp #$10                  ;check left foot metatile for warp pipe left metatile
12279          bne ExPipeE               ;branch to leave if not found
12280          lda #$30
12281          sta ChangeAreaTimer       ;set timer for change of area
12282          lda #$03
12283          sta GameEngineSubroutine  ;set to run vertical pipe entry routine on next frame
12284          lda #Sfx_PipeDown_Injury
12285          sta Square1SoundQueue     ;load pipedown/injury sound
12286          lda #%00100000
12287          sta Player_SprAttrib      ;set background priority bit in player's attributes
12288          lda WarpZoneControl       ;check warp zone control
12289          beq ExPipeE               ;branch to leave if none found
12290          and #%00000011            ;mask out all but 2 LSB
12291          asl
12292          asl                       ;multiply by four
12293          tax                       ;save as offset to warp zone numbers (starts at left pipe)
12294          lda Player_X_Position     ;get player's horizontal position
12295          cmp #$60      
12296          bcc GetWNum               ;if player at left, not near middle, use offset and skip ahead
12297          inx                       ;otherwise increment for middle pipe
12298          cmp #$a0      
12299          bcc GetWNum               ;if player at middle, but not too far right, use offset and skip
12300          inx                       ;otherwise increment for last pipe
12301 GetWNum: ldy WarpZoneNumbers,x     ;get warp zone numbers
12302          dey                       ;decrement for use as world number
12303          sty WorldNumber           ;store as world number and offset
12304          ldx WorldAddrOffsets,y    ;get offset to where this world's area offsets are
12305          lda AreaAddrOffsets,x     ;get area offset based on world offset
12306          sta AreaPointer           ;store area offset here to be used to change areas
12307          lda #Silence
12308          sta EventMusicQueue       ;silence music
12309          lda #$00
12310          sta EntrancePage          ;initialize starting page number
12311          sta AreaNumber            ;initialize area number used for area address offset
12312          sta LevelNumber           ;initialize level number used for world display
12313          sta AltEntranceControl    ;initialize mode of entry
12314          inc Hidden1UpFlag         ;set flag for hidden 1-up blocks
12315          inc FetchNewGameTimerFlag ;set flag to load new game timer
12316 ExPipeE: rts                       ;leave!!!
12317 
12318 ImpedePlayerMove:
12319        lda #$00                  ;initialize value here
12320        ldy Player_X_Speed        ;get player's horizontal speed
12321        ldx $00                   ;check value set earlier for
12322        dex                       ;left side collision
12323        bne RImpd                 ;if right side collision, skip this part
12324        inx                       ;return value to X
12325        cpy #$00                  ;if player moving to the left,
12326        bmi ExIPM                 ;branch to invert bit and leave
12327        lda #$ff                  ;otherwise load A with value to be used later
12328        jmp NXSpd                 ;and jump to affect movement
12329 RImpd: ldx #$02                  ;return $02 to X
12330        cpy #$01                  ;if player moving to the right,
12331        bpl ExIPM                 ;branch to invert bit and leave
12332        lda #$01                  ;otherwise load A with value to be used here
12333 NXSpd: ldy #$10
12334        sty SideCollisionTimer    ;set timer of some sort
12335        ldy #$00
12336        sty Player_X_Speed        ;nullify player's horizontal speed
12337        cmp #$00                  ;if value set in A not set to $ff,
12338        bpl PlatF                 ;branch ahead, do not decrement Y
12339        dey                       ;otherwise decrement Y now
12340 PlatF: sty $00                   ;store Y as high bits of horizontal adder
12341        clc
12342        adc Player_X_Position     ;add contents of A to player's horizontal
12343        sta Player_X_Position     ;position to move player left or right
12344        lda Player_PageLoc
12345        adc $00                   ;add high bits and carry to
12346        sta Player_PageLoc        ;page location if necessary
12347 ExIPM: txa                       ;invert contents of X
12348        eor #$ff
12349        and Player_CollisionBits  ;mask out bit that was set here
12350        sta Player_CollisionBits  ;store to clear bit
12351        rts
12352 
12353 ;--------------------------------
12354 
12355 SolidMTileUpperExt:
12356       .db $10, $61, $88, $c4
12357 
12358 CheckForSolidMTiles:
12359       jsr GetMTileAttrib        ;find appropriate offset based on metatile's 2 MSB
12360       cmp SolidMTileUpperExt,x  ;compare current metatile with solid metatiles
12361       rts
12362 
12363 ClimbMTileUpperExt:
12364       .db $24, $6d, $8a, $c6
12365 
12366 CheckForClimbMTiles:
12367       jsr GetMTileAttrib        ;find appropriate offset based on metatile's 2 MSB
12368       cmp ClimbMTileUpperExt,x  ;compare current metatile with climbable metatiles
12369       rts
12370 
12371 CheckForCoinMTiles:
12372          cmp #$c2              ;check for regular coin
12373          beq CoinSd            ;branch if found
12374          cmp #$c3              ;check for underwater coin
12375          beq CoinSd            ;branch if found
12376          clc                   ;otherwise clear carry and leave
12377          rts
12378 CoinSd:  lda #Sfx_CoinGrab
12379          sta Square2SoundQueue ;load coin grab sound and leave
12380          rts
12381 
12382 GetMTileAttrib:
12383        tay            ;save metatile value into Y
12384        and #%11000000 ;mask out all but 2 MSB
12385        asl
12386        rol            ;shift and rotate d7-d6 to d1-d0
12387        rol
12388        tax            ;use as offset for metatile data
12389        tya            ;get original metatile value back
12390 ExEBG: rts            ;leave
12391 
12392 ;-------------------------------------------------------------------------------------
12393 ;$06-$07 - address from block buffer routine
12394 
12395 EnemyBGCStateData:
12396       .db $01, $01, $02, $02, $02, $05
12397 
12398 EnemyBGCXSpdData:
12399       .db $10, $f0
12400 
12401 EnemyToBGCollisionDet:
12402       lda Enemy_State,x        ;check enemy state for d6 set
12403       and #%00100000
12404       bne ExEBG                ;if set, branch to leave
12405       jsr SubtEnemyYPos        ;otherwise, do a subroutine here
12406       bcc ExEBG                ;if enemy vertical coord + 62 < 68, branch to leave
12407       ldy Enemy_ID,x
12408       cpy #Spiny               ;if enemy object is not spiny, branch elsewhere
12409       bne DoIDCheckBGColl
12410       lda Enemy_Y_Position,x
12411       cmp #$25                 ;if enemy vertical coordinate < 36 branch to leave
12412       bcc ExEBG
12413 
12414 DoIDCheckBGColl:
12415        cpy #GreenParatroopaJump ;check for some other enemy object
12416        bne HBChk                ;branch if not found
12417        jmp EnemyJump            ;otherwise jump elsewhere
12418 HBChk: cpy #HammerBro           ;check for hammer bro
12419        bne CInvu                ;branch if not found
12420        jmp HammerBroBGColl      ;otherwise jump elsewhere
12421 CInvu: cpy #Spiny               ;if enemy object is spiny, branch
12422        beq YesIn
12423        cpy #PowerUpObject       ;if special power-up object, branch
12424        beq YesIn
12425        cpy #$07                 ;if enemy object =>$07, branch to leave
12426        bcs ExEBGChk
12427 YesIn: jsr ChkUnderEnemy        ;if enemy object < $07, or = $12 or $2e, do this sub
12428        bne HandleEToBGCollision ;if block underneath enemy, branch
12429 
12430 NoEToBGCollision:
12431        jmp ChkForRedKoopa       ;otherwise skip and do something else
12432 
12433 ;--------------------------------
12434 ;$02 - vertical coordinate from block buffer routine
12435 
12436 HandleEToBGCollision:
12437       jsr ChkForNonSolids       ;if something is underneath enemy, find out what
12438       beq NoEToBGCollision      ;if blank $26, coins, or hidden blocks, jump, enemy falls through
12439       cmp #$23
12440       bne LandEnemyProperly     ;check for blank metatile $23 and branch if not found
12441       ldy $02                   ;get vertical coordinate used to find block
12442       lda #$00                  ;store default blank metatile in that spot so we won't
12443       sta ($06),y               ;trigger this routine accidentally again
12444       lda Enemy_ID,x
12445       cmp #$15                  ;if enemy object => $15, branch ahead
12446       bcs ChkToStunEnemies
12447       cmp #Goomba               ;if enemy object not goomba, branch ahead of this routine
12448       bne GiveOEPoints
12449       jsr KillEnemyAboveBlock   ;if enemy object IS goomba, do this sub
12450 
12451 GiveOEPoints:
12452       lda #$01                  ;award 100 points for hitting block beneath enemy
12453       jsr SetupFloateyNumber
12454 
12455 ChkToStunEnemies:
12456           cmp #$09                   ;perform many comparisons on enemy object identifier
12457           bcc SetStun      
12458           cmp #$11                   ;if the enemy object identifier is equal to the values
12459           bcs SetStun                ;$09, $0e, $0f or $10, it will be modified, and not
12460           cmp #$0a                   ;modified if not any of those values, note that piranha plant will
12461           bcc Demote                 ;always fail this test because A will still have vertical
12462           cmp #PiranhaPlant          ;coordinate from previous addition, also these comparisons
12463           bcc SetStun                ;are only necessary if branching from $d7a1
12464 Demote:   and #%00000001             ;erase all but LSB, essentially turning enemy object
12465           sta Enemy_ID,x             ;into green or red koopa troopa to demote them
12466 SetStun:  lda Enemy_State,x          ;load enemy state
12467           and #%11110000             ;save high nybble
12468           ora #%00000010
12469           sta Enemy_State,x          ;set d1 of enemy state
12470           dec Enemy_Y_Position,x
12471           dec Enemy_Y_Position,x     ;subtract two pixels from enemy's vertical position
12472           lda Enemy_ID,x
12473           cmp #Bloober               ;check for bloober object
12474           beq SetWYSpd
12475           lda #$fd                   ;set default vertical speed
12476           ldy AreaType
12477           bne SetNotW                ;if area type not water, set as speed, otherwise
12478 SetWYSpd: lda #$ff                   ;change the vertical speed
12479 SetNotW:  sta Enemy_Y_Speed,x        ;set vertical speed now
12480           ldy #$01
12481           jsr PlayerEnemyDiff        ;get horizontal difference between player and enemy object
12482           bpl ChkBBill               ;branch if enemy is to the right of player
12483           iny                        ;increment Y if not
12484 ChkBBill: lda Enemy_ID,x      
12485           cmp #BulletBill_CannonVar  ;check for bullet bill (cannon variant)
12486           beq NoCDirF
12487           cmp #BulletBill_FrenzyVar  ;check for bullet bill (frenzy variant)
12488           beq NoCDirF                ;branch if either found, direction does not change
12489           sty Enemy_MovingDir,x      ;store as moving direction
12490 NoCDirF:  dey                        ;decrement and use as offset
12491           lda EnemyBGCXSpdData,y     ;get proper horizontal speed
12492           sta Enemy_X_Speed,x        ;and store, then leave
12493 ExEBGChk: rts
12494 
12495 ;--------------------------------
12496 ;$04 - low nybble of vertical coordinate from block buffer routine
12497 
12498 LandEnemyProperly:
12499        lda $04                 ;check lower nybble of vertical coordinate saved earlier
12500        sec
12501        sbc #$08                ;subtract eight pixels
12502        cmp #$05                ;used to determine whether enemy landed from falling
12503        bcs ChkForRedKoopa      ;branch if lower nybble in range of $0d-$0f before subtract
12504        lda Enemy_State,x      
12505        and #%01000000          ;branch if d6 in enemy state is set
12506        bne LandEnemyInitState
12507        lda Enemy_State,x
12508        asl                     ;branch if d7 in enemy state is not set
12509        bcc ChkLandedEnemyState
12510 SChkA: jmp DoEnemySideCheck    ;if lower nybble < $0d, d7 set but d6 not set, jump here
12511 
12512 ChkLandedEnemyState:
12513            lda Enemy_State,x         ;if enemy in normal state, branch back to jump here
12514            beq SChkA
12515            cmp #$05                  ;if in state used by spiny's egg
12516            beq ProcEnemyDirection    ;then branch elsewhere
12517            cmp #$03                  ;if already in state used by koopas and buzzy beetles
12518            bcs ExSteChk              ;or in higher numbered state, branch to leave
12519            lda Enemy_State,x         ;load enemy state again (why?)
12520            cmp #$02                  ;if not in $02 state (used by koopas and buzzy beetles)
12521            bne ProcEnemyDirection    ;then branch elsewhere
12522            lda #$10                  ;load default timer here
12523            ldy Enemy_ID,x            ;check enemy identifier for spiny
12524            cpy #Spiny
12525            bne SetForStn             ;branch if not found
12526            lda #$00                  ;set timer for $00 if spiny
12527 SetForStn: sta EnemyIntervalTimer,x  ;set timer here
12528            lda #$03                  ;set state here, apparently used to render
12529            sta Enemy_State,x         ;upside-down koopas and buzzy beetles
12530            jsr EnemyLanding          ;then land it properly
12531 ExSteChk:  rts                       ;then leave
12532 
12533 ProcEnemyDirection:
12534          lda Enemy_ID,x            ;check enemy identifier for goomba
12535          cmp #Goomba               ;branch if found
12536          beq LandEnemyInitState
12537          cmp #Spiny                ;check for spiny
12538          bne InvtD                 ;branch if not found
12539          lda #$01
12540          sta Enemy_MovingDir,x     ;send enemy moving to the right by default
12541          lda #$08
12542          sta Enemy_X_Speed,x       ;set horizontal speed accordingly
12543          lda FrameCounter
12544          and #%00000111            ;if timed appropriately, spiny will skip over
12545          beq LandEnemyInitState    ;trying to face the player
12546 InvtD:   ldy #$01                  ;load 1 for enemy to face the left (inverted here)
12547          jsr PlayerEnemyDiff       ;get horizontal difference between player and enemy
12548          bpl CNwCDir               ;if enemy to the right of player, branch
12549          iny                       ;if to the left, increment by one for enemy to face right (inverted)
12550 CNwCDir: tya
12551          cmp Enemy_MovingDir,x     ;compare direction in A with current direction in memory
12552          bne LandEnemyInitState
12553          jsr ChkForBump_HammerBroJ ;if equal, not facing in correct dir, do sub to turn around
12554 
12555 LandEnemyInitState:
12556       jsr EnemyLanding       ;land enemy properly
12557       lda Enemy_State,x
12558       and #%10000000         ;if d7 of enemy state is set, branch
12559       bne NMovShellFallBit
12560       lda #$00               ;otherwise initialize enemy state and leave
12561       sta Enemy_State,x      ;note this will also turn spiny's egg into spiny
12562       rts
12563 
12564 NMovShellFallBit:
12565       lda Enemy_State,x   ;nullify d6 of enemy state, save other bits
12566       and #%10111111      ;and store, then leave
12567       sta Enemy_State,x
12568       rts
12569 
12570 ;--------------------------------
12571 
12572 ChkForRedKoopa:
12573              lda Enemy_ID,x            ;check for red koopa troopa $03
12574              cmp #RedKoopa
12575              bne Chk2MSBSt             ;branch if not found
12576              lda Enemy_State,x
12577              beq ChkForBump_HammerBroJ ;if enemy found and in normal state, branch
12578 Chk2MSBSt:   lda Enemy_State,x         ;save enemy state into Y
12579              tay
12580              asl                       ;check for d7 set
12581              bcc GetSteFromD           ;branch if not set
12582              lda Enemy_State,x
12583              ora #%01000000            ;set d6
12584              jmp SetD6Ste              ;jump ahead of this part
12585 GetSteFromD: lda EnemyBGCStateData,y   ;load new enemy state with old as offset
12586 SetD6Ste:    sta Enemy_State,x         ;set as new state
12587 
12588 ;--------------------------------
12589 ;$00 - used to store bitmask (not used but initialized here)
12590 ;$eb - used in DoEnemySideCheck as counter and to compare moving directions
12591 
12592 DoEnemySideCheck:
12593           lda Enemy_Y_Position,x     ;if enemy within status bar, branch to leave
12594           cmp #$20                   ;because there's nothing there that impedes movement
12595           bcc ExESdeC
12596           ldy #$16                   ;start by finding block to the left of enemy ($00,$14)
12597           lda #$02                   ;set value here in what is also used as
12598           sta $eb                    ;OAM data offset
12599 SdeCLoop: lda $eb                    ;check value
12600           cmp Enemy_MovingDir,x      ;compare value against moving direction
12601           bne NextSdeC               ;branch if different and do not seek block there
12602           lda #$01                   ;set flag in A for save horizontal coordinate 
12603           jsr BlockBufferChk_Enemy   ;find block to left or right of enemy object
12604           beq NextSdeC               ;if nothing found, branch
12605           jsr ChkForNonSolids        ;check for non-solid blocks
12606           bne ChkForBump_HammerBroJ  ;branch if not found
12607 NextSdeC: dec $eb                    ;move to the next direction
12608           iny
12609           cpy #$18                   ;increment Y, loop only if Y < $18, thus we check
12610           bcc SdeCLoop               ;enemy ($00, $14) and ($10, $14) pixel coordinates
12611 ExESdeC:  rts
12612 
12613 ChkForBump_HammerBroJ: 
12614         cpx #$05               ;check if we're on the special use slot
12615         beq NoBump             ;and if so, branch ahead and do not play sound
12616         lda Enemy_State,x      ;if enemy state d7 not set, branch
12617         asl                    ;ahead and do not play sound
12618         bcc NoBump
12619         lda #Sfx_Bump          ;otherwise, play bump sound
12620         sta Square1SoundQueue  ;sound will never be played if branching from ChkForRedKoopa
12621 NoBump: lda Enemy_ID,x         ;check for hammer bro
12622         cmp #$05
12623         bne InvEnemyDir        ;branch if not found
12624         lda #$00
12625         sta $00                ;initialize value here for bitmask  
12626         ldy #$fa               ;load default vertical speed for jumping
12627         jmp SetHJ              ;jump to code that makes hammer bro jump
12628 
12629 InvEnemyDir:
12630       jmp RXSpd     ;jump to turn the enemy around
12631 
12632 ;--------------------------------
12633 ;$00 - used to hold horizontal difference between player and enemy
12634 
12635 PlayerEnemyDiff:
12636       lda Enemy_X_Position,x  ;get distance between enemy object's
12637       sec                     ;horizontal coordinate and the player's
12638       sbc Player_X_Position   ;horizontal coordinate
12639       sta $00                 ;and store here
12640       lda Enemy_PageLoc,x
12641       sbc Player_PageLoc      ;subtract borrow, then leave
12642       rts
12643 
12644 ;--------------------------------
12645 
12646 EnemyLanding:
12647       jsr InitVStf            ;do something here to vertical speed and something else
12648       lda Enemy_Y_Position,x
12649       and #%11110000          ;save high nybble of vertical coordinate, and
12650       ora #%00001000          ;set d3, then store, probably used to set enemy object
12651       sta Enemy_Y_Position,x  ;neatly on whatever it's landing on
12652       rts
12653 
12654 SubtEnemyYPos:
12655       lda Enemy_Y_Position,x  ;add 62 pixels to enemy object's
12656       clc                     ;vertical coordinate
12657       adc #$3e
12658       cmp #$44                ;compare against a certain range
12659       rts                     ;and leave with flags set for conditional branch
12660 
12661 EnemyJump:
12662         jsr SubtEnemyYPos     ;do a sub here
12663         bcc DoSide            ;if enemy vertical coord + 62 < 68, branch to leave
12664         lda Enemy_Y_Speed,x
12665         clc                   ;add two to vertical speed
12666         adc #$02
12667         cmp #$03              ;if green paratroopa not falling, branch ahead
12668         bcc DoSide
12669         jsr ChkUnderEnemy     ;otherwise, check to see if green paratroopa is 
12670         beq DoSide            ;standing on anything, then branch to same place if not
12671         jsr ChkForNonSolids   ;check for non-solid blocks
12672         beq DoSide            ;branch if found
12673         jsr EnemyLanding      ;change vertical coordinate and speed
12674         lda #$fd
12675         sta Enemy_Y_Speed,x   ;make the paratroopa jump again
12676 DoSide: jmp DoEnemySideCheck  ;check for horizontal blockage, then leave
12677 
12678 ;--------------------------------
12679 
12680 HammerBroBGColl:
12681       jsr ChkUnderEnemy    ;check to see if hammer bro is standing on anything
12682       beq NoUnderHammerBro      
12683       cmp #$23             ;check for blank metatile $23 and branch if not found
12684       bne UnderHammerBro
12685 
12686 KillEnemyAboveBlock:
12687       jsr ShellOrBlockDefeat  ;do this sub to kill enemy
12688       lda #$fc                ;alter vertical speed of enemy and leave
12689       sta Enemy_Y_Speed,x
12690       rts
12691 
12692 UnderHammerBro:
12693       lda EnemyFrameTimer,x ;check timer used by hammer bro
12694       bne NoUnderHammerBro  ;branch if not expired
12695       lda Enemy_State,x
12696       and #%10001000        ;save d7 and d3 from enemy state, nullify other bits
12697       sta Enemy_State,x     ;and store
12698       jsr EnemyLanding      ;modify vertical coordinate, speed and something else
12699       jmp DoEnemySideCheck  ;then check for horizontal blockage and leave
12700 
12701 NoUnderHammerBro:
12702       lda Enemy_State,x  ;if hammer bro is not standing on anything, set d0
12703       ora #$01           ;in the enemy state to indicate jumping or falling, then leave
12704       sta Enemy_State,x
12705       rts
12706 
12707 ChkUnderEnemy:
12708       lda #$00                  ;set flag in A for save vertical coordinate
12709       ldy #$15                  ;set Y to check the bottom middle (8,18) of enemy object
12710       jmp BlockBufferChk_Enemy  ;hop to it!
12711 
12712 ChkForNonSolids:
12713        cmp #$26       ;blank metatile used for vines?
12714        beq NSFnd
12715        cmp #$c2       ;regular coin?
12716        beq NSFnd
12717        cmp #$c3       ;underwater coin?
12718        beq NSFnd
12719        cmp #$5f       ;hidden coin block?
12720        beq NSFnd
12721        cmp #$60       ;hidden 1-up block?
12722 NSFnd: rts
12723 
12724 ;-------------------------------------------------------------------------------------
12725 
12726 FireballBGCollision:
12727       lda Fireball_Y_Position,x   ;check fireball's vertical coordinate
12728       cmp #$18
12729       bcc ClearBounceFlag         ;if within the status bar area of the screen, branch ahead
12730       jsr BlockBufferChk_FBall    ;do fireball to background collision detection on bottom of it
12731       beq ClearBounceFlag         ;if nothing underneath fireball, branch
12732       jsr ChkForNonSolids         ;check for non-solid metatiles
12733       beq ClearBounceFlag         ;branch if any found
12734       lda Fireball_Y_Speed,x      ;if fireball's vertical speed set to move upwards,
12735       bmi InitFireballExplode     ;branch to set exploding bit in fireball's state
12736       lda FireballBouncingFlag,x  ;if bouncing flag already set,
12737       bne InitFireballExplode     ;branch to set exploding bit in fireball's state
12738       lda #$fd
12739       sta Fireball_Y_Speed,x      ;otherwise set vertical speed to move upwards (give it bounce)
12740       lda #$01
12741       sta FireballBouncingFlag,x  ;set bouncing flag
12742       lda Fireball_Y_Position,x
12743       and #$f8                    ;modify vertical coordinate to land it properly
12744       sta Fireball_Y_Position,x   ;store as new vertical coordinate
12745       rts                         ;leave
12746 
12747 ClearBounceFlag:
12748       lda #$00
12749       sta FireballBouncingFlag,x  ;clear bouncing flag by default
12750       rts                         ;leave
12751 
12752 InitFireballExplode:
12753       lda #$80
12754       sta Fireball_State,x        ;set exploding flag in fireball's state
12755       lda #Sfx_Bump
12756       sta Square1SoundQueue       ;load bump sound
12757       rts                         ;leave
12758 
12759 ;-------------------------------------------------------------------------------------
12760 ;$00 - used to hold one of bitmasks, or offset
12761 ;$01 - used for relative X coordinate, also used to store middle screen page location
12762 ;$02 - used for relative Y coordinate, also used to store middle screen coordinate
12763 
12764 ;this data added to relative coordinates of sprite objects
12765 ;stored in order: left edge, top edge, right edge, bottom edge
12766 BoundBoxCtrlData:
12767       .db $02, $08, $0e, $20 
12768       .db $03, $14, $0d, $20
12769       .db $02, $14, $0e, $20
12770       .db $02, $09, $0e, $15
12771       .db $00, $00, $18, $06
12772       .db $00, $00, $20, $0d
12773       .db $00, $00, $30, $0d
12774       .db $00, $00, $08, $08
12775       .db $06, $04, $0a, $08
12776       .db $03, $0e, $0d, $14
12777       .db $00, $02, $10, $15
12778       .db $04, $04, $0c, $1c
12779 
12780 GetFireballBoundBox:
12781       txa         ;add seven bytes to offset
12782       clc         ;to use in routines as offset for fireball
12783       adc #$07
12784       tax
12785       ldy #$02    ;set offset for relative coordinates
12786       bne FBallB  ;unconditional branch
12787 
12788 GetMiscBoundBox:
12789         txa                       ;add nine bytes to offset
12790         clc                       ;to use in routines as offset for misc object
12791         adc #$09
12792         tax
12793         ldy #$06                  ;set offset for relative coordinates
12794 FBallB: jsr BoundingBoxCore       ;get bounding box coordinates
12795         jmp CheckRightScreenBBox  ;jump to handle any offscreen coordinates
12796 
12797 GetEnemyBoundBox:
12798       ldy #$48                 ;store bitmask here for now
12799       sty $00
12800       ldy #$44                 ;store another bitmask here for now and jump
12801       jmp GetMaskedOffScrBits
12802 
12803 SmallPlatformBoundBox:
12804       ldy #$08                 ;store bitmask here for now
12805       sty $00
12806       ldy #$04                 ;store another bitmask here for now
12807 
12808 GetMaskedOffScrBits:
12809         lda Enemy_X_Position,x      ;get enemy object position relative
12810         sec                         ;to the left side of the screen
12811         sbc ScreenLeft_X_Pos
12812         sta $01                     ;store here
12813         lda Enemy_PageLoc,x         ;subtract borrow from current page location
12814         sbc ScreenLeft_PageLoc      ;of left side
12815         bmi CMBits                  ;if enemy object is beyond left edge, branch
12816         ora $01
12817         beq CMBits                  ;if precisely at the left edge, branch
12818         ldy $00                     ;if to the right of left edge, use value in $00 for A
12819 CMBits: tya                         ;otherwise use contents of Y
12820         and Enemy_OffscreenBits     ;preserve bitwise whatever's in here
12821         sta EnemyOffscrBitsMasked,x ;save masked offscreen bits here
12822         bne MoveBoundBoxOffscreen   ;if anything set here, branch
12823         jmp SetupEOffsetFBBox       ;otherwise, do something else
12824 
12825 LargePlatformBoundBox:
12826       inx                        ;increment X to get the proper offset
12827       jsr GetXOffscreenBits      ;then jump directly to the sub for horizontal offscreen bits
12828       dex                        ;decrement to return to original offset
12829       cmp #$fe                   ;if completely offscreen, branch to put entire bounding
12830       bcs MoveBoundBoxOffscreen  ;box offscreen, otherwise start getting coordinates
12831 
12832 SetupEOffsetFBBox:
12833       txa                        ;add 1 to offset to properly address
12834       clc                        ;the enemy object memory locations
12835       adc #$01
12836       tax
12837       ldy #$01                   ;load 1 as offset here, same reason
12838       jsr BoundingBoxCore        ;do a sub to get the coordinates of the bounding box
12839       jmp CheckRightScreenBBox   ;jump to handle offscreen coordinates of bounding box
12840 
12841 MoveBoundBoxOffscreen:
12842       txa                            ;multiply offset by 4
12843       asl
12844       asl
12845       tay                            ;use as offset here
12846       lda #$ff
12847       sta EnemyBoundingBoxCoord,y    ;load value into four locations here and leave
12848       sta EnemyBoundingBoxCoord+1,y
12849       sta EnemyBoundingBoxCoord+2,y
12850       sta EnemyBoundingBoxCoord+3,y
12851       rts
12852 
12853 BoundingBoxCore:
12854       stx $00                     ;save offset here
12855       lda SprObject_Rel_YPos,y    ;store object coordinates relative to screen
12856       sta $02                     ;vertically and horizontally, respectively
12857       lda SprObject_Rel_XPos,y
12858       sta $01
12859       txa                         ;multiply offset by four and save to stack
12860       asl
12861       asl
12862       pha
12863       tay                         ;use as offset for Y, X is left alone
12864       lda SprObj_BoundBoxCtrl,x   ;load value here to be used as offset for X
12865       asl                         ;multiply that by four and use as X
12866       asl
12867       tax
12868       lda $01                     ;add the first number in the bounding box data to the
12869       clc                         ;relative horizontal coordinate using enemy object offset
12870       adc BoundBoxCtrlData,x      ;and store somewhere using same offset * 4
12871       sta BoundingBox_UL_Corner,y ;store here
12872       lda $01
12873       clc
12874       adc BoundBoxCtrlData+2,x    ;add the third number in the bounding box data to the
12875       sta BoundingBox_LR_Corner,y ;relative horizontal coordinate and store
12876       inx                         ;increment both offsets
12877       iny
12878       lda $02                     ;add the second number to the relative vertical coordinate
12879       clc                         ;using incremented offset and store using the other
12880       adc BoundBoxCtrlData,x      ;incremented offset
12881       sta BoundingBox_UL_Corner,y
12882       lda $02
12883       clc
12884       adc BoundBoxCtrlData+2,x    ;add the fourth number to the relative vertical coordinate
12885       sta BoundingBox_LR_Corner,y ;and store
12886       pla                         ;get original offset loaded into $00 * y from stack
12887       tay                         ;use as Y
12888       ldx $00                     ;get original offset and use as X again
12889       rts
12890 
12891 CheckRightScreenBBox:
12892        lda ScreenLeft_X_Pos       ;add 128 pixels to left side of screen
12893        clc                        ;and store as horizontal coordinate of middle
12894        adc #$80
12895        sta $02
12896        lda ScreenLeft_PageLoc     ;add carry to page location of left side of screen
12897        adc #$00                   ;and store as page location of middle
12898        sta $01
12899        lda SprObject_X_Position,x ;get horizontal coordinate
12900        cmp $02                    ;compare against middle horizontal coordinate
12901        lda SprObject_PageLoc,x    ;get page location
12902        sbc $01                    ;subtract from middle page location
12903        bcc CheckLeftScreenBBox    ;if object is on the left side of the screen, branch
12904        lda BoundingBox_DR_XPos,y  ;check right-side edge of bounding box for offscreen
12905        bmi NoOfs                  ;coordinates, branch if still on the screen
12906        lda #$ff                   ;load offscreen value here to use on one or both horizontal sides
12907        ldx BoundingBox_UL_XPos,y  ;check left-side edge of bounding box for offscreen
12908        bmi SORte                  ;coordinates, and branch if still on the screen
12909        sta BoundingBox_UL_XPos,y  ;store offscreen value for left side
12910 SORte: sta BoundingBox_DR_XPos,y  ;store offscreen value for right side
12911 NoOfs: ldx ObjectOffset           ;get object offset and leave
12912        rts
12913 
12914 CheckLeftScreenBBox:
12915         lda BoundingBox_UL_XPos,y  ;check left-side edge of bounding box for offscreen
12916         bpl NoOfs2                 ;coordinates, and branch if still on the screen
12917         cmp #$a0                   ;check to see if left-side edge is in the middle of the
12918         bcc NoOfs2                 ;screen or really offscreen, and branch if still on
12919         lda #$00
12920         ldx BoundingBox_DR_XPos,y  ;check right-side edge of bounding box for offscreen
12921         bpl SOLft                  ;coordinates, branch if still onscreen
12922         sta BoundingBox_DR_XPos,y  ;store offscreen value for right side
12923 SOLft:  sta BoundingBox_UL_XPos,y  ;store offscreen value for left side
12924 NoOfs2: ldx ObjectOffset           ;get object offset and leave
12925         rts
12926 
12927 ;-------------------------------------------------------------------------------------
12928 ;$06 - second object's offset
12929 ;$07 - counter
12930 
12931 PlayerCollisionCore:
12932       ldx #$00     ;initialize X to use player's bounding box for comparison
12933 
12934 SprObjectCollisionCore:
12935       sty $06      ;save contents of Y here
12936       lda #$01
12937       sta $07      ;save value 1 here as counter, compare horizontal coordinates first
12938 
12939 CollisionCoreLoop:
12940       lda BoundingBox_UL_Corner,y  ;compare left/top coordinates
12941       cmp BoundingBox_UL_Corner,x  ;of first and second objects' bounding boxes
12942       bcs FirstBoxGreater          ;if first left/top => second, branch
12943       cmp BoundingBox_LR_Corner,x  ;otherwise compare to right/bottom of second
12944       bcc SecondBoxVerticalChk     ;if first left/top < second right/bottom, branch elsewhere
12945       beq CollisionFound           ;if somehow equal, collision, thus branch
12946       lda BoundingBox_LR_Corner,y  ;if somehow greater, check to see if bottom of
12947       cmp BoundingBox_UL_Corner,y  ;first object's bounding box is greater than its top
12948       bcc CollisionFound           ;if somehow less, vertical wrap collision, thus branch
12949       cmp BoundingBox_UL_Corner,x  ;otherwise compare bottom of first bounding box to the top
12950       bcs CollisionFound           ;of second box, and if equal or greater, collision, thus branch
12951       ldy $06                      ;otherwise return with carry clear and Y = $0006
12952       rts                          ;note horizontal wrapping never occurs
12953 
12954 SecondBoxVerticalChk:
12955       lda BoundingBox_LR_Corner,x  ;check to see if the vertical bottom of the box
12956       cmp BoundingBox_UL_Corner,x  ;is greater than the vertical top
12957       bcc CollisionFound           ;if somehow less, vertical wrap collision, thus branch
12958       lda BoundingBox_LR_Corner,y  ;otherwise compare horizontal right or vertical bottom
12959       cmp BoundingBox_UL_Corner,x  ;of first box with horizontal left or vertical top of second box
12960       bcs CollisionFound           ;if equal or greater, collision, thus branch
12961       ldy $06                      ;otherwise return with carry clear and Y = $0006
12962       rts
12963 
12964 FirstBoxGreater:
12965       cmp BoundingBox_UL_Corner,x  ;compare first and second box horizontal left/vertical top again
12966       beq CollisionFound           ;if first coordinate = second, collision, thus branch
12967       cmp BoundingBox_LR_Corner,x  ;if not, compare with second object right or bottom edge
12968       bcc CollisionFound           ;if left/top of first less than or equal to right/bottom of second
12969       beq CollisionFound           ;then collision, thus branch
12970       cmp BoundingBox_LR_Corner,y  ;otherwise check to see if top of first box is greater than bottom
12971       bcc NoCollisionFound         ;if less than or equal, no collision, branch to end
12972       beq NoCollisionFound
12973       lda BoundingBox_LR_Corner,y  ;otherwise compare bottom of first to top of second
12974       cmp BoundingBox_UL_Corner,x  ;if bottom of first is greater than top of second, vertical wrap
12975       bcs CollisionFound           ;collision, and branch, otherwise, proceed onwards here
12976 
12977 NoCollisionFound:
12978       clc          ;clear carry, then load value set earlier, then leave
12979       ldy $06      ;like previous ones, if horizontal coordinates do not collide, we do
12980       rts          ;not bother checking vertical ones, because what's the point?
12981 
12982 CollisionFound:
12983       inx                    ;increment offsets on both objects to check
12984       iny                    ;the vertical coordinates
12985       dec $07                ;decrement counter to reflect this
12986       bpl CollisionCoreLoop  ;if counter not expired, branch to loop
12987       sec                    ;otherwise we already did both sets, therefore collision, so set carry
12988       ldy $06                ;load original value set here earlier, then leave
12989       rts
12990 
12991 ;-------------------------------------------------------------------------------------
12992 ;$02 - modified y coordinate
12993 ;$03 - stores metatile involved in block buffer collisions
12994 ;$04 - comes in with offset to block buffer adder data, goes out with low nybble x/y coordinate
12995 ;$05 - modified x coordinate
12996 ;$06-$07 - block buffer address
12997 
12998 BlockBufferChk_Enemy:
12999       pha        ;save contents of A to stack
13000       txa
13001       clc        ;add 1 to X to run sub with enemy offset in mind
13002       adc #$01
13003       tax
13004       pla        ;pull A from stack and jump elsewhere
13005       jmp BBChk_E
13006 
13007 ResidualMiscObjectCode:
13008       txa
13009       clc           ;supposedly used once to set offset for
13010       adc #$0d      ;miscellaneous objects
13011       tax
13012       ldy #$1b      ;supposedly used once to set offset for block buffer data
13013       jmp ResJmpM   ;probably used in early stages to do misc to bg collision detection
13014 
13015 BlockBufferChk_FBall:
13016          ldy #$1a                  ;set offset for block buffer adder data
13017          txa
13018          clc
13019          adc #$07                  ;add seven bytes to use
13020          tax
13021 ResJmpM: lda #$00                  ;set A to return vertical coordinate
13022 BBChk_E: jsr BlockBufferCollision  ;do collision detection subroutine for sprite object
13023          ldx ObjectOffset          ;get object offset
13024          cmp #$00                  ;check to see if object bumped into anything
13025          rts
13026 
13027 BlockBufferAdderData:
13028       .db $00, $07, $0e
13029 
13030 BlockBuffer_X_Adder:
13031       .db $08, $03, $0c, $02, $02, $0d, $0d, $08
13032       .db $03, $0c, $02, $02, $0d, $0d, $08, $03
13033       .db $0c, $02, $02, $0d, $0d, $08, $00, $10
13034       .db $04, $14, $04, $04
13035 
13036 BlockBuffer_Y_Adder:
13037       .db $04, $20, $20, $08, $18, $08, $18, $02
13038       .db $20, $20, $08, $18, $08, $18, $12, $20
13039       .db $20, $18, $18, $18, $18, $18, $14, $14
13040       .db $06, $06, $08, $10
13041 
13042 BlockBufferColli_Feet:
13043        iny            ;if branched here, increment to next set of adders
13044 
13045 BlockBufferColli_Head:
13046        lda #$00       ;set flag to return vertical coordinate
13047        .db $2c        ;BIT instruction opcode
13048 
13049 BlockBufferColli_Side:
13050        lda #$01       ;set flag to return horizontal coordinate
13051        ldx #$00       ;set offset for player object
13052 
13053 BlockBufferCollision:
13054        pha                         ;save contents of A to stack
13055        sty $04                     ;save contents of Y here
13056        lda BlockBuffer_X_Adder,y   ;add horizontal coordinate
13057        clc                         ;of object to value obtained using Y as offset
13058        adc SprObject_X_Position,x
13059        sta $05                     ;store here
13060        lda SprObject_PageLoc,x
13061        adc #$00                    ;add carry to page location
13062        and #$01                    ;get LSB, mask out all other bits
13063        lsr                         ;move to carry
13064        ora $05                     ;get stored value
13065        ror                         ;rotate carry to MSB of A
13066        lsr                         ;and effectively move high nybble to
13067        lsr                         ;lower, LSB which became MSB will be
13068        lsr                         ;d4 at this point
13069        jsr GetBlockBufferAddr      ;get address of block buffer into $06, $07
13070        ldy $04                     ;get old contents of Y
13071        lda SprObject_Y_Position,x  ;get vertical coordinate of object
13072        clc
13073        adc BlockBuffer_Y_Adder,y   ;add it to value obtained using Y as offset
13074        and #%11110000              ;mask out low nybble
13075        sec
13076        sbc #$20                    ;subtract 32 pixels for the status bar
13077        sta $02                     ;store result here
13078        tay                         ;use as offset for block buffer
13079        lda ($06),y                 ;check current content of block buffer
13080        sta $03                     ;and store here
13081        ldy $04                     ;get old contents of Y again
13082        pla                         ;pull A from stack
13083        bne RetXC                   ;if A = 1, branch
13084        lda SprObject_Y_Position,x  ;if A = 0, load vertical coordinate
13085        jmp RetYC                   ;and jump
13086 RetXC: lda SprObject_X_Position,x  ;otherwise load horizontal coordinate
13087 RetYC: and #%00001111              ;and mask out high nybble
13088        sta $04                     ;store masked out result here
13089        lda $03                     ;get saved content of block buffer
13090        rts                         ;and leave
13091 
13092 ;-------------------------------------------------------------------------------------
13093 
13094 ;unused byte
13095       .db $ff
13096 
13097 ;-------------------------------------------------------------------------------------
13098 ;$00 - offset to vine Y coordinate adder
13099 ;$02 - offset to sprite data
13100 
13101 VineYPosAdder:
13102       .db $00, $30
13103 
13104 DrawVine:
13105          sty $00                    ;save offset here
13106          lda Enemy_Rel_YPos         ;get relative vertical coordinate
13107          clc
13108          adc VineYPosAdder,y        ;add value using offset in Y to get value
13109          ldx VineObjOffset,y        ;get offset to vine
13110          ldy Enemy_SprDataOffset,x  ;get sprite data offset
13111          sty $02                    ;store sprite data offset here
13112          jsr SixSpriteStacker       ;stack six sprites on top of each other vertically
13113          lda Enemy_Rel_XPos         ;get relative horizontal coordinate
13114          sta Sprite_X_Position,y    ;store in first, third and fifth sprites
13115          sta Sprite_X_Position+8,y
13116          sta Sprite_X_Position+16,y
13117          clc
13118          adc #$06                   ;add six pixels to second, fourth and sixth sprites
13119          sta Sprite_X_Position+4,y  ;to give characteristic staggered vine shape to
13120          sta Sprite_X_Position+12,y ;our vertical stack of sprites
13121          sta Sprite_X_Position+20,y
13122          lda #%00100001             ;set bg priority and palette attribute bits
13123          sta Sprite_Attributes,y    ;set in first, third and fifth sprites
13124          sta Sprite_Attributes+8,y
13125          sta Sprite_Attributes+16,y
13126          ora #%01000000             ;additionally, set horizontal flip bit
13127          sta Sprite_Attributes+4,y  ;for second, fourth and sixth sprites
13128          sta Sprite_Attributes+12,y
13129          sta Sprite_Attributes+20,y
13130          ldx #$05                   ;set tiles for six sprites
13131 VineTL:  lda #$e1                   ;set tile number for sprite
13132          sta Sprite_Tilenumber,y
13133          iny                        ;move offset to next sprite data
13134          iny
13135          iny
13136          iny
13137          dex                        ;move onto next sprite
13138          bpl VineTL                 ;loop until all sprites are done
13139          ldy $02                    ;get original offset
13140          lda $00                    ;get offset to vine adding data
13141          bne SkpVTop                ;if offset not zero, skip this part
13142          lda #$e0
13143          sta Sprite_Tilenumber,y    ;set other tile number for top of vine
13144 SkpVTop: ldx #$00                   ;start with the first sprite again
13145 ChkFTop: lda VineStart_Y_Position   ;get original starting vertical coordinate
13146          sec
13147          sbc Sprite_Y_Position,y    ;subtract top-most sprite's Y coordinate
13148          cmp #$64                   ;if two coordinates are less than 100/$64 pixels
13149          bcc NextVSp                ;apart, skip this to leave sprite alone
13150          lda #$f8
13151          sta Sprite_Y_Position,y    ;otherwise move sprite offscreen
13152 NextVSp: iny                        ;move offset to next OAM data
13153          iny
13154          iny
13155          iny
13156          inx                        ;move onto next sprite
13157          cpx #$06                   ;do this until all sprites are checked
13158          bne ChkFTop
13159          ldy $00                    ;return offset set earlier
13160          rts
13161 
13162 SixSpriteStacker:
13163        ldx #$06           ;do six sprites
13164 StkLp: sta Sprite_Data,y  ;store X or Y coordinate into OAM data
13165        clc
13166        adc #$08           ;add eight pixels
13167        iny
13168        iny                ;move offset four bytes forward
13169        iny
13170        iny
13171        dex                ;do another sprite
13172        bne StkLp          ;do this until all sprites are done
13173        ldy $02            ;get saved OAM data offset and leave
13174        rts
13175 
13176 ;-------------------------------------------------------------------------------------
13177 
13178 FirstSprXPos:
13179       .db $04, $00, $04, $00
13180 
13181 FirstSprYPos:
13182       .db $00, $04, $00, $04
13183 
13184 SecondSprXPos:
13185       .db $00, $08, $00, $08
13186 
13187 SecondSprYPos:
13188       .db $08, $00, $08, $00
13189 
13190 FirstSprTilenum:
13191       .db $80, $82, $81, $83
13192 
13193 SecondSprTilenum:
13194       .db $81, $83, $80, $82
13195 
13196 HammerSprAttrib:
13197       .db $03, $03, $c3, $c3
13198 
13199 DrawHammer:
13200             ldy Misc_SprDataOffset,x    ;get misc object OAM data offset
13201             lda TimerControl
13202             bne ForceHPose              ;if master timer control set, skip this part
13203             lda Misc_State,x            ;otherwise get hammer's state
13204             and #%01111111              ;mask out d7
13205             cmp #$01                    ;check to see if set to 1 yet
13206             beq GetHPose                ;if so, branch
13207 ForceHPose: ldx #$00                    ;reset offset here
13208             beq RenderH                 ;do unconditional branch to rendering part
13209 GetHPose:   lda FrameCounter            ;get frame counter
13210             lsr                         ;move d3-d2 to d1-d0
13211             lsr
13212             and #%00000011              ;mask out all but d1-d0 (changes every four frames)
13213             tax                         ;use as timing offset
13214 RenderH:    lda Misc_Rel_YPos           ;get relative vertical coordinate
13215             clc
13216             adc FirstSprYPos,x          ;add first sprite vertical adder based on offset
13217             sta Sprite_Y_Position,y     ;store as sprite Y coordinate for first sprite
13218             clc
13219             adc SecondSprYPos,x         ;add second sprite vertical adder based on offset
13220             sta Sprite_Y_Position+4,y   ;store as sprite Y coordinate for second sprite
13221             lda Misc_Rel_XPos           ;get relative horizontal coordinate
13222             clc
13223             adc FirstSprXPos,x          ;add first sprite horizontal adder based on offset
13224             sta Sprite_X_Position,y     ;store as sprite X coordinate for first sprite
13225             clc
13226             adc SecondSprXPos,x         ;add second sprite horizontal adder based on offset
13227             sta Sprite_X_Position+4,y   ;store as sprite X coordinate for second sprite
13228             lda FirstSprTilenum,x
13229             sta Sprite_Tilenumber,y     ;get and store tile number of first sprite
13230             lda SecondSprTilenum,x
13231             sta Sprite_Tilenumber+4,y   ;get and store tile number of second sprite
13232             lda HammerSprAttrib,x
13233             sta Sprite_Attributes,y     ;get and store attribute bytes for both
13234             sta Sprite_Attributes+4,y   ;note in this case they use the same data
13235             ldx ObjectOffset            ;get misc object offset
13236             lda Misc_OffscreenBits
13237             and #%11111100              ;check offscreen bits
13238             beq NoHOffscr               ;if all bits clear, leave object alone
13239             lda #$00
13240             sta Misc_State,x            ;otherwise nullify misc object state
13241             lda #$f8
13242             jsr DumpTwoSpr              ;do sub to move hammer sprites offscreen
13243 NoHOffscr:  rts                         ;leave
13244 
13245 ;-------------------------------------------------------------------------------------
13246 ;$00-$01 - used to hold tile numbers ($01 addressed in draw floatey number part)
13247 ;$02 - used to hold Y coordinate for floatey number
13248 ;$03 - residual byte used for flip (but value set here affects nothing)
13249 ;$04 - attribute byte for floatey number
13250 ;$05 - used as X coordinate for floatey number
13251 
13252 FlagpoleScoreNumTiles:
13253       .db $f9, $50
13254       .db $f7, $50
13255       .db $fa, $fb
13256       .db $f8, $fb
13257       .db $f6, $fb
13258 
13259 FlagpoleGfxHandler:
13260       ldy Enemy_SprDataOffset,x      ;get sprite data offset for flagpole flag
13261       lda Enemy_Rel_XPos             ;get relative horizontal coordinate
13262       sta Sprite_X_Position,y        ;store as X coordinate for first sprite
13263       clc
13264       adc #$08                       ;add eight pixels and store
13265       sta Sprite_X_Position+4,y      ;as X coordinate for second and third sprites
13266       sta Sprite_X_Position+8,y
13267       clc
13268       adc #$0c                       ;add twelve more pixels and
13269       sta $05                        ;store here to be used later by floatey number
13270       lda Enemy_Y_Position,x         ;get vertical coordinate
13271       jsr DumpTwoSpr                 ;and do sub to dump into first and second sprites
13272       adc #$08                       ;add eight pixels
13273       sta Sprite_Y_Position+8,y      ;and store into third sprite
13274       lda FlagpoleFNum_Y_Pos         ;get vertical coordinate for floatey number
13275       sta $02                        ;store it here
13276       lda #$01
13277       sta $03                        ;set value for flip which will not be used, and
13278       sta $04                        ;attribute byte for floatey number
13279       sta Sprite_Attributes,y        ;set attribute bytes for all three sprites
13280       sta Sprite_Attributes+4,y
13281       sta Sprite_Attributes+8,y
13282       lda #$7e
13283       sta Sprite_Tilenumber,y        ;put triangle shaped tile
13284       sta Sprite_Tilenumber+8,y      ;into first and third sprites
13285       lda #$7f
13286       sta Sprite_Tilenumber+4,y      ;put skull tile into second sprite
13287       lda FlagpoleCollisionYPos      ;get vertical coordinate at time of collision
13288       beq ChkFlagOffscreen           ;if zero, branch ahead
13289       tya
13290       clc                            ;add 12 bytes to sprite data offset
13291       adc #$0c
13292       tay                            ;put back in Y
13293       lda FlagpoleScore              ;get offset used to award points for touching flagpole
13294       asl                            ;multiply by 2 to get proper offset here
13295       tax
13296       lda FlagpoleScoreNumTiles,x    ;get appropriate tile data
13297       sta $00
13298       lda FlagpoleScoreNumTiles+1,x
13299       jsr DrawOneSpriteRow           ;use it to render floatey number
13300 
13301 ChkFlagOffscreen:
13302       ldx ObjectOffset               ;get object offset for flag
13303       ldy Enemy_SprDataOffset,x      ;get OAM data offset
13304       lda Enemy_OffscreenBits        ;get offscreen bits
13305       and #%00001110                 ;mask out all but d3-d1
13306       beq ExitDumpSpr                ;if none of these bits set, branch to leave
13307 
13308 ;-------------------------------------------------------------------------------------
13309 
13310 MoveSixSpritesOffscreen:
13311       lda #$f8                  ;set offscreen coordinate if jumping here
13312 
13313 DumpSixSpr:
13314       sta Sprite_Data+20,y      ;dump A contents
13315       sta Sprite_Data+16,y      ;into third row sprites
13316 
13317 DumpFourSpr:
13318       sta Sprite_Data+12,y      ;into second row sprites
13319 
13320 DumpThreeSpr:
13321       sta Sprite_Data+8,y
13322 
13323 DumpTwoSpr:
13324       sta Sprite_Data+4,y       ;and into first row sprites
13325       sta Sprite_Data,y
13326 
13327 ExitDumpSpr:
13328       rts
13329 
13330 ;-------------------------------------------------------------------------------------
13331 
13332 DrawLargePlatform:
13333       ldy Enemy_SprDataOffset,x   ;get OAM data offset
13334       sty $02                     ;store here
13335       iny                         ;add 3 to it for offset
13336       iny                         ;to X coordinate
13337       iny
13338       lda Enemy_Rel_XPos          ;get horizontal relative coordinate
13339       jsr SixSpriteStacker        ;store X coordinates using A as base, stack horizontally
13340       ldx ObjectOffset
13341       lda Enemy_Y_Position,x      ;get vertical coordinate
13342       jsr DumpFourSpr             ;dump into first four sprites as Y coordinate
13343       ldy AreaType
13344       cpy #$03                    ;check for castle-type level
13345       beq ShrinkPlatform
13346       ldy SecondaryHardMode       ;check for secondary hard mode flag set
13347       beq SetLast2Platform        ;branch if not set elsewhere
13348 
13349 ShrinkPlatform:
13350       lda #$f8                    ;load offscreen coordinate if flag set or castle-type level
13351 
13352 SetLast2Platform:
13353       ldy Enemy_SprDataOffset,x   ;get OAM data offset
13354       sta Sprite_Y_Position+16,y  ;store vertical coordinate or offscreen
13355       sta Sprite_Y_Position+20,y  ;coordinate into last two sprites as Y coordinate
13356       lda #$5b                    ;load default tile for platform (girder)
13357       ldx CloudTypeOverride
13358       beq SetPlatformTilenum      ;if cloud level override flag not set, use
13359       lda #$75                    ;otherwise load other tile for platform (puff)
13360 
13361 SetPlatformTilenum:
13362         ldx ObjectOffset            ;get enemy object buffer offset
13363         iny                         ;increment Y for tile offset
13364         jsr DumpSixSpr              ;dump tile number into all six sprites
13365         lda #$02                    ;set palette controls
13366         iny                         ;increment Y for sprite attributes
13367         jsr DumpSixSpr              ;dump attributes into all six sprites
13368         inx                         ;increment X for enemy objects
13369         jsr GetXOffscreenBits       ;get offscreen bits again
13370         dex
13371         ldy Enemy_SprDataOffset,x   ;get OAM data offset
13372         asl                         ;rotate d7 into carry, save remaining
13373         pha                         ;bits to the stack
13374         bcc SChk2
13375         lda #$f8                    ;if d7 was set, move first sprite offscreen
13376         sta Sprite_Y_Position,y
13377 SChk2:  pla                         ;get bits from stack
13378         asl                         ;rotate d6 into carry
13379         pha                         ;save to stack
13380         bcc SChk3
13381         lda #$f8                    ;if d6 was set, move second sprite offscreen
13382         sta Sprite_Y_Position+4,y
13383 SChk3:  pla                         ;get bits from stack
13384         asl                         ;rotate d5 into carry
13385         pha                         ;save to stack
13386         bcc SChk4
13387         lda #$f8                    ;if d5 was set, move third sprite offscreen
13388         sta Sprite_Y_Position+8,y
13389 SChk4:  pla                         ;get bits from stack
13390         asl                         ;rotate d4 into carry
13391         pha                         ;save to stack
13392         bcc SChk5
13393         lda #$f8                    ;if d4 was set, move fourth sprite offscreen
13394         sta Sprite_Y_Position+12,y
13395 SChk5:  pla                         ;get bits from stack
13396         asl                         ;rotate d3 into carry
13397         pha                         ;save to stack
13398         bcc SChk6
13399         lda #$f8                    ;if d3 was set, move fifth sprite offscreen
13400         sta Sprite_Y_Position+16,y
13401 SChk6:  pla                         ;get bits from stack
13402         asl                         ;rotate d2 into carry
13403         bcc SLChk                   ;save to stack
13404         lda #$f8
13405         sta Sprite_Y_Position+20,y  ;if d2 was set, move sixth sprite offscreen
13406 SLChk:  lda Enemy_OffscreenBits     ;check d7 of offscreen bits
13407         asl                         ;and if d7 is not set, skip sub
13408         bcc ExDLPl
13409         jsr MoveSixSpritesOffscreen ;otherwise branch to move all sprites offscreen
13410 ExDLPl: rts
13411 
13412 ;-------------------------------------------------------------------------------------
13413 
13414 DrawFloateyNumber_Coin:
13415           lda FrameCounter          ;get frame counter
13416           lsr                       ;divide by 2
13417           bcs NotRsNum              ;branch if d0 not set to raise number every other frame
13418           dec Misc_Y_Position,x     ;otherwise, decrement vertical coordinate
13419 NotRsNum: lda Misc_Y_Position,x     ;get vertical coordinate
13420           jsr DumpTwoSpr            ;dump into both sprites
13421           lda Misc_Rel_XPos         ;get relative horizontal coordinate
13422           sta Sprite_X_Position,y   ;store as X coordinate for first sprite
13423           clc
13424           adc #$08                  ;add eight pixels
13425           sta Sprite_X_Position+4,y ;store as X coordinate for second sprite
13426           lda #$02
13427           sta Sprite_Attributes,y   ;store attribute byte in both sprites
13428           sta Sprite_Attributes+4,y
13429           lda #$f7
13430           sta Sprite_Tilenumber,y   ;put tile numbers into both sprites
13431           lda #$fb                  ;that resemble "200"
13432           sta Sprite_Tilenumber+4,y
13433           jmp ExJCGfx               ;then jump to leave (why not an rts here instead?)
13434 
13435 JumpingCoinTiles:
13436       .db $60, $61, $62, $63
13437 
13438 JCoinGfxHandler:
13439          ldy Misc_SprDataOffset,x    ;get coin/floatey number's OAM data offset
13440          lda Misc_State,x            ;get state of misc object
13441          cmp #$02                    ;if 2 or greater, 
13442          bcs DrawFloateyNumber_Coin  ;branch to draw floatey number
13443          lda Misc_Y_Position,x       ;store vertical coordinate as
13444          sta Sprite_Y_Position,y     ;Y coordinate for first sprite
13445          clc
13446          adc #$08                    ;add eight pixels
13447          sta Sprite_Y_Position+4,y   ;store as Y coordinate for second sprite
13448          lda Misc_Rel_XPos           ;get relative horizontal coordinate
13449          sta Sprite_X_Position,y
13450          sta Sprite_X_Position+4,y   ;store as X coordinate for first and second sprites
13451          lda FrameCounter            ;get frame counter
13452          lsr                         ;divide by 2 to alter every other frame
13453          and #%00000011              ;mask out d2-d1
13454          tax                         ;use as graphical offset
13455          lda JumpingCoinTiles,x      ;load tile number
13456          iny                         ;increment OAM data offset to write tile numbers
13457          jsr DumpTwoSpr              ;do sub to dump tile number into both sprites
13458          dey                         ;decrement to get old offset
13459          lda #$02
13460          sta Sprite_Attributes,y     ;set attribute byte in first sprite
13461          lda #$82
13462          sta Sprite_Attributes+4,y   ;set attribute byte with vertical flip in second sprite
13463          ldx ObjectOffset            ;get misc object offset
13464 ExJCGfx: rts                         ;leave
13465 
13466 ;-------------------------------------------------------------------------------------
13467 ;$00-$01 - used to hold tiles for drawing the power-up, $00 also used to hold power-up type
13468 ;$02 - used to hold bottom row Y position
13469 ;$03 - used to hold flip control (not used here)
13470 ;$04 - used to hold sprite attributes
13471 ;$05 - used to hold X position
13472 ;$07 - counter
13473 
13474 ;tiles arranged in top left, right, bottom left, right order
13475 PowerUpGfxTable:
13476       .db $76, $77, $78, $79 ;regular mushroom
13477       .db $d6, $d6, $d9, $d9 ;fire flower
13478       .db $8d, $8d, $e4, $e4 ;star
13479       .db $76, $77, $78, $79 ;1-up mushroom
13480 
13481 PowerUpAttributes:
13482       .db $02, $01, $02, $01
13483 
13484 DrawPowerUp:
13485       ldy Enemy_SprDataOffset+5  ;get power-up's sprite data offset
13486       lda Enemy_Rel_YPos         ;get relative vertical coordinate
13487       clc
13488       adc #$08                   ;add eight pixels
13489       sta $02                    ;store result here
13490       lda Enemy_Rel_XPos         ;get relative horizontal coordinate
13491       sta $05                    ;store here
13492       ldx PowerUpType            ;get power-up type
13493       lda PowerUpAttributes,x    ;get attribute data for power-up type
13494       ora Enemy_SprAttrib+5      ;add background priority bit if set
13495       sta $04                    ;store attributes here
13496       txa
13497       pha                        ;save power-up type to the stack
13498       asl
13499       asl                        ;multiply by four to get proper offset
13500       tax                        ;use as X
13501       lda #$01
13502       sta $07                    ;set counter here to draw two rows of sprite object
13503       sta $03                    ;init d1 of flip control
13504 
13505 PUpDrawLoop:
13506         lda PowerUpGfxTable,x      ;load left tile of power-up object
13507         sta $00
13508         lda PowerUpGfxTable+1,x    ;load right tile
13509         jsr DrawOneSpriteRow       ;branch to draw one row of our power-up object
13510         dec $07                    ;decrement counter
13511         bpl PUpDrawLoop            ;branch until two rows are drawn
13512         ldy Enemy_SprDataOffset+5  ;get sprite data offset again
13513         pla                        ;pull saved power-up type from the stack
13514         beq PUpOfs                 ;if regular mushroom, branch, do not change colors or flip
13515         cmp #$03
13516         beq PUpOfs                 ;if 1-up mushroom, branch, do not change colors or flip
13517         sta $00                    ;store power-up type here now
13518         lda FrameCounter           ;get frame counter
13519         lsr                        ;divide by 2 to change colors every two frames
13520         and #%00000011             ;mask out all but d1 and d0 (previously d2 and d1)
13521         ora Enemy_SprAttrib+5      ;add background priority bit if any set
13522         sta Sprite_Attributes,y    ;set as new palette bits for top left and
13523         sta Sprite_Attributes+4,y  ;top right sprites for fire flower and star
13524         ldx $00
13525         dex                        ;check power-up type for fire flower
13526         beq FlipPUpRightSide       ;if found, skip this part
13527         sta Sprite_Attributes+8,y  ;otherwise set new palette bits  for bottom left
13528         sta Sprite_Attributes+12,y ;and bottom right sprites as well for star only
13529 
13530 FlipPUpRightSide:
13531         lda Sprite_Attributes+4,y
13532         ora #%01000000             ;set horizontal flip bit for top right sprite
13533         sta Sprite_Attributes+4,y
13534         lda Sprite_Attributes+12,y
13535         ora #%01000000             ;set horizontal flip bit for bottom right sprite
13536         sta Sprite_Attributes+12,y ;note these are only done for fire flower and star power-ups
13537 PUpOfs: jmp SprObjectOffscrChk     ;jump to check to see if power-up is offscreen at all, then leave
13538 
13539 ;-------------------------------------------------------------------------------------
13540 ;$00-$01 - used in DrawEnemyObjRow to hold sprite tile numbers
13541 ;$02 - used to store Y position
13542 ;$03 - used to store moving direction, used to flip enemies horizontally
13543 ;$04 - used to store enemy's sprite attributes
13544 ;$05 - used to store X position
13545 ;$eb - used to hold sprite data offset
13546 ;$ec - used to hold either altered enemy state or special value used in gfx handler as condition
13547 ;$ed - used to hold enemy state from buffer 
13548 ;$ef - used to hold enemy code used in gfx handler (may or may not resemble Enemy_ID values)
13549 
13550 ;tiles arranged in top left, right, middle left, right, bottom left, right order
13551 EnemyGraphicsTable:
13552       .db $fc, $fc, $aa, $ab, $ac, $ad  ;buzzy beetle frame 1
13553       .db $fc, $fc, $ae, $af, $b0, $b1  ;             frame 2
13554       .db $fc, $a5, $a6, $a7, $a8, $a9  ;koopa troopa frame 1
13555       .db $fc, $a0, $a1, $a2, $a3, $a4  ;             frame 2
13556       .db $69, $a5, $6a, $a7, $a8, $a9  ;koopa paratroopa frame 1
13557       .db $6b, $a0, $6c, $a2, $a3, $a4  ;                 frame 2
13558       .db $fc, $fc, $96, $97, $98, $99  ;spiny frame 1
13559       .db $fc, $fc, $9a, $9b, $9c, $9d  ;      frame 2
13560       .db $fc, $fc, $8f, $8e, $8e, $8f  ;spiny's egg frame 1
13561       .db $fc, $fc, $95, $94, $94, $95  ;            frame 2
13562       .db $fc, $fc, $dc, $dc, $df, $df  ;bloober frame 1
13563       .db $dc, $dc, $dd, $dd, $de, $de  ;        frame 2
13564       .db $fc, $fc, $b2, $b3, $b4, $b5  ;cheep-cheep frame 1
13565       .db $fc, $fc, $b6, $b3, $b7, $b5  ;            frame 2
13566       .db $fc, $fc, $70, $71, $72, $73  ;goomba
13567       .db $fc, $fc, $6e, $6e, $6f, $6f  ;koopa shell frame 1 (upside-down)
13568       .db $fc, $fc, $6d, $6d, $6f, $6f  ;            frame 2
13569       .db $fc, $fc, $6f, $6f, $6e, $6e  ;koopa shell frame 1 (rightsideup)
13570       .db $fc, $fc, $6f, $6f, $6d, $6d  ;            frame 2
13571       .db $fc, $fc, $f4, $f4, $f5, $f5  ;buzzy beetle shell frame 1 (rightsideup)
13572       .db $fc, $fc, $f4, $f4, $f5, $f5  ;                   frame 2
13573       .db $fc, $fc, $f5, $f5, $f4, $f4  ;buzzy beetle shell frame 1 (upside-down)
13574       .db $fc, $fc, $f5, $f5, $f4, $f4  ;                   frame 2
13575       .db $fc, $fc, $fc, $fc, $ef, $ef  ;defeated goomba
13576       .db $b9, $b8, $bb, $ba, $bc, $bc  ;lakitu frame 1
13577       .db $fc, $fc, $bd, $bd, $bc, $bc  ;       frame 2
13578       .db $7a, $7b, $da, $db, $d8, $d8  ;princess
13579       .db $cd, $cd, $ce, $ce, $cf, $cf  ;mushroom retainer
13580       .db $7d, $7c, $d1, $8c, $d3, $d2  ;hammer bro frame 1
13581       .db $7d, $7c, $89, $88, $8b, $8a  ;           frame 2
13582       .db $d5, $d4, $e3, $e2, $d3, $d2  ;           frame 3
13583       .db $d5, $d4, $e3, $e2, $8b, $8a  ;           frame 4
13584       .db $e5, $e5, $e6, $e6, $eb, $eb  ;piranha plant frame 1
13585       .db $ec, $ec, $ed, $ed, $ee, $ee  ;              frame 2
13586       .db $fc, $fc, $d0, $d0, $d7, $d7  ;podoboo
13587       .db $bf, $be, $c1, $c0, $c2, $fc  ;bowser front frame 1
13588       .db $c4, $c3, $c6, $c5, $c8, $c7  ;bowser rear frame 1
13589       .db $bf, $be, $ca, $c9, $c2, $fc  ;       front frame 2
13590       .db $c4, $c3, $c6, $c5, $cc, $cb  ;       rear frame 2
13591       .db $fc, $fc, $e8, $e7, $ea, $e9  ;bullet bill
13592       .db $f2, $f2, $f3, $f3, $f2, $f2  ;jumpspring frame 1
13593       .db $f1, $f1, $f1, $f1, $fc, $fc  ;           frame 2
13594       .db $f0, $f0, $fc, $fc, $fc, $fc  ;           frame 3
13595 
13596 EnemyGfxTableOffsets:
13597       .db $0c, $0c, $00, $0c, $0c, $a8, $54, $3c
13598       .db $ea, $18, $48, $48, $cc, $c0, $18, $18
13599       .db $18, $90, $24, $ff, $48, $9c, $d2, $d8
13600       .db $f0, $f6, $fc
13601 
13602 EnemyAttributeData:
13603       .db $01, $02, $03, $02, $01, $01, $03, $03
13604       .db $03, $01, $01, $02, $02, $21, $01, $02
13605       .db $01, $01, $02, $ff, $02, $02, $01, $01
13606       .db $02, $02, $02
13607 
13608 EnemyAnimTimingBMask:
13609       .db $08, $18
13610 
13611 JumpspringFrameOffsets:
13612       .db $18, $19, $1a, $19, $18
13613 
13614 EnemyGfxHandler:
13615       lda Enemy_Y_Position,x      ;get enemy object vertical position
13616       sta $02
13617       lda Enemy_Rel_XPos          ;get enemy object horizontal position
13618       sta $05                     ;relative to screen
13619       ldy Enemy_SprDataOffset,x
13620       sty $eb                     ;get sprite data offset
13621       lda #$00
13622       sta VerticalFlipFlag        ;initialize vertical flip flag by default
13623       lda Enemy_MovingDir,x
13624       sta $03                     ;get enemy object moving direction
13625       lda Enemy_SprAttrib,x
13626       sta $04                     ;get enemy object sprite attributes
13627       lda Enemy_ID,x
13628       cmp #PiranhaPlant           ;is enemy object piranha plant?
13629       bne CheckForRetainerObj     ;if not, branch
13630       ldy PiranhaPlant_Y_Speed,x
13631       bmi CheckForRetainerObj     ;if piranha plant moving upwards, branch
13632       ldy EnemyFrameTimer,x
13633       beq CheckForRetainerObj     ;if timer for movement expired, branch
13634       rts                         ;if all conditions fail, leave
13635 
13636 CheckForRetainerObj:
13637       lda Enemy_State,x           ;store enemy state
13638       sta $ed
13639       and #%00011111              ;nullify all but 5 LSB and use as Y
13640       tay
13641       lda Enemy_ID,x              ;check for mushroom retainer/princess object
13642       cmp #RetainerObject
13643       bne CheckForBulletBillCV    ;if not found, branch
13644       ldy #$00                    ;if found, nullify saved state in Y
13645       lda #$01                    ;set value that will not be used
13646       sta $03
13647       lda #$15                    ;set value $15 as code for mushroom retainer/princess object
13648 
13649 CheckForBulletBillCV:
13650        cmp #BulletBill_CannonVar   ;otherwise check for bullet bill object
13651        bne CheckForJumpspring      ;if not found, branch again
13652        dec $02                     ;decrement saved vertical position
13653        lda #$03
13654        ldy EnemyFrameTimer,x       ;get timer for enemy object
13655        beq SBBAt                   ;if expired, do not set priority bit
13656        ora #%00100000              ;otherwise do so
13657 SBBAt: sta $04                     ;set new sprite attributes
13658        ldy #$00                    ;nullify saved enemy state both in Y and in
13659        sty $ed                     ;memory location here
13660        lda #$08                    ;set specific value to unconditionally branch once
13661 
13662 CheckForJumpspring:
13663       cmp #JumpspringObject        ;check for jumpspring object
13664       bne CheckForPodoboo
13665       ldy #$03                     ;set enemy state -2 MSB here for jumpspring object
13666       ldx JumpspringAnimCtrl       ;get current frame number for jumpspring object
13667       lda JumpspringFrameOffsets,x ;load data using frame number as offset
13668 
13669 CheckForPodoboo:
13670       sta $ef                 ;store saved enemy object value here
13671       sty $ec                 ;and Y here (enemy state -2 MSB if not changed)
13672       ldx ObjectOffset        ;get enemy object offset
13673       cmp #$0c                ;check for podoboo object
13674       bne CheckBowserGfxFlag  ;branch if not found
13675       lda Enemy_Y_Speed,x     ;if moving upwards, branch
13676       bmi CheckBowserGfxFlag
13677       inc VerticalFlipFlag    ;otherwise, set flag for vertical flip
13678 
13679 CheckBowserGfxFlag:
13680              lda BowserGfxFlag   ;if not drawing bowser at all, skip to something else
13681              beq CheckForGoomba
13682              ldy #$16            ;if set to 1, draw bowser's front
13683              cmp #$01
13684              beq SBwsrGfxOfs
13685              iny                 ;otherwise draw bowser's rear
13686 SBwsrGfxOfs: sty $ef
13687 
13688 CheckForGoomba:
13689           ldy $ef               ;check value for goomba object
13690           cpy #Goomba
13691           bne CheckBowserFront  ;branch if not found
13692           lda Enemy_State,x
13693           cmp #$02              ;check for defeated state
13694           bcc GmbaAnim          ;if not defeated, go ahead and animate
13695           ldx #$04              ;if defeated, write new value here
13696           stx $ec
13697 GmbaAnim: and #%00100000        ;check for d5 set in enemy object state 
13698           ora TimerControl      ;or timer disable flag set
13699           bne CheckBowserFront  ;if either condition true, do not animate goomba
13700           lda FrameCounter
13701           and #%00001000        ;check for every eighth frame
13702           bne CheckBowserFront
13703           lda $03
13704           eor #%00000011        ;invert bits to flip horizontally every eight frames
13705           sta $03               ;leave alone otherwise
13706 
13707 CheckBowserFront:
13708              lda EnemyAttributeData,y    ;load sprite attribute using enemy object
13709              ora $04                     ;as offset, and add to bits already loaded
13710              sta $04
13711              lda EnemyGfxTableOffsets,y  ;load value based on enemy object as offset
13712              tax                         ;save as X
13713              ldy $ec                     ;get previously saved value
13714              lda BowserGfxFlag
13715              beq CheckForSpiny           ;if not drawing bowser object at all, skip all of this
13716              cmp #$01
13717              bne CheckBowserRear         ;if not drawing front part, branch to draw the rear part
13718              lda BowserBodyControls      ;check bowser's body control bits
13719              bpl ChkFrontSte             ;branch if d7 not set (control's bowser's mouth)      
13720              ldx #$de                    ;otherwise load offset for second frame
13721 ChkFrontSte: lda $ed                     ;check saved enemy state
13722              and #%00100000              ;if bowser not defeated, do not set flag
13723              beq DrawBowser
13724 
13725 FlipBowserOver:
13726       stx VerticalFlipFlag  ;set vertical flip flag to nonzero
13727 
13728 DrawBowser:
13729       jmp DrawEnemyObject   ;draw bowser's graphics now
13730 
13731 CheckBowserRear:
13732             lda BowserBodyControls  ;check bowser's body control bits
13733             and #$01
13734             beq ChkRearSte          ;branch if d0 not set (control's bowser's feet)
13735             ldx #$e4                ;otherwise load offset for second frame
13736 ChkRearSte: lda $ed                 ;check saved enemy state
13737             and #%00100000          ;if bowser not defeated, do not set flag
13738             beq DrawBowser
13739             lda $02                 ;subtract 16 pixels from
13740             sec                     ;saved vertical coordinate
13741             sbc #$10
13742             sta $02
13743             jmp FlipBowserOver      ;jump to set vertical flip flag
13744 
13745 CheckForSpiny:
13746         cpx #$24               ;check if value loaded is for spiny
13747         bne CheckForLakitu     ;if not found, branch
13748         cpy #$05               ;if enemy state set to $05, do this,
13749         bne NotEgg             ;otherwise branch
13750         ldx #$30               ;set to spiny egg offset
13751         lda #$02
13752         sta $03                ;set enemy direction to reverse sprites horizontally
13753         lda #$05
13754         sta $ec                ;set enemy state
13755 NotEgg: jmp CheckForHammerBro  ;skip a big chunk of this if we found spiny but not in egg
13756 
13757 CheckForLakitu:
13758         cpx #$90                  ;check value for lakitu's offset loaded
13759         bne CheckUpsideDownShell  ;branch if not loaded
13760         lda $ed
13761         and #%00100000            ;check for d5 set in enemy state
13762         bne NoLAFr                ;branch if set
13763         lda FrenzyEnemyTimer
13764         cmp #$10                  ;check timer to see if we've reached a certain range
13765         bcs NoLAFr                ;branch if not
13766         ldx #$96                  ;if d6 not set and timer in range, load alt frame for lakitu
13767 NoLAFr: jmp CheckDefeatedState    ;skip this next part if we found lakitu but alt frame not needed
13768 
13769 CheckUpsideDownShell:
13770       lda $ef                    ;check for enemy object => $04
13771       cmp #$04
13772       bcs CheckRightSideUpShell  ;branch if true
13773       cpy #$02
13774       bcc CheckRightSideUpShell  ;branch if enemy state < $02
13775       ldx #$5a                   ;set for upside-down koopa shell by default
13776       ldy $ef
13777       cpy #BuzzyBeetle           ;check for buzzy beetle object
13778       bne CheckRightSideUpShell
13779       ldx #$7e                   ;set for upside-down buzzy beetle shell if found
13780       inc $02                    ;increment vertical position by one pixel
13781 
13782 CheckRightSideUpShell:
13783       lda $ec                ;check for value set here
13784       cmp #$04               ;if enemy state < $02, do not change to shell, if
13785       bne CheckForHammerBro  ;enemy state => $02 but not = $04, leave shell upside-down
13786       ldx #$72               ;set right-side up buzzy beetle shell by default
13787       inc $02                ;increment saved vertical position by one pixel
13788       ldy $ef
13789       cpy #BuzzyBeetle       ;check for buzzy beetle object
13790       beq CheckForDefdGoomba ;branch if found
13791       ldx #$66               ;change to right-side up koopa shell if not found
13792       inc $02                ;and increment saved vertical position again
13793 
13794 CheckForDefdGoomba:
13795       cpy #Goomba            ;check for goomba object (necessary if previously
13796       bne CheckForHammerBro  ;failed buzzy beetle object test)
13797       ldx #$54               ;load for regular goomba
13798       lda $ed                ;note that this only gets performed if enemy state => $02
13799       and #%00100000         ;check saved enemy state for d5 set
13800       bne CheckForHammerBro  ;branch if set
13801       ldx #$8a               ;load offset for defeated goomba
13802       dec $02                ;set different value and decrement saved vertical position
13803 
13804 CheckForHammerBro:
13805       ldy ObjectOffset
13806       lda $ef                  ;check for hammer bro object
13807       cmp #HammerBro
13808       bne CheckForBloober      ;branch if not found
13809       lda $ed
13810       beq CheckToAnimateEnemy  ;branch if not in normal enemy state
13811       and #%00001000
13812       beq CheckDefeatedState   ;if d3 not set, branch further away
13813       ldx #$b4                 ;otherwise load offset for different frame
13814       bne CheckToAnimateEnemy  ;unconditional branch
13815 
13816 CheckForBloober:
13817       cpx #$48                 ;check for cheep-cheep offset loaded
13818       beq CheckToAnimateEnemy  ;branch if found
13819       lda EnemyIntervalTimer,y
13820       cmp #$05
13821       bcs CheckDefeatedState   ;branch if some timer is above a certain point
13822       cpx #$3c                 ;check for bloober offset loaded
13823       bne CheckToAnimateEnemy  ;branch if not found this time
13824       cmp #$01
13825       beq CheckDefeatedState   ;branch if timer is set to certain point
13826       inc $02                  ;increment saved vertical coordinate three pixels
13827       inc $02
13828       inc $02
13829       jmp CheckAnimationStop   ;and do something else
13830 
13831 CheckToAnimateEnemy:
13832       lda $ef                  ;check for specific enemy objects
13833       cmp #Goomba
13834       beq CheckDefeatedState   ;branch if goomba
13835       cmp #$08
13836       beq CheckDefeatedState   ;branch if bullet bill (note both variants use $08 here)
13837       cmp #Podoboo
13838       beq CheckDefeatedState   ;branch if podoboo
13839       cmp #$18                 ;branch if => $18
13840       bcs CheckDefeatedState
13841       ldy #$00    
13842       cmp #$15                 ;check for mushroom retainer/princess object
13843       bne CheckForSecondFrame  ;which uses different code here, branch if not found
13844       iny                      ;residual instruction
13845       lda WorldNumber          ;are we on world 8?
13846       cmp #World8
13847       bcs CheckDefeatedState   ;if so, leave the offset alone (use princess)
13848       ldx #$a2                 ;otherwise, set for mushroom retainer object instead
13849       lda #$03                 ;set alternate state here
13850       sta $ec
13851       bne CheckDefeatedState   ;unconditional branch
13852 
13853 CheckForSecondFrame:
13854       lda FrameCounter            ;load frame counter
13855       and EnemyAnimTimingBMask,y  ;mask it (partly residual, one byte not ever used)
13856       bne CheckDefeatedState      ;branch if timing is off
13857 
13858 CheckAnimationStop:
13859       lda $ed                 ;check saved enemy state
13860       and #%10100000          ;for d7 or d5, or check for timers stopped
13861       ora TimerControl
13862       bne CheckDefeatedState  ;if either condition true, branch
13863       txa
13864       clc
13865       adc #$06                ;add $06 to current enemy offset
13866       tax                     ;to animate various enemy objects
13867 
13868 CheckDefeatedState:
13869       lda $ed               ;check saved enemy state
13870       and #%00100000        ;for d5 set
13871       beq DrawEnemyObject   ;branch if not set
13872       lda $ef
13873       cmp #$04              ;check for saved enemy object => $04
13874       bcc DrawEnemyObject   ;branch if less
13875       ldy #$01
13876       sty VerticalFlipFlag  ;set vertical flip flag
13877       dey
13878       sty $ec               ;init saved value here
13879 
13880 DrawEnemyObject:
13881       ldy $eb                    ;load sprite data offset
13882       jsr DrawEnemyObjRow        ;draw six tiles of data
13883       jsr DrawEnemyObjRow        ;into sprite data
13884       jsr DrawEnemyObjRow
13885       ldx ObjectOffset           ;get enemy object offset
13886       ldy Enemy_SprDataOffset,x  ;get sprite data offset
13887       lda $ef
13888       cmp #$08                   ;get saved enemy object and check
13889       bne CheckForVerticalFlip   ;for bullet bill, branch if not found
13890 
13891 SkipToOffScrChk:
13892       jmp SprObjectOffscrChk     ;jump if found
13893 
13894 CheckForVerticalFlip:
13895       lda VerticalFlipFlag       ;check if vertical flip flag is set here
13896       beq CheckForESymmetry      ;branch if not
13897       lda Sprite_Attributes,y    ;get attributes of first sprite we dealt with
13898       ora #%10000000             ;set bit for vertical flip
13899       iny
13900       iny                        ;increment two bytes so that we store the vertical flip
13901       jsr DumpSixSpr             ;in attribute bytes of enemy obj sprite data
13902       dey
13903       dey                        ;now go back to the Y coordinate offset
13904       tya
13905       tax                        ;give offset to X
13906       lda $ef
13907       cmp #HammerBro             ;check saved enemy object for hammer bro
13908       beq FlipEnemyVertically
13909       cmp #Lakitu                ;check saved enemy object for lakitu
13910       beq FlipEnemyVertically    ;branch for hammer bro or lakitu
13911       cmp #$15
13912       bcs FlipEnemyVertically    ;also branch if enemy object => $15
13913       txa
13914       clc
13915       adc #$08                   ;if not selected objects or => $15, set
13916       tax                        ;offset in X for next row
13917 
13918 FlipEnemyVertically:
13919       lda Sprite_Tilenumber,x     ;load first or second row tiles
13920       pha                         ;and save tiles to the stack
13921       lda Sprite_Tilenumber+4,x
13922       pha
13923       lda Sprite_Tilenumber+16,y  ;exchange third row tiles
13924       sta Sprite_Tilenumber,x     ;with first or second row tiles
13925       lda Sprite_Tilenumber+20,y
13926       sta Sprite_Tilenumber+4,x
13927       pla                         ;pull first or second row tiles from stack
13928       sta Sprite_Tilenumber+20,y  ;and save in third row
13929       pla
13930       sta Sprite_Tilenumber+16,y
13931 
13932 CheckForESymmetry:
13933         lda BowserGfxFlag           ;are we drawing bowser at all?
13934         bne SkipToOffScrChk         ;branch if so
13935         lda $ef       
13936         ldx $ec                     ;get alternate enemy state
13937         cmp #$05                    ;check for hammer bro object
13938         bne ContES
13939         jmp SprObjectOffscrChk      ;jump if found
13940 ContES: cmp #Bloober                ;check for bloober object
13941         beq MirrorEnemyGfx
13942         cmp #PiranhaPlant           ;check for piranha plant object
13943         beq MirrorEnemyGfx
13944         cmp #Podoboo                ;check for podoboo object
13945         beq MirrorEnemyGfx          ;branch if either of three are found
13946         cmp #Spiny                  ;check for spiny object
13947         bne ESRtnr                  ;branch closer if not found
13948         cpx #$05                    ;check spiny's state
13949         bne CheckToMirrorLakitu     ;branch if not an egg, otherwise
13950 ESRtnr: cmp #$15                    ;check for princess/mushroom retainer object
13951         bne SpnySC
13952         lda #$42                    ;set horizontal flip on bottom right sprite
13953         sta Sprite_Attributes+20,y  ;note that palette bits were already set earlier
13954 SpnySC: cpx #$02                    ;if alternate enemy state set to 1 or 0, branch
13955         bcc CheckToMirrorLakitu
13956 
13957 MirrorEnemyGfx:
13958         lda BowserGfxFlag           ;if enemy object is bowser, skip all of this
13959         bne CheckToMirrorLakitu
13960         lda Sprite_Attributes,y     ;load attribute bits of first sprite
13961         and #%10100011
13962         sta Sprite_Attributes,y     ;save vertical flip, priority, and palette bits
13963         sta Sprite_Attributes+8,y   ;in left sprite column of enemy object OAM data
13964         sta Sprite_Attributes+16,y
13965         ora #%01000000              ;set horizontal flip
13966         cpx #$05                    ;check for state used by spiny's egg
13967         bne EggExc                  ;if alternate state not set to $05, branch
13968         ora #%10000000              ;otherwise set vertical flip
13969 EggExc: sta Sprite_Attributes+4,y   ;set bits of right sprite column
13970         sta Sprite_Attributes+12,y  ;of enemy object sprite data
13971         sta Sprite_Attributes+20,y
13972         cpx #$04                    ;check alternate enemy state
13973         bne CheckToMirrorLakitu     ;branch if not $04
13974         lda Sprite_Attributes+8,y   ;get second row left sprite attributes
13975         ora #%10000000
13976         sta Sprite_Attributes+8,y   ;store bits with vertical flip in
13977         sta Sprite_Attributes+16,y  ;second and third row left sprites
13978         ora #%01000000
13979         sta Sprite_Attributes+12,y  ;store with horizontal and vertical flip in
13980         sta Sprite_Attributes+20,y  ;second and third row right sprites
13981 
13982 CheckToMirrorLakitu:
13983         lda $ef                     ;check for lakitu enemy object
13984         cmp #Lakitu
13985         bne CheckToMirrorJSpring    ;branch if not found
13986         lda VerticalFlipFlag
13987         bne NVFLak                  ;branch if vertical flip flag not set
13988         lda Sprite_Attributes+16,y  ;save vertical flip and palette bits
13989         and #%10000001              ;in third row left sprite
13990         sta Sprite_Attributes+16,y
13991         lda Sprite_Attributes+20,y  ;set horizontal flip and palette bits
13992         ora #%01000001              ;in third row right sprite
13993         sta Sprite_Attributes+20,y
13994         ldx FrenzyEnemyTimer        ;check timer
13995         cpx #$10
13996         bcs SprObjectOffscrChk      ;branch if timer has not reached a certain range
13997         sta Sprite_Attributes+12,y  ;otherwise set same for second row right sprite
13998         and #%10000001
13999         sta Sprite_Attributes+8,y   ;preserve vertical flip and palette bits for left sprite
14000         bcc SprObjectOffscrChk      ;unconditional branch
14001 NVFLak: lda Sprite_Attributes,y     ;get first row left sprite attributes
14002         and #%10000001
14003         sta Sprite_Attributes,y     ;save vertical flip and palette bits
14004         lda Sprite_Attributes+4,y   ;get first row right sprite attributes
14005         ora #%01000001              ;set horizontal flip and palette bits
14006         sta Sprite_Attributes+4,y   ;note that vertical flip is left as-is
14007 
14008 CheckToMirrorJSpring:
14009       lda $ef                     ;check for jumpspring object (any frame)
14010       cmp #$18
14011       bcc SprObjectOffscrChk      ;branch if not jumpspring object at all
14012       lda #$82
14013       sta Sprite_Attributes+8,y   ;set vertical flip and palette bits of 
14014       sta Sprite_Attributes+16,y  ;second and third row left sprites
14015       ora #%01000000
14016       sta Sprite_Attributes+12,y  ;set, in addition to those, horizontal flip
14017       sta Sprite_Attributes+20,y  ;for second and third row right sprites
14018 
14019 SprObjectOffscrChk:
14020          ldx ObjectOffset          ;get enemy buffer offset
14021          lda Enemy_OffscreenBits   ;check offscreen information
14022          lsr
14023          lsr                       ;shift three times to the right
14024          lsr                       ;which puts d2 into carry
14025          pha                       ;save to stack
14026          bcc LcChk                 ;branch if not set
14027          lda #$04                  ;set for right column sprites
14028          jsr MoveESprColOffscreen  ;and move them offscreen
14029 LcChk:   pla                       ;get from stack
14030          lsr                       ;move d3 to carry
14031          pha                       ;save to stack
14032          bcc Row3C                 ;branch if not set
14033          lda #$00                  ;set for left column sprites,
14034          jsr MoveESprColOffscreen  ;move them offscreen
14035 Row3C:   pla                       ;get from stack again
14036          lsr                       ;move d5 to carry this time
14037          lsr
14038          pha                       ;save to stack again
14039          bcc Row23C                ;branch if carry not set
14040          lda #$10                  ;set for third row of sprites
14041          jsr MoveESprRowOffscreen  ;and move them offscreen
14042 Row23C:  pla                       ;get from stack
14043          lsr                       ;move d6 into carry
14044          pha                       ;save to stack
14045          bcc AllRowC
14046          lda #$08                  ;set for second and third rows
14047          jsr MoveESprRowOffscreen  ;move them offscreen
14048 AllRowC: pla                       ;get from stack once more
14049          lsr                       ;move d7 into carry
14050          bcc ExEGHandler
14051          jsr MoveESprRowOffscreen  ;move all sprites offscreen (A should be 0 by now)
14052          lda Enemy_ID,x
14053          cmp #Podoboo              ;check enemy identifier for podoboo
14054          beq ExEGHandler           ;skip this part if found, we do not want to erase podoboo!
14055          lda Enemy_Y_HighPos,x     ;check high byte of vertical position
14056          cmp #$02                  ;if not yet past the bottom of the screen, branch
14057          bne ExEGHandler
14058          jsr EraseEnemyObject      ;what it says
14059 
14060 ExEGHandler:
14061       rts
14062 
14063 DrawEnemyObjRow:
14064       lda EnemyGraphicsTable,x    ;load two tiles of enemy graphics
14065       sta $00
14066       lda EnemyGraphicsTable+1,x
14067 
14068 DrawOneSpriteRow:
14069       sta $01
14070       jmp DrawSpriteObject        ;draw them
14071 
14072 MoveESprRowOffscreen:
14073       clc                         ;add A to enemy object OAM data offset
14074       adc Enemy_SprDataOffset,x
14075       tay                         ;use as offset
14076       lda #$f8
14077       jmp DumpTwoSpr              ;move first row of sprites offscreen
14078 
14079 MoveESprColOffscreen:
14080       clc                         ;add A to enemy object OAM data offset
14081       adc Enemy_SprDataOffset,x
14082       tay                         ;use as offset
14083       jsr MoveColOffscreen        ;move first and second row sprites in column offscreen
14084       sta Sprite_Data+16,y        ;move third row sprite in column offscreen
14085       rts
14086 
14087 ;-------------------------------------------------------------------------------------
14088 ;$00-$01 - tile numbers
14089 ;$02 - relative Y position
14090 ;$03 - horizontal flip flag (not used here)
14091 ;$04 - attributes
14092 ;$05 - relative X position
14093 
14094 DefaultBlockObjTiles:
14095       .db $85, $85, $86, $86             ;brick w/ line (these are sprite tiles, not BG!)
14096 
14097 DrawBlock:
14098            lda Block_Rel_YPos            ;get relative vertical coordinate of block object
14099            sta $02                       ;store here
14100            lda Block_Rel_XPos            ;get relative horizontal coordinate of block object
14101            sta $05                       ;store here
14102            lda #$03
14103            sta $04                       ;set attribute byte here
14104            lsr
14105            sta $03                       ;set horizontal flip bit here (will not be used)
14106            ldy Block_SprDataOffset,x     ;get sprite data offset
14107            ldx #$00                      ;reset X for use as offset to tile data
14108 DBlkLoop:  lda DefaultBlockObjTiles,x    ;get left tile number
14109            sta $00                       ;set here
14110            lda DefaultBlockObjTiles+1,x  ;get right tile number
14111            jsr DrawOneSpriteRow          ;do sub to write tile numbers to first row of sprites
14112            cpx #$04                      ;check incremented offset
14113            bne DBlkLoop                  ;and loop back until all four sprites are done
14114            ldx ObjectOffset              ;get block object offset
14115            ldy Block_SprDataOffset,x     ;get sprite data offset
14116            lda AreaType
14117            cmp #$01                      ;check for ground level type area
14118            beq ChkRep                    ;if found, branch to next part
14119            lda #$86
14120            sta Sprite_Tilenumber,y       ;otherwise remove brick tiles with lines
14121            sta Sprite_Tilenumber+4,y     ;and replace then with lineless brick tiles
14122 ChkRep:    lda Block_Metatile,x          ;check replacement metatile
14123            cmp #$c4                      ;if not used block metatile, then
14124            bne BlkOffscr                 ;branch ahead to use current graphics
14125            lda #$87                      ;set A for used block tile
14126            iny                           ;increment Y to write to tile bytes
14127            jsr DumpFourSpr               ;do sub to dump into all four sprites
14128            dey                           ;return Y to original offset
14129            lda #$03                      ;set palette bits
14130            ldx AreaType
14131            dex                           ;check for ground level type area again
14132            beq SetBFlip                  ;if found, use current palette bits
14133            lsr                           ;otherwise set to $01
14134 SetBFlip:  ldx ObjectOffset              ;put block object offset back in X
14135            sta Sprite_Attributes,y       ;store attribute byte as-is in first sprite
14136            ora #%01000000
14137            sta Sprite_Attributes+4,y     ;set horizontal flip bit for second sprite
14138            ora #%10000000
14139            sta Sprite_Attributes+12,y    ;set both flip bits for fourth sprite
14140            and #%10000011
14141            sta Sprite_Attributes+8,y     ;set vertical flip bit for third sprite
14142 BlkOffscr: lda Block_OffscreenBits       ;get offscreen bits for block object
14143            pha                           ;save to stack
14144            and #%00000100                ;check to see if d2 in offscreen bits are set
14145            beq PullOfsB                  ;if not set, branch, otherwise move sprites offscreen
14146            lda #$f8                      ;move offscreen two OAMs
14147            sta Sprite_Y_Position+4,y     ;on the right side
14148            sta Sprite_Y_Position+12,y
14149 PullOfsB:  pla                           ;pull offscreen bits from stack
14150 ChkLeftCo: and #%00001000                ;check to see if d3 in offscreen bits are set
14151            beq ExDBlk                    ;if not set, branch, otherwise move sprites offscreen
14152 
14153 MoveColOffscreen:
14154         lda #$f8                   ;move offscreen two OAMs
14155         sta Sprite_Y_Position,y    ;on the left side (or two rows of enemy on either side
14156         sta Sprite_Y_Position+8,y  ;if branched here from enemy graphics handler)
14157 ExDBlk: rts
14158 
14159 ;-------------------------------------------------------------------------------------
14160 ;$00 - used to hold palette bits for attribute byte or relative X position
14161 
14162 DrawBrickChunks:
14163          lda #$02                   ;set palette bits here
14164          sta $00
14165          lda #$75                   ;set tile number for ball (something residual, likely)
14166          ldy GameEngineSubroutine
14167          cpy #$05                   ;if end-of-level routine running,
14168          beq DChunks                ;use palette and tile number assigned
14169          lda #$03                   ;otherwise set different palette bits
14170          sta $00
14171          lda #$84                   ;and set tile number for brick chunks
14172 DChunks: ldy Block_SprDataOffset,x  ;get OAM data offset
14173          iny                        ;increment to start with tile bytes in OAM
14174          jsr DumpFourSpr            ;do sub to dump tile number into all four sprites
14175          lda FrameCounter           ;get frame counter
14176          asl
14177          asl
14178          asl                        ;move low nybble to high
14179          asl
14180          and #$c0                   ;get what was originally d3-d2 of low nybble
14181          ora $00                    ;add palette bits
14182          iny                        ;increment offset for attribute bytes
14183          jsr DumpFourSpr            ;do sub to dump attribute data into all four sprites
14184          dey
14185          dey                        ;decrement offset to Y coordinate
14186          lda Block_Rel_YPos         ;get first block object's relative vertical coordinate
14187          jsr DumpTwoSpr             ;do sub to dump current Y coordinate into two sprites
14188          lda Block_Rel_XPos         ;get first block object's relative horizontal coordinate
14189          sta Sprite_X_Position,y    ;save into X coordinate of first sprite
14190          lda Block_Orig_XPos,x      ;get original horizontal coordinate
14191          sec
14192          sbc ScreenLeft_X_Pos       ;subtract coordinate of left side from original coordinate
14193          sta $00                    ;store result as relative horizontal coordinate of original
14194          sec
14195          sbc Block_Rel_XPos         ;get difference of relative positions of original - current
14196          adc $00                    ;add original relative position to result
14197          adc #$06                   ;plus 6 pixels to position second brick chunk correctly
14198          sta Sprite_X_Position+4,y  ;save into X coordinate of second sprite
14199          lda Block_Rel_YPos+1       ;get second block object's relative vertical coordinate
14200          sta Sprite_Y_Position+8,y
14201          sta Sprite_Y_Position+12,y ;dump into Y coordinates of third and fourth sprites
14202          lda Block_Rel_XPos+1       ;get second block object's relative horizontal coordinate
14203          sta Sprite_X_Position+8,y  ;save into X coordinate of third sprite
14204          lda $00                    ;use original relative horizontal position
14205          sec
14206          sbc Block_Rel_XPos+1       ;get difference of relative positions of original - current
14207          adc $00                    ;add original relative position to result
14208          adc #$06                   ;plus 6 pixels to position fourth brick chunk correctly
14209          sta Sprite_X_Position+12,y ;save into X coordinate of fourth sprite
14210          lda Block_OffscreenBits    ;get offscreen bits for block object
14211          jsr ChkLeftCo              ;do sub to move left half of sprites offscreen if necessary
14212          lda Block_OffscreenBits    ;get offscreen bits again
14213          asl                        ;shift d7 into carry
14214          bcc ChnkOfs                ;if d7 not set, branch to last part
14215          lda #$f8
14216          jsr DumpTwoSpr             ;otherwise move top sprites offscreen
14217 ChnkOfs: lda $00                    ;if relative position on left side of screen,
14218          bpl ExBCDr                 ;go ahead and leave
14219          lda Sprite_X_Position,y    ;otherwise compare left-side X coordinate
14220          cmp Sprite_X_Position+4,y  ;to right-side X coordinate
14221          bcc ExBCDr                 ;branch to leave if less
14222          lda #$f8                   ;otherwise move right half of sprites offscreen
14223          sta Sprite_Y_Position+4,y
14224          sta Sprite_Y_Position+12,y
14225 ExBCDr:  rts                        ;leave
14226 
14227 ;-------------------------------------------------------------------------------------
14228 
14229 DrawFireball:
14230       ldy FBall_SprDataOffset,x  ;get fireball's sprite data offset
14231       lda Fireball_Rel_YPos      ;get relative vertical coordinate
14232       sta Sprite_Y_Position,y    ;store as sprite Y coordinate
14233       lda Fireball_Rel_XPos      ;get relative horizontal coordinate
14234       sta Sprite_X_Position,y    ;store as sprite X coordinate, then do shared code
14235 
14236 DrawFirebar:
14237        lda FrameCounter         ;get frame counter
14238        lsr                      ;divide by four
14239        lsr
14240        pha                      ;save result to stack
14241        and #$01                 ;mask out all but last bit
14242        eor #$64                 ;set either tile $64 or $65 as fireball tile
14243        sta Sprite_Tilenumber,y  ;thus tile changes every four frames
14244        pla                      ;get from stack
14245        lsr                      ;divide by four again
14246        lsr
14247        lda #$02                 ;load value $02 to set palette in attrib byte
14248        bcc FireA                ;if last bit shifted out was not set, skip this
14249        ora #%11000000           ;otherwise flip both ways every eight frames
14250 FireA: sta Sprite_Attributes,y  ;store attribute byte and leave
14251        rts
14252 
14253 ;-------------------------------------------------------------------------------------
14254 
14255 ExplosionTiles:
14256       .db $68, $67, $66
14257 
14258 DrawExplosion_Fireball:
14259       ldy Alt_SprDataOffset,x  ;get OAM data offset of alternate sort for fireball's explosion
14260       lda Fireball_State,x     ;load fireball state
14261       inc Fireball_State,x     ;increment state for next frame
14262       lsr                      ;divide by 2
14263       and #%00000111           ;mask out all but d3-d1
14264       cmp #$03                 ;check to see if time to kill fireball
14265       bcs KillFireBall         ;branch if so, otherwise continue to draw explosion
14266 
14267 DrawExplosion_Fireworks:
14268       tax                         ;use whatever's in A for offset
14269       lda ExplosionTiles,x        ;get tile number using offset
14270       iny                         ;increment Y (contains sprite data offset)
14271       jsr DumpFourSpr             ;and dump into tile number part of sprite data
14272       dey                         ;decrement Y so we have the proper offset again
14273       ldx ObjectOffset            ;return enemy object buffer offset to X
14274       lda Fireball_Rel_YPos       ;get relative vertical coordinate
14275       sec                         ;subtract four pixels vertically
14276       sbc #$04                    ;for first and third sprites
14277       sta Sprite_Y_Position,y
14278       sta Sprite_Y_Position+8,y
14279       clc                         ;add eight pixels vertically
14280       adc #$08                    ;for second and fourth sprites
14281       sta Sprite_Y_Position+4,y
14282       sta Sprite_Y_Position+12,y
14283       lda Fireball_Rel_XPos       ;get relative horizontal coordinate
14284       sec                         ;subtract four pixels horizontally
14285       sbc #$04                    ;for first and second sprites
14286       sta Sprite_X_Position,y
14287       sta Sprite_X_Position+4,y
14288       clc                         ;add eight pixels horizontally
14289       adc #$08                    ;for third and fourth sprites
14290       sta Sprite_X_Position+8,y
14291       sta Sprite_X_Position+12,y
14292       lda #$02                    ;set palette attributes for all sprites, but
14293       sta Sprite_Attributes,y     ;set no flip at all for first sprite
14294       lda #$82
14295       sta Sprite_Attributes+4,y   ;set vertical flip for second sprite
14296       lda #$42
14297       sta Sprite_Attributes+8,y   ;set horizontal flip for third sprite
14298       lda #$c2
14299       sta Sprite_Attributes+12,y  ;set both flips for fourth sprite
14300       rts                         ;we are done
14301 
14302 KillFireBall:
14303       lda #$00                    ;clear fireball state to kill it
14304       sta Fireball_State,x
14305       rts
14306 
14307 ;-------------------------------------------------------------------------------------
14308 
14309 DrawSmallPlatform:
14310        ldy Enemy_SprDataOffset,x   ;get OAM data offset
14311        lda #$5b                    ;load tile number for small platforms
14312        iny                         ;increment offset for tile numbers
14313        jsr DumpSixSpr              ;dump tile number into all six sprites
14314        iny                         ;increment offset for attributes
14315        lda #$02                    ;load palette controls
14316        jsr DumpSixSpr              ;dump attributes into all six sprites
14317        dey                         ;decrement for original offset
14318        dey
14319        lda Enemy_Rel_XPos          ;get relative horizontal coordinate
14320        sta Sprite_X_Position,y
14321        sta Sprite_X_Position+12,y  ;dump as X coordinate into first and fourth sprites
14322        clc
14323        adc #$08                    ;add eight pixels
14324        sta Sprite_X_Position+4,y   ;dump into second and fifth sprites
14325        sta Sprite_X_Position+16,y
14326        clc
14327        adc #$08                    ;add eight more pixels
14328        sta Sprite_X_Position+8,y   ;dump into third and sixth sprites
14329        sta Sprite_X_Position+20,y
14330        lda Enemy_Y_Position,x      ;get vertical coordinate
14331        tax
14332        pha                         ;save to stack
14333        cpx #$20                    ;if vertical coordinate below status bar,
14334        bcs TopSP                   ;do not mess with it
14335        lda #$f8                    ;otherwise move first three sprites offscreen
14336 TopSP: jsr DumpThreeSpr            ;dump vertical coordinate into Y coordinates
14337        pla                         ;pull from stack
14338        clc
14339        adc #$80                    ;add 128 pixels
14340        tax
14341        cpx #$20                    ;if below status bar (taking wrap into account)
14342        bcs BotSP                   ;then do not change altered coordinate
14343        lda #$f8                    ;otherwise move last three sprites offscreen
14344 BotSP: sta Sprite_Y_Position+12,y  ;dump vertical coordinate + 128 pixels
14345        sta Sprite_Y_Position+16,y  ;into Y coordinates
14346        sta Sprite_Y_Position+20,y
14347        lda Enemy_OffscreenBits     ;get offscreen bits
14348        pha                         ;save to stack
14349        and #%00001000              ;check d3
14350        beq SOfs
14351        lda #$f8                    ;if d3 was set, move first and
14352        sta Sprite_Y_Position,y     ;fourth sprites offscreen
14353        sta Sprite_Y_Position+12,y
14354 SOfs:  pla                         ;move out and back into stack
14355        pha
14356        and #%00000100              ;check d2
14357        beq SOfs2
14358        lda #$f8                    ;if d2 was set, move second and
14359        sta Sprite_Y_Position+4,y   ;fifth sprites offscreen
14360        sta Sprite_Y_Position+16,y
14361 SOfs2: pla                         ;get from stack
14362        and #%00000010              ;check d1
14363        beq ExSPl
14364        lda #$f8                    ;if d1 was set, move third and
14365        sta Sprite_Y_Position+8,y   ;sixth sprites offscreen
14366        sta Sprite_Y_Position+20,y
14367 ExSPl: ldx ObjectOffset            ;get enemy object offset and leave
14368        rts
14369 
14370 ;-------------------------------------------------------------------------------------
14371 
14372 DrawBubble:
14373         ldy Player_Y_HighPos        ;if player's vertical high position
14374         dey                         ;not within screen, skip all of this
14375         bne ExDBub
14376         lda Bubble_OffscreenBits    ;check air bubble's offscreen bits
14377         and #%00001000
14378         bne ExDBub                  ;if bit set, branch to leave
14379         ldy Bubble_SprDataOffset,x  ;get air bubble's OAM data offset
14380         lda Bubble_Rel_XPos         ;get relative horizontal coordinate
14381         sta Sprite_X_Position,y     ;store as X coordinate here
14382         lda Bubble_Rel_YPos         ;get relative vertical coordinate
14383         sta Sprite_Y_Position,y     ;store as Y coordinate here
14384         lda #$74
14385         sta Sprite_Tilenumber,y     ;put air bubble tile into OAM data
14386         lda #$02
14387         sta Sprite_Attributes,y     ;set attribute byte
14388 ExDBub: rts                         ;leave
14389 
14390 ;-------------------------------------------------------------------------------------
14391 ;$00 - used to store player's vertical offscreen bits
14392 
14393 PlayerGfxTblOffsets:
14394       .db $20, $28, $c8, $18, $00, $40, $50, $58
14395       .db $80, $88, $b8, $78, $60, $a0, $b0, $b8
14396 
14397 ;tiles arranged in order, 2 tiles per row, top to bottom
14398 
14399 PlayerGraphicsTable:
14400 ;big player table
14401       .db $00, $01, $02, $03, $04, $05, $06, $07 ;walking frame 1
14402       .db $08, $09, $0a, $0b, $0c, $0d, $0e, $0f ;        frame 2
14403       .db $10, $11, $12, $13, $14, $15, $16, $17 ;        frame 3
14404       .db $18, $19, $1a, $1b, $1c, $1d, $1e, $1f ;skidding
14405       .db $20, $21, $22, $23, $24, $25, $26, $27 ;jumping
14406       .db $08, $09, $28, $29, $2a, $2b, $2c, $2d ;swimming frame 1
14407       .db $08, $09, $0a, $0b, $0c, $30, $2c, $2d ;         frame 2
14408       .db $08, $09, $0a, $0b, $2e, $2f, $2c, $2d ;         frame 3
14409       .db $08, $09, $28, $29, $2a, $2b, $5c, $5d ;climbing frame 1
14410       .db $08, $09, $0a, $0b, $0c, $0d, $5e, $5f ;         frame 2
14411       .db $fc, $fc, $08, $09, $58, $59, $5a, $5a ;crouching
14412       .db $08, $09, $28, $29, $2a, $2b, $0e, $0f ;fireball throwing
14413 
14414 ;small player table
14415       .db $fc, $fc, $fc, $fc, $32, $33, $34, $35 ;walking frame 1
14416       .db $fc, $fc, $fc, $fc, $36, $37, $38, $39 ;        frame 2
14417       .db $fc, $fc, $fc, $fc, $3a, $37, $3b, $3c ;        frame 3
14418       .db $fc, $fc, $fc, $fc, $3d, $3e, $3f, $40 ;skidding
14419       .db $fc, $fc, $fc, $fc, $32, $41, $42, $43 ;jumping
14420       .db $fc, $fc, $fc, $fc, $32, $33, $44, $45 ;swimming frame 1
14421       .db $fc, $fc, $fc, $fc, $32, $33, $44, $47 ;         frame 2
14422       .db $fc, $fc, $fc, $fc, $32, $33, $48, $49 ;         frame 3
14423       .db $fc, $fc, $fc, $fc, $32, $33, $90, $91 ;climbing frame 1
14424       .db $fc, $fc, $fc, $fc, $3a, $37, $92, $93 ;         frame 2
14425       .db $fc, $fc, $fc, $fc, $9e, $9e, $9f, $9f ;killed
14426 
14427 ;used by both player sizes
14428       .db $fc, $fc, $fc, $fc, $3a, $37, $4f, $4f ;small player standing
14429       .db $fc, $fc, $00, $01, $4c, $4d, $4e, $4e ;intermediate grow frame
14430       .db $00, $01, $4c, $4d, $4a, $4a, $4b, $4b ;big player standing
14431 
14432 SwimKickTileNum:
14433       .db $31, $46
14434 
14435 PlayerGfxHandler:
14436         lda InjuryTimer             ;if player's injured invincibility timer
14437         beq CntPl                   ;not set, skip checkpoint and continue code
14438         lda FrameCounter
14439         lsr                         ;otherwise check frame counter and branch
14440         bcs ExPGH                   ;to leave on every other frame (when d0 is set)
14441 CntPl:  lda GameEngineSubroutine    ;if executing specific game engine routine,
14442         cmp #$0b                    ;branch ahead to some other part
14443         beq PlayerKilled
14444         lda PlayerChangeSizeFlag    ;if grow/shrink flag set
14445         bne DoChangeSize            ;then branch to some other code
14446         ldy SwimmingFlag            ;if swimming flag set, branch to
14447         beq FindPlayerAction        ;different part, do not return
14448         lda Player_State
14449         cmp #$00                    ;if player status normal,
14450         beq FindPlayerAction        ;branch and do not return
14451         jsr FindPlayerAction        ;otherwise jump and return
14452         lda FrameCounter
14453         and #%00000100              ;check frame counter for d2 set (8 frames every
14454         bne ExPGH                   ;eighth frame), and branch if set to leave
14455         tax                         ;initialize X to zero
14456         ldy Player_SprDataOffset    ;get player sprite data offset
14457         lda PlayerFacingDir         ;get player's facing direction
14458         lsr
14459         bcs SwimKT                  ;if player facing to the right, use current offset
14460         iny
14461         iny                         ;otherwise move to next OAM data
14462         iny
14463         iny
14464 SwimKT: lda PlayerSize              ;check player's size
14465         beq BigKTS                  ;if big, use first tile
14466         lda Sprite_Tilenumber+24,y  ;check tile number of seventh/eighth sprite
14467         cmp SwimTileRepOffset       ;against tile number in player graphics table
14468         beq ExPGH                   ;if spr7/spr8 tile number = value, branch to leave
14469         inx                         ;otherwise increment X for second tile
14470 BigKTS: lda SwimKickTileNum,x       ;overwrite tile number in sprite 7/8
14471         sta Sprite_Tilenumber+24,y  ;to animate player's feet when swimming
14472 ExPGH:  rts                         ;then leave
14473 
14474 FindPlayerAction:
14475       jsr ProcessPlayerAction       ;find proper offset to graphics table by player's actions
14476       jmp PlayerGfxProcessing       ;draw player, then process for fireball throwing
14477 
14478 DoChangeSize:
14479       jsr HandleChangeSize          ;find proper offset to graphics table for grow/shrink
14480       jmp PlayerGfxProcessing       ;draw player, then process for fireball throwing
14481 
14482 PlayerKilled:
14483       ldy #$0e                      ;load offset for player killed
14484       lda PlayerGfxTblOffsets,y     ;get offset to graphics table
14485 
14486 PlayerGfxProcessing:
14487        sta PlayerGfxOffset           ;store offset to graphics table here
14488        lda #$04
14489        jsr RenderPlayerSub           ;draw player based on offset loaded
14490        jsr ChkForPlayerAttrib        ;set horizontal flip bits as necessary
14491        lda FireballThrowingTimer
14492        beq PlayerOffscreenChk        ;if fireball throw timer not set, skip to the end
14493        ldy #$00                      ;set value to initialize by default
14494        lda PlayerAnimTimer           ;get animation frame timer
14495        cmp FireballThrowingTimer     ;compare to fireball throw timer
14496        sty FireballThrowingTimer     ;initialize fireball throw timer
14497        bcs PlayerOffscreenChk        ;if animation frame timer => fireball throw timer skip to end
14498        sta FireballThrowingTimer     ;otherwise store animation timer into fireball throw timer
14499        ldy #$07                      ;load offset for throwing
14500        lda PlayerGfxTblOffsets,y     ;get offset to graphics table
14501        sta PlayerGfxOffset           ;store it for use later
14502        ldy #$04                      ;set to update four sprite rows by default
14503        lda Player_X_Speed
14504        ora Left_Right_Buttons        ;check for horizontal speed or left/right button press
14505        beq SUpdR                     ;if no speed or button press, branch using set value in Y
14506        dey                           ;otherwise set to update only three sprite rows
14507 SUpdR: tya                           ;save in A for use
14508        jsr RenderPlayerSub           ;in sub, draw player object again
14509 
14510 PlayerOffscreenChk:
14511            lda Player_OffscreenBits      ;get player's offscreen bits
14512            lsr
14513            lsr                           ;move vertical bits to low nybble
14514            lsr
14515            lsr
14516            sta $00                       ;store here
14517            ldx #$03                      ;check all four rows of player sprites
14518            lda Player_SprDataOffset      ;get player's sprite data offset
14519            clc
14520            adc #$18                      ;add 24 bytes to start at bottom row
14521            tay                           ;set as offset here
14522 PROfsLoop: lda #$f8                      ;load offscreen Y coordinate just in case
14523            lsr $00                       ;shift bit into carry
14524            bcc NPROffscr                 ;if bit not set, skip, do not move sprites
14525            jsr DumpTwoSpr                ;otherwise dump offscreen Y coordinate into sprite data
14526 NPROffscr: tya
14527            sec                           ;subtract eight bytes to do
14528            sbc #$08                      ;next row up
14529            tay
14530            dex                           ;decrement row counter
14531            bpl PROfsLoop                 ;do this until all sprite rows are checked
14532            rts                           ;then we are done!
14533 
14534 ;-------------------------------------------------------------------------------------
14535 
14536 IntermediatePlayerData:
14537         .db $58, $01, $00, $60, $ff, $04
14538 
14539 DrawPlayer_Intermediate:
14540           ldx #$05                       ;store data into zero page memory
14541 PIntLoop: lda IntermediatePlayerData,x   ;load data to display player as he always
14542           sta $02,x                      ;appears on world/lives display
14543           dex
14544           bpl PIntLoop                   ;do this until all data is loaded
14545           ldx #$b8                       ;load offset for small standing
14546           ldy #$04                       ;load sprite data offset
14547           jsr DrawPlayerLoop             ;draw player accordingly
14548           lda Sprite_Attributes+36       ;get empty sprite attributes
14549           ora #%01000000                 ;set horizontal flip bit for bottom-right sprite
14550           sta Sprite_Attributes+32       ;store and leave
14551           rts
14552 
14553 ;-------------------------------------------------------------------------------------
14554 ;$00-$01 - used to hold tile numbers, $00 also used to hold upper extent of animation frames
14555 ;$02 - vertical position
14556 ;$03 - facing direction, used as horizontal flip control
14557 ;$04 - attributes
14558 ;$05 - horizontal position
14559 ;$07 - number of rows to draw
14560 ;these also used in IntermediatePlayerData
14561 
14562 RenderPlayerSub:
14563         sta $07                      ;store number of rows of sprites to draw
14564         lda Player_Rel_XPos
14565         sta Player_Pos_ForScroll     ;store player's relative horizontal position
14566         sta $05                      ;store it here also
14567         lda Player_Rel_YPos
14568         sta $02                      ;store player's vertical position
14569         lda PlayerFacingDir
14570         sta $03                      ;store player's facing direction
14571         lda Player_SprAttrib
14572         sta $04                      ;store player's sprite attributes
14573         ldx PlayerGfxOffset          ;load graphics table offset
14574         ldy Player_SprDataOffset     ;get player's sprite data offset
14575 
14576 DrawPlayerLoop:
14577         lda PlayerGraphicsTable,x    ;load player's left side
14578         sta $00
14579         lda PlayerGraphicsTable+1,x  ;now load right side
14580         jsr DrawOneSpriteRow
14581         dec $07                      ;decrement rows of sprites to draw
14582         bne DrawPlayerLoop           ;do this until all rows are drawn
14583         rts
14584 
14585 ProcessPlayerAction:
14586         lda Player_State      ;get player's state
14587         cmp #$03
14588         beq ActionClimbing    ;if climbing, branch here
14589         cmp #$02
14590         beq ActionFalling     ;if falling, branch here
14591         cmp #$01
14592         bne ProcOnGroundActs  ;if not jumping, branch here
14593         lda SwimmingFlag
14594         bne ActionSwimming    ;if swimming flag set, branch elsewhere
14595         ldy #$06              ;load offset for crouching
14596         lda CrouchingFlag     ;get crouching flag
14597         bne NonAnimatedActs   ;if set, branch to get offset for graphics table
14598         ldy #$00              ;otherwise load offset for jumping
14599         jmp NonAnimatedActs   ;go to get offset to graphics table
14600 
14601 ProcOnGroundActs:
14602         ldy #$06                   ;load offset for crouching
14603         lda CrouchingFlag          ;get crouching flag
14604         bne NonAnimatedActs        ;if set, branch to get offset for graphics table
14605         ldy #$02                   ;load offset for standing
14606         lda Player_X_Speed         ;check player's horizontal speed
14607         ora Left_Right_Buttons     ;and left/right controller bits
14608         beq NonAnimatedActs        ;if no speed or buttons pressed, use standing offset
14609         lda Player_XSpeedAbsolute  ;load walking/running speed
14610         cmp #$09
14611         bcc ActionWalkRun          ;if less than a certain amount, branch, too slow to skid
14612         lda Player_MovingDir       ;otherwise check to see if moving direction
14613         and PlayerFacingDir        ;and facing direction are the same
14614         bne ActionWalkRun          ;if moving direction = facing direction, branch, don't skid
14615         iny                        ;otherwise increment to skid offset ($03)
14616 
14617 NonAnimatedActs:
14618         jsr GetGfxOffsetAdder      ;do a sub here to get offset adder for graphics table
14619         lda #$00
14620         sta PlayerAnimCtrl         ;initialize animation frame control
14621         lda PlayerGfxTblOffsets,y  ;load offset to graphics table using size as offset
14622         rts
14623 
14624 ActionFalling:
14625         ldy #$04                  ;load offset for walking/running
14626         jsr GetGfxOffsetAdder     ;get offset to graphics table
14627         jmp GetCurrentAnimOffset  ;execute instructions for falling state
14628 
14629 ActionWalkRun:
14630         ldy #$04               ;load offset for walking/running
14631         jsr GetGfxOffsetAdder  ;get offset to graphics table
14632         jmp FourFrameExtent    ;execute instructions for normal state
14633 
14634 ActionClimbing:
14635         ldy #$05               ;load offset for climbing
14636         lda Player_Y_Speed     ;check player's vertical speed
14637         beq NonAnimatedActs    ;if no speed, branch, use offset as-is
14638         jsr GetGfxOffsetAdder  ;otherwise get offset for graphics table
14639         jmp ThreeFrameExtent   ;then skip ahead to more code
14640 
14641 ActionSwimming:
14642         ldy #$01               ;load offset for swimming
14643         jsr GetGfxOffsetAdder
14644         lda JumpSwimTimer      ;check jump/swim timer
14645         ora PlayerAnimCtrl     ;and animation frame control
14646         bne FourFrameExtent    ;if any one of these set, branch ahead
14647         lda A_B_Buttons
14648         asl                    ;check for A button pressed
14649         bcs FourFrameExtent    ;branch to same place if A button pressed
14650 
14651 GetCurrentAnimOffset:
14652         lda PlayerAnimCtrl         ;get animation frame control
14653         jmp GetOffsetFromAnimCtrl  ;jump to get proper offset to graphics table
14654 
14655 FourFrameExtent:
14656         lda #$03              ;load upper extent for frame control
14657         jmp AnimationControl  ;jump to get offset and animate player object
14658 
14659 ThreeFrameExtent:
14660         lda #$02              ;load upper extent for frame control for climbing
14661 
14662 AnimationControl:
14663           sta $00                   ;store upper extent here
14664           jsr GetCurrentAnimOffset  ;get proper offset to graphics table
14665           pha                       ;save offset to stack
14666           lda PlayerAnimTimer       ;load animation frame timer
14667           bne ExAnimC               ;branch if not expired
14668           lda PlayerAnimTimerSet    ;get animation frame timer amount
14669           sta PlayerAnimTimer       ;and set timer accordingly
14670           lda PlayerAnimCtrl
14671           clc                       ;add one to animation frame control
14672           adc #$01
14673           cmp $00                   ;compare to upper extent
14674           bcc SetAnimC              ;if frame control + 1 < upper extent, use as next
14675           lda #$00                  ;otherwise initialize frame control
14676 SetAnimC: sta PlayerAnimCtrl        ;store as new animation frame control
14677 ExAnimC:  pla                       ;get offset to graphics table from stack and leave
14678           rts
14679 
14680 GetGfxOffsetAdder:
14681         lda PlayerSize  ;get player's size
14682         beq SzOfs       ;if player big, use current offset as-is
14683         tya             ;for big player
14684         clc             ;otherwise add eight bytes to offset
14685         adc #$08        ;for small player
14686         tay
14687 SzOfs:  rts             ;go back
14688 
14689 ChangeSizeOffsetAdder:
14690         .db $00, $01, $00, $01, $00, $01, $02, $00, $01, $02
14691         .db $02, $00, $02, $00, $02, $00, $02, $00, $02, $00
14692 
14693 HandleChangeSize:
14694          ldy PlayerAnimCtrl           ;get animation frame control
14695          lda FrameCounter
14696          and #%00000011               ;get frame counter and execute this code every
14697          bne GorSLog                  ;fourth frame, otherwise branch ahead
14698          iny                          ;increment frame control
14699          cpy #$0a                     ;check for preset upper extent
14700          bcc CSzNext                  ;if not there yet, skip ahead to use
14701          ldy #$00                     ;otherwise initialize both grow/shrink flag
14702          sty PlayerChangeSizeFlag     ;and animation frame control
14703 CSzNext: sty PlayerAnimCtrl           ;store proper frame control
14704 GorSLog: lda PlayerSize               ;get player's size
14705          bne ShrinkPlayer             ;if player small, skip ahead to next part
14706          lda ChangeSizeOffsetAdder,y  ;get offset adder based on frame control as offset
14707          ldy #$0f                     ;load offset for player growing
14708 
14709 GetOffsetFromAnimCtrl:
14710         asl                        ;multiply animation frame control
14711         asl                        ;by eight to get proper amount
14712         asl                        ;to add to our offset
14713         adc PlayerGfxTblOffsets,y  ;add to offset to graphics table
14714         rts                        ;and return with result in A
14715 
14716 ShrinkPlayer:
14717         tya                          ;add ten bytes to frame control as offset
14718         clc
14719         adc #$0a                     ;this thing apparently uses two of the swimming frames
14720         tax                          ;to draw the player shrinking
14721         ldy #$09                     ;load offset for small player swimming
14722         lda ChangeSizeOffsetAdder,x  ;get what would normally be offset adder
14723         bne ShrPlF                   ;and branch to use offset if nonzero
14724         ldy #$01                     ;otherwise load offset for big player swimming
14725 ShrPlF: lda PlayerGfxTblOffsets,y    ;get offset to graphics table based on offset loaded
14726         rts                          ;and leave
14727 
14728 ChkForPlayerAttrib:
14729            ldy Player_SprDataOffset    ;get sprite data offset
14730            lda GameEngineSubroutine
14731            cmp #$0b                    ;if executing specific game engine routine,
14732            beq KilledAtt               ;branch to change third and fourth row OAM attributes
14733            lda PlayerGfxOffset         ;get graphics table offset
14734            cmp #$50
14735            beq C_S_IGAtt               ;if crouch offset, either standing offset,
14736            cmp #$b8                    ;or intermediate growing offset,
14737            beq C_S_IGAtt               ;go ahead and execute code to change 
14738            cmp #$c0                    ;fourth row OAM attributes only
14739            beq C_S_IGAtt
14740            cmp #$c8
14741            bne ExPlyrAt                ;if none of these, branch to leave
14742 KilledAtt: lda Sprite_Attributes+16,y
14743            and #%00111111              ;mask out horizontal and vertical flip bits
14744            sta Sprite_Attributes+16,y  ;for third row sprites and save
14745            lda Sprite_Attributes+20,y
14746            and #%00111111  
14747            ora #%01000000              ;set horizontal flip bit for second
14748            sta Sprite_Attributes+20,y  ;sprite in the third row
14749 C_S_IGAtt: lda Sprite_Attributes+24,y
14750            and #%00111111              ;mask out horizontal and vertical flip bits
14751            sta Sprite_Attributes+24,y  ;for fourth row sprites and save
14752            lda Sprite_Attributes+28,y
14753            and #%00111111
14754            ora #%01000000              ;set horizontal flip bit for second
14755            sta Sprite_Attributes+28,y  ;sprite in the fourth row
14756 ExPlyrAt:  rts                         ;leave
14757 
14758 ;-------------------------------------------------------------------------------------
14759 ;$00 - used in adding to get proper offset
14760 
14761 RelativePlayerPosition:
14762         ldx #$00      ;set offsets for relative cooordinates
14763         ldy #$00      ;routine to correspond to player object
14764         jmp RelWOfs   ;get the coordinates
14765 
14766 RelativeBubblePosition:
14767         ldy #$01                ;set for air bubble offsets
14768         jsr GetProperObjOffset  ;modify X to get proper air bubble offset
14769         ldy #$03
14770         jmp RelWOfs             ;get the coordinates
14771 
14772 RelativeFireballPosition:
14773          ldy #$00                    ;set for fireball offsets
14774          jsr GetProperObjOffset      ;modify X to get proper fireball offset
14775          ldy #$02
14776 RelWOfs: jsr GetObjRelativePosition  ;get the coordinates
14777          ldx ObjectOffset            ;return original offset
14778          rts                         ;leave
14779 
14780 RelativeMiscPosition:
14781         ldy #$02                ;set for misc object offsets
14782         jsr GetProperObjOffset  ;modify X to get proper misc object offset
14783         ldy #$06
14784         jmp RelWOfs             ;get the coordinates
14785 
14786 RelativeEnemyPosition:
14787         lda #$01                     ;get coordinates of enemy object 
14788         ldy #$01                     ;relative to the screen
14789         jmp VariableObjOfsRelPos
14790 
14791 RelativeBlockPosition:
14792         lda #$09                     ;get coordinates of one block object
14793         ldy #$04                     ;relative to the screen
14794         jsr VariableObjOfsRelPos
14795         inx                          ;adjust offset for other block object if any
14796         inx
14797         lda #$09
14798         iny                          ;adjust other and get coordinates for other one
14799 
14800 VariableObjOfsRelPos:
14801         stx $00                     ;store value to add to A here
14802         clc
14803         adc $00                     ;add A to value stored
14804         tax                         ;use as enemy offset
14805         jsr GetObjRelativePosition
14806         ldx ObjectOffset            ;reload old object offset and leave
14807         rts
14808 
14809 GetObjRelativePosition:
14810         lda SprObject_Y_Position,x  ;load vertical coordinate low
14811         sta SprObject_Rel_YPos,y    ;store here
14812         lda SprObject_X_Position,x  ;load horizontal coordinate
14813         sec                         ;subtract left edge coordinate
14814         sbc ScreenLeft_X_Pos
14815         sta SprObject_Rel_XPos,y    ;store result here
14816         rts
14817 
14818 ;-------------------------------------------------------------------------------------
14819 ;$00 - used as temp variable to hold offscreen bits
14820 
14821 GetPlayerOffscreenBits:
14822         ldx #$00                 ;set offsets for player-specific variables
14823         ldy #$00                 ;and get offscreen information about player
14824         jmp GetOffScreenBitsSet
14825 
14826 GetFireballOffscreenBits:
14827         ldy #$00                 ;set for fireball offsets
14828         jsr GetProperObjOffset   ;modify X to get proper fireball offset
14829         ldy #$02                 ;set other offset for fireball's offscreen bits
14830         jmp GetOffScreenBitsSet  ;and get offscreen information about fireball
14831 
14832 GetBubbleOffscreenBits:
14833         ldy #$01                 ;set for air bubble offsets
14834         jsr GetProperObjOffset   ;modify X to get proper air bubble offset
14835         ldy #$03                 ;set other offset for airbubble's offscreen bits
14836         jmp GetOffScreenBitsSet  ;and get offscreen information about air bubble
14837 
14838 GetMiscOffscreenBits:
14839         ldy #$02                 ;set for misc object offsets
14840         jsr GetProperObjOffset   ;modify X to get proper misc object offset
14841         ldy #$06                 ;set other offset for misc object's offscreen bits
14842         jmp GetOffScreenBitsSet  ;and get offscreen information about misc object
14843 
14844 ObjOffsetData:
14845         .db $07, $16, $0d
14846 
14847 GetProperObjOffset:
14848         txa                  ;move offset to A
14849         clc
14850         adc ObjOffsetData,y  ;add amount of bytes to offset depending on setting in Y
14851         tax                  ;put back in X and leave
14852         rts
14853 
14854 GetEnemyOffscreenBits:
14855         lda #$01                 ;set A to add 1 byte in order to get enemy offset
14856         ldy #$01                 ;set Y to put offscreen bits in Enemy_OffscreenBits
14857         jmp SetOffscrBitsOffset
14858 
14859 GetBlockOffscreenBits:
14860         lda #$09       ;set A to add 9 bytes in order to get block obj offset
14861         ldy #$04       ;set Y to put offscreen bits in Block_OffscreenBits
14862 
14863 SetOffscrBitsOffset:
14864         stx $00
14865         clc           ;add contents of X to A to get
14866         adc $00       ;appropriate offset, then give back to X
14867         tax
14868 
14869 GetOffScreenBitsSet:
14870         tya                         ;save offscreen bits offset to stack for now
14871         pha
14872         jsr RunOffscrBitsSubs
14873         asl                         ;move low nybble to high nybble
14874         asl
14875         asl
14876         asl
14877         ora $00                     ;mask together with previously saved low nybble
14878         sta $00                     ;store both here
14879         pla                         ;get offscreen bits offset from stack
14880         tay
14881         lda $00                     ;get value here and store elsewhere
14882         sta SprObject_OffscrBits,y
14883         ldx ObjectOffset
14884         rts
14885 
14886 RunOffscrBitsSubs:
14887         jsr GetXOffscreenBits  ;do subroutine here
14888         lsr                    ;move high nybble to low
14889         lsr
14890         lsr
14891         lsr
14892         sta $00                ;store here
14893         jmp GetYOffscreenBits
14894 
14895 ;--------------------------------
14896 ;(these apply to these three subsections)
14897 ;$04 - used to store proper offset
14898 ;$05 - used as adder in DividePDiff
14899 ;$06 - used to store preset value used to compare to pixel difference in $07
14900 ;$07 - used to store difference between coordinates of object and screen edges
14901 
14902 XOffscreenBitsData:
14903         .db $7f, $3f, $1f, $0f, $07, $03, $01, $00
14904         .db $80, $c0, $e0, $f0, $f8, $fc, $fe, $ff
14905 
14906 DefaultXOnscreenOfs:
14907         .db $07, $0f, $07
14908 
14909 GetXOffscreenBits:
14910           stx $04                     ;save position in buffer to here
14911           ldy #$01                    ;start with right side of screen
14912 XOfsLoop: lda ScreenEdge_X_Pos,y      ;get pixel coordinate of edge
14913           sec                         ;get difference between pixel coordinate of edge
14914           sbc SprObject_X_Position,x  ;and pixel coordinate of object position
14915           sta $07                     ;store here
14916           lda ScreenEdge_PageLoc,y    ;get page location of edge
14917           sbc SprObject_PageLoc,x     ;subtract from page location of object position
14918           ldx DefaultXOnscreenOfs,y   ;load offset value here
14919           cmp #$00      
14920           bmi XLdBData                ;if beyond right edge or in front of left edge, branch
14921           ldx DefaultXOnscreenOfs+1,y ;if not, load alternate offset value here
14922           cmp #$01      
14923           bpl XLdBData                ;if one page or more to the left of either edge, branch
14924           lda #$38                    ;if no branching, load value here and store
14925           sta $06
14926           lda #$08                    ;load some other value and execute subroutine
14927           jsr DividePDiff
14928 XLdBData: lda XOffscreenBitsData,x    ;get bits here
14929           ldx $04                     ;reobtain position in buffer
14930           cmp #$00                    ;if bits not zero, branch to leave
14931           bne ExXOfsBS
14932           dey                         ;otherwise, do left side of screen now
14933           bpl XOfsLoop                ;branch if not already done with left side
14934 ExXOfsBS: rts
14935 
14936 ;--------------------------------
14937 
14938 YOffscreenBitsData:
14939         .db $00, $08, $0c, $0e
14940         .db $0f, $07, $03, $01
14941         .db $00
14942 
14943 DefaultYOnscreenOfs:
14944         .db $04, $00, $04
14945 
14946 HighPosUnitData:
14947         .db $ff, $00
14948 
14949 GetYOffscreenBits:
14950           stx $04                      ;save position in buffer to here
14951           ldy #$01                     ;start with top of screen
14952 YOfsLoop: lda HighPosUnitData,y        ;load coordinate for edge of vertical unit
14953           sec
14954           sbc SprObject_Y_Position,x   ;subtract from vertical coordinate of object
14955           sta $07                      ;store here
14956           lda #$01                     ;subtract one from vertical high byte of object
14957           sbc SprObject_Y_HighPos,x
14958           ldx DefaultYOnscreenOfs,y    ;load offset value here
14959           cmp #$00
14960           bmi YLdBData                 ;if under top of the screen or beyond bottom, branch
14961           ldx DefaultYOnscreenOfs+1,y  ;if not, load alternate offset value here
14962           cmp #$01
14963           bpl YLdBData                 ;if one vertical unit or more above the screen, branch
14964           lda #$20                     ;if no branching, load value here and store
14965           sta $06
14966           lda #$04                     ;load some other value and execute subroutine
14967           jsr DividePDiff
14968 YLdBData: lda YOffscreenBitsData,x     ;get offscreen data bits using offset
14969           ldx $04                      ;reobtain position in buffer
14970           cmp #$00
14971           bne ExYOfsBS                 ;if bits not zero, branch to leave
14972           dey                          ;otherwise, do bottom of the screen now
14973           bpl YOfsLoop
14974 ExYOfsBS: rts
14975 
14976 ;--------------------------------
14977 
14978 DividePDiff:
14979           sta $05       ;store current value in A here
14980           lda $07       ;get pixel difference
14981           cmp $06       ;compare to preset value
14982           bcs ExDivPD   ;if pixel difference >= preset value, branch
14983           lsr           ;divide by eight
14984           lsr
14985           lsr
14986           and #$07      ;mask out all but 3 LSB
14987           cpy #$01      ;right side of the screen or top?
14988           bcs SetOscrO  ;if so, branch, use difference / 8 as offset
14989           adc $05       ;if not, add value to difference / 8
14990 SetOscrO: tax           ;use as offset
14991 ExDivPD:  rts           ;leave
14992 
14993 ;-------------------------------------------------------------------------------------
14994 ;$00-$01 - tile numbers
14995 ;$02 - Y coordinate
14996 ;$03 - flip control
14997 ;$04 - sprite attributes
14998 ;$05 - X coordinate
14999 
15000 DrawSpriteObject:
15001          lda $03                    ;get saved flip control bits
15002          lsr
15003          lsr                        ;move d1 into carry
15004          lda $00
15005          bcc NoHFlip                ;if d1 not set, branch
15006          sta Sprite_Tilenumber+4,y  ;store first tile into second sprite
15007          lda $01                    ;and second into first sprite
15008          sta Sprite_Tilenumber,y
15009          lda #$40                   ;activate horizontal flip OAM attribute
15010          bne SetHFAt                ;and unconditionally branch
15011 NoHFlip: sta Sprite_Tilenumber,y    ;store first tile into first sprite
15012          lda $01                    ;and second into second sprite
15013          sta Sprite_Tilenumber+4,y
15014          lda #$00                   ;clear bit for horizontal flip
15015 SetHFAt: ora $04                    ;add other OAM attributes if necessary
15016          sta Sprite_Attributes,y    ;store sprite attributes
15017          sta Sprite_Attributes+4,y
15018          lda $02                    ;now the y coordinates
15019          sta Sprite_Y_Position,y    ;note because they are
15020          sta Sprite_Y_Position+4,y  ;side by side, they are the same
15021          lda $05       
15022          sta Sprite_X_Position,y    ;store x coordinate, then
15023          clc                        ;add 8 pixels and store another to
15024          adc #$08                   ;put them side by side
15025          sta Sprite_X_Position+4,y
15026          lda $02                    ;add eight pixels to the next y
15027          clc                        ;coordinate
15028          adc #$08
15029          sta $02
15030          tya                        ;add eight to the offset in Y to
15031          clc                        ;move to the next two sprites
15032          adc #$08
15033          tay
15034          inx                        ;increment offset to return it to the
15035          inx                        ;routine that called this subroutine
15036          rts
15037 
15038 ;-------------------------------------------------------------------------------------
15039 
15040 ;unused space
15041         .db $ff, $ff, $ff, $ff, $ff, $ff
15042 
15043 ;-------------------------------------------------------------------------------------
15044 
15045 SoundEngine:
15046          lda OperMode              ;are we in title screen mode?
15047          bne SndOn
15048          sta SND_MASTERCTRL_REG    ;if so, disable sound and leave
15049          rts
15050 SndOn:   lda #$ff
15051          sta JOYPAD_PORT2          ;disable irqs and set frame counter mode???
15052          lda #$0f
15053          sta SND_MASTERCTRL_REG    ;enable first four channels
15054          lda PauseModeFlag         ;is sound already in pause mode?
15055          bne InPause
15056          lda PauseSoundQueue       ;if not, check pause sfx queue    
15057          cmp #$01
15058          bne RunSoundSubroutines   ;if queue is empty, skip pause mode routine
15059 InPause: lda PauseSoundBuffer      ;check pause sfx buffer
15060          bne ContPau
15061          lda PauseSoundQueue       ;check pause queue
15062          beq SkipSoundSubroutines
15063          sta PauseSoundBuffer      ;if queue full, store in buffer and activate
15064          sta PauseModeFlag         ;pause mode to interrupt game sounds
15065          lda #$00                  ;disable sound and clear sfx buffers
15066          sta SND_MASTERCTRL_REG
15067          sta Square1SoundBuffer
15068          sta Square2SoundBuffer
15069          sta NoiseSoundBuffer
15070          lda #$0f
15071          sta SND_MASTERCTRL_REG    ;enable sound again
15072          lda #$2a                  ;store length of sound in pause counter
15073          sta Squ1_SfxLenCounter
15074 PTone1F: lda #$44                  ;play first tone
15075          bne PTRegC                ;unconditional branch
15076 ContPau: lda Squ1_SfxLenCounter    ;check pause length left
15077          cmp #$24                  ;time to play second?
15078          beq PTone2F
15079          cmp #$1e                  ;time to play first again?
15080          beq PTone1F
15081          cmp #$18                  ;time to play second again?
15082          bne DecPauC               ;only load regs during times, otherwise skip
15083 PTone2F: lda #$64                  ;store reg contents and play the pause sfx
15084 PTRegC:  ldx #$84
15085          ldy #$7f
15086          jsr PlaySqu1Sfx
15087 DecPauC: dec Squ1_SfxLenCounter    ;decrement pause sfx counter
15088          bne SkipSoundSubroutines
15089          lda #$00                  ;disable sound if in pause mode and
15090          sta SND_MASTERCTRL_REG    ;not currently playing the pause sfx
15091          lda PauseSoundBuffer      ;if no longer playing pause sfx, check to see
15092          cmp #$02                  ;if we need to be playing sound again
15093          bne SkipPIn
15094          lda #$00                  ;clear pause mode to allow game sounds again
15095          sta PauseModeFlag
15096 SkipPIn: lda #$00                  ;clear pause sfx buffer
15097          sta PauseSoundBuffer
15098          beq SkipSoundSubroutines
15099 
15100 RunSoundSubroutines:
15101          jsr Square1SfxHandler  ;play sfx on square channel 1
15102          jsr Square2SfxHandler  ; ''  ''  '' square channel 2
15103          jsr NoiseSfxHandler    ; ''  ''  '' noise channel
15104          jsr MusicHandler       ;play music on all channels
15105          lda #$00               ;clear the music queues
15106          sta AreaMusicQueue
15107          sta EventMusicQueue
15108 
15109 SkipSoundSubroutines:
15110           lda #$00               ;clear the sound effects queues
15111           sta Square1SoundQueue
15112           sta Square2SoundQueue
15113           sta NoiseSoundQueue
15114           sta PauseSoundQueue
15115           ldy DAC_Counter        ;load some sort of counter 
15116           lda AreaMusicBuffer
15117           and #%00000011         ;check for specific music
15118           beq NoIncDAC
15119           inc DAC_Counter        ;increment and check counter
15120           cpy #$30
15121           bcc StrWave            ;if not there yet, just store it
15122 NoIncDAC: tya
15123           beq StrWave            ;if we are at zero, do not decrement 
15124           dec DAC_Counter        ;decrement counter
15125 StrWave:  sty SND_DELTA_REG+1    ;store into DMC load register (??)
15126           rts                    ;we are done here
15127 
15128 ;--------------------------------
15129 
15130 Dump_Squ1_Regs:
15131       sty SND_SQUARE1_REG+1  ;dump the contents of X and Y into square 1's control regs
15132       stx SND_SQUARE1_REG
15133       rts
15134       
15135 PlaySqu1Sfx:
15136       jsr Dump_Squ1_Regs     ;do sub to set ctrl regs for square 1, then set frequency regs
15137 
15138 SetFreq_Squ1:
15139       ldx #$00               ;set frequency reg offset for square 1 sound channel
15140 
15141 Dump_Freq_Regs:
15142         tay
15143         lda FreqRegLookupTbl+1,y  ;use previous contents of A for sound reg offset
15144         beq NoTone                ;if zero, then do not load
15145         sta SND_REGISTER+2,x      ;first byte goes into LSB of frequency divider
15146         lda FreqRegLookupTbl,y    ;second byte goes into 3 MSB plus extra bit for 
15147         ora #%00001000            ;length counter
15148         sta SND_REGISTER+3,x
15149 NoTone: rts
15150 
15151 Dump_Sq2_Regs:
15152       stx SND_SQUARE2_REG    ;dump the contents of X and Y into square 2's control regs
15153       sty SND_SQUARE2_REG+1
15154       rts
15155 
15156 PlaySqu2Sfx:
15157       jsr Dump_Sq2_Regs      ;do sub to set ctrl regs for square 2, then set frequency regs
15158 
15159 SetFreq_Squ2:
15160       ldx #$04               ;set frequency reg offset for square 2 sound channel
15161       bne Dump_Freq_Regs     ;unconditional branch
15162 
15163 SetFreq_Tri:
15164       ldx #$08               ;set frequency reg offset for triangle sound channel
15165       bne Dump_Freq_Regs     ;unconditional branch
15166 
15167 ;--------------------------------
15168 
15169 SwimStompEnvelopeData:
15170       .db $9f, $9b, $98, $96, $95, $94, $92, $90
15171       .db $90, $9a, $97, $95, $93, $92
15172 
15173 PlayFlagpoleSlide:
15174        lda #$40               ;store length of flagpole sound
15175        sta Squ1_SfxLenCounter
15176        lda #$62               ;load part of reg contents for flagpole sound
15177        jsr SetFreq_Squ1
15178        ldx #$99               ;now load the rest
15179        bne FPS2nd
15180 
15181 PlaySmallJump:
15182        lda #$26               ;branch here for small mario jumping sound
15183        bne JumpRegContents
15184 
15185 PlayBigJump:
15186        lda #$18               ;branch here for big mario jumping sound
15187 
15188 JumpRegContents:
15189        ldx #$82               ;note that small and big jump borrow each others' reg contents
15190        ldy #$a7               ;anyway, this loads the first part of mario's jumping sound
15191        jsr PlaySqu1Sfx
15192        lda #$28               ;store length of sfx for both jumping sounds
15193        sta Squ1_SfxLenCounter ;then continue on here
15194 
15195 ContinueSndJump:
15196           lda Squ1_SfxLenCounter ;jumping sounds seem to be composed of three parts
15197           cmp #$25               ;check for time to play second part yet
15198           bne N2Prt
15199           ldx #$5f               ;load second part
15200           ldy #$f6
15201           bne DmpJpFPS           ;unconditional branch
15202 N2Prt:    cmp #$20               ;check for third part
15203           bne DecJpFPS
15204           ldx #$48               ;load third part
15205 FPS2nd:   ldy #$bc               ;the flagpole slide sound shares part of third part
15206 DmpJpFPS: jsr Dump_Squ1_Regs
15207           bne DecJpFPS           ;unconditional branch outta here
15208 
15209 PlayFireballThrow:
15210         lda #$05
15211         ldy #$99                 ;load reg contents for fireball throw sound
15212         bne Fthrow               ;unconditional branch
15213 
15214 PlayBump:
15215           lda #$0a                ;load length of sfx and reg contents for bump sound
15216           ldy #$93
15217 Fthrow:   ldx #$9e                ;the fireball sound shares reg contents with the bump sound
15218           sta Squ1_SfxLenCounter
15219           lda #$0c                ;load offset for bump sound
15220           jsr PlaySqu1Sfx
15221 
15222 ContinueBumpThrow:    
15223           lda Squ1_SfxLenCounter  ;check for second part of bump sound
15224           cmp #$06   
15225           bne DecJpFPS
15226           lda #$bb                ;load second part directly
15227           sta SND_SQUARE1_REG+1
15228 DecJpFPS: bne BranchToDecLength1  ;unconditional branch
15229 
15230 
15231 Square1SfxHandler:
15232        ldy Square1SoundQueue   ;check for sfx in queue
15233        beq CheckSfx1Buffer
15234        sty Square1SoundBuffer  ;if found, put in buffer
15235        bmi PlaySmallJump       ;small jump
15236        lsr Square1SoundQueue
15237        bcs PlayBigJump         ;big jump
15238        lsr Square1SoundQueue
15239        bcs PlayBump            ;bump
15240        lsr Square1SoundQueue
15241        bcs PlaySwimStomp       ;swim/stomp
15242        lsr Square1SoundQueue
15243        bcs PlaySmackEnemy      ;smack enemy
15244        lsr Square1SoundQueue
15245        bcs PlayPipeDownInj     ;pipedown/injury
15246        lsr Square1SoundQueue
15247        bcs PlayFireballThrow   ;fireball throw
15248        lsr Square1SoundQueue
15249        bcs PlayFlagpoleSlide   ;slide flagpole
15250 
15251 CheckSfx1Buffer:
15252        lda Square1SoundBuffer   ;check for sfx in buffer 
15253        beq ExS1H                ;if not found, exit sub
15254        bmi ContinueSndJump      ;small mario jump 
15255        lsr
15256        bcs ContinueSndJump      ;big mario jump 
15257        lsr
15258        bcs ContinueBumpThrow    ;bump
15259        lsr
15260        bcs ContinueSwimStomp    ;swim/stomp
15261        lsr
15262        bcs ContinueSmackEnemy   ;smack enemy
15263        lsr
15264        bcs ContinuePipeDownInj  ;pipedown/injury
15265        lsr
15266        bcs ContinueBumpThrow    ;fireball throw
15267        lsr
15268        bcs DecrementSfx1Length  ;slide flagpole
15269 ExS1H: rts
15270 
15271 PlaySwimStomp:
15272       lda #$0e               ;store length of swim/stomp sound
15273       sta Squ1_SfxLenCounter
15274       ldy #$9c               ;store reg contents for swim/stomp sound
15275       ldx #$9e
15276       lda #$26
15277       jsr PlaySqu1Sfx
15278 
15279 ContinueSwimStomp: 
15280       ldy Squ1_SfxLenCounter        ;look up reg contents in data section based on
15281       lda SwimStompEnvelopeData-1,y ;length of sound left, used to control sound's
15282       sta SND_SQUARE1_REG           ;envelope
15283       cpy #$06   
15284       bne BranchToDecLength1
15285       lda #$9e                      ;when the length counts down to a certain point, put this
15286       sta SND_SQUARE1_REG+2         ;directly into the LSB of square 1's frequency divider
15287 
15288 BranchToDecLength1: 
15289       bne DecrementSfx1Length  ;unconditional branch (regardless of how we got here)
15290 
15291 PlaySmackEnemy:
15292       lda #$0e                 ;store length of smack enemy sound
15293       ldy #$cb
15294       ldx #$9f
15295       sta Squ1_SfxLenCounter
15296       lda #$28                 ;store reg contents for smack enemy sound
15297       jsr PlaySqu1Sfx
15298       bne DecrementSfx1Length  ;unconditional branch
15299 
15300 ContinueSmackEnemy:
15301         ldy Squ1_SfxLenCounter  ;check about halfway through
15302         cpy #$08
15303         bne SmSpc
15304         lda #$a0                ;if we're at the about-halfway point, make the second tone
15305         sta SND_SQUARE1_REG+2   ;in the smack enemy sound
15306         lda #$9f
15307         bne SmTick
15308 SmSpc:  lda #$90                ;this creates spaces in the sound, giving it its distinct noise
15309 SmTick: sta SND_SQUARE1_REG
15310 
15311 DecrementSfx1Length:
15312       dec Squ1_SfxLenCounter    ;decrement length of sfx
15313       bne ExSfx1
15314 
15315 StopSquare1Sfx:
15316         ldx #$00                ;if end of sfx reached, clear buffer
15317         stx $f1                 ;and stop making the sfx
15318         ldx #$0e
15319         stx SND_MASTERCTRL_REG
15320         ldx #$0f
15321         stx SND_MASTERCTRL_REG
15322 ExSfx1: rts
15323 
15324 PlayPipeDownInj:  
15325       lda #$2f                ;load length of pipedown sound
15326       sta Squ1_SfxLenCounter
15327 
15328 ContinuePipeDownInj:
15329          lda Squ1_SfxLenCounter  ;some bitwise logic, forces the regs
15330          lsr                     ;to be written to only during six specific times
15331          bcs NoPDwnL             ;during which d3 must be set and d1-0 must be clear
15332          lsr
15333          bcs NoPDwnL
15334          and #%00000010
15335          beq NoPDwnL
15336          ldy #$91                ;and this is where it actually gets written in
15337          ldx #$9a
15338          lda #$44
15339          jsr PlaySqu1Sfx
15340 NoPDwnL: jmp DecrementSfx1Length
15341 
15342 ;--------------------------------
15343 
15344 ExtraLifeFreqData:
15345       .db $58, $02, $54, $56, $4e, $44
15346 
15347 PowerUpGrabFreqData:
15348       .db $4c, $52, $4c, $48, $3e, $36, $3e, $36, $30
15349       .db $28, $4a, $50, $4a, $64, $3c, $32, $3c, $32
15350       .db $2c, $24, $3a, $64, $3a, $34, $2c, $22, $2c
15351 
15352 ;residual frequency data
15353       .db $22, $1c, $14
15354 
15355 PUp_VGrow_FreqData:
15356       .db $14, $04, $22, $24, $16, $04, $24, $26 ;used by both
15357       .db $18, $04, $26, $28, $1a, $04, $28, $2a
15358       .db $1c, $04, $2a, $2c, $1e, $04, $2c, $2e ;used by vinegrow
15359       .db $20, $04, $2e, $30, $22, $04, $30, $32
15360 
15361 PlayCoinGrab:
15362         lda #$35             ;load length of coin grab sound
15363         ldx #$8d             ;and part of reg contents
15364         bne CGrab_TTickRegL
15365 
15366 PlayTimerTick:
15367         lda #$06             ;load length of timer tick sound
15368         ldx #$98             ;and part of reg contents
15369 
15370 CGrab_TTickRegL:
15371         sta Squ2_SfxLenCounter 
15372         ldy #$7f                ;load the rest of reg contents 
15373         lda #$42                ;of coin grab and timer tick sound
15374         jsr PlaySqu2Sfx
15375 
15376 ContinueCGrabTTick:
15377         lda Squ2_SfxLenCounter  ;check for time to play second tone yet
15378         cmp #$30                ;timer tick sound also executes this, not sure why
15379         bne N2Tone
15380         lda #$54                ;if so, load the tone directly into the reg
15381         sta SND_SQUARE2_REG+2
15382 N2Tone: bne DecrementSfx2Length
15383 
15384 PlayBlast:
15385         lda #$20                ;load length of fireworks/gunfire sound
15386         sta Squ2_SfxLenCounter
15387         ldy #$94                ;load reg contents of fireworks/gunfire sound
15388         lda #$5e
15389         bne SBlasJ
15390 
15391 ContinueBlast:
15392         lda Squ2_SfxLenCounter  ;check for time to play second part
15393         cmp #$18
15394         bne DecrementSfx2Length
15395         ldy #$93                ;load second part reg contents then
15396         lda #$18
15397 SBlasJ: bne BlstSJp             ;unconditional branch to load rest of reg contents
15398 
15399 PlayPowerUpGrab:
15400         lda #$36                    ;load length of power-up grab sound
15401         sta Squ2_SfxLenCounter
15402 
15403 ContinuePowerUpGrab:   
15404         lda Squ2_SfxLenCounter      ;load frequency reg based on length left over
15405         lsr                         ;divide by 2
15406         bcs DecrementSfx2Length     ;alter frequency every other frame
15407         tay
15408         lda PowerUpGrabFreqData-1,y ;use length left over / 2 for frequency offset
15409         ldx #$5d                    ;store reg contents of power-up grab sound
15410         ldy #$7f
15411 
15412 LoadSqu2Regs:
15413         jsr PlaySqu2Sfx
15414 
15415 DecrementSfx2Length:
15416         dec Squ2_SfxLenCounter   ;decrement length of sfx
15417         bne ExSfx2
15418 
15419 EmptySfx2Buffer:
15420         ldx #$00                ;initialize square 2's sound effects buffer
15421         stx Square2SoundBuffer
15422 
15423 StopSquare2Sfx:
15424         ldx #$0d                ;stop playing the sfx
15425         stx SND_MASTERCTRL_REG 
15426         ldx #$0f
15427         stx SND_MASTERCTRL_REG
15428 ExSfx2: rts
15429 
15430 Square2SfxHandler:
15431         lda Square2SoundBuffer ;special handling for the 1-up sound to keep it
15432         and #Sfx_ExtraLife     ;from being interrupted by other sounds on square 2
15433         bne ContinueExtraLife
15434         ldy Square2SoundQueue  ;check for sfx in queue
15435         beq CheckSfx2Buffer
15436         sty Square2SoundBuffer ;if found, put in buffer and check for the following
15437         bmi PlayBowserFall     ;bowser fall
15438         lsr Square2SoundQueue
15439         bcs PlayCoinGrab       ;coin grab
15440         lsr Square2SoundQueue
15441         bcs PlayGrowPowerUp    ;power-up reveal
15442         lsr Square2SoundQueue
15443         bcs PlayGrowVine       ;vine grow
15444         lsr Square2SoundQueue
15445         bcs PlayBlast          ;fireworks/gunfire
15446         lsr Square2SoundQueue
15447         bcs PlayTimerTick      ;timer tick
15448         lsr Square2SoundQueue
15449         bcs PlayPowerUpGrab    ;power-up grab
15450         lsr Square2SoundQueue
15451         bcs PlayExtraLife      ;1-up
15452 
15453 CheckSfx2Buffer:
15454         lda Square2SoundBuffer   ;check for sfx in buffer
15455         beq ExS2H                ;if not found, exit sub
15456         bmi ContinueBowserFall   ;bowser fall
15457         lsr
15458         bcs Cont_CGrab_TTick     ;coin grab
15459         lsr
15460         bcs ContinueGrowItems    ;power-up reveal
15461         lsr
15462         bcs ContinueGrowItems    ;vine grow
15463         lsr
15464         bcs ContinueBlast        ;fireworks/gunfire
15465         lsr
15466         bcs Cont_CGrab_TTick     ;timer tick
15467         lsr
15468         bcs ContinuePowerUpGrab  ;power-up grab
15469         lsr
15470         bcs ContinueExtraLife    ;1-up
15471 ExS2H:  rts
15472 
15473 Cont_CGrab_TTick:
15474         jmp ContinueCGrabTTick
15475 
15476 JumpToDecLength2:
15477         jmp DecrementSfx2Length
15478 
15479 PlayBowserFall:    
15480          lda #$38                ;load length of bowser defeat sound
15481          sta Squ2_SfxLenCounter
15482          ldy #$c4                ;load contents of reg for bowser defeat sound
15483          lda #$18
15484 BlstSJp: bne PBFRegs
15485 
15486 ContinueBowserFall:
15487           lda Squ2_SfxLenCounter   ;check for almost near the end
15488           cmp #$08
15489           bne DecrementSfx2Length
15490           ldy #$a4                 ;if so, load the rest of reg contents for bowser defeat sound
15491           lda #$5a
15492 PBFRegs:  ldx #$9f                 ;the fireworks/gunfire sound shares part of reg contents here
15493 EL_LRegs: bne LoadSqu2Regs         ;this is an unconditional branch outta here
15494 
15495 PlayExtraLife:
15496         lda #$30                  ;load length of 1-up sound
15497         sta Squ2_SfxLenCounter
15498 
15499 ContinueExtraLife:
15500           lda Squ2_SfxLenCounter   
15501           ldx #$03                  ;load new tones only every eight frames
15502 DivLLoop: lsr
15503           bcs JumpToDecLength2      ;if any bits set here, branch to dec the length
15504           dex
15505           bne DivLLoop              ;do this until all bits checked, if none set, continue
15506           tay
15507           lda ExtraLifeFreqData-1,y ;load our reg contents
15508           ldx #$82
15509           ldy #$7f
15510           bne EL_LRegs              ;unconditional branch
15511 
15512 PlayGrowPowerUp:
15513         lda #$10                ;load length of power-up reveal sound
15514         bne GrowItemRegs
15515 
15516 PlayGrowVine:
15517         lda #$20                ;load length of vine grow sound
15518 
15519 GrowItemRegs:
15520         sta Squ2_SfxLenCounter   
15521         lda #$7f                  ;load contents of reg for both sounds directly
15522         sta SND_SQUARE2_REG+1
15523         lda #$00                  ;start secondary counter for both sounds
15524         sta Sfx_SecondaryCounter
15525 
15526 ContinueGrowItems:
15527         inc Sfx_SecondaryCounter  ;increment secondary counter for both sounds
15528         lda Sfx_SecondaryCounter  ;this sound doesn't decrement the usual counter
15529         lsr                       ;divide by 2 to get the offset
15530         tay
15531         cpy Squ2_SfxLenCounter    ;have we reached the end yet?
15532         beq StopGrowItems         ;if so, branch to jump, and stop playing sounds
15533         lda #$9d                  ;load contents of other reg directly
15534         sta SND_SQUARE2_REG
15535         lda PUp_VGrow_FreqData,y  ;use secondary counter / 2 as offset for frequency regs
15536         jsr SetFreq_Squ2
15537         rts
15538 
15539 StopGrowItems:
15540         jmp EmptySfx2Buffer       ;branch to stop playing sounds
15541 
15542 ;--------------------------------
15543 
15544 BrickShatterFreqData:
15545         .db $01, $0e, $0e, $0d, $0b, $06, $0c, $0f
15546         .db $0a, $09, $03, $0d, $08, $0d, $06, $0c
15547 
15548 PlayBrickShatter:
15549         lda #$20                 ;load length of brick shatter sound
15550         sta Noise_SfxLenCounter
15551 
15552 ContinueBrickShatter:
15553         lda Noise_SfxLenCounter  
15554         lsr                         ;divide by 2 and check for bit set to use offset
15555         bcc DecrementSfx3Length
15556         tay
15557         ldx BrickShatterFreqData,y  ;load reg contents of brick shatter sound
15558         lda BrickShatterEnvData,y
15559 
15560 PlayNoiseSfx:
15561         sta SND_NOISE_REG        ;play the sfx
15562         stx SND_NOISE_REG+2
15563         lda #$18
15564         sta SND_NOISE_REG+3
15565 
15566 DecrementSfx3Length:
15567         dec Noise_SfxLenCounter  ;decrement length of sfx
15568         bne ExSfx3
15569         lda #$f0                 ;if done, stop playing the sfx
15570         sta SND_NOISE_REG
15571         lda #$00
15572         sta NoiseSoundBuffer
15573 ExSfx3: rts
15574 
15575 NoiseSfxHandler:
15576         ldy NoiseSoundQueue   ;check for sfx in queue
15577         beq CheckNoiseBuffer
15578         sty NoiseSoundBuffer  ;if found, put in buffer
15579         lsr NoiseSoundQueue
15580         bcs PlayBrickShatter  ;brick shatter
15581         lsr NoiseSoundQueue
15582         bcs PlayBowserFlame   ;bowser flame
15583 
15584 CheckNoiseBuffer:
15585         lda NoiseSoundBuffer      ;check for sfx in buffer
15586         beq ExNH                  ;if not found, exit sub
15587         lsr
15588         bcs ContinueBrickShatter  ;brick shatter
15589         lsr
15590         bcs ContinueBowserFlame   ;bowser flame
15591 ExNH:   rts
15592 
15593 PlayBowserFlame:
15594         lda #$40                    ;load length of bowser flame sound
15595         sta Noise_SfxLenCounter
15596 
15597 ContinueBowserFlame:
15598         lda Noise_SfxLenCounter
15599         lsr
15600         tay
15601         ldx #$0f                    ;load reg contents of bowser flame sound
15602         lda BowserFlameEnvData-1,y
15603         bne PlayNoiseSfx            ;unconditional branch here
15604 
15605 ;--------------------------------
15606 
15607 ContinueMusic:
15608         jmp HandleSquare2Music  ;if we have music, start with square 2 channel
15609 
15610 MusicHandler:
15611         lda EventMusicQueue     ;check event music queue
15612         bne LoadEventMusic
15613         lda AreaMusicQueue      ;check area music queue
15614         bne LoadAreaMusic
15615         lda EventMusicBuffer    ;check both buffers
15616         ora AreaMusicBuffer
15617         bne ContinueMusic 
15618         rts                     ;no music, then leave
15619 
15620 LoadEventMusic:
15621            sta EventMusicBuffer      ;copy event music queue contents to buffer
15622            cmp #DeathMusic           ;is it death music?
15623            bne NoStopSfx             ;if not, jump elsewhere
15624            jsr StopSquare1Sfx        ;stop sfx in square 1 and 2
15625            jsr StopSquare2Sfx        ;but clear only square 1's sfx buffer
15626 NoStopSfx: ldx AreaMusicBuffer
15627            stx AreaMusicBuffer_Alt   ;save current area music buffer to be re-obtained later
15628            ldy #$00
15629            sty NoteLengthTblAdder    ;default value for additional length byte offset
15630            sty AreaMusicBuffer       ;clear area music buffer
15631            cmp #TimeRunningOutMusic  ;is it time running out music?
15632            bne FindEventMusicHeader
15633            ldx #$08                  ;load offset to be added to length byte of header
15634            stx NoteLengthTblAdder
15635            bne FindEventMusicHeader  ;unconditional branch
15636 
15637 LoadAreaMusic:
15638          cmp #$04                  ;is it underground music?
15639          bne NoStop1               ;no, do not stop square 1 sfx
15640          jsr StopSquare1Sfx
15641 NoStop1: ldy #$10                  ;start counter used only by ground level music
15642 GMLoopB: sty GroundMusicHeaderOfs
15643 
15644 HandleAreaMusicLoopB:
15645          ldy #$00                  ;clear event music buffer
15646          sty EventMusicBuffer
15647          sta AreaMusicBuffer       ;copy area music queue contents to buffer
15648          cmp #$01                  ;is it ground level music?
15649          bne FindAreaMusicHeader
15650          inc GroundMusicHeaderOfs  ;increment but only if playing ground level music
15651          ldy GroundMusicHeaderOfs  ;is it time to loopback ground level music?
15652          cpy #$32
15653          bne LoadHeader            ;branch ahead with alternate offset
15654          ldy #$11
15655          bne GMLoopB               ;unconditional branch
15656 
15657 FindAreaMusicHeader:
15658         ldy #$08                   ;load Y for offset of area music
15659         sty MusicOffset_Square2    ;residual instruction here
15660 
15661 FindEventMusicHeader:
15662         iny                       ;increment Y pointer based on previously loaded queue contents
15663         lsr                       ;bit shift and increment until we find a set bit for music
15664         bcc FindEventMusicHeader
15665 
15666 LoadHeader:
15667         lda MusicHeaderOffsetData,y  ;load offset for header
15668         tay
15669         lda MusicHeaderData,y        ;now load the header
15670         sta NoteLenLookupTblOfs
15671         lda MusicHeaderData+1,y
15672         sta MusicDataLow
15673         lda MusicHeaderData+2,y
15674         sta MusicDataHigh
15675         lda MusicHeaderData+3,y
15676         sta MusicOffset_Triangle
15677         lda MusicHeaderData+4,y
15678         sta MusicOffset_Square1
15679         lda MusicHeaderData+5,y
15680         sta MusicOffset_Noise
15681         sta NoiseDataLoopbackOfs
15682         lda #$01                     ;initialize music note counters
15683         sta Squ2_NoteLenCounter
15684         sta Squ1_NoteLenCounter
15685         sta Tri_NoteLenCounter
15686         sta Noise_BeatLenCounter
15687         lda #$00                     ;initialize music data offset for square 2
15688         sta MusicOffset_Square2
15689         sta AltRegContentFlag        ;initialize alternate control reg data used by square 1
15690         lda #$0b                     ;disable triangle channel and reenable it
15691         sta SND_MASTERCTRL_REG
15692         lda #$0f
15693         sta SND_MASTERCTRL_REG
15694 
15695 HandleSquare2Music:
15696         dec Squ2_NoteLenCounter  ;decrement square 2 note length
15697         bne MiscSqu2MusicTasks   ;is it time for more data?  if not, branch to end tasks
15698         ldy MusicOffset_Square2  ;increment square 2 music offset and fetch data
15699         inc MusicOffset_Square2
15700         lda (MusicData),y
15701         beq EndOfMusicData       ;if zero, the data is a null terminator
15702         bpl Squ2NoteHandler      ;if non-negative, data is a note
15703         bne Squ2LengthHandler    ;otherwise it is length data
15704 
15705 EndOfMusicData:
15706         lda EventMusicBuffer     ;check secondary buffer for time running out music
15707         cmp #TimeRunningOutMusic
15708         bne NotTRO
15709         lda AreaMusicBuffer_Alt  ;load previously saved contents of primary buffer
15710         bne MusicLoopBack        ;and start playing the song again if there is one
15711 NotTRO: and #VictoryMusic        ;check for victory music (the only secondary that loops)
15712         bne VictoryMLoopBack
15713         lda AreaMusicBuffer      ;check primary buffer for any music except pipe intro
15714         and #%01011111
15715         bne MusicLoopBack        ;if any area music except pipe intro, music loops
15716         lda #$00                 ;clear primary and secondary buffers and initialize
15717         sta AreaMusicBuffer      ;control regs of square and triangle channels
15718         sta EventMusicBuffer
15719         sta SND_TRIANGLE_REG
15720         lda #$90    
15721         sta SND_SQUARE1_REG
15722         sta SND_SQUARE2_REG
15723         rts
15724 
15725 MusicLoopBack:
15726         jmp HandleAreaMusicLoopB
15727 
15728 VictoryMLoopBack:
15729         jmp LoadEventMusic
15730 
15731 Squ2LengthHandler:
15732         jsr ProcessLengthData    ;store length of note
15733         sta Squ2_NoteLenBuffer
15734         ldy MusicOffset_Square2  ;fetch another byte (MUST NOT BE LENGTH BYTE!)
15735         inc MusicOffset_Square2
15736         lda (MusicData),y
15737 
15738 Squ2NoteHandler:
15739           ldx Square2SoundBuffer     ;is there a sound playing on this channel?
15740           bne SkipFqL1
15741           jsr SetFreq_Squ2           ;no, then play the note
15742           beq Rest                   ;check to see if note is rest
15743           jsr LoadControlRegs        ;if not, load control regs for square 2
15744 Rest:     sta Squ2_EnvelopeDataCtrl  ;save contents of A
15745           jsr Dump_Sq2_Regs          ;dump X and Y into square 2 control regs
15746 SkipFqL1: lda Squ2_NoteLenBuffer     ;save length in square 2 note counter
15747           sta Squ2_NoteLenCounter
15748 
15749 MiscSqu2MusicTasks:
15750            lda Square2SoundBuffer     ;is there a sound playing on square 2?
15751            bne HandleSquare1Music
15752            lda EventMusicBuffer       ;check for death music or d4 set on secondary buffer
15753            and #%10010001             ;note that regs for death music or d4 are loaded by default
15754            bne HandleSquare1Music
15755            ldy Squ2_EnvelopeDataCtrl  ;check for contents saved from LoadControlRegs
15756            beq NoDecEnv1
15757            dec Squ2_EnvelopeDataCtrl  ;decrement unless already zero
15758 NoDecEnv1: jsr LoadEnvelopeData       ;do a load of envelope data to replace default
15759            sta SND_SQUARE2_REG        ;based on offset set by first load unless playing
15760            ldx #$7f                   ;death music or d4 set on secondary buffer
15761            stx SND_SQUARE2_REG+1
15762 
15763 HandleSquare1Music:
15764         ldy MusicOffset_Square1    ;is there a nonzero offset here?
15765         beq HandleTriangleMusic    ;if not, skip ahead to the triangle channel
15766         dec Squ1_NoteLenCounter    ;decrement square 1 note length
15767         bne MiscSqu1MusicTasks     ;is it time for more data?
15768 
15769 FetchSqu1MusicData:
15770         ldy MusicOffset_Square1    ;increment square 1 music offset and fetch data
15771         inc MusicOffset_Square1
15772         lda (MusicData),y
15773         bne Squ1NoteHandler        ;if nonzero, then skip this part
15774         lda #$83
15775         sta SND_SQUARE1_REG        ;store some data into control regs for square 1
15776         lda #$94                   ;and fetch another byte of data, used to give
15777         sta SND_SQUARE1_REG+1      ;death music its unique sound
15778         sta AltRegContentFlag
15779         bne FetchSqu1MusicData     ;unconditional branch
15780 
15781 Squ1NoteHandler:
15782            jsr AlternateLengthHandler
15783            sta Squ1_NoteLenCounter    ;save contents of A in square 1 note counter
15784            ldy Square1SoundBuffer     ;is there a sound playing on square 1?
15785            bne HandleTriangleMusic
15786            txa
15787            and #%00111110             ;change saved data to appropriate note format
15788            jsr SetFreq_Squ1           ;play the note
15789            beq SkipCtrlL
15790            jsr LoadControlRegs
15791 SkipCtrlL: sta Squ1_EnvelopeDataCtrl  ;save envelope offset
15792            jsr Dump_Squ1_Regs
15793 
15794 MiscSqu1MusicTasks:
15795               lda Square1SoundBuffer     ;is there a sound playing on square 1?
15796               bne HandleTriangleMusic
15797               lda EventMusicBuffer       ;check for death music or d4 set on secondary buffer
15798               and #%10010001
15799               bne DeathMAltReg
15800               ldy Squ1_EnvelopeDataCtrl  ;check saved envelope offset
15801               beq NoDecEnv2
15802               dec Squ1_EnvelopeDataCtrl  ;decrement unless already zero
15803 NoDecEnv2:    jsr LoadEnvelopeData       ;do a load of envelope data
15804               sta SND_SQUARE1_REG        ;based on offset set by first load
15805 DeathMAltReg: lda AltRegContentFlag      ;check for alternate control reg data
15806               bne DoAltLoad
15807               lda #$7f                   ;load this value if zero, the alternate value
15808 DoAltLoad:    sta SND_SQUARE1_REG+1      ;if nonzero, and let's move on
15809 
15810 HandleTriangleMusic:
15811         lda MusicOffset_Triangle
15812         dec Tri_NoteLenCounter    ;decrement triangle note length
15813         bne HandleNoiseMusic      ;is it time for more data?
15814         ldy MusicOffset_Triangle  ;increment square 1 music offset and fetch data
15815         inc MusicOffset_Triangle
15816         lda (MusicData),y
15817         beq LoadTriCtrlReg        ;if zero, skip all this and move on to noise 
15818         bpl TriNoteHandler        ;if non-negative, data is note
15819         jsr ProcessLengthData     ;otherwise, it is length data
15820         sta Tri_NoteLenBuffer     ;save contents of A
15821         lda #$1f
15822         sta SND_TRIANGLE_REG      ;load some default data for triangle control reg
15823         ldy MusicOffset_Triangle  ;fetch another byte
15824         inc MusicOffset_Triangle
15825         lda (MusicData),y
15826         beq LoadTriCtrlReg        ;check once more for nonzero data
15827 
15828 TriNoteHandler:
15829           jsr SetFreq_Tri
15830           ldx Tri_NoteLenBuffer   ;save length in triangle note counter
15831           stx Tri_NoteLenCounter
15832           lda EventMusicBuffer
15833           and #%01101110          ;check for death music or d4 set on secondary buffer
15834           bne NotDOrD4            ;if playing any other secondary, skip primary buffer check
15835           lda AreaMusicBuffer     ;check primary buffer for water or castle level music
15836           and #%00001010
15837           beq HandleNoiseMusic    ;if playing any other primary, or death or d4, go on to noise routine
15838 NotDOrD4: txa                     ;if playing water or castle music or any secondary
15839           cmp #$12                ;besides death music or d4 set, check length of note
15840           bcs LongN
15841           lda EventMusicBuffer    ;check for win castle music again if not playing a long note
15842           and #EndOfCastleMusic
15843           beq MediN
15844           lda #$0f                ;load value $0f if playing the win castle music and playing a short
15845           bne LoadTriCtrlReg      ;note, load value $1f if playing water or castle level music or any
15846 MediN:    lda #$1f                ;secondary besides death and d4 except win castle or win castle and playing
15847           bne LoadTriCtrlReg      ;a short note, and load value $ff if playing a long note on water, castle
15848 LongN:    lda #$ff                ;or any secondary (including win castle) except death and d4
15849 
15850 LoadTriCtrlReg:           
15851         sta SND_TRIANGLE_REG      ;save final contents of A into control reg for triangle
15852 
15853 HandleNoiseMusic:
15854         lda AreaMusicBuffer       ;check if playing underground or castle music
15855         and #%11110011
15856         beq ExitMusicHandler      ;if so, skip the noise routine
15857         dec Noise_BeatLenCounter  ;decrement noise beat length
15858         bne ExitMusicHandler      ;is it time for more data?
15859 
15860 FetchNoiseBeatData:
15861         ldy MusicOffset_Noise       ;increment noise beat offset and fetch data
15862         inc MusicOffset_Noise
15863         lda (MusicData),y           ;get noise beat data, if nonzero, branch to handle
15864         bne NoiseBeatHandler
15865         lda NoiseDataLoopbackOfs    ;if data is zero, reload original noise beat offset
15866         sta MusicOffset_Noise       ;and loopback next time around
15867         bne FetchNoiseBeatData      ;unconditional branch
15868 
15869 NoiseBeatHandler:
15870         jsr AlternateLengthHandler
15871         sta Noise_BeatLenCounter    ;store length in noise beat counter
15872         txa
15873         and #%00111110              ;reload data and erase length bits
15874         beq SilentBeat              ;if no beat data, silence
15875         cmp #$30                    ;check the beat data and play the appropriate
15876         beq LongBeat                ;noise accordingly
15877         cmp #$20
15878         beq StrongBeat
15879         and #%00010000  
15880         beq SilentBeat
15881         lda #$1c        ;short beat data
15882         ldx #$03
15883         ldy #$18
15884         bne PlayBeat
15885 
15886 StrongBeat:
15887         lda #$1c        ;strong beat data
15888         ldx #$0c
15889         ldy #$18
15890         bne PlayBeat
15891 
15892 LongBeat:
15893         lda #$1c        ;long beat data
15894         ldx #$03
15895         ldy #$58
15896         bne PlayBeat
15897 
15898 SilentBeat:
15899         lda #$10        ;silence
15900 
15901 PlayBeat:
15902         sta SND_NOISE_REG    ;load beat data into noise regs
15903         stx SND_NOISE_REG+2
15904         sty SND_NOISE_REG+3
15905 
15906 ExitMusicHandler:
15907         rts
15908 
15909 AlternateLengthHandler:
15910         tax            ;save a copy of original byte into X
15911         ror            ;save LSB from original byte into carry
15912         txa            ;reload original byte and rotate three times
15913         rol            ;turning xx00000x into 00000xxx, with the
15914         rol            ;bit in carry as the MSB here
15915         rol
15916 
15917 ProcessLengthData:
15918         and #%00000111              ;clear all but the three LSBs
15919         clc
15920         adc $f0                     ;add offset loaded from first header byte
15921         adc NoteLengthTblAdder      ;add extra if time running out music
15922         tay
15923         lda MusicLengthLookupTbl,y  ;load length
15924         rts
15925 
15926 LoadControlRegs:
15927            lda EventMusicBuffer  ;check secondary buffer for win castle music
15928            and #EndOfCastleMusic
15929            beq NotECstlM
15930            lda #$04              ;this value is only used for win castle music
15931            bne AllMus            ;unconditional branch
15932 NotECstlM: lda AreaMusicBuffer
15933            and #%01111101        ;check primary buffer for water music
15934            beq WaterMus
15935            lda #$08              ;this is the default value for all other music
15936            bne AllMus
15937 WaterMus:  lda #$28              ;this value is used for water music and all other event music
15938 AllMus:    ldx #$82              ;load contents of other sound regs for square 2
15939            ldy #$7f
15940            rts
15941 
15942 LoadEnvelopeData:
15943         lda EventMusicBuffer           ;check secondary buffer for win castle music
15944         and #EndOfCastleMusic
15945         beq LoadUsualEnvData
15946         lda EndOfCastleMusicEnvData,y  ;load data from offset for win castle music
15947         rts
15948 
15949 LoadUsualEnvData:
15950         lda AreaMusicBuffer            ;check primary buffer for water music
15951         and #%01111101
15952         beq LoadWaterEventMusEnvData
15953         lda AreaMusicEnvData,y         ;load default data from offset for all other music
15954         rts
15955 
15956 LoadWaterEventMusEnvData:
15957         lda WaterEventMusEnvData,y     ;load data from offset for water music and all other event music
15958         rts
15959 
15960 ;--------------------------------
15961 
15962 ;music header offsets
15963 
15964 MusicHeaderData:
15965       .db DeathMusHdr-MHD           ;event music
15966       .db GameOverMusHdr-MHD
15967       .db VictoryMusHdr-MHD
15968       .db WinCastleMusHdr-MHD
15969       .db GameOverMusHdr-MHD
15970       .db EndOfLevelMusHdr-MHD
15971       .db TimeRunningOutHdr-MHD
15972       .db SilenceHdr-MHD
15973 
15974       .db GroundLevelPart1Hdr-MHD   ;area music
15975       .db WaterMusHdr-MHD
15976       .db UndergroundMusHdr-MHD
15977       .db CastleMusHdr-MHD
15978       .db Star_CloudHdr-MHD
15979       .db GroundLevelLeadInHdr-MHD
15980       .db Star_CloudHdr-MHD
15981       .db SilenceHdr-MHD
15982 
15983       .db GroundLevelLeadInHdr-MHD  ;ground level music layout
15984       .db GroundLevelPart1Hdr-MHD, GroundLevelPart1Hdr-MHD
15985       .db GroundLevelPart2AHdr-MHD, GroundLevelPart2BHdr-MHD, GroundLevelPart2AHdr-MHD, GroundLevelPart2CHdr-MHD
15986       .db GroundLevelPart2AHdr-MHD, GroundLevelPart2BHdr-MHD, GroundLevelPart2AHdr-MHD, GroundLevelPart2CHdr-MHD
15987       .db GroundLevelPart3AHdr-MHD, GroundLevelPart3BHdr-MHD, GroundLevelPart3AHdr-MHD, GroundLevelLeadInHdr-MHD
15988       .db GroundLevelPart1Hdr-MHD, GroundLevelPart1Hdr-MHD
15989       .db GroundLevelPart4AHdr-MHD, GroundLevelPart4BHdr-MHD, GroundLevelPart4AHdr-MHD, GroundLevelPart4CHdr-MHD
15990       .db GroundLevelPart4AHdr-MHD, GroundLevelPart4BHdr-MHD, GroundLevelPart4AHdr-MHD, GroundLevelPart4CHdr-MHD
15991       .db GroundLevelPart3AHdr-MHD, GroundLevelPart3BHdr-MHD, GroundLevelPart3AHdr-MHD, GroundLevelLeadInHdr-MHD
15992       .db GroundLevelPart4AHdr-MHD, GroundLevelPart4BHdr-MHD, GroundLevelPart4AHdr-MHD, GroundLevelPart4CHdr-MHD
15993 
15994 ;music headers
15995 ;header format is as follows: 
15996 ;1 byte - length byte offset
15997 ;2 bytes -  music data address
15998 ;1 byte - triangle data offset
15999 ;1 byte - square 1 data offset
16000 ;1 byte - noise data offset (not used by secondary music)
16001 
16002 TimeRunningOutHdr:    .db $08, <TimeRunOutMusData, >TimeRunOutMusData, $27, $18
16003 Star_CloudHdr:        .db $20, <Star_CloudMData, >Star_CloudMData, $2e, $1a, $40
16004 EndOfLevelMusHdr:     .db $20, <WinLevelMusData, >WinLevelMusData, $3d, $21
16005 ResidualHeaderData:   .db $20, $c4, $fc, $3f, $1d
16006 UndergroundMusHdr:    .db $18, <UndergroundMusData, >UndergroundMusData, $00, $00
16007 SilenceHdr:           .db $08, <SilenceData, >SilenceData, $00
16008 CastleMusHdr:         .db $00, <CastleMusData, >CastleMusData, $93, $62
16009 VictoryMusHdr:        .db $10, <VictoryMusData, >VictoryMusData, $24, $14
16010 GameOverMusHdr:       .db $18, <GameOverMusData, >GameOverMusData, $1e, $14
16011 WaterMusHdr:          .db $08, <WaterMusData, >WaterMusData, $a0, $70, $68
16012 WinCastleMusHdr:      .db $08, <EndOfCastleMusData, >EndOfCastleMusData, $4c, $24
16013 GroundLevelPart1Hdr:  .db $18, <GroundM_P1Data, >GroundM_P1Data, $2d, $1c, $b8
16014 GroundLevelPart2AHdr: .db $18, <GroundM_P2AData, >GroundM_P2AData, $20, $12, $70
16015 GroundLevelPart2BHdr: .db $18, <GroundM_P2BData, >GroundM_P2BData, $1b, $10, $44
16016 GroundLevelPart2CHdr: .db $18, <GroundM_P2CData, >GroundM_P2CData, $11, $0a, $1c
16017 GroundLevelPart3AHdr: .db $18, <GroundM_P3AData, >GroundM_P3AData, $2d, $10, $58
16018 GroundLevelPart3BHdr: .db $18, <GroundM_P3BData, >GroundM_P3BData, $14, $0d, $3f
16019 GroundLevelLeadInHdr: .db $18, <GroundMLdInData, >GroundMLdInData, $15, $0d, $21
16020 GroundLevelPart4AHdr: .db $18, <GroundM_P4AData, >GroundM_P4AData, $18, $10, $7a
16021 GroundLevelPart4BHdr: .db $18, <GroundM_P4BData, >GroundM_P4BData, $19, $0f, $54
16022 GroundLevelPart4CHdr: .db $18, <GroundM_P4CData, >GroundM_P4CData, $1e, $12, $2b
16023 DeathMusHdr:          .db $18, <DeathMusData, >DeathMusData, $1e, $0f, $2d
16024 
16025 ;--------------------------------
16026 
16027 ;MUSIC DATA
16028 ;square 2/triangle format
16029 ;d7 - length byte flag (0-note, 1-length)
16030 ;if d7 is set to 0 and d6-d0 is nonzero:
16031 ;d6-d0 - note offset in frequency look-up table (must be even)
16032 ;if d7 is set to 1:
16033 ;d6-d3 - unused
16034 ;d2-d0 - length offset in length look-up table
16035 ;value of $00 in square 2 data is used as null terminator, affects all sound channels
16036 ;value of $00 in triangle data causes routine to skip note
16037 
16038 ;square 1 format
16039 ;d7-d6, d0 - length offset in length look-up table (bit order is d0,d7,d6)
16040 ;d5-d1 - note offset in frequency look-up table
16041 ;value of $00 in square 1 data is flag alternate control reg data to be loaded
16042 
16043 ;noise format
16044 ;d7-d6, d0 - length offset in length look-up table (bit order is d0,d7,d6)
16045 ;d5-d4 - beat type (0 - rest, 1 - short, 2 - strong, 3 - long)
16046 ;d3-d1 - unused
16047 ;value of $00 in noise data is used as null terminator, affects only noise
16048 
16049 ;all music data is organized into sections (unless otherwise stated):
16050 ;square 2, square 1, triangle, noise
16051 
16052 Star_CloudMData:
16053       .db $84, $2c, $2c, $2c, $82, $04, $2c, $04, $85, $2c, $84, $2c, $2c
16054       .db $2a, $2a, $2a, $82, $04, $2a, $04, $85, $2a, $84, $2a, $2a, $00
16055 
16056       .db $1f, $1f, $1f, $98, $1f, $1f, $98, $9e, $98, $1f
16057       .db $1d, $1d, $1d, $94, $1d, $1d, $94, $9c, $94, $1d
16058 
16059       .db $86, $18, $85, $26, $30, $84, $04, $26, $30
16060       .db $86, $14, $85, $22, $2c, $84, $04, $22, $2c
16061 
16062       .db $21, $d0, $c4, $d0, $31, $d0, $c4, $d0, $00
16063 
16064 GroundM_P1Data:
16065       .db $85, $2c, $22, $1c, $84, $26, $2a, $82, $28, $26, $04
16066       .db $87, $22, $34, $3a, $82, $40, $04, $36, $84, $3a, $34
16067       .db $82, $2c, $30, $85, $2a
16068 
16069 SilenceData:
16070       .db $00
16071 
16072       .db $5d, $55, $4d, $15, $19, $96, $15, $d5, $e3, $eb
16073       .db $2d, $a6, $2b, $27, $9c, $9e, $59
16074 
16075       .db $85, $22, $1c, $14, $84, $1e, $22, $82, $20, $1e, $04, $87
16076       .db $1c, $2c, $34, $82, $36, $04, $30, $34, $04, $2c, $04, $26
16077       .db $2a, $85, $22
16078 
16079 GroundM_P2AData:
16080       .db $84, $04, $82, $3a, $38, $36, $32, $04, $34
16081       .db $04, $24, $26, $2c, $04, $26, $2c, $30, $00
16082 
16083       .db $05, $b4, $b2, $b0, $2b, $ac, $84
16084       .db $9c, $9e, $a2, $84, $94, $9c, $9e
16085 
16086       .db $85, $14, $22, $84, $2c, $85, $1e
16087       .db $82, $2c, $84, $2c, $1e
16088 
16089 GroundM_P2BData:
16090       .db $84, $04, $82, $3a, $38, $36, $32, $04, $34
16091       .db $04, $64, $04, $64, $86, $64, $00
16092 
16093       .db $05, $b4, $b2, $b0, $2b, $ac, $84
16094       .db $37, $b6, $b6, $45
16095 
16096       .db $85, $14, $1c, $82, $22, $84, $2c
16097       .db $4e, $82, $4e, $84, $4e, $22
16098 
16099 GroundM_P2CData:
16100       .db $84, $04, $85, $32, $85, $30, $86, $2c, $04, $00
16101 
16102       .db $05, $a4, $05, $9e, $05, $9d, $85
16103       
16104       .db $84, $14, $85, $24, $28, $2c, $82
16105       .db $22, $84, $22, $14
16106 
16107       .db $21, $d0, $c4, $d0, $31, $d0, $c4, $d0, $00
16108 
16109 GroundM_P3AData:
16110       .db $82, $2c, $84, $2c, $2c, $82, $2c, $30
16111       .db $04, $34, $2c, $04, $26, $86, $22, $00
16112 
16113       .db $a4, $25, $25, $a4, $29, $a2, $1d, $9c, $95
16114 
16115 GroundM_P3BData:
16116       .db $82, $2c, $2c, $04, $2c, $04, $2c, $30, $85, $34, $04, $04, $00
16117 
16118       .db $a4, $25, $25, $a4, $a8, $63, $04
16119 
16120 ;triangle data used by both sections of third part
16121       .db $85, $0e, $1a, $84, $24, $85, $22, $14, $84, $0c
16122 
16123 GroundMLdInData:
16124       .db $82, $34, $84, $34, $34, $82, $2c, $84, $34, $86, $3a, $04, $00
16125 
16126       .db $a0, $21, $21, $a0, $21, $2b, $05, $a3
16127 
16128       .db $82, $18, $84, $18, $18, $82, $18, $18, $04, $86, $3a, $22
16129 
16130 ;noise data used by lead-in and third part sections
16131       .db $31, $90, $31, $90, $31, $71, $31, $90, $90, $90, $00
16132 
16133 GroundM_P4AData:
16134       .db $82, $34, $84, $2c, $85, $22, $84, $24
16135       .db $82, $26, $36, $04, $36, $86, $26, $00
16136 
16137       .db $ac, $27, $5d, $1d, $9e, $2d, $ac, $9f
16138 
16139       .db $85, $14, $82, $20, $84, $22, $2c
16140       .db $1e, $1e, $82, $2c, $2c, $1e, $04
16141 
16142 GroundM_P4BData:
16143       .db $87, $2a, $40, $40, $40, $3a, $36 
16144       .db $82, $34, $2c, $04, $26, $86, $22, $00
16145 
16146       .db $e3, $f7, $f7, $f7, $f5, $f1, $ac, $27, $9e, $9d
16147 
16148       .db $85, $18, $82, $1e, $84, $22, $2a
16149       .db $22, $22, $82, $2c, $2c, $22, $04
16150 
16151 DeathMusData:
16152       .db $86, $04 ;death music share data with fourth part c of ground level music 
16153 
16154 GroundM_P4CData:
16155       .db $82, $2a, $36, $04, $36, $87, $36, $34, $30, $86, $2c, $04, $00
16156       
16157       .db $00, $68, $6a, $6c, $45 ;death music only
16158 
16159       .db $a2, $31, $b0, $f1, $ed, $eb, $a2, $1d, $9c, $95
16160 
16161       .db $86, $04 ;death music only
16162 
16163       .db $85, $22, $82, $22, $87, $22, $26, $2a, $84, $2c, $22, $86, $14
16164 
16165 ;noise data used by fourth part sections
16166       .db $51, $90, $31, $11, $00
16167 
16168 CastleMusData:
16169       .db $80, $22, $28, $22, $26, $22, $24, $22, $26
16170       .db $22, $28, $22, $2a, $22, $28, $22, $26
16171       .db $22, $28, $22, $26, $22, $24, $22, $26
16172       .db $22, $28, $22, $2a, $22, $28, $22, $26
16173       .db $20, $26, $20, $24, $20, $26, $20, $28
16174       .db $20, $26, $20, $28, $20, $26, $20, $24
16175       .db $20, $26, $20, $24, $20, $26, $20, $28
16176       .db $20, $26, $20, $28, $20, $26, $20, $24
16177       .db $28, $30, $28, $32, $28, $30, $28, $2e
16178       .db $28, $30, $28, $2e, $28, $2c, $28, $2e
16179       .db $28, $30, $28, $32, $28, $30, $28, $2e
16180       .db $28, $30, $28, $2e, $28, $2c, $28, $2e, $00
16181 
16182       .db $04, $70, $6e, $6c, $6e, $70, $72, $70, $6e
16183       .db $70, $6e, $6c, $6e, $70, $72, $70, $6e
16184       .db $6e, $6c, $6e, $70, $6e, $70, $6e, $6c
16185       .db $6e, $6c, $6e, $70, $6e, $70, $6e, $6c
16186       .db $76, $78, $76, $74, $76, $74, $72, $74
16187       .db $76, $78, $76, $74, $76, $74, $72, $74
16188 
16189       .db $84, $1a, $83, $18, $20, $84, $1e, $83, $1c, $28
16190       .db $26, $1c, $1a, $1c
16191 
16192 GameOverMusData:
16193       .db $82, $2c, $04, $04, $22, $04, $04, $84, $1c, $87
16194       .db $26, $2a, $26, $84, $24, $28, $24, $80, $22, $00
16195 
16196       .db $9c, $05, $94, $05, $0d, $9f, $1e, $9c, $98, $9d
16197 
16198       .db $82, $22, $04, $04, $1c, $04, $04, $84, $14
16199       .db $86, $1e, $80, $16, $80, $14
16200 
16201 TimeRunOutMusData:
16202       .db $81, $1c, $30, $04, $30, $30, $04, $1e, $32, $04, $32, $32
16203       .db $04, $20, $34, $04, $34, $34, $04, $36, $04, $84, $36, $00
16204 
16205       .db $46, $a4, $64, $a4, $48, $a6, $66, $a6, $4a, $a8, $68, $a8
16206       .db $6a, $44, $2b
16207 
16208       .db $81, $2a, $42, $04, $42, $42, $04, $2c, $64, $04, $64, $64
16209       .db $04, $2e, $46, $04, $46, $46, $04, $22, $04, $84, $22
16210 
16211 WinLevelMusData:
16212       .db $87, $04, $06, $0c, $14, $1c, $22, $86, $2c, $22
16213       .db $87, $04, $60, $0e, $14, $1a, $24, $86, $2c, $24
16214       .db $87, $04, $08, $10, $18, $1e, $28, $86, $30, $30
16215       .db $80, $64, $00
16216 
16217       .db $cd, $d5, $dd, $e3, $ed, $f5, $bb, $b5, $cf, $d5
16218       .db $db, $e5, $ed, $f3, $bd, $b3, $d1, $d9, $df, $e9
16219       .db $f1, $f7, $bf, $ff, $ff, $ff, $34
16220       .db $00 ;unused byte
16221 
16222       .db $86, $04, $87, $14, $1c, $22, $86, $34, $84, $2c
16223       .db $04, $04, $04, $87, $14, $1a, $24, $86, $32, $84
16224       .db $2c, $04, $86, $04, $87, $18, $1e, $28, $86, $36
16225       .db $87, $30, $30, $30, $80, $2c
16226 
16227 ;square 2 and triangle use the same data, square 1 is unused
16228 UndergroundMusData:
16229       .db $82, $14, $2c, $62, $26, $10, $28, $80, $04
16230       .db $82, $14, $2c, $62, $26, $10, $28, $80, $04
16231       .db $82, $08, $1e, $5e, $18, $60, $1a, $80, $04
16232       .db $82, $08, $1e, $5e, $18, $60, $1a, $86, $04
16233       .db $83, $1a, $18, $16, $84, $14, $1a, $18, $0e, $0c
16234       .db $16, $83, $14, $20, $1e, $1c, $28, $26, $87
16235       .db $24, $1a, $12, $10, $62, $0e, $80, $04, $04
16236       .db $00
16237 
16238 ;noise data directly follows square 2 here unlike in other songs
16239 WaterMusData:
16240       .db $82, $18, $1c, $20, $22, $26, $28 
16241       .db $81, $2a, $2a, $2a, $04, $2a, $04, $83, $2a, $82, $22
16242       .db $86, $34, $32, $34, $81, $04, $22, $26, $2a, $2c, $30
16243       .db $86, $34, $83, $32, $82, $36, $84, $34, $85, $04, $81, $22
16244       .db $86, $30, $2e, $30, $81, $04, $22, $26, $2a, $2c, $2e
16245       .db $86, $30, $83, $22, $82, $36, $84, $34, $85, $04, $81, $22
16246       .db $86, $3a, $3a, $3a, $82, $3a, $81, $40, $82, $04, $81, $3a
16247       .db $86, $36, $36, $36, $82, $36, $81, $3a, $82, $04, $81, $36
16248       .db $86, $34, $82, $26, $2a, $36
16249       .db $81, $34, $34, $85, $34, $81, $2a, $86, $2c, $00
16250 
16251       .db $84, $90, $b0, $84, $50, $50, $b0, $00
16252 
16253       .db $98, $96, $94, $92, $94, $96, $58, $58, $58, $44
16254       .db $5c, $44, $9f, $a3, $a1, $a3, $85, $a3, $e0, $a6
16255       .db $23, $c4, $9f, $9d, $9f, $85, $9f, $d2, $a6, $23
16256       .db $c4, $b5, $b1, $af, $85, $b1, $af, $ad, $85, $95
16257       .db $9e, $a2, $aa, $6a, $6a, $6b, $5e, $9d
16258 
16259       .db $84, $04, $04, $82, $22, $86, $22
16260       .db $82, $14, $22, $2c, $12, $22, $2a, $14, $22, $2c
16261       .db $1c, $22, $2c, $14, $22, $2c, $12, $22, $2a, $14
16262       .db $22, $2c, $1c, $22, $2c, $18, $22, $2a, $16, $20
16263       .db $28, $18, $22, $2a, $12, $22, $2a, $18, $22, $2a
16264       .db $12, $22, $2a, $14, $22, $2c, $0c, $22, $2c, $14, $22, $34, $12
16265       .db $22, $30, $10, $22, $2e, $16, $22, $34, $18, $26
16266       .db $36, $16, $26, $36, $14, $26, $36, $12, $22, $36
16267       .db $5c, $22, $34, $0c, $22, $22, $81, $1e, $1e, $85, $1e
16268       .db $81, $12, $86, $14
16269 
16270 EndOfCastleMusData:
16271       .db $81, $2c, $22, $1c, $2c, $22, $1c, $85, $2c, $04
16272       .db $81, $2e, $24, $1e, $2e, $24, $1e, $85, $2e, $04
16273       .db $81, $32, $28, $22, $32, $28, $22, $85, $32
16274       .db $87, $36, $36, $36, $84, $3a, $00
16275 
16276       .db $5c, $54, $4c, $5c, $54, $4c
16277       .db $5c, $1c, $1c, $5c, $5c, $5c, $5c
16278       .db $5e, $56, $4e, $5e, $56, $4e
16279       .db $5e, $1e, $1e, $5e, $5e, $5e, $5e
16280       .db $62, $5a, $50, $62, $5a, $50
16281       .db $62, $22, $22, $62, $e7, $e7, $e7, $2b
16282 
16283       .db $86, $14, $81, $14, $80, $14, $14, $81, $14, $14, $14, $14
16284       .db $86, $16, $81, $16, $80, $16, $16, $81, $16, $16, $16, $16
16285       .db $81, $28, $22, $1a, $28, $22, $1a, $28, $80, $28, $28
16286       .db $81, $28, $87, $2c, $2c, $2c, $84, $30
16287 
16288 VictoryMusData:
16289       .db $83, $04, $84, $0c, $83, $62, $10, $84, $12
16290       .db $83, $1c, $22, $1e, $22, $26, $18, $1e, $04, $1c, $00
16291 
16292       .db $e3, $e1, $e3, $1d, $de, $e0, $23
16293       .db $ec, $75, $74, $f0, $f4, $f6, $ea, $31, $2d
16294 
16295       .db $83, $12, $14, $04, $18, $1a, $1c, $14
16296       .db $26, $22, $1e, $1c, $18, $1e, $22, $0c, $14
16297 
16298 ;unused space
16299       .db $ff, $ff, $ff
16300 
16301 FreqRegLookupTbl:
16302       .db $00, $88, $00, $2f, $00, $00
16303       .db $02, $a6, $02, $80, $02, $5c, $02, $3a
16304       .db $02, $1a, $01, $df, $01, $c4, $01, $ab
16305       .db $01, $93, $01, $7c, $01, $67, $01, $53
16306       .db $01, $40, $01, $2e, $01, $1d, $01, $0d
16307       .db $00, $fe, $00, $ef, $00, $e2, $00, $d5
16308       .db $00, $c9, $00, $be, $00, $b3, $00, $a9
16309       .db $00, $a0, $00, $97, $00, $8e, $00, $86
16310       .db $00, $77, $00, $7e, $00, $71, $00, $54
16311       .db $00, $64, $00, $5f, $00, $59, $00, $50
16312       .db $00, $47, $00, $43, $00, $3b, $00, $35
16313       .db $00, $2a, $00, $23, $04, $75, $03, $57
16314       .db $02, $f9, $02, $cf, $01, $fc, $00, $6a
16315 
16316 MusicLengthLookupTbl:
16317       .db $05, $0a, $14, $28, $50, $1e, $3c, $02
16318       .db $04, $08, $10, $20, $40, $18, $30, $0c
16319       .db $03, $06, $0c, $18, $30, $12, $24, $08
16320       .db $36, $03, $09, $06, $12, $1b, $24, $0c
16321       .db $24, $02, $06, $04, $0c, $12, $18, $08
16322       .db $12, $01, $03, $02, $06, $09, $0c, $04
16323 
16324 EndOfCastleMusicEnvData:
16325       .db $98, $99, $9a, $9b
16326 
16327 AreaMusicEnvData:
16328       .db $90, $94, $94, $95, $95, $96, $97, $98
16329 
16330 WaterEventMusEnvData:
16331       .db $90, $91, $92, $92, $93, $93, $93, $94
16332       .db $94, $94, $94, $94, $94, $95, $95, $95
16333       .db $95, $95, $95, $96, $96, $96, $96, $96
16334       .db $96, $96, $96, $96, $96, $96, $96, $96
16335       .db $96, $96, $96, $96, $95, $95, $94, $93
16336 
16337 BowserFlameEnvData:
16338       .db $15, $16, $16, $17, $17, $18, $19, $19
16339       .db $1a, $1a, $1c, $1d, $1d, $1e, $1e, $1f
16340       .db $1f, $1f, $1f, $1e, $1d, $1c, $1e, $1f
16341       .db $1f, $1e, $1d, $1c, $1a, $18, $16, $14
16342 
16343 BrickShatterEnvData:
16344       .db $15, $16, $16, $17, $17, $18, $19, $19
16345       .db $1a, $1a, $1c, $1d, $1d, $1e, $1e, $1f
16346 
16347 ;-------------------------------------------------------------------------------------
16348 ;INTERRUPT VECTORS
16349 
16350       .dw NonMaskableInterrupt
16351       .dw Start
16352       .dw $fff0  ;unused