Whisket

Super Mario Bros.

Oct 8th, 2018
325
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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
Add Comment
Please, Sign In to add comment