?login_element?

Subversion Repositories NedoOS

Rev

Rev 414 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
171 demige 1
 
2
;SMBDIS.ASM - A COMPREHENSIVE SUPER MARIO BROS. DISASSEMBLY (Super Mario Bros (JU))
3
;by doppelganger (doppelheathen@gmail.com)
4
 
5
;This file is provided for your own use as-is.  It will require the character rom data
6
;and an iNES file header to get it to work.
7
 
8
;There are so many people I have to thank for this, that taking all the credit for
9
;myself would be an unforgivable act of arrogance. Without their help this would
10
;probably not be possible.  So I thank all the peeps in the nesdev scene whose insight into
11
;the 6502 and the NES helped me learn how it works (you guys know who you are, there's no 
12
;way I could have done this without your help), as well as the authors of x816 and SMB 
13
;Utility, and the reverse-engineers who did the original Super Mario Bros. Hacking Project, 
14
;which I compared notes with but did not copy from.  Last but certainly not least, I thank
15
;Nintendo for creating this game and the NES, without which this disassembly would
16
;only be theory.
17
 
18
;Assembles with x816.
19
 
20
;< LOW  low byte
21
;> HIGH  high byte
22
 
23
;-------------------------------------------------------------------------------------
24
;DIRECTIVES
25
 
26
        if Z80==0
27
       .index 8
28
       .mem 8
29
 
30
       .org $8000
31
        endif
32
 
33
;-------------------------------------------------------------------------------------
34
 
35
Start:
36
        if Z80==0
37
             sei                          ;pretty standard 6502 type init here
38
             cld
39
             ldan ++%00010000               ;init PPU control register 1 
40
             sta PPU_CTRL_REG1
41
             ldxn ++$ff                     ;reset stack pointer
42
             txs
43
VBlank1:     lda PPU_STATUS               ;wait two frames
44
         checka
45
             bpl VBlank1
46
VBlank2:     lda PPU_STATUS
47
         checka
48
             bpl VBlank2
49
        endif
50
             ldyn16 ++MEMDATA_end-AREADATA;ColdBootOffset          ;load default cold boot pointer
51
             ldxn ++$05                     ;this is where we check for a warm boot
52
WBootCheck:  
53
        if Z80==0
54
             ldax TopScoreDisplay,x        ;check each score digit in the top score
55
             cmpn ++10                      ;to see if we have a valid digit
56
              cmpcy
57
             bcs ColdBoot                 ;if not, give up and proceed with cold boot
58
             dex                      
59
             bpl WBootCheck
60
             lda WarmBootValidation       ;second checkpoint, check to see if 
61
             cmpn ++$a5                     ;another location has a specific value
62
             bne ColdBoot  
63
             ldyn16 ++WARMMEMDATA_end-AREADATA;WarmBootOffset          ;if passed both, load warm boot pointer
64
        endif
65
ColdBoot:    jsr InitializeMemory         ;clear memory using pointer in Y
66
             sta SND_DELTA_REG+1          ;reset delta counter load register
67
             sta OperMode                 ;reset primary mode of operation
68
             ldan ++$a5                     ;set warm boot flag
69
             sta WarmBootValidation    
70
             sta PseudoRandomBitReg       ;set seed for pseudorandom register
71
             ldan ++%00001111
72
             sta SND_MASTERCTRL_REG       ;enable all sound channels except dmc
73
        if Z80==0
74
             ldan ++%00000110
75
             sta PPU_CTRL_REG2            ;turn off clipping for OAM and background
76
        endif
77
             jsr MoveAllSpritesOffscreen
78
             jsr InitializeNameTables     ;initialize both name tables
79
             inci DisableScreenFlag        ;set flag to disable screen output
80
        if Z80==0
81
             lda Mirror_PPU_CTRL_REG1
82
             oran ++%10000000               ;enable NMIs
83
             jsr WritePPUReg1
84
        endif
85
 
86
             call NonMaskableInterrupt
87
        call gettimer ;hl=timer
88
         ld (oldupdtimer),hl
89
 
90
EndlessLoop:
91
        if Z80
92
             call EmulatePPU
93
        call gettimer ;hl=timer
94
oldupdtimer=$+1
95
         ld de,oldupdtimer
96
         ld (oldupdtimer),hl
97
             or a
98
             sbc hl,de
231 alone 99
        if FASTDEMOBEFOREBREAKPOINT
174 demige 100
             ld c,1
206 alone 101
             jr z,c_logic0
171 demige 102
        else
103
             jr z,nologic
104
        endif
174 demige 105
             ld c,8
171 demige 106
             ld a,l
174 demige 107
             cp c
108
             jr nc,$+3 ;    
109
             ld c,l
206 alone 110
c_logic0
174 demige 111
            ld hl,logicframe
112
            ld (hl),c
171 demige 113
             ld b,0
114
             ld d,b
174 demige 115
logic0
171 demige 116
             call NonMaskableInterrupt
174 demige 117
            ld hl,logicframe
118
            dec (hl)
119
            jr nz,logic0
206 alone 120
                jr logicq
171 demige 121
nologic
231 alone 122
        ;jr $ ;      
123
                YIELD;halt
124
             ld b,0
125
             ld d,b
206 alone 126
logicq
171 demige 127
        endif
128
             jmp EndlessLoop              ;endless loop, need I say more?
129
 
174 demige 130
        if MUSICONINT
131
        include "smbsound.asm"
132
        include "smbmusic.asm"
289 dimkam 133
        ;display $,"<=0x8000"
174 demige 134
        endif
135
 
171 demige 136
;-------------------------------------------------------------------------------------
137
;$00 - vram buffer address table low, also used for pseudorandom bit
138
;$01 - vram buffer address table high
139
 
140
VRAM_AddrTable_Low:
141
      .db LOW VRAM_Buffer1, LOW WaterPaletteData, LOW GroundPaletteData
142
      .db LOW UndergroundPaletteData, LOW CastlePaletteData, LOW VRAM_Buffer1_Offset
143
      .db LOW VRAM_Buffer2, LOW VRAM_Buffer2, LOW BowserPaletteData
144
      .db LOW DaySnowPaletteData, LOW NightSnowPaletteData, LOW MushroomPaletteData
145
      .db LOW MarioThanksMessage, LOW LuigiThanksMessage, LOW MushroomRetainerSaved
146
      .db LOW PrincessSaved1, LOW PrincessSaved2, LOW WorldSelectMessage1
147
      .db LOW WorldSelectMessage2
148
 
149
VRAM_AddrTable_High:
150
      .db HIGH VRAM_Buffer1, HIGH WaterPaletteData, HIGH GroundPaletteData
151
      .db HIGH UndergroundPaletteData, HIGH CastlePaletteData, HIGH VRAM_Buffer1_Offset
152
      .db HIGH VRAM_Buffer2, HIGH VRAM_Buffer2, HIGH BowserPaletteData
153
      .db HIGH DaySnowPaletteData, HIGH NightSnowPaletteData, HIGH MushroomPaletteData
154
      .db HIGH MarioThanksMessage, HIGH LuigiThanksMessage, HIGH MushroomRetainerSaved
155
      .db HIGH PrincessSaved1, HIGH PrincessSaved2, HIGH WorldSelectMessage1
156
      .db HIGH WorldSelectMessage2
157
 
158
      if Z80
159
tpalettes
160
        dw waterpalette
161
        dw groundpalette
162
        dw undergroundpalette
163
        dw castlepalette
164
      endif
165
 
166
VRAM_Buffer_Offset:
167
      .db LOW VRAM_Buffer1_Offset, LOW VRAM_Buffer2_Offset
168
 
169
NonMaskableInterrupt:
170
        if Z80
171
               ;ldx VRAM_Buffer_AddrCtrl  ;load control for pointer to buffer contents
172
               ;ldax VRAM_AddrTable_High,x
173
               ;ld d,a
174
               ;ldax VRAM_AddrTable_Low,x
175
               ;ld e,a
176
               ;ex de,hl
177
               ;ld de,PPU_SPRLIST
178
               ;ld bc,0x100
179
               ;ldir
180
               ;ex de,hl
181
               ;ld d,b;0
182
               lda Mirror_PPU_CTRL_REG1  ;d0 =  ( )
183
               sta PPU_CTRL_REG1
184
        else
185
               lda Mirror_PPU_CTRL_REG1  ;disable NMIs in mirror reg
186
               andn ++%01111111            ;save all other bits
187
               sta Mirror_PPU_CTRL_REG1
188
               andn ++%01111110            ;alter name table address to be $2800 ;     
189
               sta PPU_CTRL_REG1         ;(essentially $2000) but save other bits
190
               lda Mirror_PPU_CTRL_REG2  ;disable OAM and background display by default
191
               andn ++%11100110
192
               ldy DisableScreenFlag     ;get screen disable flag
193
         checky
194
               bne ScreenOff             ;if set, used bits as-is
195
               lda Mirror_PPU_CTRL_REG2  ;otherwise reenable bits and save them
196
               oran ++%00011110
197
ScreenOff:     sta Mirror_PPU_CTRL_REG2  ;save bits for later but not in register at the moment
198
               andn ++%11100111            ;disable screen for now
199
               sta PPU_CTRL_REG2
200
               ldx PPU_STATUS            ;reset flip-flop and reset scroll registers to zero
201
               ldan ++$00
202
               jsr InitScroll ;    (   )
203
               sta PPU_SPR_ADDR          ;reset spr-ram address register
204
               ldan ++$02                  ;perform spr-ram DMA access on $0200-$02ff
205
               sta SPR_DMA
206
        endif
207
               ldx VRAM_Buffer_AddrCtrl  ;load control for pointer to buffer contents
208
               ldax VRAM_AddrTable_Low,x  ;set indirect at $00 to pointer
209
               sta SCRATCHPAD+$00
210
               ldax VRAM_AddrTable_High,x
211
               sta SCRATCHPAD+$01
212
              ;cp 0x03
213
              ;jr nz,$
214
               jsr UpdateScreen          ;update screen with buffer contents
215
               ldyn ++$00
216
               ldx VRAM_Buffer_AddrCtrl  ;check for usage of $0341 ;VRAM_Buffer2???
217
               cpxn ++$06
218
               bne InitBuffer
219
               iny                       ;get offset based on usage
220
InitBuffer:    ldxy VRAM_Buffer_Offset,y
221
               ldan ++$00                  ;clear buffer header at last location
222
               stax VRAM_Buffer1_Offset,x        
223
               stax VRAM_Buffer1,x
224
               sta VRAM_Buffer_AddrCtrl  ;reinit address control to $0301 ;VRAM_Buffer1???
225
        if Z80==0
226
               lda Mirror_PPU_CTRL_REG2  ;copy mirror of $2001 to register
227
               sta PPU_CTRL_REG2
228
        endif
174 demige 229
          if MUSICONINT==0
171 demige 230
               jsr SoundEngine           ;play sound
231 alone 231
          else
232
soundenginepatch=$+1
233
               call SoundEngine_noint           ;play sound logically
174 demige 234
          endif
171 demige 235
               jsr ReadJoypads           ;read joypads
236
              if DEMO
237
              ld a,(readdemo_stopflag)
238
              or a
239
              jr nz,randomskip;PauseSkip
240
              endif
241
               jsr PauseRoutine          ;handle pause ;-  ,       
242
               jsr UpdateTopScore
243
               lda GamePauseStatus       ;check for pause status
244
               lsr
245
               bcs PauseSkip
246
              if Z80;OPT
247
               ld a,(TimerControl)          ;if master timer control not set, decrement
248
               or a
249
               jr z,DecTimers             ;all frame and interval timers
250
               dec a
251
               ld (TimerControl),a
252
               jr nz,NoDecTimers
253
DecTimers:     ;xor a
254
               ld b,21;ldxn ++$14                  ;load end offset for end of frame timers
255
               ld hl,IntervalTimerControl
256
               dec (hl) ;decrement interval timer control,
257
               ld hl,Timers+20
258
               jp p,DecTimersLoop         ;if not expired, only frame timers will decrement
259
               ld a,20
260
               ld (IntervalTimerControl),a  ;if control for interval timers expired, (21 frame rule???)
261
               ld b,36;ldxn ++$23                  ;interval timers will decrement along with frame timers
262
               ld hl,Timers+35
263
               xor a
264
DecTimersLoop: cp (hl);ldax Timers,x              ;check current timer
265
               jr z,SkipExpTimer          ;if current timer expired, branch to skip,
266
               dec (hl);decx Timers,x              ;otherwise decrement the current timer
267
SkipExpTimer:  dec hl ;dex                       ;move onto next timer
268
               djnz DecTimersLoop         ;do this until all timers are dealt with
269
NoDecTimers:   ld hl,FrameCounter
270
               inc (hl) ;increment frame counter
271
              else ;~Z80
272
               lda TimerControl          ;if master timer control not set, decrement
273
         checka
274
               beq DecTimers             ;all frame and interval timers
275
               deci TimerControl
276
               bne NoDecTimers
277
DecTimers:     ldxn ++$14                  ;load end offset for end of frame timers
278
               deci IntervalTimerControl  ;decrement interval timer control,
279
               bpl DecTimersLoop         ;if not expired, only frame timers will decrement
280
               ldan ++$14
281
               sta IntervalTimerControl  ;if control for interval timers expired, (21 frame rule???)
282
               ldxn ++$23                  ;interval timers will decrement along with frame timers
283
DecTimersLoop: ldax Timers,x              ;check current timer
284
         checka
285
               beq SkipExpTimer          ;if current timer expired, branch to skip,
286
               decx Timers,x              ;otherwise decrement the current timer
287
SkipExpTimer:  dex                       ;move onto next timer
288
               bpl DecTimersLoop         ;do this until all timers are dealt with
289
NoDecTimers:   inci FrameCounter          ;increment frame counter
290
              endif
291
PauseSkip:     ldxn ++$00
292
               ldyn ++$07
293
               lda PseudoRandomBitReg    ;get first memory location of LSFR bytes
294
               andn ++%00000010            ;mask out all but d1
295
               sta SCRATCHPAD+$00                   ;save here
296
               lda PseudoRandomBitReg+1  ;get second memory location
297
               andn ++%00000010            ;mask out all but d1
298
               eori SCRATCHPAD+$00                   ;perform exclusive-OR on d1 from first and second bytes
299
               clc                       ;if neither or both are set, carry will be clear
300
               beq RotPRandomBit
301
               sec                       ;if one or the other is set, carry will be set
302
RotPRandomBit: rorx PseudoRandomBitReg,x  ;rotate carry into d7, and rotate last bit into carry
303
               inx                       ;increment to next byte
304
               dey                       ;decrement for loop
305
               bne RotPRandomBit
306
randomskip              
307
               lda Sprite0HitDetectFlag  ;check for flag here
308
         checka
309
               beq SkipSprite0
310
 
311
              if Z80==0
312
Sprite0Clr:    lda PPU_STATUS            ;wait for sprite 0 flag to clear, which will
313
               andn ++%01000000            ;not happen until vblank has ended
314
               bne Sprite0Clr
315
              endif
316
              if DEMO
317
              ld a,(readdemo_stopflag)
318
              or a
319
              jr nz,Sprite0Hit
320
              endif
321
               lda GamePauseStatus       ;if in pause mode, do not bother with sprites at all
322
               lsr
323
               bcs Sprite0Hit
324
               jsr MoveSpritesOffscreen ;3443t (3 Goomba + 2  + )
325
               jsr SpriteShuffler ;545t
326
Sprite0Hit:
327
              if Z80==0
328
               lda PPU_STATUS            ;do sprite ++0 hit detection
329
               andn ++%01000000
330
               beq Sprite0Hit ;,       -    
331
               ldyn ++$14                  ;small delay, to wait until we hit horizontal blank time
332
HBlankDelay:   dey
333
               bne HBlankDelay
334
              endif
335
 
336
SkipSprite0:   lda HorizontalScroll      ;set scroll registers from variables
337
               sta PPU_SCROLL_REG_H
338
               lda VerticalScroll
339
               sta PPU_SCROLL_REG_V
340
              if Z80==0
341
               lda Mirror_PPU_CTRL_REG1  ;load saved mirror of $2000
342
               pha
343
               sta PPU_CTRL_REG1
344
              endif
345
              if DEMO
346
              ld a,(readdemo_stopflag)
347
              or a
348
              jr nz,SkipMainOper
349
              endif
350
               lda GamePauseStatus       ;if in pause mode, do not perform operation mode stuff
351
               lsr ;    ??? 1
352
               bcs SkipMainOper
353
               jsr OperModeExecutionTree ;otherwise do one of many, many possible subroutines ;49489t (3 Goomba + 2  + )
354
SkipMainOper:
355
              if Z80==0
356
               lda PPU_STATUS            ;reset flip-flop
357
               pla
358
               oran ++%10000000            ;reactivate NMIs
359
               sta PPU_CTRL_REG1
360
              endif
361
               rti                       ;we are done until the next frame!
362
 
363
;-------------------------------------------------------------------------------------
364
 
365
PauseRoutine:
366
               lda OperMode           ;are we in victory mode?
367
               cmpn ++VictoryModeValue  ;if so, go ahead
368
               beq ChkPauseTimer
369
               cmpn ++GameModeValue     ;are we in game mode?
370
               bne ExitPause          ;if not, leave
371
               lda OperMode_Task      ;if we are in game mode, are we running game engine?
372
               cmpn ++$03
373
               bne ExitPause          ;if not, leave
374
ChkPauseTimer: lda GamePauseTimer     ;check if pause timer is still counting down
375
         checka
376
               beq ChkStart
377
               deci GamePauseTimer     ;if so, decrement and leave
378
               rts
379
ChkStart:      lda SavedJoypad1Bits   ;check to see if start is pressed
380
               andn ++Start_Button      ;on controller 1
381
               beq ClrPauseTimer
382
               lda GamePauseStatus    ;check to see if timer flag is set
383
               andn ++%10000000         ;and if so, do not reset timer (residual,
384
               bne ExitPause          ;joypad reading routine makes this unnecessary)
385
               ;jr $
386
               ldan ++$2b               ;set pause timer
387
               sta GamePauseTimer
388
               lda GamePauseStatus
389
               tay
390
               iny                    ;set pause sfx queue for next pause mode
391
               sty PauseSoundQueue
392
               eorn ++%00000001         ;invert d0 and set d7
393
               oran ++%10000000
394
               bne SetPause           ;unconditional branch
395
ClrPauseTimer: lda GamePauseStatus    ;clear timer flag if timer is at zero and start button
396
               andn ++%01111111         ;is not pressed
397
SetPause:      sta GamePauseStatus
398
ExitPause:     rts
399
 
400
;-------------------------------------------------------------------------------------
401
;$00 - used for preset value
402
 
403
SpriteShuffler:
404
        if Z80
405
        else
406
               ldy AreaType                ;load level type, likely residual code
407
               ldan ++$28                    ;load preset value which will put it at
408
               sta SCRATCHPAD+$00                     ;sprite #10
409
               ldxn ++$0e                    ;start at the end of OAM data offsets
410
 
411
ShuffleLoop:   ldax SprDataOffset,x         ;check for offset value against
412
               cmpi SCRATCHPAD+$00                     ;the preset value
413
              cmpcy
414
               bcc NextSprOffset           ;if less, skip this part
415
               ldy SprShuffleAmtOffset     ;get current offset to preset value we want to add
416
               clc
417
               adcy SprShuffleAmt,y         ;get shuffle amount, add to current sprite offset
418
               bcc StrSprOffset            ;if not exceeded $ff, skip second add
419
               clc
420
               adci SCRATCHPAD+$00                     ;otherwise add preset value $28 to offset
421
StrSprOffset:  stax SprDataOffset,x         ;store new offset here or old one if branched to here
422
NextSprOffset: dex                         ;move backwards to next one
423
               bpl ShuffleLoop
424
 
425
               ldx SprShuffleAmtOffset     ;load offset
426
               inx
427
               cpxn ++$03                    ;check if offset + 1 goes to 3
428
               bne SetAmtOffset            ;if offset + 1 not 3, store
429
               ldxn ++$00                    ;otherwise, init to 0
430
SetAmtOffset:  stx SprShuffleAmtOffset
431
        endif
432
               ldxn ++$08                    ;load offsets for values and storage
433
               ldyn ++$02
434
 
435
SetMiscOffset: lday SprDataOffset+5,y       ;load one of three OAM data offsets
436
               stax Misc_SprDataOffset-2,x  ;store first one unmodified, but
437
               clc                         ;add eight to the second and eight
438
               adcn ++$08                    ;more to the third one
439
               stax Misc_SprDataOffset-1,x  ;note that due to the way X is set up,
440
               clc                         ;this code loads into the misc sprite offsets
441
               adcn ++$08
442
               stax Misc_SprDataOffset,x        
443
               dex
444
               dex
445
               dex
446
               dey
447
               bpl SetMiscOffset           ;do this until all misc spr offsets are loaded (3 )
448
               rts
449
 
450
;-------------------------------------------------------------------------------------
451
 
452
OperModeExecutionTree:
453
      lda OperMode     ;this is the heart of the entire program,
454
      jsr JumpEngine   ;most of what goes on starts here
455
 
456
      .dw TitleScreenMode
457
      .dw GameMode
458
      .dw VictoryMode
459
      .dw GameOverMode
460
 
461
;-------------------------------------------------------------------------------------
462
 
463
MoveAllSpritesOffscreen:
464
              ldyn ++$00                ;this routine moves all sprites off the screen
465
              jr MoveSpritesOffscreen_go;.db $2c                 ;BIT instruction opcode
466
 
467
MoveSpritesOffscreen:
468
              ldyn ++$04                ;this routine moves all but sprite 0
469
MoveSpritesOffscreen_go
470
              ldan ++$f8                ;off the screen
471
SprInitLoop:  stay Sprite_Y_Position,y ;write 248 into OAM data's Y coordinate
472
              iny                     ;which will move it off the screen
473
              iny
474
              iny
475
              iny
476
              bne SprInitLoop
477
              rts
478
 
479
;-------------------------------------------------------------------------------------
480
 
481
TitleScreenMode:
482
      lda OperMode_Task
483
      jsr JumpEngine
484
 
485
      .dw InitializeGame
486
      .dw ScreenRoutines
487
      .dw PrimaryGameSetup
488
      .dw GameMenuRoutine
489
 
490
;-------------------------------------------------------------------------------------
491
 
492
WSelectBufferTemplate:
493
      .db $04, $20, $73, $01, $00, $00
494
 
495
GameMenuRoutine:
496
        ;jr $
497
              ldyn ++$00
498
              lda SavedJoypad1Bits        ;check to see if either player pressed
499
              orai SavedJoypad2Bits        ;only the start button (either joypad)
500
              cmpn ++Start_Button
501
              beq StartGame
502
              cmpn ++A_Button+Start_Button  ;check to see if A + start was pressed
503
              bne ChkSelect               ;if not, branch to check select button
504
StartGame:    
505
        ;jr $
506
                jmp ChkContinue             ;if either start or A + start, execute here
507
ChkSelect:    cmpn ++Select_Button          ;check to see if the select button was pressed
508
              beq SelectBLogic            ;if so, branch reset demo timer
509
              ldx DemoTimer               ;otherwise check demo timer
510
         checkx
511
              bne ChkWorldSel             ;if demo timer not expired, branch to check world selection
512
              sta SelectTimer             ;set controller bits here if running demo
513
              jsr DemoEngine              ;run through the demo actions
514
              bcs ResetTitle              ;if carry flag set, demo over, thus branch
515
        ;jr $ ; 
516
              jmp RunDemo                 ;otherwise, run game engine for demo
517
ChkWorldSel:  ldx WorldSelectEnableFlag   ;check to see if world selection has been enabled
518
         checkx
519
              beq NullJoypad
520
              cmpn ++B_Button               ;if so, check to see if the B button was pressed
521
              bne NullJoypad
522
              iny                         ;if so, increment Y and execute same code as select
523
SelectBLogic: lda DemoTimer               ;if select or B pressed, check demo timer one last time
524
        ;jr $ ;   select
525
         checka
526
              beq ResetTitle              ;if demo timer expired, branch to reset title screen mode
527
        ;jr $ ;   select    
528
              ldan ++$18                    ;otherwise reset demo timer
529
              sta DemoTimer
530
              lda SelectTimer             ;check select/B button timer
531
         checka
532
              bne NullJoypad              ;if not expired, branch
533
              ldan ++$10                    ;otherwise reset select button timer
534
              sta SelectTimer
535
              cpyn ++$01                    ;was the B button pressed earlier?  if so, branch
536
              beq IncWorldSel             ;note this will not be run if world selection is disabled
537
        ;jr $ ;   select    
538
              lda NumberOfPlayers         ;if no, must have been the select button, therefore
539
              eorn ++%00000001              ;change number of players and draw icon accordingly
540
              sta NumberOfPlayers
541
              jsr DrawMushroomIcon
542
              jmp NullJoypad
543
IncWorldSel:  ldx WorldSelectNumber       ;increment world select number
544
              inx
545
              txa
546
              andn ++%00000111              ;mask out higher bits
547
              sta WorldSelectNumber       ;store as current world select number
548
              jsr GoContinue
549
UpdateShroom: ldax WSelectBufferTemplate,x ;write template for world select in vram buffer
550
              stax VRAM_Buffer1-1,x        ;do this until all bytes are written
551
              inx
552
              cpxn ++$06
553
              bmi UpdateShroom
554
              ldy WorldNumber             ;get world number from variable and increment for
555
              iny                         ;proper display, and put in blank byte before
556
              sty VRAM_Buffer1+3          ;null terminator
557
NullJoypad:   ldan ++$00                    ;clear joypad bits for player 1
558
              sta SavedJoypad1Bits
559
RunDemo:      jsr GameCoreRoutine         ;run game engine
560
              lda GameEngineSubroutine    ;check to see if we're running lose life routine
561
              cmpn ++$06
562
              bne ExitMenu                ;if not, do not do all the resetting below
563
ResetTitle:   ldan ++$00                    ;reset game modes, disable
564
              sta OperMode                ;sprite 0 check and disable
565
              sta OperMode_Task           ;screen output
566
              sta Sprite0HitDetectFlag
567
              inci DisableScreenFlag
568
              rts
569
ChkContinue:  ldy DemoTimer               ;if timer for demo has expired, reset modes
570
         checky
571
                ;jr $
572
              beq ResetTitle ;  ???  ,     Start    ,   ,   ,    
573
              asl                         ;check to see if A button was also pushed
574
              bcc StartWorld1             ;if not, don't load continue function's world number
575
              lda ContinueWorld           ;load previously saved world number for secret
576
              jsr GoContinue              ;continue function when pressing A + start
577
StartWorld1:  jsr LoadAreaPointer
578
 
579
        ;jr $ ;   start
580
              inci Hidden1UpFlag           ;set 1-up box flag for both players
581
              inci OffScr_Hidden1UpFlag
582
              inci FetchNewGameTimerFlag   ;set fetch new game timer flag
583
              inci OperMode                ;set next game mode
584
              lda WorldSelectEnableFlag   ;if world select flag is on, then primary
585
              sta PrimaryHardMode         ;hard mode must be on as well
586
              ldan ++$00
587
              sta OperMode_Task           ;set game mode here, and clear demo timer
588
              sta DemoTimer
589
              ldxn ++$17
590
              ldan ++$00
591
InitScores:   stax ScoreAndCoinDisplay,x   ;clear player scores and coin displays
592
              dex
593
              bpl InitScores
594
ExitMenu:     rts
595
GoContinue:   sta WorldNumber             ;start both players at the first area
596
              sta OffScr_WorldNumber      ;of the previously saved world number
597
              ldxn ++$00                    ;note that on power-up using this function
598
              stx AreaNumber              ;will make no difference
599
              stx OffScr_AreaNumber  
600
              rts
601
 
602
;-------------------------------------------------------------------------------------
603
 
604
MushroomIconData:
605
      .db $07, $22, $49, $83, $ce, $24, $24, $00
606
 
607
DrawMushroomIcon:
608
              ldyn ++$07                ;read eight bytes to be read by transfer routine
609
IconDataRead: lday MushroomIconData,y  ;note that the default position is set for a
610
              stay VRAM_Buffer1-1,y    ;1-player game
611
              dey
612
              bpl IconDataRead
613
              lda NumberOfPlayers     ;check number of players
614
         checka
615
              beq ExitIcon            ;if set to 1-player game, we're done
616
              ldan ++$24                ;otherwise, load blank tile in 1-player position
617
              sta VRAM_Buffer1+3
618
              ldan ++$ce                ;then load shroom icon tile in 2-player position
619
              sta VRAM_Buffer1+5
620
ExitIcon:     rts
621
 
622
;-------------------------------------------------------------------------------------
623
 
624
DemoActionData:
625
      .db $01, $80, $02, $81, $41, $80, $01
626
      .db $42, $c2, $02, $80, $41, $c1, $41, $c1
627
      .db $01, $c1, $01, $02, $80, $00
628
 
629
DemoTimingData:
630
      .db $9b, $10, $18, $05, $2c, $20, $24
631
      .db $15, $5a, $10, $20, $28, $30, $20, $10
632
      .db $80, $20, $30, $30, $01, $ff, $00
633
 
634
DemoEngine:
635
          ldx DemoAction         ;load current demo action
636
          lda DemoActionTimer    ;load current action timer
637
         checka
638
          bne DoAction           ;if timer still counting down, skip
639
          inx
640
          inci DemoAction         ;if expired, increment action, X, and
641
          sec                    ;set carry by default for demo over
642
          ldax DemoTimingData-1,x ;get next timer
643
        if Z80
644
        sec
645
        endif
646
          sta DemoActionTimer    ;store as current timer
647
         checka
648
          beq DemoOver           ;if timer already at zero, skip
649
DoAction: ldax DemoActionData-1,x ;get and perform action (current or next)
650
          sta SavedJoypad1Bits
651
          deci DemoActionTimer    ;decrement action timer
652
          clc                    ;clear carry if demo still going
653
DemoOver: rts
654
 
655
;-------------------------------------------------------------------------------------
656
 
657
VictoryMode:
658
            jsr VictoryModeSubroutines  ;run victory mode subroutines
659
            lda OperMode_Task           ;get current task of victory mode
660
         checka
661
            beq AutoPlayer              ;if on bridge collapse, skip enemy processing
662
            ldxn ++$00
663
            stx ObjectOffset            ;otherwise reset enemy object offset 
664
            jsr EnemiesAndLoopsCore     ;and run enemy code
665
AutoPlayer: jsr RelativePlayerPosition  ;get player's relative coordinates
666
            jmp PlayerGfxHandler        ;draw the player, then leave
667
 
668
VictoryModeSubroutines:
669
      lda OperMode_Task
670
      jsr JumpEngine
671
 
672
      .dw BridgeCollapse
673
      .dw SetupVictoryMode
674
      .dw PlayerVictoryWalk
675
      .dw PrintVictoryMessages
676
      .dw PlayerEndWorld
677
 
678
;-------------------------------------------------------------------------------------
679
 
680
SetupVictoryMode:
681
      ldx ScreenRight_PageLoc  ;get page location of right side of screen
682
      inx                      ;increment to next page
683
      stx DestinationPageLoc   ;store here
684
      ldan ++EndOfCastleMusic
685
      sta EventMusicQueue      ;play win castle music
686
      jmp IncModeTask_B        ;jump to set next major task in victory mode
687
 
688
;-------------------------------------------------------------------------------------
689
 
690
PlayerVictoryWalk:
691
             ldyn ++$00                ;set value here to not walk player by default
692
             sty VictoryWalkControl
693
             lda Player_PageLoc      ;get player's page location
694
             cmpi DestinationPageLoc  ;compare with destination page location
695
             bne PerformWalk         ;if page locations don't match, branch
696
             lda Player_X_Position   ;otherwise get player's horizontal position
697
             cmpn ++$60                ;compare with preset horizontal position
698
              cmpcy
699
             bcs DontWalk            ;if still on other page, branch ahead
700
PerformWalk: inci VictoryWalkControl  ;otherwise increment value and Y
701
             iny                     ;note Y will be used to walk the player
702
DontWalk:    tya                     ;put contents of Y in A and
703
             jsr AutoControlPlayer   ;use A to move player to the right or not
704
             lda ScreenLeft_PageLoc  ;check page location of left side of screen
705
             cmpi DestinationPageLoc  ;against set value here
706
             beq ExitVWalk           ;branch if equal to change modes if necessary
707
             lda ScrollFractional
708
             clc                     ;do fixed point math on fractional part of scroll
709
             adcn ++$80        
710
             sta ScrollFractional    ;save fractional movement amount
711
             ldan ++$01                ;set 1 pixel per frame
712
             adcn ++$00                ;add carry from previous addition
713
             tay                     ;use as scroll amount
714
             jsr ScrollScreen        ;do sub to scroll the screen
715
             jsr UpdScrollVar        ;do another sub to update screen and scroll variables
716
             inci VictoryWalkControl  ;increment value to stay in this routine
717
ExitVWalk:   lda VictoryWalkControl  ;load value set here
718
         checka
719
             beq IncModeTask_A       ;if zero, branch to change modes
720
             rts                     ;otherwise leave
721
 
722
;-------------------------------------------------------------------------------------
723
 
724
PrintVictoryMessages:
725
               lda SecondaryMsgCounter   ;load secondary message counter
726
         checka
727
               bne IncMsgCounter         ;if set, branch to increment message counters
728
               lda PrimaryMsgCounter     ;otherwise load primary message counter
729
         checka
730
               beq ThankPlayer           ;if set to zero, branch to print first message
731
               cmpn ++$09                  ;if at 9 or above, branch elsewhere (this comparison
732
              cmpcy
733
               bcs IncMsgCounter         ;is residual code, counter never reaches 9)
734
               ldy WorldNumber           ;check world number
735
               cpyn ++World8
736
               bne MRetainerMsg          ;if not at world 8, skip to next part
737
               cmpn ++$03                  ;check primary message counter again
738
              cmpcy
739
               bcc IncMsgCounter         ;if not at 3 yet (world 8 only), branch to increment
740
              cmpcy
741
               sbcn ++$01                  ;otherwise subtract one
742
               jmp ThankPlayer           ;and skip to next part
743
MRetainerMsg:  cmpn ++$02                  ;check primary message counter
744
              cmpcy
745
               bcc IncMsgCounter         ;if not at 2 yet (world 1-7 only), branch
746
ThankPlayer:   tay                       ;put primary message counter into Y
747
         checka
748
               bne SecondPartMsg         ;if counter nonzero, skip this part, do not print first message
749
               lda CurrentPlayer         ;otherwise get player currently on the screen
750
         checka
751
               beq EvalForMusic          ;if mario, branch
752
               iny                       ;otherwise increment Y once for luigi and
753
               bne EvalForMusic          ;do an unconditional branch to the same place
754
SecondPartMsg: iny                       ;increment Y to do world 8's message
755
               lda WorldNumber
756
               cmpn ++World8               ;check world number
757
               beq EvalForMusic          ;if at world 8, branch to next part
758
               dey                       ;otherwise decrement Y for world 1-7's message
759
               cpyn ++$04                  ;if counter at 4 (world 1-7 only)
760
              cmpcy
761
               bcs SetEndTimer           ;branch to set victory end timer
762
               cpyn ++$03                  ;if counter at 3 (world 1-7 only)
763
              cmpcy
764
               bcs IncMsgCounter         ;branch to keep counting
765
EvalForMusic:  cpyn ++$03                  ;if counter not yet at 3 (world 8 only), branch
766
               bne PrintMsg              ;to print message only (note world 1-7 will only
767
               ldan ++VictoryMusic         ;reach this code if counter = 0, and will always branch)
768
               sta EventMusicQueue       ;otherwise load victory music first (world 8 only)
769
PrintMsg:      tya                       ;put primary message counter in A
770
               clc                       ;add $0c or 12 to counter thus giving an appropriate value,
771
               adcn ++$0c                  ;($0c-$0d = first), ($0e = world 1-7's), ($0f-$12 = world 8's)
772
               sta VRAM_Buffer_AddrCtrl  ;write message counter to vram address controller
773
IncMsgCounter: lda SecondaryMsgCounter
774
               clc
775
               adcn ++$04                      ;add four to secondary message counter
776
               sta SecondaryMsgCounter
777
               lda PrimaryMsgCounter
778
               adcn ++$00                      ;add carry to primary message counter
779
               sta PrimaryMsgCounter
780
               cmpn ++$07                      ;check primary counter one more time
781
              cmpcy
782
SetEndTimer:
783
               bcc ExitMsgs                  ;if not reached value yet, branch to leave
784
               ldan ++$06
785
               sta WorldEndTimer             ;otherwise set world end timer
786
IncModeTask_A: inci OperMode_Task             ;move onto next task in mode
787
ExitMsgs:      rts                           ;leave
788
 
789
;-------------------------------------------------------------------------------------
790
 
791
PlayerEndWorld:
792
               lda WorldEndTimer          ;check to see if world end timer expired
793
         checka
794
               bne EndExitOne             ;branch to leave if not
795
               ldy WorldNumber            ;check world number
796
               cpyn ++World8                ;if on world 8, player is done with game, 
797
              cmpcy
798
               bcs EndChkBButton          ;thus branch to read controller
799
               ldan ++$00
800
               sta AreaNumber             ;otherwise initialize area number used as offset
801
               sta LevelNumber            ;and level number control to start at area 1
802
               sta OperMode_Task          ;initialize secondary mode of operation
803
               inci WorldNumber            ;increment world number to move onto the next world
804
               jsr LoadAreaPointer        ;get area address offset for the next area
805
               inci FetchNewGameTimerFlag  ;set flag to load game timer from header
806
               ldan ++GameModeValue
807
               sta OperMode               ;set mode of operation to game mode
808
EndExitOne:    rts                        ;and leave
809
EndChkBButton: lda SavedJoypad1Bits
810
               orai SavedJoypad2Bits       ;check to see if B button was pressed on
811
               andn ++B_Button              ;either controller
812
               beq EndExitTwo             ;branch to leave if not
813
               ldan ++$01                   ;otherwise set world selection flag
814
               sta WorldSelectEnableFlag
815
               ldan ++$ff                   ;remove onscreen player's lives
816
               sta NumberofLives
817
               jsr TerminateGame          ;do sub to continue other player or end game
818
EndExitTwo:    rts                        ;leave
819
 
820
;-------------------------------------------------------------------------------------
821
 
822
;data is used as tiles for numbers
823
;that appear when you defeat enemies
824
FloateyNumTileData:
825
      .db $ff, $ff ;dummy
826
      .db $f6, $fb ; "100"
827
      .db $f7, $fb ; "200"
828
      .db $f8, $fb ; "400"
829
      .db $f9, $fb ; "500"
830
      .db $fa, $fb ; "800"
831
      .db $f6, $50 ; "1000"
832
      .db $f7, $50 ; "2000"
833
      .db $f8, $50 ; "4000"
834
      .db $f9, $50 ; "5000"
835
      .db $fa, $50 ; "8000"
836
      .db $fd, $fe ; "1-UP"
837
 
838
;high nybble is digit number, low nybble is number to
839
;add to the digit of the player's score
840
ScoreUpdateData:
841
      .db $ff ;dummy
842
      .db $41, $42, $44, $45, $48
843
      .db $31, $32, $34, $35, $38, $00
844
 
845
FloateyNumbersRoutine:
846
              ldax FloateyNum_Control,x     ;load control for floatey number
847
         checka
848
              beq EndExitOne               ;if zero, branch to leave
849
              cmpn ++$0b                     ;if less than $0b, branch
850
              cmpcy
851
              bcc ChkNumTimer
852
              ldan ++$0b                     ;otherwise set to $0b, thus keeping
853
              stax FloateyNum_Control,x     ;it in range
854
ChkNumTimer:  tay                          ;use as Y
855
              ldax FloateyNum_Timer,x       ;check value here
856
         checka
857
              bne DecNumTimer              ;if nonzero, branch ahead
858
              stax FloateyNum_Control,x     ;initialize floatey number control and leave
859
              rts
860
DecNumTimer:  decx FloateyNum_Timer,x       ;decrement value here
861
              cmpn ++$2b                     ;if not reached a certain point, branch  
862
              bne ChkTallEnemy
863
              cpyn ++$0b                     ;check offset for $0b
864
              bne LoadNumTiles             ;branch ahead if not found
865
              inci NumberofLives            ;give player one extra life (1-up)
866
              ldan ++Sfx_ExtraLife
867
              sta Square2SoundQueue        ;and play the 1-up sound
868
LoadNumTiles: lday ScoreUpdateData,y        ;load point value here
869
              lsr                          ;move high nybble to low
870
              lsr
871
              lsr
872
              lsr
873
              tax                          ;use as X offset, essentially the digit
874
              lday ScoreUpdateData,y        ;load again and this time
875
              andn ++%00001111               ;mask out the high nybble
876
              stax DigitModifier,x          ;store as amount to add to the digit
877
              jsr AddToScore               ;update the score accordingly
878
ChkTallEnemy: ldyx Enemy_SprDataOffset,x    ;get OAM data offset for enemy object
879
              ldax Enemy_ID,x               ;get enemy object identifier
880
              cmpn ++Spiny
881
              beq FloateyPart              ;branch if spiny
882
              cmpn ++PiranhaPlant
883
              beq FloateyPart              ;branch if piranha plant
884
              cmpn ++HammerBro
885
              beq GetAltOffset             ;branch elsewhere if hammer bro
886
              cmpn ++GreyCheepCheep
887
              beq FloateyPart              ;branch if cheep-cheep of either color
888
              cmpn ++RedCheepCheep
889
              beq FloateyPart
890
              cmpn ++TallEnemy
891
              cmpcy
892
              bcs GetAltOffset             ;branch elsewhere if enemy object =HIGH  $09
893
              ldax Enemy_State,x
894
              cmpn ++$02                     ;if enemy state defeated or otherwise
895
              cmpcy
896
              bcs FloateyPart              ;$02 or greater, branch beyond this part
897
GetAltOffset: ldx SprDataOffset_Ctrl       ;load some kind of control bit
898
              ldyx Alt_SprDataOffset,x      ;get alternate OAM data offset
899
              ldx ObjectOffset             ;get enemy object offset again
900
FloateyPart:  ldax FloateyNum_Y_Pos,x       ;get vertical coordinate for
901
              cmpn ++$18                     ;floatey number, if coordinate in the
902
              cmpcy
903
              bcc SetupNumSpr              ;status bar, branch
904
              cmpcy
905
              sbcn ++$01
906
              stax FloateyNum_Y_Pos,x       ;otherwise subtract one and store as new
907
SetupNumSpr:  ldax FloateyNum_Y_Pos,x       ;get vertical coordinate
908
             or a
909
              sbcn ++$08                     ;subtract eight and dump into the
910
              jsr DumpTwoSpr               ;left and right sprite's Y coordinates
911
              ldax FloateyNum_X_Pos,x       ;get horizontal coordinate
912
              stay Sprite_X_Position,y      ;store into X coordinate of left sprite
913
              clc
914
              adcn ++$08                     ;add eight pixels and store into X
915
              stay Sprite_X_Position+4,y    ;coordinate of right sprite
916
              ldan ++$02
917
              stay Sprite_Attributes,y      ;set palette control in attribute bytes
918
              stay Sprite_Attributes+4,y    ;of left and right sprites
919
              ldax FloateyNum_Control,x
920
              asl                          ;multiply our floatey number control by 2
921
              tax                          ;and use as offset for look-up table
922
              ldax FloateyNumTileData,x
923
              stay Sprite_Tilenumber,y      ;display first half of number of points
924
              ldax FloateyNumTileData+1,x
925
              stay Sprite_Tilenumber+4,y    ;display the second half
926
              ldx ObjectOffset             ;get enemy object offset and leave
927
              rts
928
 
929
;-------------------------------------------------------------------------------------
930
 
931
ScreenRoutines:
932
      lda ScreenRoutineTask        ;run one of the following subroutines
933
      jsr JumpEngine
934
 
935
      .dw InitScreen ;0
936
      .dw SetupIntermediate ;1
937
      .dw WriteTopStatusLine ;2
938
      .dw WriteBottomStatusLine ;3
939
      .dw DisplayTimeUp ;4
940
      .dw ResetSpritesAndScreenTimer ;5
941
      .dw DisplayIntermediate ;6
942
      .dw ResetSpritesAndScreenTimer ;7
943
      .dw AreaParserTaskControl ;8
944
      .dw GetAreaPalette ;9
945
      .dw GetBackgroundColor ;10
946
      .dw GetAlternatePalette1 ;11
947
      .dw DrawTitleScreen ;12
948
      .dw ClearBuffersDrawIcon ;13
949
      .dw WriteTopScore ;14
950
 
951
;-------------------------------------------------------------------------------------
952
 
953
InitScreen:
954
      jsr MoveAllSpritesOffscreen ;initialize all sprites including sprite ++0
955
      jsr InitializeNameTables    ;and erase both name and attribute tables
956
      lda OperMode
957
         checka
958
      beq NextSubtask             ;if mode still 0, do not load
959
      ldxn ++$03                    ;into buffer pointer
960
      jmp SetVRAMAddr_A
961
 
962
;-------------------------------------------------------------------------------------
963
 
964
SetupIntermediate:
965
      lda BackgroundColorCtrl  ;save current background color control
966
      pha                      ;and player status to stack
967
      lda PlayerStatus
968
      pha
969
      ldan ++$00                 ;set background color to black
970
      sta PlayerStatus         ;and player status to not fiery
971
      ldan ++$02                 ;this is the ONLY time background color control
972
      sta BackgroundColorCtrl  ;is set to less than 4
973
      jsr GetPlayerColors
974
      pla                      ;we only execute this routine for
975
      sta PlayerStatus         ;the intermediate lives display
976
      pla                      ;and once we're done, we return bg
977
      sta BackgroundColorCtrl  ;color ctrl and player status from stack
978
      jmp IncSubtask           ;then move onto the next task
979
 
980
;-------------------------------------------------------------------------------------
981
 
982
        if Z80==0
983
AreaPalette:
984
      .db $01, $02, $03, $04
985
        endif
986
 
987
GetAreaPalette:
988
        if Z80
989
                ld a,(AreaType)
990
                add a,a
991
                ld e,a
992
                ld hl,tpalettes
993
                add hl,de
994
                ld a,(hl)
995
                inc hl
996
                ld h,(hl)
997
                ld l,a
998
                ld (curpalette),hl
999
                jp IncSubtask           ;move onto next task
1000
        else
1001
               ldy AreaType             ;select appropriate palette to load
1002
               ldxy AreaPalette,y        ;based on area type
1003
        endif
1004
SetVRAMAddr_A: stx VRAM_Buffer_AddrCtrl ;store offset into buffer control
1005
NextSubtask:   jmp IncSubtask           ;move onto next task
1006
 
1007
;-------------------------------------------------------------------------------------
1008
;$00 - used as temp counter in GetPlayerColors
1009
 
1010
BGColorCtrl_Addr:
1011
      .db $00, $09, $0a, $04
1012
 
1013
BackgroundColors:
180 demige 1014
        if Z80BGCOLOR
231 alone 1015
        db 0xcc,0xcc,0xff,0xff ;used by area type if bg color ctrl not set
1016
        db 0xff,0xcc,0xff,0xff ;used by background color control if set
180 demige 1017
        else
171 demige 1018
      .db $22, $22, $0f, $0f ;used by area type if bg color ctrl not set
1019
      .db $0f, $22, $0f, $0f ;used by background color control if set
180 demige 1020
        endif
171 demige 1021
 
1022
PlayerColors:
174 demige 1023
        if Z80MARIOCOLOR
231 alone 1024
      dw 0x3f3f,0xbdbd ;mario's colors
1025
      dw 0x3f3f,0xefef ;luigi's colors
1026
      dw 0x3f3f,0x0c0c ;fiery (used by both)
174 demige 1027
        else
171 demige 1028
      .db $22, $16, $27, $18 ;mario's colors
1029
      .db $22, $30, $27, $19 ;luigi's colors
1030
      .db $22, $37, $27, $16 ;fiery (used by both)
174 demige 1031
        endif
171 demige 1032
 
1033
GetBackgroundColor:
1034
           ldy BackgroundColorCtrl   ;check background color control
1035
         checky
1036
           beq NoBGColor             ;if not set, increment task and fetch palette
180 demige 1037
        if Z80BGCOLOR
1038
        else
171 demige 1039
           lday BGColorCtrl_Addr-4,y  ;put appropriate palette into vram
1040
           sta VRAM_Buffer_AddrCtrl  ;note that if set to 5-7, $0301 (VRAM_Buffer1) will not be read
180 demige 1041
        endif
171 demige 1042
NoBGColor: inci ScreenRoutineTask     ;increment to next subtask and plod on through
1043
 
1044
GetPlayerColors:
174 demige 1045
        if Z80MARIOCOLOR
1046
               lda CurrentPlayer        ;check which player is on the screen
1047
               ld de,PlayerColors
1048
               or a
1049
               beq ChkFiery
1050
               ld de,PlayerColors+4;ldyn ++$04                 ;load offset for luigi
1051
ChkFiery:      lda PlayerStatus         ;check player status
1052
               cmpn ++$02
1053
               bne StartClrGet          ;if fiery, load alternate offset for fiery player
1054
               ld de,PlayerColors+8;ldyn ++$08
1055
StartClrGet:
1056
               ld hl,(curpalette)
1057
               ld c,12*2
1058
               add hl,bc
1059
               ex de,hl
1060
               ;c>=4
1061
               ldi
1062
               ldi
1063
               inc de
1064
               inc de
1065
               ldi
1066
               ldi
1067
               ld (oldpalette),hl ;!=curpalette,   
180 demige 1068
 
174 demige 1069
               ld d,b
180 demige 1070
 
1071
          if Z80BGCOLOR
1072
               ldy BackgroundColorCtrl  ;if this value is four or greater, it will be set
1073
         checky
1074
               bne SetBGColor           ;therefore use it as offset to background color
1075
               ldy AreaType             ;otherwise use area type bits from area offset as offset
1076
SetBGColor:    lday BackgroundColors,y   ;to background color instead
1077
               ;jr $
1078
               ld hl,(curpalette)
1079
               ld (hl),a
1080
               inc hl
1081
               ld (hl),a
1082
          endif
1083
 
174 demige 1084
                ret
1085
        else
171 demige 1086
               ldx VRAM_Buffer1_Offset  ;get current buffer offset
1087
               ldyn ++$00
1088
               lda CurrentPlayer        ;check which player is on the screen
1089
         checka
1090
               beq ChkFiery
1091
               ldyn ++$04                 ;load offset for luigi
1092
ChkFiery:      lda PlayerStatus         ;check player status
1093
               cmpn ++$02
1094
               bne StartClrGet          ;if fiery, load alternate offset for fiery player
1095
               ldyn ++$08
1096
StartClrGet:   ldan ++$03                 ;do four colors
1097
               sta SCRATCHPAD+$00
1098
ClrGetLoop:    lday PlayerColors,y       ;fetch player colors and store them
1099
               stax VRAM_Buffer1+3,x     ;in the buffer
1100
               iny
1101
               inx
1102
               deci SCRATCHPAD+$00
1103
               bpl ClrGetLoop
1104
               ldx VRAM_Buffer1_Offset  ;load original offset from before
1105
               ldy BackgroundColorCtrl  ;if this value is four or greater, it will be set
1106
         checky
1107
               bne SetBGColor           ;therefore use it as offset to background color
1108
               ldy AreaType             ;otherwise use area type bits from area offset as offset
1109
SetBGColor:    lday BackgroundColors,y   ;to background color instead
1110
               stax VRAM_Buffer1+3,x
1111
               ldan ++HIGH PPU_SPRPAL;++$3f                 ;set for sprite palette address
1112
               stax VRAM_Buffer1,x       ;save to buffer
1113
               ldan ++LOW PPU_SPRPAL;++$10
1114
               stax VRAM_Buffer1+1,x
1115
               ldan ++$04                 ;write length byte to buffer
1116
               stax VRAM_Buffer1+2,x
1117
               ldan ++$00                 ;now the null terminator
1118
               stax VRAM_Buffer1+7,x
1119
               txa                      ;move the buffer pointer ahead 7 bytes
1120
               clc                      ;in case we want to write anything else later
1121
               adcn ++$07
174 demige 1122
        endif
171 demige 1123
SetVRAMOffset: sta VRAM_Buffer1_Offset  ;store as new vram buffer offset
1124
               rts
1125
 
1126
;-------------------------------------------------------------------------------------
1127
 
1128
GetAlternatePalette1:
1129
               lda AreaStyle            ;check for mushroom level style
1130
               cmpn ++$01
1131
               bne NoAltPal
1132
               ldan ++$0b                 ;if found, load appropriate palette
1133
SetVRAMAddr_B: sta VRAM_Buffer_AddrCtrl
1134
NoAltPal:      jmp IncSubtask           ;now onto the next task
1135
 
1136
;-------------------------------------------------------------------------------------
1137
 
1138
WriteTopStatusLine:
1139
      ldan ++$00          ;select main status bar
1140
      jsr WriteGameText ;output it
1141
      jmp IncSubtask    ;onto the next task
1142
 
1143
;-------------------------------------------------------------------------------------
1144
 
1145
WriteBottomStatusLine:
1146
      jsr GetSBNybbles        ;write player's score and coin tally to screen
1147
      ldx VRAM_Buffer1_Offset
1148
      ldan ++$20                ;write address for world-area number on screen
1149
      stax VRAM_Buffer1,x
1150
      ldan ++$73
1151
      stax VRAM_Buffer1+1,x
1152
      ldan ++$03                ;write length for it
1153
      stax VRAM_Buffer1+2,x
1154
      ldy WorldNumber         ;first the world number
1155
      iny
1156
      tya
1157
      stax VRAM_Buffer1+3,x
1158
      ldan ++$28                ;next the dash
1159
      stax VRAM_Buffer1+4,x
1160
      ldy LevelNumber         ;next the level number
1161
      iny                     ;increment for proper number display
1162
      tya
1163
      stax VRAM_Buffer1+5,x    
1164
      ldan ++$00                ;put null terminator on
1165
      stax VRAM_Buffer1+6,x
1166
      txa                     ;move the buffer offset up by 6 bytes
1167
      clc
1168
      adcn ++$06
1169
      sta VRAM_Buffer1_Offset
1170
      jmp IncSubtask
1171
 
1172
;-------------------------------------------------------------------------------------
1173
 
1174
DisplayTimeUp:
1175
          lda GameTimerExpiredFlag  ;if game timer not expired, increment task
1176
         checka
1177
          beq NoTimeUp              ;control 2 tasks forward, otherwise, stay here
1178
          ldan ++$00
1179
          sta GameTimerExpiredFlag  ;reset timer expiration flag
1180
          ldan ++$02                  ;output time-up screen to buffer
1181
          jmp OutputInter
1182
NoTimeUp: inci ScreenRoutineTask     ;increment control task 2 tasks forward
1183
          jmp IncSubtask
1184
 
1185
;-------------------------------------------------------------------------------------
1186
 
1187
DisplayIntermediate:
1188
               lda OperMode                 ;check primary mode of operation
1189
         checka
1190
               beq NoInter                  ;if in title screen mode, skip this
1191
               cmpn ++GameOverModeValue       ;are we in game over mode?
1192
               beq GameOverInter            ;if so, proceed to display game over screen
1193
               lda AltEntranceControl       ;otherwise check for mode of alternate entry
1194
         checka
1195
               bne NoInter                  ;and branch if found
1196
               ldy AreaType                 ;check if we are on castle level
1197
               cpyn ++$03                     ;and if so, branch (possibly residual)
1198
               beq PlayerInter
1199
               lda DisableIntermediate      ;if this flag is set, skip intermediate lives display
1200
         checka
1201
               bne NoInter                  ;and jump to specific task, otherwise
1202
PlayerInter:   jsr DrawPlayer_Intermediate  ;put player in appropriate place for
1203
               ldan ++$01                     ;lives display, then output lives display to buffer
1204
OutputInter:   jsr WriteGameText
1205
               jsr ResetScreenTimer
1206
               ldan ++$00
1207
               sta DisableScreenFlag        ;reenable screen output
1208
               rts
1209
GameOverInter: ldan ++$12                     ;set screen timer
1210
               sta ScreenTimer
1211
               ldan ++$03                     ;output game over screen to buffer
1212
               jsr WriteGameText
1213
               jmp IncModeTask_B
1214
NoInter:       ldan ++$08                     ;set for specific task (AreaParserTaskControl) and leave
1215
               sta ScreenRoutineTask
1216
               rts
1217
 
1218
;-------------------------------------------------------------------------------------
1219
 
1220
AreaParserTaskControl:
1221
           inci DisableScreenFlag     ;turn off screen
1222
TaskLoop:  jsr AreaParserTaskHandler ;render column set of current area
1223
           lda AreaParserTaskNum     ;check number of tasks
1224
         checka
1225
           bne TaskLoop              ;if tasks still not all done, do another one
1226
           deci ColumnSets            ;do we need to render more column sets?
1227
           bpl OutputCol
1228
           inci ScreenRoutineTask     ;if not, move on to the next task
1229
OutputCol: ldan ++$06                  ;set vram buffer to output rendered column set
1230
           sta VRAM_Buffer_AddrCtrl  ;on next NMI
1231
           rts
1232
 
1233
;-------------------------------------------------------------------------------------
1234
 
1235
;$00 - vram buffer address table low
1236
;$01 - vram buffer address table high
1237
 
1238
DrawTitleScreen:
1239
        ;jr $
1240
            lda OperMode                 ;are we in title screen mode?
1241
         checka
1242
            bne IncModeTask_B            ;if not, exit
1243
        if Z80
1244
DrawTitleScreen_go
1245
            ld hl,TitleScreen
1246
            ld de,VRAM_Buffer1_Offset
1247
            ld bc,TitleScreenDataSize ;0x13a = 314 ( ???)
1248
            ldir
1249
            ld d,b;0
1250
        else
1251
            ldan ++HIGH TitleScreenDataOffset  ;load address $1ec0 into
1252
            sta PPU_ADDRESS              ;the vram address register
1253
            ldan ++LOW TitleScreenDataOffset
1254
            sta PPU_ADDRESS
1255
            ldan ++$03                     ;put address $0300 into
1256
            sta SCRATCHPAD+$01                      ;the indirect at $00
1257
            ldyn ++$00
1258
            sty SCRATCHPAD+$00
1259
            lda PPU_DATA                 ;do one garbage read
1260
OutputTScr: lda PPU_DATA                 ;get title screen from chr-rom
1261
            stayindirect (SCRATCHPAD+$00),y                  ;store 256 bytes into buffer
1262
            iny
1263
            bne ChkHiByte                ;if not past 256 bytes, do not increment
1264
            inci SCRATCHPAD+$01                      ;otherwise increment high byte of indirect
1265
ChkHiByte:  lda SCRATCHPAD+$01                      ;check high byte?
1266
            cmpn ++$04                     ;at $0400?
1267
            bne OutputTScr               ;if not, loop back and do another
1268
            cpyn ++$3a                     ;check if offset points past end of data
1269
              cmpcy
1270
            bcc OutputTScr               ;if not, loop back and do another
1271
        endif
1272
            ldan ++$05                     ;set buffer transfer control to $0300,
1273
            jmp SetVRAMAddr_B            ;increment task and exit
1274
 
1275
;-------------------------------------------------------------------------------------
1276
 
1277
ClearBuffersDrawIcon:
1278
             lda OperMode               ;check game mode
1279
         checka
1280
             bne IncModeTask_B          ;if not title screen mode, leave
1281
             ldxn ++$00                   ;otherwise, clear buffer space
1282
TScrClear:   stax VRAM_Buffer1-1,x
1283
             stax VRAM_Buffer1-1+$100,x ;???   ?
1284
             dex
1285
             bne TScrClear
1286
             jsr DrawMushroomIcon       ;draw player select icon
1287
IncSubtask:  inci ScreenRoutineTask      ;move onto next task
1288
             rts
1289
 
1290
;-------------------------------------------------------------------------------------
1291
 
1292
WriteTopScore:
1293
               ldan ++$fa           ;run display routine to display top score on title
1294
               jsr UpdateNumber
1295
IncModeTask_B: inci OperMode_Task  ;move onto next mode
1296
               rts
1297
 
1298
;-------------------------------------------------------------------------------------
1299
 
1300
GameText:
1301
TopStatusBarLine:
1302
  .db $20, $43, $05,  $16, $0a, $1b, $12, $18 ; "MARIO"
1303
  .db $20, $52, $0b,  $20, $18, $1b, $15, $0d ; "WORLD  TIME"
1304
  .db $24, $24, $1d,  $12, $16, $0e
1305
  .db $20, $68, $05,  $00, $24, $24, $2e, $29 ; score trailing digit and coin display
1306
  .db $23, $c0,  $7f, $aa ; attribute table data, clears name table 0 to palette 2
1307
  .db $23, $c2, $01,  $ea ; attribute table data, used for coin icon in status bar
1308
  .db $ff ; end of data block
1309
 
1310
WorldLivesDisplay:
1311
  .db $21, $cd, $07,  $24, $24 ; cross with spaces used on
1312
  .db $29, $24, $24,  $24, $24 ; lives display
1313
  .db $21, $4b, $09,  $20, $18 ; "WORLD  - " used on lives display
1314
  .db $1b, $15, $0d, $24, $24, $28, $24
1315
  .db $22, $0c,  $47, $24 ; possibly used to clear time up
1316
  .db $23, $dc, $01,  $ba ; attribute table data for crown if more than 9 lives
1317
  .db $ff
1318
 
1319
TwoPlayerTimeUp:
1320
  .db $21, $cd, $05,  $16, $0a, $1b, $12, $18 ; "MARIO"
1321
OnePlayerTimeUp:
1322
  .db $22, $0c, $07,  $1d, $12, $16, $0e, $24, $1e, $19 ; "TIME UP"
1323
  .db $ff
1324
 
1325
TwoPlayerGameOver:
1326
  .db $21, $cd, $05,  $16, $0a, $1b, $12, $18 ; "MARIO"
1327
OnePlayerGameOver:
1328
  .db $22, $0b, $09,  $10, $0a, $16, $0e, $24 ; "GAME OVER"
1329
  .db $18, $1f, $0e, $1b
1330
  .db $ff
1331
 
1332
WarpZoneWelcome:
1333
  .db $25, $84, $15,  $20, $0e, $15, $0c, $18, $16 ; "WELCOME TO WARP ZONE!"
1334
  .db $0e, $24, $1d, $18, $24, $20, $0a, $1b, $19
1335
  .db $24, $23, $18, $17, $0e, $2b
1336
  .db $26, $25, $01,  $24         ; placeholder for left pipe
1337
  .db $26, $2d, $01,  $24         ; placeholder for middle pipe
1338
  .db $26, $35, $01,  $24         ; placeholder for right pipe
1339
  .db $27, $d9,  $46, $aa         ; attribute data
1340
  .db $27, $e1,  $45, $aa
1341
  .db $ff
1342
 
1343
LuigiName:
1344
  .db $15, $1e, $12, $10, $12    ; "LUIGI", no address or length
1345
 
1346
WarpZoneNumbers:
1347
  .db $04, $03, $02, $00         ; warp zone numbers, note spaces on middle
1348
  .db $24, $05, $24, $00         ; zone, partly responsible for
1349
  .db $08, $07, $06, $00         ; the minus world
1350
 
1351
GameTextOffsets:
1352
  .db TopStatusBarLine-GameText, TopStatusBarLine-GameText
1353
  .db WorldLivesDisplay-GameText, WorldLivesDisplay-GameText
1354
  .db TwoPlayerTimeUp-GameText, OnePlayerTimeUp-GameText
1355
  .db TwoPlayerGameOver-GameText, OnePlayerGameOver-GameText
1356
  .db WarpZoneWelcome-GameText, WarpZoneWelcome-GameText
1357
 
1358
WriteGameText:
1359
               pha                      ;save text number to stack
1360
               asl
1361
               tay                      ;multiply by 2 and use as offset
1362
               cpyn ++$04                 ;if set to do top status bar or world/lives display,
1363
              cmpcy
1364
               bcc LdGameText           ;branch to use current offset as-is
1365
               cpyn ++$08                 ;if set to do time-up or game over,
1366
              cmpcy
1367
               bcc Chk2Players          ;branch to check players
1368
               ldyn ++$08                 ;otherwise warp zone, therefore set offset
1369
Chk2Players:   lda NumberOfPlayers      ;check for number of players
1370
         checka
1371
               bne LdGameText           ;if there are two, use current offset to also print name
1372
               iny                      ;otherwise increment offset by one to not print name
1373
LdGameText:    ldxy GameTextOffsets,y    ;get offset to message we want to print
1374
               ldyn ++$00
1375
GameTextLoop:  ldax GameText,x           ;load message data
1376
               cmpn ++$ff                 ;check for terminator
1377
               beq EndGameText          ;branch to end text if found
1378
               stay VRAM_Buffer1,y       ;otherwise write data to buffer
1379
               inx                      ;and increment increment
1380
               iny
1381
               bne GameTextLoop         ;do this for 256 bytes if no terminator found
1382
EndGameText:   ldan ++$00                 ;put null terminator at end
1383
               stay VRAM_Buffer1,y
1384
               pla                      ;pull original text number from stack
1385
               tax
1386
               cmpn ++$04                 ;are we printing warp zone?
1387
              cmpcy
1388
               bcs PrintWarpZoneNumbers
1389
               dex                      ;are we printing the world/lives display?
1390
               bne CheckPlayerName      ;if not, branch to check player's name
1391
               lda NumberofLives        ;otherwise, check number of lives
1392
               clc                      ;and increment by one for display
1393
               adcn ++$01
1394
               cmpn ++10                  ;more than 9 lives?
1395
              cmpcy
1396
               bcc PutLives
1397
              cmpcy
1398
               sbcn ++10                  ;if so, subtract 10 and put a crown tile
1399
               ldyn ++$9f                 ;next to the difference...strange things happen if
1400
               sty VRAM_Buffer1+7       ;the number of lives exceeds 19
1401
PutLives:      sta VRAM_Buffer1+8
1402
               ldy WorldNumber          ;write world and level numbers (incremented for display)
1403
               iny                      ;to the buffer in the spaces surrounding the dash
1404
               sty VRAM_Buffer1+19
1405
               ldy LevelNumber
1406
               iny
1407
               sty VRAM_Buffer1+21      ;we're done here
1408
               rts
1409
 
1410
CheckPlayerName:
1411
             lda NumberOfPlayers    ;check number of players
1412
         checka
1413
             beq ExitChkName        ;if only 1 player, leave
1414
             lda CurrentPlayer      ;load current player
1415
             dex                    ;check to see if current message number is for time up
1416
             bne ChkLuigi
1417
             ldy OperMode           ;check for game over mode
1418
             cpyn ++GameOverModeValue
1419
             beq ChkLuigi
1420
             eorn ++%00000001         ;if not, must be time up, invert d0 to do other player
1421
ChkLuigi:    lsr
1422
             bcc ExitChkName        ;if mario is current player, do not change the name
1423
             ldyn ++$04
1424
NameLoop:    lday LuigiName,y        ;otherwise, replace "MARIO" with "LUIGI"
1425
             stay VRAM_Buffer1+3,y
1426
             dey
1427
             bpl NameLoop           ;do this until each letter is replaced
1428
ExitChkName: rts
1429
 
1430
PrintWarpZoneNumbers:
1431
;CY = 0???
1432
            or a
1433
             sbcn ++$04               ;subtract 4 and then shift to the left
1434
             asl                    ;twice to get proper warp zone number
1435
             asl                    ;offset
1436
             tax
1437
             ldyn ++$00
1438
WarpNumLoop: ldax WarpZoneNumbers,x  ;print warp zone numbers into the
1439
             stay VRAM_Buffer1+27,y  ;placeholders from earlier
1440
             inx
1441
             iny                    ;put a number in every fourth space
1442
             iny
1443
             iny
1444
             iny
1445
             cpyn ++$0c
1446
              cmpcy
1447
             bcc WarpNumLoop
1448
             ldan ++$2c               ;load new buffer pointer at end of message
1449
             jmp SetVRAMOffset
1450
 
1451
;-------------------------------------------------------------------------------------
1452
 
1453
ResetSpritesAndScreenTimer:
1454
         lda ScreenTimer             ;check if screen timer has expired
1455
         checka
1456
         bne NoReset                 ;if not, branch to leave
1457
         jsr MoveAllSpritesOffscreen ;otherwise reset sprites now
1458
 
1459
ResetScreenTimer:
1460
         ldan ++$07                    ;reset timer again
1461
         sta ScreenTimer
1462
         inci ScreenRoutineTask       ;move onto next task
1463
NoReset: rts
1464
 
1465
;-------------------------------------------------------------------------------------
1466
;$00 - temp vram buffer offset
1467
;$01 - temp metatile buffer offset
1468
;$02 - temp metatile graphics table offset
1469
;$03 - used to store attribute bits
1470
;$04 - used to determine attribute table row
1471
;$05 - used to determine attribute table column
1472
;$06 - metatile graphics table address low
1473
;$07 - metatile graphics table address high
1474
 
1475
RenderAreaGraphics:
1476
           if Z80OPT4
1477
            ;lda CurrentColumnPos         ;store LSB of where we're at
1478
            ;andn ++$01
1479
            ;sta SCRATCHPAD+$05
1480
            ldy VRAM_Buffer2_Offset      ;store vram buffer offset
1481
            ld ix,VRAM_Buffer2
1482
            add ix,de
1483
            ld a,(CurrentNTAddr_Low)        ;get current name table address we're supposed to render
1484
            ld (ix+1),a;stay VRAM_Buffer2+1,y
1485
            ld a,(CurrentNTAddr_High)
1486
            ld (ix+0),a;stay VRAM_Buffer2,y
1487
            ld a,++$9a                     ;store length byte of 26 here with d7 set
1488
            ld (ix+2),a;stay VRAM_Buffer2+2,y         ;to increment by 32 (in columns)            
1489
            ld bc,MetatileBuffer;ld c,0                    ;row
1490
            ld hy,13
1491
;row=0..12
1492
DrawMTLoop:
1493
; Z80     -    
1494
        ;ld hl,MetatileBuffer
1495
        ;add hl,bc
1496
        ld a,(bc);(hl);ldax MetatileBuffer,x         ;get first metatile number ;%xx000000 - attribute table bits, %00xxxxxx - metatile number
1497
            ld e,d;0
1498
            add a,a ;*2
1499
            rl e
1500
            add a,a ;*4
1501
            rl e ;e=0..3
1502
            ld hl,AreaParserTaskNum        ;get current task number for level processing and
1503
            bit 0,(hl) ;get current task number for level processing and mask out all but LSB
1504
            jr nz,$+4
1505
             add a,2 ;multiply by 2, then add to the tile offset so we can draw either side of the metatiles
1506
            ld hl,MetatileGraphics_Low
1507
            add hl,de ;e=0..3
1508
            add a,(hl);l,(iy)
1509
            inc hl
1510
            inc hl
1511
            inc hl
1512
            inc hl
1513
           ;ld e,a
1514
           ;adc a,(hl)
1515
           ;sub e
1516
           ;ld h,a
1517
           ;ld l,e ;23t
1518
              ld h,(hl);(iy+MetatileGraphics_High-MetatileGraphics_Low) ;get address to graphics table from here
1519
              jr nc,$+3
1520
              inc h
1521
              ld l,a ;20.5t
1522
             ld a,(hl);ldayindirect (SCRATCHPAD+$06),y ;get first tile number (top left or top right) and store
1523
             ld (ix+3),a
1524
             inc hl
1525
             ld a,(hl) ;now get the second (bottom left or bottom right) and store
1526
             ld (ix+4),a;stax VRAM_Buffer2+4,x
1527
             inc ix;inci SCRATCHPAD+$00                      ;increment vram buffer offset by 2
1528
             inc ix;inci SCRATCHPAD+$00
1529
            inc bc ;next row                         
1530
            ;ld a,c
1531
            dec hy ;cp $0d ;check for the bottom of the screen
1532
            jp nz,DrawMTLoop ;jp c,DrawMTLoop               ;if not there yet, loop back
1533
            ld b,d;0
1534
 
1535
;  vram buffer offset  13*2,    3  :
1536
            ld (ix+3),b;0       ;put null terminator at end of data for name table
1537
            ld a,(VRAM_Buffer2_Offset)
1538
            add a,13*2+3
1539
            ld (VRAM_Buffer2_Offset),a ;store new buffer offset
1540
            ld hl,CurrentNTAddr_Low
1541
            inc (hl);inci CurrentNTAddr_Low        ;increment name table address low
1542
            ld a,(hl);lda CurrentNTAddr_Low        ;check current low byte
1543
            and ++%00011111               ;if no wraparound, just skip this part
1544
            jr nz,ExitDrawM
1545
            ;ld a,++$80                     ;if wraparound occurs, make sure low byte stays
1546
            ld (hl),$80;sta CurrentNTAddr_Low        ;just under the status bar
1547
            ld hl,CurrentNTAddr_High
1548
            ld a,(hl);lda CurrentNTAddr_High       ;and then invert d2 of the name table address high
1549
            xor ++%00000100               ;to move onto the next appropriate name table
1550
            ld (hl),a;sta CurrentNTAddr_High
1551
ExitDrawM:  ;jmp SetVRAMCtrl              ;jump to set buffer to $0341 (VRAM_Buffer2) and leave
1552
             ldan ++$06
1553
             sta VRAM_Buffer_AddrCtrl ;set buffer to $0341 (VRAM_Buffer2) and leave
1554
             ret
1555
 
1556
           else ;~Z80
1557
 
1558
            lda CurrentColumnPos         ;store LSB of where we're at
1559
            andn ++$01
1560
            sta SCRATCHPAD+$05          
1561
            ldy VRAM_Buffer2_Offset      ;store vram buffer offset
1562
             sty SCRATCHPAD+$00
1563
            lda CurrentNTAddr_Low        ;get current name table address we're supposed to render
1564
            stay VRAM_Buffer2+1,y
1565
            lda CurrentNTAddr_High
1566
            stay VRAM_Buffer2,y
1567
            ldan ++$9a                     ;store length byte of 26 here with d7 set
1568
            stay VRAM_Buffer2+2,y         ;to increment by 32 (in columns)
1569
            ldan ++$00                     ;init attribute row
1570
            sta SCRATCHPAD+$04 ;current attribute row
1571
            tax ;x=row
1572
;x=row=0..12
1573
DrawMTLoop:
1574
            stx SCRATCHPAD+$01                      ;store init value of 0 or incremented offset for buffer
1575
            ldax MetatileBuffer,x         ;get first metatile number, and mask out all but 2 MSB
1576
            andn ++%11000000
1577
            sta SCRATCHPAD+$03                      ;store attribute table bits here
1578
            asl                          ;note that metatile format is:
1579
            rol                          ;%xx000000 - attribute table bits, 
1580
            rol                          ;%00xxxxxx - metatile number
1581
            tay                          ;rotate bits to d1-d0 and use as offset here            
1582
            lday MetatileGraphics_Low,y   ;get address to graphics table from here
1583
            sta SCRATCHPAD+$06
1584
            lday MetatileGraphics_High,y
1585
            sta SCRATCHPAD+$07
1586
            ldax MetatileBuffer,x         ;get metatile number again
1587
            asl                          ;multiply by 4 and use as tile offset
1588
            asl
1589
            sta SCRATCHPAD+$02
1590
            lda AreaParserTaskNum        ;get current task number for level processing and
1591
            andn ++%00000001               ;mask out all but LSB, then invert LSB, multiply by 2
1592
            eorn ++%00000001               ;to get the correct column position in the metatile,
1593
            asl                          ;then add to the tile offset so we can draw either side
1594
            adci SCRATCHPAD+$02                      ;of the metatiles
1595
            tay
1596
            ldx SCRATCHPAD+$00                      ;use vram buffer offset from before as X
1597
            ldayindirect (SCRATCHPAD+$06),y
1598
            stax VRAM_Buffer2+3,x         ;get first tile number (top left or top right) and store
1599
            iny
1600
            ldayindirect (SCRATCHPAD+$06),y                  ;now get the second (bottom left or bottom right) and store
1601
            stax VRAM_Buffer2+4,x
1602
 
1603
            ldy SCRATCHPAD+$04                      ;get current attribute row
1604
            lda SCRATCHPAD+$05                      ;get LSB of current column where we're at, and
1605
         checka
1606
            bne RightCheck               ;branch if set (clear = left attrib, set = right)
1607
            lda SCRATCHPAD+$01                      ;get current row we're rendering
1608
            lsr                          ;branch if LSB set (clear = top left, set = bottom left)
1609
            bcs LLeft
1610
            roli SCRATCHPAD+$03                      ;rotate attribute bits 3 to the left
1611
            roli SCRATCHPAD+$03                      ;thus in d1-d0, for upper left square
1612
            roli SCRATCHPAD+$03
1613
            jmp SetAttrib
1614
RightCheck: lda SCRATCHPAD+$01                      ;get LSB of current row we're rendering
1615
            lsr                          ;branch if set (clear = top right, set = bottom right)
1616
            bcs NextMTRow
1617
            lsri SCRATCHPAD+$03                      ;shift attribute bits 4 to the right
1618
            lsri SCRATCHPAD+$03                      ;thus in d3-d2, for upper right square
1619
            lsri SCRATCHPAD+$03
1620
            lsri SCRATCHPAD+$03
1621
            jmp SetAttrib
1622
LLeft:      lsri SCRATCHPAD+$03                      ;shift attribute bits 2 to the right
1623
            lsri SCRATCHPAD+$03                      ;thus in d5-d4 for lower left square
1624
NextMTRow:  inci SCRATCHPAD+$04                      ;move onto next attribute row  
1625
SetAttrib:  lday AttributeBuffer,y        ;get previously saved bits from before
1626
            orai SCRATCHPAD+$03                      ;if any, and put new bits, if any, onto
1627
            stay AttributeBuffer,y        ;the old, and store
1628
             inci SCRATCHPAD+$00                      ;increment vram buffer offset by 2
1629
             inci SCRATCHPAD+$00
1630
            ldx SCRATCHPAD+$01                      ;get current gfx buffer row, and check for
1631
            inx                          ;the bottom of the screen
1632
            cpxn ++$0d
1633
              cmpcy
1634
            bcc DrawMTLoop               ;if not there yet, loop back
1635
 
1636
;  vram buffer offset  13*2,    3  :           
1637
            ldy SCRATCHPAD+$00                      ;get current vram buffer offset, increment by 3
1638
            iny                          ;(for name table address and length bytes)
1639
            iny
1640
            iny
1641
            ldan ++$00
1642
            stay VRAM_Buffer2,y           ;put null terminator at end of data for name table
1643
            sty VRAM_Buffer2_Offset      ;store new buffer offset
1644
 
1645
            inci CurrentNTAddr_Low        ;increment name table address low
1646
            lda CurrentNTAddr_Low        ;check current low byte
1647
            andn ++%00011111               ;if no wraparound, just skip this part
1648
            bne ExitDrawM
1649
            ldan ++$80                     ;if wraparound occurs, make sure low byte stays
1650
            sta CurrentNTAddr_Low        ;just under the status bar
1651
            lda CurrentNTAddr_High       ;and then invert d2 of the name table address high
1652
            eorn ++%00000100               ;to move onto the next appropriate name table
1653
            sta CurrentNTAddr_High
1654
ExitDrawM:  jmp SetVRAMCtrl              ;jump to set buffer to $0341 (VRAM_Buffer2) and leave
1655
           endif
1656
 
1657
;-------------------------------------------------------------------------------------
1658
             if Z80OPT4==0 ; Z80     -    
1659
;$00 - temp attribute table address high (big endian order this time!)
1660
;$01 - temp attribute table address low
1661
RenderAttributeTables:
1662
             lda CurrentNTAddr_Low    ;get low byte of next name table address
1663
             andn ++%00011111           ;to be written to, mask out all but 5 LSB,
1664
             secsub                      ;subtract four 
1665
             sbcn ++$04
1666
              cmpcy
1667
        if Z80
1668
        push af
1669
        endif
1670
             andn ++%00011111           ;mask out bits again and store
1671
             sta SCRATCHPAD+$01
1672
        if Z80
1673
        pop af
1674
        endif
1675
             lda CurrentNTAddr_High   ;get high byte and branch if borrow not set
1676
             bcs SetATHigh
1677
             eorn ++%00000100           ;otherwise invert d2
1678
SetATHigh:   andn ++%00000100           ;mask out all other bits
1679
             oran ++$23                 ;add $2300 to the high byte and store
1680
             sta SCRATCHPAD+$00
1681
             lda SCRATCHPAD+$01                  ;get low byte - 4, divide by 4, add offset for
1682
             lsr                      ;attribute table and store
1683
             lsr
1684
             adcn ++$c0                 ;we should now have the appropriate block of
1685
             sta SCRATCHPAD+$01                  ;attribute table in our temp address
1686
             ldxn ++$00
1687
             ldy VRAM_Buffer2_Offset  ;get buffer offset
1688
AttribLoop:  lda SCRATCHPAD+$00
1689
             stay VRAM_Buffer2,y       ;store high byte of attribute table address
1690
             lda SCRATCHPAD+$01
1691
             clc                      ;get low byte, add 8 because we want to start
1692
             adcn ++$08                 ;below the status bar, and store
1693
             stay VRAM_Buffer2+1,y
1694
             sta SCRATCHPAD+$01                  ;also store in temp again
1695
             ldax AttributeBuffer,x    ;fetch current attribute table byte and store
1696
             stay VRAM_Buffer2+3,y     ;in the buffer
1697
             ldan ++$01
1698
             stay VRAM_Buffer2+2,y     ;store length of 1 in buffer
1699
             lsr
1700
             stax AttributeBuffer,x    ;clear current byte in attribute buffer
1701
             iny                      ;increment buffer offset by 4 bytes
1702
             iny
1703
             iny
1704
             iny
1705
             inx                      ;increment attribute offset and check to see
1706
             cpxn ++$07                 ;if we're at the end yet
1707
              cmpcy
1708
             bcc AttribLoop
1709
             stay VRAM_Buffer2,y       ;put null terminator at the end
1710
             sty VRAM_Buffer2_Offset  ;store offset in case we want to do any more
1711
SetVRAMCtrl: ldan ++$06
1712
             sta VRAM_Buffer_AddrCtrl ;set buffer to $0341 (VRAM_Buffer2) and leave
1713
             rts
1714
            endif
1715
 
1716
;-------------------------------------------------------------------------------------
1717
 
1718
;$00 - used as temporary counter in ColorRotation
1719
 
1720
ColorRotatePalette:
180 demige 1721
        if Z80COINCYCLECOLOR
1722
        db 0xa1,0xa1,0xa1,0x31,0xf1,0x31
1723
        else
171 demige 1724
       .db $27, $27, $27, $17, $07, $17
180 demige 1725
        endif
171 demige 1726
 
1727
BlankPalette:
1728
       .db $3f, $0c, $04, $ff, $ff, $ff, $ff, $00
1729
 
1730
;used based on area type
1731
Palette3Data:
1732
       .db $0f, $07, $12, $0f
1733
       .db $0f, $07, $17, $0f
1734
       .db $0f, $07, $17, $1c
1735
       .db $0f, $07, $17, $00
1736
 
1737
ColorRotation:
1738
              lda FrameCounter         ;get frame counter
1739
              andn ++$07                 ;mask out all but three LSB
180 demige 1740
        if Z80COINCYCLECOLOR
1741
                ret nz
1742
              ;lda AreaType             ;get area type
1743
              ;asl                      ;multiply by 4 to get proper offset
1744
              ;asl
1745
              ;tay                      ;save as offset here
1746
              ;lday Palette3Data,y       ;fetch palette to be written based on area type
1747
 
1748
              ldy ColorRotateOffset    ;get color cycling offset
1749
              lday ColorRotatePalette,y
1750
                ld hl,(curpalette)
1751
                ld e,11*2
1752
                add hl,de
1753
                ld (hl),a
1754
                inc hl
1755
                ld (hl),a
1756
 
1757
              inci ColorRotateOffset    ;increment color cycling offset
1758
              lda ColorRotateOffset
1759
              cmpn ++$06                 ;check to see if it's still in range
1760
              ;cmpcy
1761
              ret c;bcc ExitColorRot         ;if so, branch to leave
1762
              xor a;ldan ++$00
1763
              sta ColorRotateOffset    ;otherwise, init to keep it in range
1764
                ret
1765
        else
171 demige 1766
              bne ExitColorRot         ;branch if not set to zero to do this every eighth frame
1767
              ldx VRAM_Buffer1_Offset  ;check vram buffer offset
1768
              cpxn ++$31
1769
              cmpcy
1770
              bcs ExitColorRot         ;if offset over 48 bytes, branch to leave
1771
              tay                      ;otherwise use frame counter's 3 LSB as offset here
1772
GetBlankPal:  lday BlankPalette,y       ;get blank palette for palette 3
1773
              stax VRAM_Buffer1,x       ;store it in the vram buffer
1774
              inx                      ;increment offsets
1775
              iny
1776
              cpyn ++$08
1777
              cmpcy
1778
              bcc GetBlankPal          ;do this until all bytes are copied
1779
              ldx VRAM_Buffer1_Offset  ;get current vram buffer offset
1780
              ldan ++$03
1781
              sta SCRATCHPAD+$00                  ;set counter here
1782
              lda AreaType             ;get area type
1783
              asl                      ;multiply by 4 to get proper offset
1784
              asl
1785
              tay                      ;save as offset here
1786
GetAreaPal:   lday Palette3Data,y       ;fetch palette to be written based on area type
1787
              stax VRAM_Buffer1+3,x     ;store it to overwrite blank palette in vram buffer
1788
              iny
1789
              inx
1790
              deci SCRATCHPAD+$00                  ;decrement counter
1791
              bpl GetAreaPal           ;do this until the palette is all copied
1792
              ldx VRAM_Buffer1_Offset  ;get current vram buffer offset
1793
              ldy ColorRotateOffset    ;get color cycling offset
1794
              lday ColorRotatePalette,y
1795
              stax VRAM_Buffer1+4,x     ;get and store current color in second slot of palette
1796
              lda VRAM_Buffer1_Offset
1797
              clc                      ;add seven bytes to vram buffer offset
1798
              adcn ++$07
1799
              sta VRAM_Buffer1_Offset
1800
              inci ColorRotateOffset    ;increment color cycling offset
1801
              lda ColorRotateOffset
1802
              cmpn ++$06                 ;check to see if it's still in range
1803
              cmpcy
1804
              bcc ExitColorRot         ;if so, branch to leave
1805
              ldan ++$00
1806
              sta ColorRotateOffset    ;otherwise, init to keep it in range
1807
ExitColorRot: rts                      ;leave
180 demige 1808
        endif
171 demige 1809
 
1810
;-------------------------------------------------------------------------------------
1811
;$00 - temp store for offset control bit
1812
;$01 - temp vram buffer offset
1813
;$02 - temp store for vertical high nybble in block buffer routine
1814
;$03 - temp adder for high byte of name table address
1815
;$04, $05 - name table address low/high
1816
;$06, $07 - block buffer address low/high
1817
 
1818
BlockGfxData:
1819
       .db $45, $45, $47, $47
1820
       .db $47, $47, $47, $47
1821
       .db $57, $58, $59, $5a
1822
       .db $24, $24, $24, $24 ;blank metatile
1823
       .db y26, y26, y26, y26 ;water/lava ;blank metatile for water
1824
 
1825
RemoveCoin_Axe:
1826
              ldyn ++$41                 ;set low byte so offset points to $0341
1827
              ldan ++$03                 ;load offset for default blank metatile
1828
              ldx AreaType             ;check area type
1829
         checkx
1830
              bne WriteBlankMT         ;if not water type, use offset
1831
              ldan ++$04                 ;otherwise load offset for blank metatile used in water
1832
WriteBlankMT: jsr PutBlockMetatile     ;do a sub to write blank metatile to vram buffer
1833
              ldan ++$06
1834
              sta VRAM_Buffer_AddrCtrl ;set vram address controller to $0341 (VRAM_Buffer2) and leave
1835
              rts
1836
 
1837
ReplaceBlockMetatile:
1838
       jsr WriteBlockMetatile    ;write metatile to vram buffer to replace block object
1839
       inci Block_ResidualCounter ;increment unused counter (residual code)
1840
       decx Block_RepFlag,x       ;decrement flag (residual code)
1841
       rts                       ;leave
1842
 
1843
DestroyBlockMetatile:
1844
       ldan ++$00       ;force blank metatile if branched/jumped to this point
1845
 
1846
WriteBlockMetatile:
1847
             ldyn ++$03                ;load offset for blank metatile
1848
             cmpn ++$00                ;check contents of A for blank metatile
1849
             beq UseBOffset          ;branch if found (unconditional if branched from 8a6b)
1850
             ldyn ++$00                ;load offset for brick metatile w/ line
1851
             cmpn ++$58
1852
             beq UseBOffset          ;use offset if metatile is brick with coins (w/ line)
1853
             cmpn ++$51
1854
             beq UseBOffset          ;use offset if metatile is breakable brick w/ line
1855
             iny                     ;increment offset for brick metatile w/o line
1856
             cmpn ++$5d
1857
             beq UseBOffset          ;use offset if metatile is brick with coins (w/o line)
1858
             cmpn ++$52
1859
             beq UseBOffset          ;use offset if metatile is breakable brick w/o line
1860
             iny                     ;if any other metatile, increment offset for empty block
1861
UseBOffset:  tya                     ;put Y in A
1862
             ldy VRAM_Buffer1_Offset ;get vram buffer offset
1863
             iny                     ;move onto next byte
1864
             jsr PutBlockMetatile    ;get appropriate block data and write to vram buffer
1865
MoveVOffset: dey                     ;decrement vram buffer offset
1866
             tya                     ;add 10 bytes to it
1867
             clc
1868
             adcn ++10
1869
             jmp SetVRAMOffset       ;branch to store as new vram buffer offset
1870
 
1871
PutBlockMetatile:
1872
            stx SCRATCHPAD+$00               ;store control bit from SprDataOffset_Ctrl
1873
            sty SCRATCHPAD+$01               ;store vram buffer offset for next byte
1874
            asl
1875
            asl                   ;multiply A by four and use as X
1876
            tax
1877
            ldyn ++$20              ;load high byte for name table 0
1878
            lda SCRATCHPAD+$06               ;get low byte of block buffer pointer
1879
            cmpn ++$d0              ;check to see if we're on odd-page block buffer
1880
              cmpcy
1881
            bcc SaveHAdder        ;if not, use current high byte
1882
            ldyn ++$24              ;otherwise load high byte for name table 1
1883
SaveHAdder: sty SCRATCHPAD+$03               ;save high byte here
1884
            andn ++$0f              ;mask out high nybble of block buffer pointer
1885
            asl                   ;multiply by 2 to get appropriate name table low byte
1886
            sta SCRATCHPAD+$04               ;and then store it here
1887
            ldan ++$00
1888
            sta SCRATCHPAD+$05               ;initialize temp high byte
1889
            lda SCRATCHPAD+$02               ;get vertical high nybble offset used in block buffer routine
1890
            clc
1891
            adcn ++$20              ;add 32 pixels for the status bar
1892
            asl
1893
            roli SCRATCHPAD+$05               ;shift and rotate d7 onto d0 and d6 into carry
1894
            asl
1895
            roli SCRATCHPAD+$05               ;shift and rotate d6 onto d0 and d5 into carry
1896
            adci SCRATCHPAD+$04               ;add low byte of name table and carry to vertical high nybble
1897
            sta SCRATCHPAD+$04               ;and store here
1898
            lda SCRATCHPAD+$05               ;get whatever was in d7 and d6 of vertical high nybble
1899
            adcn ++$00              ;add carry
1900
            clc
1901
            adci SCRATCHPAD+$03               ;then add high byte of name table
1902
            sta SCRATCHPAD+$05               ;store here
1903
            ldy SCRATCHPAD+$01               ;get vram buffer offset to be used
1904
RemBridge:  ldax BlockGfxData,x    ;write top left and top right
1905
            stay VRAM_Buffer1+2,y  ;tile numbers into first spot
1906
            ldax BlockGfxData+1,x
1907
            stay VRAM_Buffer1+3,y
1908
            ldax BlockGfxData+2,x  ;write bottom left and bottom
1909
            stay VRAM_Buffer1+7,y  ;right tiles numbers into
1910
            ldax BlockGfxData+3,x  ;second spot
1911
            stay VRAM_Buffer1+8,y
1912
            lda SCRATCHPAD+$04
1913
            stay VRAM_Buffer1,y    ;write low byte of name table
1914
            clc                   ;into first slot as read
1915
            adcn ++$20              ;add 32 bytes to value
1916
            stay VRAM_Buffer1+5,y  ;write low byte of name table
1917
            lda SCRATCHPAD+$05               ;plus 32 bytes into second slot
1918
            stay VRAM_Buffer1-1,y  ;write high byte of name
1919
            stay VRAM_Buffer1+4,y  ;table address to both slots
1920
            ldan ++$02
1921
            stay VRAM_Buffer1+1,y  ;put length of 2 in
1922
            stay VRAM_Buffer1+6,y  ;both slots
1923
            ldan ++$00
1924
            stay VRAM_Buffer1+9,y  ;put null terminator at end
1925
            ldx SCRATCHPAD+$00               ;get offset control bit here
1926
            rts                   ;and leave
1927
 
1928
;-------------------------------------------------------------------------------------
1929
;METATILE GRAPHICS TABLE
1930
 
1931
MetatileGraphics_Low:
1932
  .db LOW Palette0_MTiles, LOW Palette1_MTiles, LOW Palette2_MTiles, LOW Palette3_MTiles
1933
 
1934
MetatileGraphics_High:
1935
  .db HIGH Palette0_MTiles, HIGH Palette1_MTiles, HIGH Palette2_MTiles, HIGH Palette3_MTiles
1936
 
1937
  if Z80ATTR
1938
xa0=0xec
1939
xa1=0xed
1940
xa2=0xee
1941
xa3=0xef
1942
x27=0xf0
1943
xba=0xf1
1944
xbb=0xf2
1945
x86=0xf3
1946
x87=0xf4
1947
x8a=0xf5
1948
x8b=0xf6
1949
x8e=0xf7
1950
x8f=0xf8
1951
y25=0xf9
1952
y26=0xfa
1953
y35=0xfb
1954
y36=0xfc
1955
y37=0xfd
1956
y38=0xfe
1957
w26=10+('X'-'A')
1958
;(water pipe bottom):
1959
x91=10+('J'-'A');0x91
1960
x92=10+('F'-'A');0x92
1961
;            ?
1962
  else
1963
xa0=0xa0
1964
xa1=0xa1
1965
xa2=0xa2
1966
xa3=0xa3
1967
x27=0x27
1968
xba=0xba
1969
xbb=0xbb
1970
x86=0x86
1971
x87=0x87
1972
x8a=0x8a
1973
x8b=0x8b
1974
x8e=0x8e
1975
x8f=0x8f
1976
y25=0x25
1977
y26=0x26
1978
y35=0x35
1979
y36=0x36
1980
y37=0x37
1981
y38=0x38
1982
w26=0x26
1983
x91=0x91
1984
x92=0x92
1985
  endif
1986
 
1987
Palette0_MTiles:
1988
  .db $24, $24, $24, $24 ;blank
1989
  .db $27, $27, $27, $27 ;black metatile
1990
  .db $24, $24, $24, $35 ;bush left
1991
  .db $36, $25, $37, $25 ;bush middle
1992
  .db $24, $38, $24, $24 ;bush right
1993
  .db $24, $30, $30, w26 ;mountain left
1994
  .db w26, w26, $34, w26 ;mountain left bottom/middle center
1995
  .db $24, $31, $24, $32 ;mountain middle top
1996
  .db $33, w26, $24, $33 ;mountain right
1997
  .db $34, w26, w26, w26 ;mountain right bottom
1998
  .db w26, w26, w26, w26 ;mountain middle bottom
1999
  .db $24, $c0, $24, $c0 ;bridge guardrail
2000
  .db $24, $7f, $7f, $24 ;chain
2001
  .db $b8, $ba, $b9, $bb ;tall tree top, top half
2002
  .db $b8, $bc, $b9, $bd ;short tree top
2003
  .db $ba, $bc, $bb, $bd ;tall tree top, bottom half
2004
  .db $60, $64, $61, $65 ;warp pipe end left, points up
2005
  .db $62, $66, $63, $67 ;warp pipe end right, points up
2006
  .db $60, $64, $61, $65 ;decoration pipe end left, points up
2007
  .db $62, $66, $63, $67 ;decoration pipe end right, points up
2008
  .db $68, $68, $69, $69 ;pipe shaft left
2009
  .db w26, w26, $6a, $6a ;pipe shaft right
2010
  .db $4b, $4c, $4d, $4e ;tree ledge left edge
2011
  .db $4d, $4f, $4d, $4f ;tree ledge middle
2012
  .db $4d, $4e, $50, $51 ;tree ledge right edge
2013
  .db $6b, $70, $2c, $2d ;mushroom left edge
2014
  .db $6c, $71, $6d, $72 ;mushroom middle
2015
  .db $6e, $73, $6f, $74 ;mushroom right edge
2016
  .db $86, $8a, $87, $8b ;sideways pipe end top ;$1c?
2017
  .db $88, $8c, $88, $8c ;sideways pipe shaft top
2018
  .db $89, $8d, $69, $69 ;sideways pipe joint top
2019
  .db $8e, $91, $8f, $92 ;sideways pipe end bottom
2020
  .db w26, $93, w26, $93 ;sideways pipe shaft bottom
2021
  .db $90, $94, $69, $69 ;sideways pipe joint bottom
2022
  .db $a4, $e9, $ea, $eb ;seaplant ;  0- ???
2023
  .db $24, $24, $24, $24 ;blank, used on bricks or blocks that are hit
2024
  .db $24, $2f, $24, $3d ;flagpole ball
2025
  .db $a2, $a2, $a3, $a3 ;flagpole shaft
2026
  .db $24, $24, $24, $24 ;blank, used in conjunction with vines
2027
 
2028
 
2029
Palette1_MTiles:
2030
  .db xa2, xa2, xa3, xa3 ;vertical rope
2031
  .db $99, $24, $99, $24 ;horizontal rope
2032
  .db $24, xa2, $3e, $3f ;left pulley
2033
  .db $5b, $5c, $24, xa3 ;right pulley
2034
  .db $24, $24, $24, $24 ;blank used for balance rope
2035
  .db $9d, $47, $9e, $47 ;castle top
2036
  .db $47, $47, x27, x27 ;castle window left
2037
  .db $47, $47, $47, $47 ;castle brick wall
2038
  .db x27, x27, $47, $47 ;castle window right
2039
  .db $a9, $47, $aa, $47 ;castle top w/ brick
2040
  .db $9b, x27, $9c, x27 ;entrance top
2041
  .db x27, x27, x27, x27 ;entrance bottom
2042
  .db $52, $52, $52, $52 ;green ledge stump
2043
  .db $80, xa0, $81, xa1 ;fence
2044
  .db $be, $be, $bf, $bf ;tree trunk
2045
  .db $75, xba, $76, xbb ;mushroom stump top
2046
  .db xba, xba, xbb, xbb ;mushroom stump bottom
2047
  .db $45, $47, $45, $47 ;breakable brick w/ line 
2048
  .db $47, $47, $47, $47 ;breakable brick 
2049
  .db $45, $47, $45, $47 ;breakable brick (not used)
2050
  .db $b4, $b6, $b5, $b7 ;cracked rock terrain
2051
  .db $45, $47, $45, $47 ;brick with line (power-up)
2052
  .db $45, $47, $45, $47 ;brick with line (vine)
2053
  .db $45, $47, $45, $47 ;brick with line (star)
2054
  .db $45, $47, $45, $47 ;brick with line (coins)
2055
  .db $45, $47, $45, $47 ;brick with line (1-up)
2056
  .db $47, $47, $47, $47 ;brick (power-up)
2057
  .db $47, $47, $47, $47 ;brick (vine)
2058
  .db $47, $47, $47, $47 ;brick (star)
2059
  .db $47, $47, $47, $47 ;brick (coins)
2060
  .db $47, $47, $47, $47 ;brick (1-up)
2061
  .db $24, $24, $24, $24 ;hidden block (1 coin)
2062
  .db $24, $24, $24, $24 ;hidden block (1-up)
2063
  .db $ab, $ac, $ad, $ae ;solid block (3-d block)
2064
  .db $5d, $5e, $5d, $5e ;solid block (white wall)
2065
  .db $c1, $24, $c1, $24 ;bridge
2066
  .db $c6, $c8, $c7, $c9 ;bullet bill cannon barrel
2067
  .db $ca, $cc, $cb, $cd ;bullet bill cannon top
2068
  .db $2a, $2a, $40, $40 ;bullet bill cannon bottom
2069
  .db $24, $24, $24, $24 ;blank used for jumpspring
2070
  .db $24, $47, $24, $47 ;half brick used for jumpspring
2071
  .db $82, $83, $84, $85 ;solid block (water level, green rock)
2072
  .db $24, $47, $24, $47 ;half brick (???)
2073
  .db x86, x8a, x87, x8b ;water pipe top
2074
  .db x8e, x91, x8f, x92 ;water pipe bottom
2075
  .db $24, $2f, $24, $3d ;flag ball (residual object) ; ???
2076
 
2077
Palette2_MTiles:
2078
  .db $24, $24, $24, y35 ;cloud left
2079
  .db y36, y25, y37, y25 ;cloud middle
2080
  .db $24, y38, $24, $24 ;cloud right
2081
  .db $24, $24, $39, $24 ;cloud bottom left
2082
  .db $3a, $24, $3b, $24 ;cloud bottom middle
2083
  .db $3c, $24, $24, $24 ;cloud bottom right
2084
  .db $41, y26, $41, y26 ;water/lava top
2085
  .db y26, y26, y26, y26 ;water/lava
2086
  .db $b0, $b1, $b2, $b3 ;cloud level terrain
2087
  .db $77, $79, $77, $79 ;bowser's bridge
2088
 
2089
Palette3_MTiles:
2090
  .db $53, $55, $54, $56 ;question block (coin)
2091
  .db $53, $55, $54, $56 ;question block (power-up)
2092
  .db $a5, $a7, $a6, $a8 ;coin
2093
  .db $c2, $c4, $c3, $c5 ;underwater coin ;  3- ???
2094
  .db $57, $59, $58, $5a ;empty block
2095
  .db $7b, $7d, $7c, $7e ;axe
2096
 
2097
;-------------------------------------------------------------------------------------
2098
;VRAM BUFFER DATA FOR LOCATIONS IN PRG-ROM
2099
 
2100
WaterPaletteData:
2101
  .db $3f, $00, $20
2102
  .db $0f, $15, $12, $25  
2103
  .db $0f, $3a, $1a, $0f
2104
  .db $0f, $30, $12, $0f
2105
  .db $0f, $27, $12, $0f
2106
  .db $22, $16, $27, $18
2107
  .db $0f, $10, $30, $27
2108
  .db $0f, $16, $30, $27
2109
  .db $0f, $0f, $30, $10
2110
  .db $00
2111
 
2112
GroundPaletteData:
2113
  .db $3f, $00, $20
2114
  .db $0f, $29, $1a, $0f
2115
  .db $0f, $36, $17, $0f
2116
  .db $0f, $30, $21, $0f
2117
  .db $0f, $27, $17, $0f
2118
  .db $0f, $16, $27, $18
2119
  .db $0f, $1a, $30, $27
2120
  .db $0f, $16, $30, $27
2121
  .db $0f, $0f, $36, $17
2122
  .db $00
2123
 
2124
UndergroundPaletteData:
2125
  .db $3f, $00, $20
2126
  .db $0f, $29, $1a, $09
2127
  .db $0f, $3c, $1c, $0f
2128
  .db $0f, $30, $21, $1c
2129
  .db $0f, $27, $17, $1c
2130
  .db $0f, $16, $27, $18
2131
  .db $0f, $1c, $36, $17
2132
  .db $0f, $16, $30, $27
2133
  .db $0f, $0c, $3c, $1c
2134
  .db $00
2135
 
2136
CastlePaletteData:
2137
  .db $3f, $00, $20
2138
  .db $0f, $30, $10, $00
2139
  .db $0f, $30, $10, $00
2140
  .db $0f, $30, $16, $00
2141
  .db $0f, $27, $17, $00
2142
  .db $0f, $16, $27, $18
2143
  .db $0f, $1c, $36, $17
2144
  .db $0f, $16, $30, $27
2145
  .db $0f, $00, $30, $10
2146
  .db $00
2147
 
2148
DaySnowPaletteData:
2149
  .db $3f, $00, $04
2150
  .db $22, $30, $00, $10
2151
  .db $00
2152
 
2153
NightSnowPaletteData:
2154
  .db $3f, $00, $04
2155
  .db $0f, $30, $00, $10
2156
  .db $00
2157
 
2158
MushroomPaletteData:
2159
  .db $3f, $00, $04
2160
  .db $22, $27, $16, $0f
2161
  .db $00
2162
 
2163
BowserPaletteData:
2164
  .db $3f, $14, $04
2165
  .db $0f, $1a, $30, $27
2166
  .db $00
2167
 
2168
MarioThanksMessage:
2169
;"THANK YOU MARIO!"
2170
  .db $25, $48, $10
2171
  .db $1d, $11, $0a, $17, $14, $24
2172
  .db $22, $18, $1e, $24
2173
  .db $16, $0a, $1b, $12, $18, $2b
2174
  .db $00
2175
 
2176
LuigiThanksMessage:
2177
;"THANK YOU LUIGI!"
2178
  .db $25, $48, $10
2179
  .db $1d, $11, $0a, $17, $14, $24
2180
  .db $22, $18, $1e, $24
2181
  .db $15, $1e, $12, $10, $12, $2b
2182
  .db $00
2183
 
2184
MushroomRetainerSaved:
2185
;"BUT OUR PRINCESS IS IN"
2186
  .db $25, $c5, $16
2187
  .db $0b, $1e, $1d, $24, $18, $1e, $1b, $24
2188
  .db $19, $1b, $12, $17, $0c, $0e, $1c, $1c, $24
2189
  .db $12, $1c, $24, $12, $17
2190
;"ANOTHER CASTLE!"
2191
  .db $26, $05, $0f
2192
  .db $0a, $17, $18, $1d, $11, $0e, $1b, $24
2193
  .db $0c, $0a, $1c, $1d, $15, $0e, $2b, $00
2194
 
2195
PrincessSaved1:
2196
;"YOUR QUEST IS OVER."
2197
  .db $25, $a7, $13
2198
  .db $22, $18, $1e, $1b, $24
2199
  .db $1a, $1e, $0e, $1c, $1d, $24
2200
  .db $12, $1c, $24, $18, $1f, $0e, $1b, $af
2201
  .db $00
2202
 
2203
PrincessSaved2:
2204
;"WE PRESENT YOU A NEW QUEST."
2205
  .db $25, $e3, $1b
2206
  .db $20, $0e, $24
2207
  .db $19, $1b, $0e, $1c, $0e, $17, $1d, $24
2208
  .db $22, $18, $1e, $24, $0a, $24, $17, $0e, $20, $24
2209
  .db $1a, $1e, $0e, $1c, $1d, $af
2210
  .db $00
2211
 
2212
WorldSelectMessage1:
2213
;"PUSH BUTTON B"
2214
  .db $26, $4a, $0d
2215
  .db $19, $1e, $1c, $11, $24
2216
  .db $0b, $1e, $1d, $1d, $18, $17, $24, $0b
2217
  .db $00
2218
 
2219
WorldSelectMessage2:
2220
;"TO SELECT A WORLD"
2221
  .db $26, $88, $11
2222
  .db $1d, $18, $24, $1c, $0e, $15, $0e, $0c, $1d, $24
2223
  .db $0a, $24, $20, $18, $1b, $15, $0d
2224
  .db $00
2225
 
2226
;-------------------------------------------------------------------------------------
2227
;$04 - address low to jump address
2228
;$05 - address high to jump address
2229
;$06 - jump address low
2230
;$07 - jump address high
2231
 
2232
;a=function number
2233
;addresses of functions follow the jsr
2234
JumpEngine:
2235
        if Z80
2236
        add a,a
2237
        pop hl ;pull saved return address from stack
2238
        add a,l
2239
        ld l,a
2240
        adc a,h
2241
        sub l
2242
        ld h,a
2243
        ld a,(hl)
2244
        inc hl
2245
        ld h,(hl)
2246
        ld l,a
2247
         or a ;CY=0 ;??? ;   1-2
2248
        jp (hl)
2249
 
2250
        else
2251
       asl          ;shift bit from contents of A
2252
       tay
2253
       pla          ;pull saved return address from stack
2254
       sta SCRATCHPAD+$04      ;save to indirect
2255
       pla
2256
       sta SCRATCHPAD+$05 ;($04..05) = return addr???
2257
       iny ;y = A*2 + 1???
2258
       ldayindirect (SCRATCHPAD+$04),y  ;load pointer from indirect
2259
       sta SCRATCHPAD+$06      ;note that if an RTS is performed in next routine
2260
       iny ;y = A*2 + 2???          ;it will return to the execution before the sub
2261
       ldayindirect (SCRATCHPAD+$04),y  ;that called this routine
2262
       sta SCRATCHPAD+$07
2263
       jmpindirect (SCRATCHPAD+$06)    ;jump to the address we loaded
2264
        endif
2265
 
2266
;-------------------------------------------------------------------------------------
2267
 
2268
InitializeNameTables:
2269
        if Z80==0
2270
              lda PPU_STATUS            ;reset flip-flop
2271
              lda Mirror_PPU_CTRL_REG1  ;load mirror of ppu reg $2000
2272
              oran ++%00010000            ;set sprites for first 4k and background for second 4k
2273
              andn ++%11110000            ;clear rest of lower nybble, leave higher alone
2274
              jsr WritePPUReg1
2275
        endif
2276
              ldan ++$24                  ;set vram address to start of name table 1
2277
              jsr WriteNTAddr
2278
              ldan ++$20                  ;and then set it to name table 0
2279
WriteNTAddr:
2280
        if Z80
2281
              ld hx,a
2282
              ld lx,0
2283
        else
2284
              sta PPU_ADDRESS
2285
              ldan ++$00
2286
              sta PPU_ADDRESS
2287
        endif
2288
              ldxn ++$04                  ;clear name table with blank tile #24
2289
              ldyn ++$c0
2290
              ldan ++$24
2291
InitNTLoop:  
2292
        if Z80
2293
              ld (ix),a
2294
              inc ix
2295
        else
2296
              sta PPU_DATA              ;count out exactly 768 tiles
2297
        endif
2298
              dey
2299
              bne InitNTLoop
2300
              dex
2301
              bne InitNTLoop
2302
              ldyn ++64                   ;now to clear the attribute table (with zero this time)
2303
              txa
2304
              sta VRAM_Buffer1_Offset   ;init vram buffer 1 offset
2305
              sta VRAM_Buffer1          ;init vram buffer 1
2306
InitATLoop:  
2307
        if Z80
2308
              ld (ix),a
2309
              inc ix
2310
        else
2311
              sta PPU_DATA
2312
        endif
2313
              dey
2314
              bne InitATLoop
2315
              sta HorizontalScroll      ;reset scroll variables
2316
              sta VerticalScroll
2317
              jmp InitScroll            ;initialize scroll registers to zero
2318
 
2319
;-------------------------------------------------------------------------------------
2320
;$00 - temp joypad bit
2321
 
2322
;bit - button (ZX key)
2323
;7 - A (A)
2324
;6 - B (S)
2325
;5 - Select (Space)
2326
;4 - Start (Enter)
2327
;3 - Up (7)
2328
;2 - Down (6)
2329
;1 - Left (5)
2330
;0 - Right (8)
2331
ReadJoypads:
414 alone 2332
              ldan ++$01               ;reset and clear strobe of joypad ports
2333
              sta JOYPAD_PORT
2334
              lsr
2335
              tax                    ;start with joypad 1's port
2336
              sta JOYPAD_PORT
2337
              jsr ReadPortBits
2338
              inx                    ;increment for joypad 2's port
2339
ReadPortBits:
171 demige 2340
        if Z80
414 alone 2341
        push bc
174 demige 2342
        if OSCALLS
212 alone 2343
        OS_GETKEYMATRIX ;out: bcdehlix =  cs...space
174 demige 2344
        else
2345
        ld bc,0x7ffe
2346
        in a,(c)
2347
        ld lx,a  ;lx=%???bnmS_
2348
        ld b,0xbf
2349
        in a,(c)
2350
        ld hx,a  ;hx=%???hjklE
2351
        ld b,0xdf
2352
        in l,(c)  ;l=%???yuiop
2353
        ld b,0xef
2354
        in h,(c)  ;h=%???67890
2355
        ld b,0xf7
2356
        in e,(c)  ;e=%???54321
2357
        ld b,0xfb
2358
        in d,(c)  ;d=%???trewq
2359
        ld a,0xfd
2360
        in a,(0xfe);c=%???gfdsa
2361
        ld b,c;0xfe
2362
        in b,(c)  ;b=%???vcxzC
2363
        ld c,a
2364
        endif
171 demige 2365
        ld a,lx
2366
        or b
2367
        rra
2368
        jp nc,quit
2369
        if DEMO
2370
         bit 3,b ;'c'
2371
         call z,democontinue
2372
         bit 2,c ;'d'
2373
         call z,demooff
2374
        endif
2375
        rr c ;'a'
2376
        rla ;A
2377
        rr c ;'s'
2378
        rla ;B
2379
        ld c,lx
2380
        rr c ;'Space'
2381
        rla ;Select
2382
        ld c,hx
2383
        rr c ;'Enter'
2384
        rla ;Start
2385
        add a,a
2386
        bit 3,h ;7
2387
        jr z,$+3
2388
        inc a ;Up
2389
        add a,a
2390
        bit 4,h ;6
2391
        jr z,$+3
2392
        inc a ;Down
2393
        add a,a
2394
        bit 4,e ;5
2395
        jr z,$+3
2396
        inc a ;Left
2397
        add a,a
2398
        bit 2,h ;8
2399
        jr z,$+3
2400
        inc a ;Right
2401
        cpl
2402
        if DEMO
524 alone 2403
         pop de ;x = joypad number
2404
         push de
2405
         dec e ;( joy1/2)
171 demige 2406
        push bc
524 alone 2407
        call nz,readdemo ;  writedemo ( joy2)
171 demige 2408
        pop bc
2409
        push af
2410
         bit 4,b ;'v'
2411
         call z,savedemo
2412
        pop af
2413
        endif
2414
        ld d,0
414 alone 2415
        pop bc ;ld bc,0 ;x = joypad number
171 demige 2416
        else
2417
 
414 alone 2418
              ldyn ++$08
171 demige 2419
PortLoop:     pha                    ;push previous bit onto stack
2420
              ldax JOYPAD_PORT,x      ;read current bit on joypad port
2421
              sta SCRATCHPAD+$00                ;check d1 and d0 of port output
2422
              lsr                    ;this is necessary on the old
2423
              orai SCRATCHPAD+$00                ;famicom systems in japan
2424
              lsr
2425
              ;pla                    ;read bits from stack
2426
              ;rol                    ;rotate bit from carry flag
2427
               plarol
2428
              dey
2429
              bne PortLoop           ;count down bits left
2430
        endif
2431
              stax SavedJoypadBits,x  ;save controller status here always
2432
              pha
2433
              andn ++%00110000         ;check for select or start
2434
              andx JoypadBitMask,x    ;if neither saved state nor current state
2435
              beq Save8Bits          ;have any of these two set, branch
2436
              pla
2437
              andn ++%11001111         ;otherwise store without select
2438
              stax SavedJoypadBits,x  ;or start bits and leave
2439
              rts
2440
Save8Bits:    pla
2441
              stax JoypadBitMask,x    ;save with all bits in another place and leave ;    
2442
              rts
2443
 
2444
;-------------------------------------------------------------------------------------
2445
;$00 - vram buffer address table low
2446
;$01 - vram buffer address table high
2447
 
2448
; :
2449
;addrH, addrL, [SRLLLLLL (S=inc32, R=repeat, L=length),] S0BBBBBB?
2450
        if Z80
2451
UpdateScreen:  
2452
        ld hl,(SCRATCHPAD+$00)
2453
UpdateScreen0:  
2454
        ld a,(hl)
2455
        or a
2456
        ret z
231 alone 2457
                 ;cp 0x40
2458
                 ;jr nc,$ ; -     $42???
171 demige 2459
                ld d,a
2460
                inc hl
2461
                ld e,(hl)           ;load next byte (second)
2462
                inc hl
2463
                ld a,(hl)            ;load next byte (third)
2464
                ex de,hl
2465
               add a,a
2466
                ld c,32
2467
                jr c,$+4
2468
                ld c,1 ;if d7 of third byte was clear, ppu will only increment by 1
2469
               add a,a
2470
               jr nc,GetLength             ;if d6 of third byte was clear, do not repeat byte
2471
               srl a
2472
               rra
2473
                ld lx,a
2474
               inc de
2475
                ld a,(de)
2476
RepeatByte0:
2477
                ld (hl),a
2478
                add hl,bc
2479
                dec lx
2480
               jp nz,RepeatByte0
2481
               jp OutputToVRAM_q
2482
GetLength:
2483
;CY=0
2484
                rra                       ;shift back to the right to get proper length
2485
                rra                      ;note that d1 will now be in carry
2486
                ld lx,a
2487
OutputToVRAM0:
2488
                inc de
2489
                ld a,(de)
2490
                ld (hl),a
2491
                add hl,bc
2492
                dec lx
2493
               jp nz,OutputToVRAM0
2494
OutputToVRAM_q
2495
                ex de,hl
2496
               ld d,b;0
2497
               inc hl
2498
               jp UpdateScreen0
2499
        else
2500
WriteBufferToScreen:
2501
;a=addrH
2502
;y=0
2503
               sta PPU_ADDRESS           ;store high byte of vram address
2504
               iny
2505
               ldayindirect (SCRATCHPAD+$00),y               ;load next byte (second)
2506
               sta PPU_ADDRESS           ;store low byte of vram address
2507
               iny
2508
               ldayindirect (SCRATCHPAD+$00),y               ;load next byte (third)
2509
               asl                       ;shift to left and save in stack
2510
               pha
2511
               lda Mirror_PPU_CTRL_REG1  ;load mirror of $2000,
2512
               oran ++%00000100            ;set ppu to increment by 32 by default
2513
               bcs SetupWrites           ;if d7 of third byte was clear, ppu will
2514
               andn ++%11111011            ;only increment by 1
2515
SetupWrites:   jsr WritePPUReg1          ;write to register
2516
               pla                       ;pull from stack and shift to left again
2517
               asl
2518
               bcc GetLength             ;if d6 of third byte was clear, do not repeat byte
2519
               oran ++%00000010            ;otherwise set d1 and increment Y
2520
               iny
2521
GetLength:     lsr                       ;shift back to the right to get proper length
2522
               lsr                       ;note that d1 will now be in carry
2523
               tax
2524
OutputToVRAM:  bcs RepeatByte            ;if carry set, repeat loading the same byte
2525
               iny                       ;otherwise increment Y to load next byte
2526
RepeatByte:    ldayindirect (SCRATCHPAD+$00),y               ;load more data from buffer and write to vram
2527
               sta PPU_DATA
2528
               dex                       ;done writing?
2529
               bne OutputToVRAM
2530
               sec          
2531
               tya ;a=end shift
2532
               adci SCRATCHPAD+$00                   ;add end length plus one to the indirect at $00
2533
               sta SCRATCHPAD+$00                   ;to allow this routine to read another set of updates
2534
               ldan ++$00
2535
               adci SCRATCHPAD+$01
2536
               sta SCRATCHPAD+$01
2537
               ldan ++$3f                  ;sets vram address to $3f00 (  16 ,   16 ) ;???
2538
               sta PPU_ADDRESS
2539
               ldan ++$00
2540
               sta PPU_ADDRESS
2541
               sta PPU_ADDRESS           ;then reinitializes it for some reason ;   0???
2542
               sta PPU_ADDRESS
2543
UpdateScreen:  
2544
               ldx PPU_STATUS            ;reset flip-flop
2545
               ldyn ++$00                  ;load first byte from indirect as a pointer
2546
               ldayindirect (SCRATCHPAD+$00),y  
2547
         checka
2548
               bne WriteBufferToScreen   ;if byte is zero we have no further updates to make here
2549
        endif
2550
InitScroll:    sta PPU_SCROLL_REG_H        ;store contents of A into scroll registers
2551
               sta PPU_SCROLL_REG_V        ;and end whatever subroutine led us here
2552
               rts
2553
 
2554
;-------------------------------------------------------------------------------------
2555
 
2556
        if Z80==0
2557
WritePPUReg1:
2558
               sta PPU_CTRL_REG1         ;write contents of A to PPU register 1
2559
               sta Mirror_PPU_CTRL_REG1  ;and its mirror
2560
               rts
2561
        endif
2562
 
2563
;-------------------------------------------------------------------------------------
2564
;$00 - used to store status bar nybbles
2565
;$02 - used as temp vram offset
2566
;$03 - used to store length of status bar number
2567
 
2568
;status bar name table offset and length data
2569
StatusBarData:
2570
      .db $f0, $06 ; top score display on title screen
2571
      .db $62, $06 ; player score
2572
      .db $62, $06
2573
      .db $6d, $02 ; coin tally
2574
      .db $6d, $02
2575
      .db $7a, $03 ; game timer
2576
 
2577
StatusBarOffset:
2578
      .db $06, $0c, $12, $18, $1e, $24
2579
 
2580
PrintStatusBarNumbers:
2581
      sta SCRATCHPAD+$00            ;store player-specific offset
2582
      jsr OutputNumbers  ;use first nybble to print the coin display
2583
      lda SCRATCHPAD+$00            ;move high nybble to low
2584
      lsr                ;and print to score display
2585
      lsr
2586
      lsr
2587
      lsr
2588
 
2589
OutputNumbers:
2590
             clc                      ;add 1 to low nybble
2591
             adcn ++$01
2592
             andn ++%00001111           ;mask out high nybble
2593
             cmpn ++$06
2594
              cmpcy
2595
             bcs ExitOutputN
2596
             pha                      ;save incremented value to stack for now and
2597
             asl                      ;shift to left and use as offset
2598
             tay
2599
             ldx VRAM_Buffer1_Offset  ;get current buffer pointer
2600
             ldan ++$20                 ;put at top of screen by default
2601
             cpyn ++$00                 ;are we writing top score on title screen?
2602
             bne SetupNums
2603
             ldan ++$22                 ;if so, put further down on the screen
2604
SetupNums:   stax VRAM_Buffer1,x
2605
             lday StatusBarData,y      ;write low vram address and length of thing
2606
             stax VRAM_Buffer1+1,x     ;we're printing to the buffer
2607
             lday StatusBarData+1,y
2608
             stax VRAM_Buffer1+2,x
2609
             sta SCRATCHPAD+$03                  ;save length byte in counter
2610
             stx SCRATCHPAD+$02                  ;and buffer pointer elsewhere for now
2611
             pla                      ;pull original incremented value from stack
2612
             tax
2613
             ldax StatusBarOffset,x    ;load offset to value we want to write
2614
             secsub
2615
             sbcy StatusBarData+1,y    ;subtract from length byte we read before
2616
             tay                      ;use value as offset to display digits
2617
             ldx SCRATCHPAD+$02
2618
DigitPLoop:  lday DisplayDigits,y      ;write digits to the buffer
2619
             stax VRAM_Buffer1+3,x    
2620
             inx
2621
             iny
2622
             deci SCRATCHPAD+$03                  ;do this until all the digits are written
2623
             bne DigitPLoop
2624
             ldan ++$00                 ;put null terminator at end
2625
             stax VRAM_Buffer1+3,x
2626
             inx                      ;increment buffer pointer by 3
2627
             inx
2628
             inx
2629
             stx VRAM_Buffer1_Offset  ;store it in case we want to use it again
2630
ExitOutputN: rts
2631
 
2632
;-------------------------------------------------------------------------------------
2633
 
2634
;y= 
2635
DigitsMathRoutine:
2636
            lda OperMode              ;check mode of operation
2637
            cmpn ++TitleScreenModeValue
2638
            beq EraseDMods            ;if in title screen mode, branch to lock score
2639
            ldxn ++$05
2640
AddModLoop: ldax DigitModifier,x       ;load digit amount to increment
2641
            clc
2642
            adcy DisplayDigits,y       ;add to current digit
2643
            bmi BorrowOne             ;if result is a negative number, branch to subtract
2644
            cmpn ++10
2645
              cmpcy
2646
            bcs CarryOne              ;if digit greater than $09, branch to add
2647
StoreNewD:  stay DisplayDigits,y       ;store as new score or game timer digit
2648
            dey                       ;move onto next digits in score or game timer
2649
            dex                       ;and digit amounts to increment
2650
            bpl AddModLoop            ;loop back if we're not done yet
2651
EraseDMods: ldan ++$00                  ;store zero here
2652
            ldxn ++$06                  ;start with the last digit
2653
EraseMLoop: stax DigitModifier-1,x     ;initialize the digit amounts to increment
2654
            dex
2655
            bpl EraseMLoop            ;do this until they're all reset, then leave
2656
            rts
2657
BorrowOne:  decx DigitModifier-1,x     ;decrement the previous digit, then put $09 in
2658
            ldan ++$09                  ;the game timer digit we're currently on to "borrow
2659
         checka
2660
            bne StoreNewD             ;the one", then do an unconditional branch back
2661
CarryOne:   secsub    ;   ???                   ;subtract ten from our digit to make it a
2662
            sbcn ++10                   ;proper BCD number, then increment the digit
2663
            incx DigitModifier-1,x     ;preceding current digit to "carry the one" properly
2664
            jmp StoreNewD             ;go back to just after we branched here
2665
 
2666
;-------------------------------------------------------------------------------------
2667
 
2668
UpdateTopScore:
2669
      ldxn ++$05          ;start with mario's score
2670
      jsr TopScoreCheck
2671
      ldxn ++$0b          ;now do luigi's score
2672
 
2673
TopScoreCheck:
2674
              ldyn ++$05                 ;start with the lowest digit
2675
              secsub           ;   ???
2676
GetScoreDiff: ldax PlayerScoreDisplay,x ;subtract each player digit from each high score digit
2677
        if Z80
2678
        secsub
2679
        endif
2680
              sbcy TopScoreDisplay,y    ;from lowest to highest, if any top score digit exceeds
2681
              dex                      ;any player digit, borrow will be set until a subsequent
2682
              dey                      ;subtraction clears it (player digit is higher than top)
2683
              bpl GetScoreDiff      
2684
              cmpcy
2685
              bcc NoTopSc              ;check to see if borrow is still set, if so, no new high score
2686
              inx                      ;increment X and Y once to the start of the score
2687
              iny
2688
CopyScore:    ldax PlayerScoreDisplay,x ;store player's score digits into high score memory area
2689
              stay TopScoreDisplay,y
2690
              inx
2691
              iny
2692
              cpyn ++$06                 ;do this until we have stored them all
2693
              cmpcy
2694
              bcc CopyScore
2695
NoTopSc:      rts
2696
 
2697
;-------------------------------------------------------------------------------------
2698
 
2699
DefaultSprOffsets:
2700
      .db $04, $30, $48, $60, $78, $90, $a8, $c0
2701
      .db $d8, $e8, $24, $f8, $fc, $28, $2c
2702
 
2703
Sprite0Data:
2704
      .db $18, $ff, $23, $58
2705
 
2706
;-------------------------------------------------------------------------------------
2707
 
2708
InitializeGame:
2709
             ldyn16 ++GAMEDATA_end-AREADATA;++$6f              ;clear all memory as in initialization procedure,
2710
             jsr InitializeMemory  ;but this time, clear only as far as $076f
2711
             ldyn ++$1f
2712
ClrSndLoop:  stay SoundMemory,y     ;clear out memory used
2713
             dey                   ;by the sound engines
2714
             bpl ClrSndLoop
2715
             ldan ++$18              ;set demo timer
2716
             sta DemoTimer
2717
             jsr LoadAreaPointer
2718
 
2719
InitializeArea:
2720
               ldyn16 ++AREADATA_end-AREADATA;++$4b                 ;clear all memory again, only as far as $074b
2721
               jsr InitializeMemory     ;this is only necessary if branching from
2722
               ldxn ++$21
2723
               ldan ++$00
2724
ClrTimersLoop: stax Timers,x             ;clear out memory between
2725
               dex                      ;$0780 and $07a1
2726
               bpl ClrTimersLoop
2727
               lda HalfwayPage
2728
               ldy AltEntranceControl   ;if AltEntranceControl not set, use halfway page, if any found
2729
         checky
2730
               beq StartPage
2731
               lda EntrancePage         ;otherwise use saved entry page number here
2732
StartPage:     sta ScreenLeft_PageLoc   ;set as value here
2733
               sta CurrentPageLoc       ;also set as current page
2734
               sta BackloadingFlag      ;set flag here if halfway page or saved entry page number found
2735
               jsr GetScreenPosition    ;get pixel coordinates for screen borders
2736
               ldyn ++$20                 ;if on odd numbered page, use $2480 as start of rendering
2737
               andn ++%00000001           ;otherwise use $2080, this address used later as name table
2738
               beq SetInitNTHigh        ;address for rendering of game area
2739
               ldyn ++$24
2740
SetInitNTHigh: sty CurrentNTAddr_High   ;store name table address
2741
               ldyn ++$80
2742
               sty CurrentNTAddr_Low
2743
               asl                      ;store LSB of page number in high nybble
2744
               asl                      ;of block buffer column position
2745
               asl
2746
               asl
2747
               sta BlockBufferColumnPos
2748
               deci AreaObjectLength     ;set area object lengths for all empty
2749
               deci AreaObjectLength+1
2750
               deci AreaObjectLength+2
2751
               ldan ++$0b                 ;set value for renderer to update 12 column sets
2752
               sta ColumnSets           ;12 column sets = 24 metatile columns = 1 1/2 screens
2753
               jsr GetAreaDataAddrs     ;get enemy and level addresses and load header
2754
               lda PrimaryHardMode      ;check to see if primary hard mode has been activated
2755
         checka
2756
               bne SetSecHard           ;if so, activate the secondary no matter where we're at
2757
               lda WorldNumber          ;otherwise check world number
2758
               cmpn ++World5              ;if less than 5, do not activate secondary
2759
              cmpcy
2760
               bcc CheckHalfway
2761
               bne SetSecHard           ;if not equal to, then world HIGH  5, thus activate
2762
               lda LevelNumber          ;otherwise, world 5, so check level number
2763
               cmpn ++Level3              ;if 1 or 2, do not set secondary hard mode flag
2764
              cmpcy
2765
               bcc CheckHalfway
2766
SetSecHard:    inci SecondaryHardMode    ;set secondary hard mode flag for areas 5-3 and beyond
2767
CheckHalfway:  lda HalfwayPage
2768
         checka
2769
               beq DoneInitArea
2770
               ldan ++$02                 ;if halfway page set, overwrite start position from header
2771
               sta PlayerEntranceCtrl
2772
DoneInitArea:  ldan ++Silence             ;silence music
2773
               sta AreaMusicQueue
2774
               ldan ++$01                 ;disable screen output
2775
               sta DisableScreenFlag
2776
               inci OperMode_Task        ;increment one of the modes
2777
               rts
2778
 
2779
;-------------------------------------------------------------------------------------
2780
 
2781
PrimaryGameSetup:
2782
      ldan ++$01
2783
      sta FetchNewGameTimerFlag   ;set flag to load game timer from header
2784
      sta PlayerSize              ;set player's size to small
2785
      ldan ++$02
2786
      sta NumberofLives           ;give each player three lives
2787
      sta OffScr_NumberofLives
2788
 
2789
SecondaryGameSetup:
2790
             ldan ++$00
2791
             sta DisableScreenFlag     ;enable screen output
2792
             tay
2793
ClearVRLoop: stay VRAM_Buffer1-1,y      ;clear buffer at $0300-$03ff
2794
             iny
2795
             bne ClearVRLoop
2796
             sta GameTimerExpiredFlag  ;clear game timer exp flag
2797
             sta DisableIntermediate   ;clear skip lives display flag
2798
             sta BackloadingFlag       ;clear value here
2799
             ldan ++$ff
2800
             sta BalPlatformAlignment  ;initialize balance platform assignment flag
2801
             lda ScreenLeft_PageLoc    ;get left side page location
2802
             lsri Mirror_PPU_CTRL_REG1  ;shift LSB of ppu register #1 mirror out
2803
        if Z80==0
2804
             andn ++$01                  ;mask out all but LSB of page location
2805
        endif
2806
             ror                       ;rotate LSB of page location into carry then onto mirror
2807
             roli Mirror_PPU_CTRL_REG1  ;this is to set the proper PPU name table
2808
             jsr GetAreaMusic          ;load proper music into queue
2809
             ldan ++$38                  ;load sprite shuffle amounts to be used later
2810
             sta SprShuffleAmt+2
2811
             ldan ++$48
2812
             sta SprShuffleAmt+1
2813
             ldan ++$58
2814
             sta SprShuffleAmt
2815
             ldxn ++$0e                  ;load default OAM offsets into $06e4-$06f2
2816
ShufAmtLoop: ldax DefaultSprOffsets,x
2817
             stax SprDataOffset,x
2818
             dex                       ;do this until they're all set
2819
             bpl ShufAmtLoop
2820
             ldyn ++$03                  ;set up sprite #0
2821
ISpr0Loop:   lday Sprite0Data,y
2822
             stay Sprite_Data,y
2823
             dey
2824
             bpl ISpr0Loop
2825
             jsr DoNothing2            ;these jsrs doesn't do anything useful
2826
             jsr DoNothing1
2827
             inci Sprite0HitDetectFlag  ;set sprite #0 check flag ;     
2828
             inci OperMode_Task         ;increment to next task
2829
             rts
2830
 
2831
;-------------------------------------------------------------------------------------
2832
 
2833
;$06 - RAM address low
2834
;$07 - RAM address high
2835
 
2836
;y = endaddr
2837
;out: a=0
2838
InitializeMemory:
2839
        if Z80
2840
                push de
2841
                ld hl,AREADATA
2842
                ld de,AREADATA+1
2843
                pop bc
2844
                dec bc
2845
                xor a
2846
                ld (hl),a
2847
                ldir
2848
                ld d,b;0
2849
        else
2850
              ldxn ++$07          ;set initial high byte to $0700-$07ff
2851
              ldan ++$00          ;set initial low byte to start of page (at $00 of page)
2852
              sta SCRATCHPAD+$06
2853
InitPageLoop: stx SCRATCHPAD+$07
2854
InitByteLoop: cpxn ++$01          ;check to see if we're on the stack ($0100-$01ff)
2855
              bne InitByte      ;if not, go ahead anyway
2856
              cpyn ++$60          ;otherwise, check to see if we're at $0160-$01ff
2857
              cmpcy
2858
              bcs SkipByte      ;if so, skip write
2859
InitByte:     stayindirect (SCRATCHPAD+$06),y       ;otherwise, initialize byte with current low byte in Y
2860
SkipByte:     dey
2861
              cpyn ++$ff          ;do this until all bytes in page have been erased
2862
              bne InitByteLoop
2863
              dex               ;go onto the next page
2864
              bpl InitPageLoop  ;do this until all pages of memory have been erased
2865
        endif
2866
              rts
2867
 
2868
;-------------------------------------------------------------------------------------
2869
 
2870
MusicSelectData:
2871
      .db WaterMusic, GroundMusic, UndergroundMusic, CastleMusic
2872
      .db CloudMusic, PipeIntroMusic
2873
 
2874
GetAreaMusic:
2875
             lda OperMode           ;if in title screen mode, leave
2876
         checka
2877
             beq ExitGetM
2878
             lda AltEntranceControl ;check for specific alternate mode of entry
2879
             cmpn ++$02               ;if found, branch without checking starting position
2880
             beq ChkAreaType        ;from area object data header
2881
             ldyn ++$05               ;select music for pipe intro scene by default
2882
             lda PlayerEntranceCtrl ;check value from level header for certain values
2883
             cmpn ++$06
2884
             beq StoreMusic         ;load music for pipe intro scene if header
2885
             cmpn ++$07               ;start position either value $06 or $07
2886
             beq StoreMusic
2887
ChkAreaType: ldy AreaType           ;load area type as offset for music bit
2888
             lda CloudTypeOverride
2889
         checka
2890
             beq StoreMusic         ;check for cloud type override
2891
             ldyn ++$04               ;select music for cloud type level if found
2892
StoreMusic:  lday MusicSelectData,y  ;otherwise select appropriate music for level type
2893
             sta AreaMusicQueue     ;store in queue and leave
2894
ExitGetM:    rts
2895
 
2896
;-------------------------------------------------------------------------------------
2897
 
2898
PlayerStarting_X_Pos:
2899
      .db $28, $18
2900
      .db $38, $28
2901
 
2902
AltYPosOffset:
2903
      .db $08, $00
2904
 
2905
PlayerStarting_Y_Pos:
2906
      .db $00, $20, $b0, $50, $00, $00, $b0, $b0
2907
      .db $f0
2908
 
2909
PlayerBGPriorityData:
2910
      .db $00, $20, $00, $00, $00, $00, $00, $00
2911
 
2912
GameTimerData:
2913
      .db $20 ;dummy byte, used as part of bg priority data
2914
      .db $04, $03, $02
2915
 
2916
Entrance_GameTimerSetup:
2917
          lda ScreenLeft_PageLoc      ;set current page for area objects
2918
          sta Player_PageLoc          ;as page location for player
2919
          ldan ++$28                    ;store value here
2920
          sta VerticalForceDown       ;for fractional movement downwards if necessary
2921
          ldan ++$01                    ;set high byte of player position and
2922
          sta PlayerFacingDir         ;set facing direction so that player faces right
2923
          sta Player_Y_HighPos
2924
          ldan ++$00                    ;set player state to on the ground by default
2925
          sta Player_State
2926
          deci Player_CollisionBits    ;initialize player's collision bits
2927
          ldyn ++$00                    ;initialize halfway page
2928
          sty HalfwayPage      
2929
          lda AreaType                ;check area type
2930
         checka
2931
          bne ChkStPos                ;if water type, set swimming flag, otherwise do not set
2932
          iny
2933
ChkStPos: sty SwimmingFlag
2934
          ldx PlayerEntranceCtrl      ;get starting position loaded from header
2935
          ldy AltEntranceControl      ;check alternate mode of entry flag for 0 or 1
2936
         checky
2937
          beq SetStPos
2938
          cpyn ++$01
2939
          beq SetStPos
2940
          ldxy AltYPosOffset-2,y       ;if not 0 or 1, override $0710 with new offset in X
2941
SetStPos: lday PlayerStarting_X_Pos,y  ;load appropriate horizontal position
2942
          sta Player_X_Position       ;and vertical positions for the player, using
2943
          ldax PlayerStarting_Y_Pos,x  ;AltEntranceControl as offset for horizontal and either $0710
2944
          sta Player_Y_Position       ;or value that overwrote $0710 as offset for vertical
2945
          ldax PlayerBGPriorityData,x
2946
          sta Player_SprAttrib        ;set player sprite attributes using offset in X
2947
          jsr GetPlayerColors         ;get appropriate player palette
2948
          ldy GameTimerSetting        ;get timer control value from header
2949
         checky
2950
          beq ChkOverR                ;if set to zero, branch (do not use dummy byte for this)
2951
          lda FetchNewGameTimerFlag   ;do we need to set the game timer? if not, use 
2952
         checka
2953
          beq ChkOverR                ;old game timer setting
2954
          lday GameTimerData,y         ;if game timer is set and game timer flag is also set,
2955
          sta GameTimerDisplay        ;use value of game timer control for first digit of game timer
2956
          ldan ++$01
2957
          sta GameTimerDisplay+2      ;set last digit of game timer to 1
2958
          lsr
2959
          sta GameTimerDisplay+1      ;set second digit of game timer
2960
          sta FetchNewGameTimerFlag   ;clear flag for game timer reset
2961
          sta StarInvincibleTimer     ;clear star mario timer
2962
ChkOverR: ldy JoypadOverride          ;if controller bits not set, branch to skip this part
2963
         checky
2964
          beq ChkSwimE
2965
          ldan ++$03                    ;set player state to climbing
2966
          sta Player_State
2967
          ldxn ++$00                    ;set offset for first slot, for block object
2968
          jsr InitBlock_XY_Pos
2969
          ldan ++$f0                    ;set vertical coordinate for block object
2970
          sta Block_Y_Position
2971
          ldxn ++$05                    ;set offset in X for last enemy object buffer slot
2972
          ldyn ++$00                    ;set offset in Y for object coordinates used earlier
2973
          jsr Setup_Vine              ;do a sub to grow vine
2974
ChkSwimE: ldy AreaType                ;if level not water-type,
2975
         checky
2976
          bne SetPESub                ;skip this subroutine
2977
          jsr SetupBubble             ;otherwise, execute sub to set up air bubbles
2978
SetPESub: ldan ++$07                    ;set to run player entrance subroutine
2979
          sta GameEngineSubroutine    ;on the next frame of game engine
2980
          rts
2981
 
2982
;-------------------------------------------------------------------------------------
2983
 
2984
;page numbers are in order from -1 to -4
2985
HalfwayPageNybbles:
2986
      .db $56, $40
2987
      .db $65, $70
2988
      .db $66, $40
2989
      .db $66, $40
2990
      .db $66, $40
2991
      .db $66, $60
2992
      .db $65, $70
2993
      .db $00, $00
2994
 
2995
PlayerLoseLife:
2996
             inci DisableScreenFlag    ;disable screen and sprite 0 check
2997
             ldan ++$00
2998
             sta Sprite0HitDetectFlag
2999
             ldan ++Silence             ;silence music
3000
             sta EventMusicQueue
3001
            if INFINITELIVES
3002
             xor a
3003
            else
3004
             deci NumberofLives        ;take one life from player
3005
            endif
3006
             bpl StillInGame          ;if player still has lives, branch
3007
             ldan ++$00
3008
             sta OperMode_Task        ;initialize mode task,
3009
             ldan ++GameOverModeValue   ;switch to game over mode
3010
             sta OperMode             ;and leave
3011
             rts
3012
StillInGame: lda WorldNumber          ;multiply world number by 2 and use
3013
             asl                      ;as offset
3014
             tax
3015
             lda LevelNumber          ;if in area -3 or -4, increment
3016
             andn ++$02                 ;offset by one byte, otherwise
3017
             beq GetHalfway           ;leave offset alone
3018
             inx
3019
GetHalfway:  ldyx HalfwayPageNybbles,x ;get halfway page number with offset
3020
             lda LevelNumber          ;check area number's LSB
3021
             lsr
3022
             tya                      ;if in area -2 or -4, use lower nybble
3023
             bcs MaskHPNyb
3024
             lsr                      ;move higher nybble to lower if area
3025
             lsr                      ;number is -1 or -3
3026
             lsr
3027
             lsr
3028
MaskHPNyb:   andn ++%00001111           ;mask out all but lower nybble
3029
             cmpi ScreenLeft_PageLoc
3030
              cmpcy
3031
             beq SetHalfway           ;left side of screen must be at the halfway page,
3032
             bcc SetHalfway           ;otherwise player must start at the
3033
             ldan ++$00                 ;beginning of the level
3034
SetHalfway:  sta HalfwayPage          ;store as halfway page for player
3035
             jsr TransposePlayers     ;switch players around if 2-player game
3036
             jmp ContinueGame         ;continue the game
3037
 
3038
;-------------------------------------------------------------------------------------
3039
 
3040
GameOverMode:
3041
      lda OperMode_Task
3042
      jsr JumpEngine
3043
 
3044
      .dw SetupGameOver
3045
      .dw ScreenRoutines
3046
      .dw RunGameOver
3047
 
3048
;-------------------------------------------------------------------------------------
3049
 
3050
SetupGameOver:
3051
      ldan ++$00                  ;reset screen routine task control for title screen, game,
3052
      sta ScreenRoutineTask     ;and game over modes
3053
      sta Sprite0HitDetectFlag  ;disable sprite 0 check
3054
      ldan ++GameOverMusic
3055
      sta EventMusicQueue       ;put game over music in secondary queue
3056
      inci DisableScreenFlag     ;disable screen output
3057
      inci OperMode_Task         ;set secondary mode to 1
3058
      rts
3059
 
3060
;-------------------------------------------------------------------------------------
3061
 
3062
RunGameOver:
3063
      ldan ++$00              ;reenable screen
3064
      sta DisableScreenFlag
3065
      lda SavedJoypad1Bits  ;check controller for start pressed
3066
      andn ++Start_Button
3067
      bne TerminateGame
3068
      lda ScreenTimer       ;if not pressed, wait for
3069
         checka
3070
      bne GameIsOn          ;screen timer to expire
3071
TerminateGame:
3072
      ldan ++Silence          ;silence music
3073
      sta EventMusicQueue
3074
      jsr TransposePlayers  ;check if other player can keep
3075
      bcc ContinueGame      ;going, and do so if possible
3076
      lda WorldNumber       ;otherwise put world number of current
3077
      sta ContinueWorld     ;player into secret continue function variable
3078
      ldan ++$00
3079
      asl                   ;residual ASL instruction
3080
      sta OperMode_Task     ;reset all modes to title screen and
3081
      sta ScreenTimer       ;leave
3082
      sta OperMode
3083
      rts
3084
 
3085
ContinueGame:
3086
           jsr LoadAreaPointer       ;update level pointer with
3087
           ldan ++$01                  ;actual world and area numbers, then
3088
           sta PlayerSize            ;reset player's size, status, and
3089
           inci FetchNewGameTimerFlag ;set game timer flag to reload
3090
           ldan ++$00                  ;game timer from header
3091
           sta TimerControl          ;also set flag for timers to count again
3092
           sta PlayerStatus
3093
           sta GameEngineSubroutine  ;reset task for game core
3094
           sta OperMode_Task         ;set modes and leave
3095
           ldan ++$01                  ;if in game over mode, switch back to
3096
           sta OperMode              ;game mode, because game is still on
3097
GameIsOn:  rts
3098
 
3099
TransposePlayers:
3100
           sec                       ;set carry flag by default to end game
3101
           lda NumberOfPlayers       ;if only a 1 player game, leave
3102
         checka
3103
           beq ExTrans
3104
           lda OffScr_NumberofLives  ;does offscreen player have any lives left?
3105
         checka
3106
           bmi ExTrans               ;branch if not
3107
           lda CurrentPlayer         ;invert bit to update
3108
           eorn ++%00000001            ;which player is on the screen
3109
           sta CurrentPlayer
3110
           ldxn ++$06
3111
TransLoop: ldax OnscreenPlayerInfo,x    ;transpose the information
3112
           pha                         ;of the onscreen player
3113
           ldax OffscreenPlayerInfo,x   ;with that of the offscreen player
3114
           stax OnscreenPlayerInfo,x
3115
           pla
3116
           stax OffscreenPlayerInfo,x
3117
           dex
3118
           bpl TransLoop
3119
           clc            ;clear carry flag to get game going
3120
ExTrans:   rts
3121
 
3122
;-------------------------------------------------------------------------------------
3123
 
3124
DoNothing1:
3125
      ldan ++$ff       ;this is residual code, this value is
3126
      sta UnusedVariable;$06c9      ;not used anywhere in the program
3127
DoNothing2:
3128
      rts
3129
 
3130
;-------------------------------------------------------------------------------------
3131
 
3132
AreaParserTaskHandler:
3133
        ;ret
3134
              ldy AreaParserTaskNum     ;check number of tasks here
3135
         checky
3136
              bne DoAPTasks             ;if already set, go ahead
3137
              ldyn ++$08 ;  
3138
              sty AreaParserTaskNum     ;otherwise, set eight by default
3139
DoAPTasks:    dey
3140
              tya
3141
              jsr AreaParserTasks
3142
              deci AreaParserTaskNum     ;if all tasks not complete do not
3143
             if Z80OPT4==0
3144
              bne SkipATRender          ;render attribute table yet
3145
              jsr RenderAttributeTables ;  RenderAreaGraphics #1 (.. 4-)?
3146
SkipATRender:
3147
             endif
3148
              rts
3149
 
3150
AreaParserTasks:
3151
      jsr JumpEngine
3152
;  7..0?
3153
      .dw IncrementColumnPos ;0
3154
      .dw RenderAreaGraphics ;1
3155
      .dw RenderAreaGraphics ;2
3156
      .dw AreaParserCore ;3
3157
      .dw IncrementColumnPos ;4
3158
      .dw RenderAreaGraphics ;5
3159
      .dw RenderAreaGraphics ;6
3160
      .dw AreaParserCore ;7
3161
 
3162
;-------------------------------------------------------------------------------------
3163
 
3164
IncrementColumnPos:
3165
           inci CurrentColumnPos     ;increment column where we're at
3166
           lda CurrentColumnPos
3167
           andn ++%00001111           ;mask out higher nybble
3168
           bne NoColWrap
3169
           sta CurrentColumnPos     ;if no bits left set, wrap back to zero (0-f)
3170
           inci CurrentPageLoc       ;and increment page number where we're at
3171
NoColWrap: inci BlockBufferColumnPos ;increment column offset where we're at
3172
           lda BlockBufferColumnPos
3173
           andn ++%00011111           ;mask out all but 5 LSB (0-1f)
3174
           sta BlockBufferColumnPos ;and save
3175
           rts
3176
 
3177
;-------------------------------------------------------------------------------------
3178
;$00 - used as counter, store for low nybble for background, ceiling byte for terrain
3179
;$01 - used to store floor byte for terrain
3180
;$07 - used to store terrain metatile
3181
;$06-$07 - used to store block buffer address
3182
 
3183
BSceneDataOffsets:
3184
      .db $00, $30, $60
3185
 
3186
BackSceneryData: ;metatiles???
3187
   .db $93, $00, $00, $11, $12, $12, $13, $00 ;clouds (palette 2???)
3188
   .db $00, $51, $52, $53, $00, $00, $00, $00
3189
   .db $00, $00, $01, $02, $02, $03, $00, $00
3190
   .db $00, $00, $00, $00, $91, $92, $93, $00
3191
   .db $00, $00, $00, $51, $52, $53, $41, $42
3192
   .db $43, $00, $00, $00, $00, $00, $91, $92
3193
 
3194
   .db $97, $87, $88, $89, $99, $00, $00, $00 ;mountains and bushes
3195
   .db $11, $12, $13, $a4, $a5, $a5, $a5, $a6
3196
   .db $97, $98, $99, $01, $02, $03, $00, $a4
3197
   .db $a5, $a6, $00, $11, $12, $12, $12, $13
3198
   .db $00, $00, $00, $00, $01, $02, $02, $03
3199
   .db $00, $a4, $a5, $a5, $a6, $00, $00, $00
3200
 
3201
   .db $11, $12, $12, $13, $00, $00, $00, $00 ;trees and fences
3202
   .db $00, $00, $00, $9c, $00, $8b, $aa, $aa
3203
   .db $aa, $aa, $11, $12, $13, $8b, $00, $9c
3204
   .db $9c, $00, $00, $01, $02, $03, $11, $12
3205
   .db $12, $13, $00, $00, $00, $00, $aa, $aa
3206
   .db $9c, $aa, $00, $8b, $00, $01, $02, $03
3207
 
3208
BackSceneryMetatiles:
3209
   .db $80, $83, $00 ;cloud left
3210
   .db $81, $84, $00 ;cloud middle
3211
   .db $82, $85, $00 ;cloud right
3212
   .db $02, $00, $00 ;bush left
3213
   .db $03, $00, $00 ;bush middle
3214
   .db $04, $00, $00 ;bush right
3215
   .db $00, $05, $06 ;mountain left
3216
   .db $07, $06, $0a ;mountain middle
3217
   .db $00, $08, $09 ;mountain right
3218
   .db $4d, $00, $00 ;fence
3219
   .db $0d, $0f, $4e ;tall tree
3220
   .db $0e, $4e, $4e ;short tree
3221
 
3222
FSceneDataOffsets:
3223
      .db $00, $0d, $1a
3224
 
3225
ForeSceneryData:
3226
   .db $86, $87, $87, $87, $87, $87, $87   ;in water
3227
   .db $87, $87, $87, $87, $69, $69
3228
 
3229
   .db $00, $00, $00, $00, $00, $45, $47   ;wall
3230
   .db $47, $47, $47, $47, $00, $00
3231
 
3232
   .db $00, $00, $00, $00, $00, $00, $00   ;over water
3233
   .db $00, $00, $00, $00, $86, $87
3234
 
3235
TerrainMetatiles:
3236
      .db $69, $54, $52, $62
3237
 
3238
TerrainRenderBits:
3239
      .db %00000000, %00000000 ;no ceiling or floor
3240
      .db %00000000, %00011000 ;no ceiling, floor 2
3241
      .db %00000001, %00011000 ;ceiling 1, floor 2
3242
      .db %00000111, %00011000 ;ceiling 3, floor 2
3243
      .db %00001111, %00011000 ;ceiling 4, floor 2
3244
      .db %11111111, %00011000 ;ceiling 8, floor 2
3245
      .db %00000001, %00011111 ;ceiling 1, floor 5
3246
      .db %00000111, %00011111 ;ceiling 3, floor 5
3247
      .db %00001111, %00011111 ;ceiling 4, floor 5
3248
      .db %10000001, %00011111 ;ceiling 1, floor 6
3249
      .db %00000001, %00000000 ;ceiling 1, no floor
3250
      .db %10001111, %00011111 ;ceiling 4, floor 6
3251
      .db %11110001, %00011111 ;ceiling 1, floor 9
3252
      .db %11111001, %00011000 ;ceiling 1, middle 5, floor 2
3253
      .db %11110001, %00011000 ;ceiling 1, middle 4, floor 2
3254
      .db %11111111, %00011111 ;completely solid top to bottom
3255
 
3256
AreaParserCore:
3257
      lda BackloadingFlag       ;check to see if we are starting right of start
3258
         checka
3259
      beq RenderSceneryTerrain  ;if not, go ahead and render background, foreground and terrain
3260
      jsr ProcessAreaData       ;otherwise skip ahead and load level data
3261
 
3262
RenderSceneryTerrain:
3263
          ldxn ++$0c
3264
          ldan ++$00
3265
ClrMTBuf: stax MetatileBuffer,x       ;clear out metatile buffer
3266
          dex
3267
          bpl ClrMTBuf
3268
        ;jr $
3269
          ldy BackgroundScenery      ;do we need to render the background scenery?
3270
         checky
3271
          beq RendFore               ;if not, skip to check the foreground
3272
          lda CurrentPageLoc         ;otherwise check for every third page
3273
ThirdP:   cmpn ++$03
3274
          bmi RendBack               ;if less than three we're there
3275
          secsub
3276
          sbcn ++$03                   ;if 3 or more, subtract 3 and 
3277
          bpl ThirdP                 ;do an unconditional branch
3278
RendBack: asl                        ;move results to higher nybble
3279
          asl
3280
          asl
3281
          asl
3282
          adcy BSceneDataOffsets-1,y  ;add to it offset loaded from here
3283
          adci CurrentColumnPos       ;add to the result our current column position
3284
          tax
3285
          ldax BackSceneryData,x      ;load data from sum of offsets
3286
         checka
3287
          beq RendFore               ;if zero, no scenery for that part
3288
         pha
3289
          andn ++$0f                   ;save to stack and clear high nybble
3290
          secsub
3291
          sbcn ++$01                   ;subtract one (because low nybble is $01-$0c)
3292
          sta SCRATCHPAD+$00                    ;save low nybble
3293
          asl                        ;multiply by three (shift to left and add result to old one)
3294
          adci SCRATCHPAD+$00                    ;note that since d7 was nulled, the carry flag is always clear
3295
          tax                        ;save as offset for background scenery metatile data
3296
         pla                        ;get high nybble from stack, move low
3297
          lsr
3298
          lsr
3299
          lsr
3300
          lsr
3301
          tay                        ;use as second offset (used to determine height)
3302
          ldan ++$03                   ;use previously saved memory location for counter
3303
          sta SCRATCHPAD+$00
3304
SceLoop1: ldax BackSceneryMetatiles,x ;load metatile data from offset of (lsb - 1) * 3
3305
          stay MetatileBuffer,y       ;store into buffer from offset of (msb / 16)
3306
          inx
3307
          iny
3308
          cpyn ++$0b                   ;if at this location, leave loop
3309
          beq RendFore
3310
          deci SCRATCHPAD+$00                    ;decrement until counter expires, barring exception
3311
          bne SceLoop1
3312
RendFore: ldx ForegroundScenery      ;check for foreground data needed or not
3313
         checkx
3314
          beq RendTerr               ;if not, skip this part
3315
          ldyx FSceneDataOffsets-1,x  ;load offset from location offset by header value, then
3316
          ldxn ++$00                   ;reinit X
3317
SceLoop2: lday ForeSceneryData,y      ;load data until counter expires
3318
         checka
3319
          beq NoFore                 ;do not store if zero found
3320
          stax MetatileBuffer,x
3321
NoFore:   iny
3322
          inx
3323
          cpxn ++$0d                   ;store up to end of metatile buffer
3324
          bne SceLoop2
3325
RendTerr: ldy AreaType               ;check world type for water level
3326
         checky
3327
          bne TerMTile               ;if not water level, skip this part
3328
          lda WorldNumber            ;check world number, if not world number eight
3329
          cmpn ++World8                ;then skip this part
3330
          bne TerMTile
3331
          ldan ++$62                   ;if set as water level and world number eight,
3332
          jmp StoreMT                ;use castle wall metatile as terrain type
3333
TerMTile: lday TerrainMetatiles,y     ;otherwise get appropriate metatile for area type
3334
          ldy CloudTypeOverride      ;check for cloud type override
3335
         checky
3336
          beq StoreMT                ;if not set, keep value otherwise
3337
          ldan ++$88                   ;use cloud block terrain
3338
StoreMT:  sta SCRATCHPAD+$07                    ;store value here
3339
          ldxn ++$00                   ;initialize X, use as metatile buffer offset
3340
          lda TerrainControl         ;use yet another value from the header
3341
          asl                        ;multiply by 2 and use as yet another offset
3342
          tay
3343
TerrLoop: lday TerrainRenderBits,y    ;get one of the terrain rendering bit data
3344
          sta SCRATCHPAD+$00
3345
          iny                        ;increment Y and use as offset next time around
3346
          sty SCRATCHPAD+$01
3347
          lda CloudTypeOverride      ;skip if value here is zero
3348
         checka
3349
          beq NoCloud2
3350
          cpxn ++$00                   ;otherwise, check if we're doing the ceiling byte
3351
          beq NoCloud2
3352
          lda SCRATCHPAD+$00                    ;if not, mask out all but d3
3353
          andn ++%00001000
3354
          sta SCRATCHPAD+$00
3355
NoCloud2: ldyn ++$00                   ;start at beginning of bitmasks
3356
TerrBChk: lday Bitmasks,y             ;load bitmask, then perform AND on contents of first byte
3357
          biti SCRATCHPAD+$00
3358
          beq NextTBit               ;if not set, skip this part (do not write terrain to buffer)
3359
          lda SCRATCHPAD+$07
3360
          stax MetatileBuffer,x       ;load terrain type metatile number and store into buffer here
3361
NextTBit: inx                        ;continue until end of buffer
3362
          cpxn ++$0d
3363
          beq RendBBuf               ;if we're at the end, break out of this loop
3364
          lda AreaType               ;check world type for underground area
3365
          cmpn ++$02
3366
          bne EndUChk                ;if not underground, skip this part
3367
          cpxn ++$0b
3368
          bne EndUChk                ;if we're at the bottom of the screen, override
3369
          ldan ++$54                   ;old terrain type with ground level terrain type
3370
          sta SCRATCHPAD+$07
3371
EndUChk:  iny                        ;increment bitmasks offset in Y
3372
          cpyn ++$08
3373
          bne TerrBChk               ;if not all bits checked, loop back    
3374
          ldy SCRATCHPAD+$01
3375
         checky
3376
          bne TerrLoop               ;unconditional branch, use Y to load next byte
3377
RendBBuf:
3378
 
3379
          jsr ProcessAreaData        ;do the area data loading routine now
3380
 
3381
        if Z80OPT
3382
        ld a,(BlockBufferColumnPos)
3383
        ld hl,Block_Buffer_1
3384
        bit 4,a
3385
        jr z,$+5
3386
         ld hl,Block_Buffer_2
3387
        and 0x0f
3388
        ld c,a
3389
        add hl,bc
3390
        ld (SCRATCHPAD+$06),hl
3391
        else
3392
          lda BlockBufferColumnPos
3393
          jsr GetBlockBufferAddr     ;get block buffer address from where we're at
3394
        endif
3395
 
3396
          ldxn ++$00
3397
          ldyn ++$00                   ;init index regs and start at beginning of smaller buffer
3398
ChkMTLow: sty SCRATCHPAD+$00
3399
          ldax MetatileBuffer,x       ;load stored metatile number
3400
          andn ++%11000000             ;mask out all but 2 MSB
3401
          asl
3402
          rol                        ;make %xx000000 into %000000xx
3403
          rol
3404
          tay                        ;use as offset in Y
3405
          ldax MetatileBuffer,x       ;reload original unmasked value here
3406
          cmpy BlockBuffLowBounds,y   ;check for certain values depending on bits set
3407
              cmpcy
3408
          bcs StrBlock               ;if equal or greater, branch
3409
          ldan ++$00                   ;if less, init value before storing
3410
StrBlock: ldy SCRATCHPAD+$00                    ;get offset for block buffer
3411
          stayindirect (SCRATCHPAD+$06),y                ;store value into block buffer ;$06$07 = Block_Buffer_1(2)+BlockBufferColumnPos
3412
           ;jr $
3413
          tya
3414
          clc                        ;add 16 (move down one row) to offset
3415
          adcn ++$10
3416
          tay
3417
          inx                        ;increment column value
3418
          cpxn ++$0d ;13   16 
3419
              cmpcy
3420
          bcc ChkMTLow               ;continue until we pass last row, then leave
3421
          rts
3422
 
3423
;numbers lower than these with the same attribute bits
3424
;will not be stored in the block buffer
3425
BlockBuffLowBounds:
3426
      .db $10, $51, $88, $c0
3427
 
3428
;-------------------------------------------------------------------------------------
3429
;$00 - used to store area object identifier
3430
;$07 - used as adder to find proper area object code
3431
 
3432
;TODO 
3433
 
3434
ProcessAreaData:
3435
        if Z80OPT3
3436
            ld c,++$02                 ;start at the end of area object buffer
3437
ProcADLoop:
3438
         if Z80OPT3ly
3439
            ld ly,c;stx ObjectOffset ;  DecodeAreaData
3440
         else
3441
            stx ObjectOffset ;  DecodeAreaData
3442
         endif
3443
            xor a                ;reset flag
3444
            ld (BehindAreaParserFlag),a
3445
           ld hl,AreaDataOffset
3446
           ld e,(hl)      ;get offset of area data pointer
3447
            ld hl,AreaObjectLength
3448
            add hl,bc
3449
            bit 7,(hl)   ;check area object buffer flag
3450
            jp z,RdyDecode_AreaObjectLength_positive            ;if buffer not negative, branch, otherwise
3451
           ld ix,(AreaData)
3452
           add ix,de ;TODO hl?     DecodeAreaData
3453
            ld a,(ix)      ;get first byte of area object
3454
            cp ++$fd                 ;if end-of-area, skip all this crap
3455
            jp z,RdyDecode_endofarea
3456
           bit 7,(ix+1)      ;get second byte of area object
3457
            jr z,Chk1Row13 ;check for page select bit (d7), branch if not set
3458
            ld hl,AreaObjectPageSel
3459
            inc (hl)    ;check page select
3460
            dec (hl)
3461
            jr nz,Chk1Row13
3462
            inc (hl)   ;if not already set, set it now
3463
            ld hl,AreaObjectPageLoc
3464
            inc (hl)   ;and increment page location
3465
Chk1Row13:  
3466
           ;ld a,(ix)      ;reread first byte of level object
3467
            and ++$0f                 ;mask out high nybble
3468
            cp ++$0d                 ;row 13?
3469
            jr nz,Chk1Row14
3470
           bit 6,(ix+1) ;if so, reread second byte of level object
3471
            jr nz,CheckRear ;check for d6 set (if not, object is page control)
3472
            ld a,(AreaObjectPageSel)    ;if page select is set, do not reread
3473
            or a
3474
            jr nz,CheckRear
3475
           ld a,(ix+1)                     ;if d6 not set, reread second byte
3476
            and ++%00011111           ;mask out all but 5 LSB and store in page control
3477
            ld (AreaObjectPageLoc),a
3478
            ld hl,AreaObjectPageSel
3479
            inc (hl)    ;increment page select
3480
            jmp NextAObj
3481
Chk1Row14:  cp ++$0e                 ;row 14?
3482
            jr nz,CheckRear
3483
            ld a,(BackloadingFlag)      ;check flag for saved page number and branch if set
3484
            or a
3485
            jr nz,RdyDecode            ;to render the object (otherwise bg might not look right)
3486
CheckRear:  ld a,(AreaObjectPageLoc)    ;check to see if current page of level object is
3487
            ld hl,CurrentPageLoc
3488
            cp (hl)     ;behind current page of renderer
3489
            jr c,SetBehind            ;if so branch
3490
RdyDecode:  
3491
            ;push ix
3492
          ldayindirect (AreaData),y           ;get first byte of level object again
3493
            call DecodeAreaData       ;do sub and do not turn on flag       ;y !!!
3494
            ;pop ix
3495
            jp ChkLength
3496
RdyDecode_AreaObjectLength_positive:
3497
          ldyx AreaObjOffsetBuffer,x  ;if not, get offset from buffer
3498
            ;push ix
3499
          ldayindirect (AreaData),y           ;get first byte of level object again
3500
            call DecodeAreaData       ;do sub and do not turn on flag       ;y !!!
3501
            ;pop ix
3502
            jp ChkLength
3503
SetBehind:  
3504
            ld hl,BehindAreaParserFlag
3505
            inc (hl) ;turn on flag if object is behind renderer
3506
NextAObj:  
3507
           ld hl,AreaDataOffset
3508
           inc (hl)
3509
           inc (hl) ;       
3510
           xor a
3511
           ld (AreaObjectPageSel),a
3512
 
3513
RdyDecode_endofarea:
3514
ChkLength:  
3515
         if Z80OPT3ly
3516
            ;ld hl,ObjectOffset
3517
            ld c,ly;ld c,(hl)       ;get buffer offset
3518
         else
3519
            ld hl,ObjectOffset
3520
            ld c,(hl)       ;get buffer offset
3521
         endif
3522
            ld hl,AreaObjectLength
3523
            add hl,bc
3524
            ld a,(hl) ;check object length for anything stored here
3525
            rla
3526
            jr c,ProcLoopb            ;if not, branch to handle loopback
3527
            dec (hl)   ;otherwise decrement length or get rid of it
3528
ProcLoopb:  dec c                      ;decrement buffer offset
3529
            jp p,ProcADLoop           ;and loopback unless exceeded buffer
3530
            ld a,(BehindAreaParserFlag) ;check for flag set if objects were behind renderer
3531
            or a
3532
            jp nz,ProcessAreaData      ;branch if true to load more level data, otherwise
3533
            ld a,(BackloadingFlag)      ;check for flag set if starting right of page $00
3534
            or a
3535
            jp nz,ProcessAreaData      ;branch if true to load more level data, otherwise leave
3536
            ret
3537
 
3538
        else ;~Z80
3539
 
3540
            ldxn ++$02                 ;start at the end of area object buffer
3541
ProcADLoop: stx ObjectOffset
3542
            ldan ++$00                 ;reset flag
3543
            sta BehindAreaParserFlag
3544
            ldy AreaDataOffset       ;get offset of area data pointer
3545
            ldayindirect (AreaData),y         ;get first byte of area object
3546
            cmpn ++$fd                 ;if end-of-area, skip all this crap
3547
            beq RdyDecode
3548
            ldax AreaObjectLength,x   ;check area object buffer flag
3549
         checka
3550
            bpl RdyDecode            ;if buffer not negative, branch, otherwise
3551
            iny
3552
            ldayindirect (AreaData),y         ;get second byte of area object
3553
            asl                      ;check for page select bit (d7), branch if not set
3554
            bcc Chk1Row13
3555
            lda AreaObjectPageSel    ;check page select
3556
         checka
3557
            bne Chk1Row13
3558
            inci AreaObjectPageSel    ;if not already set, set it now
3559
            inci AreaObjectPageLoc    ;and increment page location
3560
Chk1Row13:  dey
3561
            ldayindirect (AreaData),y         ;reread first byte of level object
3562
            andn ++$0f                 ;mask out high nybble
3563
            cmpn ++$0d                 ;row 13?
3564
            bne Chk1Row14
3565
            iny                      ;if so, reread second byte of level object
3566
            ldayindirect (AreaData),y
3567
            dey                      ;decrement to get ready to read first byte
3568
            andn ++%01000000           ;check for d6 set (if not, object is page control)
3569
            bne CheckRear
3570
            lda AreaObjectPageSel    ;if page select is set, do not reread
3571
           checka
3572
            bne CheckRear
3573
            iny                      ;if d6 not set, reread second byte
3574
            ldayindirect (AreaData),y
3575
            andn ++%00011111           ;mask out all but 5 LSB and store in page control
3576
            sta AreaObjectPageLoc
3577
            inci AreaObjectPageSel    ;increment page select
3578
            jmp NextAObj
3579
Chk1Row14:  cmpn ++$0e                 ;row 14?
3580
            bne CheckRear
3581
            lda BackloadingFlag      ;check flag for saved page number and branch if set
3582
         checka
3583
            bne RdyDecode            ;to render the object (otherwise bg might not look right)
3584
CheckRear:  lda AreaObjectPageLoc    ;check to see if current page of level object is
3585
            cmpi CurrentPageLoc       ;behind current page of renderer
3586
              cmpcy
3587
            bcc SetBehind            ;if so branch
3588
RdyDecode:  jsr DecodeAreaData       ;do sub and do not turn on flag
3589
            jmp ChkLength
3590
SetBehind:  inci BehindAreaParserFlag ;turn on flag if object is behind renderer
3591
NextAObj:  
3592
            jsr IncAreaObjOffset     ;increment buffer offset and move on
3593
ChkLength:  ldx ObjectOffset         ;get buffer offset
3594
            ldax AreaObjectLength,x   ;check object length for anything stored here
3595
         checka
3596
            bmi ProcLoopb            ;if not, branch to handle loopback
3597
            decx AreaObjectLength,x   ;otherwise decrement length or get rid of it
3598
ProcLoopb:  dex                      ;decrement buffer offset
3599
            bpl ProcADLoop           ;and loopback unless exceeded buffer
3600
            lda BehindAreaParserFlag ;check for flag set if objects were behind renderer
3601
         checka
3602
            bne ProcessAreaData      ;branch if true to load more level data, otherwise
3603
            lda BackloadingFlag      ;check for flag set if starting right of page $00
3604
         checka
3605
            bne ProcessAreaData      ;branch if true to load more level data, otherwise leave
3606
EndAParse:  rts
3607
 
3608
IncAreaObjOffset:
3609
      inci AreaDataOffset    ;increment offset of level pointer
3610
      inci AreaDataOffset
3611
      ldan ++$00              ;reset page select
3612
      sta AreaObjectPageSel
3613
      rts
3614
        endif
3615
 
3616
;x !
3617
;y !
3618
DecodeAreaData:
3619
        if Z80OPT3
3620
        if 0
3621
                ld hl,AreaObjectLength
3622
                add hl,bc
3623
                ld a,(hl)    ;check current buffer flag
3624
                or a
3625
                bmi Chk1stB
3626
                ldyx AreaObjOffsetBuffer,x  ;if not, get offset from buffer
3627
Chk1stB:
3628
                ldayindirect (AreaData),y           ;get first byte of level object again
3629
                cp ++$fd
3630
                ret z              ;if end of level, leave this routine
3631
        endif
3632
          and ++$0f                   ;otherwise, mask out low nybble
3633
         sub 15;cp $0f                   ;row 15?
3634
          jr z,ChkRow15ok               ;if so, keep the offset of 16
3635
         inc a;cp $0e                   ;row 14?
3636
          jr nz,ChkRow13
3637
ChkRow14ok
3638
          ld hy,a;0
3639
        ld a,++$2e                   ;and load A with another value
3640
        jp NormObj                ;unconditional branch
3641
ChkRow15ok
3642
        ld hy,16
3643
        jp SpecObj
3644
ChkRow12ok
3645
        ld hy,8
3646
        jp SpecObj
3647
ChkRow13: inc a;cp $0d                   ;row 13?
3648
          jr nz,ChkSRows
3649
ChkRow13ok
3650
        ld hy,34;sta SCRATCHPAD+$07  ;if so, load offset with 34
3651
        iny                        ;get next byte
3652
        ldayindirect (AreaData),y
3653
        bit 6,a;and ++%01000000             ;mask out all but d6 (page control obj bit)
3654
        ret z;jr z,LeavePar               ;if d6 clear, branch to leave (we handled this earlier)
3655
        and ++%01111111             ;mask out d7
3656
        cp ++$4b                   ;check for loop command in low nybble
3657
        jr nz,Mask2MSB               ;(plus d6 set for object other than page control)
3658
        inci LoopCommand            ;if loop command, set loop command flag
3659
Mask2MSB
3660
        and ++%00111111             ;mask out d7 and d6
3661
        jp NormObj                ;and jump
3662
ChkSRows:
3663
         inc a;cp $0c                   ;row 12?
3664
          jr z,ChkRow12ok               ;if so, keep the offset value of 8
3665
          ld hy,0                   ;otherwise nullify value by default
3666
 
3667
          iny                        ;if not, get second byte of level object
3668
          ldayindirect (AreaData),y
3669
          and ++%01110000             ;mask out all but d6-d4
3670
          jr nz,LrgObj                 ;if any bits set, branch to handle large object
3671
          ld hy,22;sta SCRATCHPAD+$07    ;otherwise set offset of 22 for small object
3672
          ldayindirect (AreaData),y           ;reload second byte of level object
3673
          and ++%00001111             ;mask out higher nybble and jump
3674
          jmp NormObj
3675
LrgObj:    sta SCRATCHPAD+$00                    ;store value here (branch for large objects)
3676
          cp ++$70                   ;check for vertical pipe object
3677
          jr nz,NotWPipe
3678
          ldayindirect (AreaData),y           ;if not, reload second byte
3679
          bit 3,a;and ++%00001000             ;mask out all but d3 (usage control bit)
3680
          jr z,NotWPipe               ;if d3 clear, branch to get original value
3681
          ldan ++$00                   ;otherwise, nullify value for warp pipe
3682
           sta SCRATCHPAD+$00
3683
NotWPipe:  lda SCRATCHPAD+$00                    ;get value and jump ahead
3684
          jmp MoveAOId
3685
SpecObj:  iny                        ;branch here for rows 12-15
3686
       if Z80OPT3hy
3687
       else
3688
        ld a,hy
3689
        ld (SCRATCHPAD+$07),a
3690
       endif
3691
          ldayindirect (AreaData),y
3692
          andn ++%01110000             ;get next byte and mask out all but d6-d4
3693
MoveAOId: lsr                        ;move d6-d4 to lower nybble
3694
          lsr
3695
          lsr
3696
          lsr
3697
NormObj:   sta SCRATCHPAD+$00                    ;store value here (branch for small objects and rows 13 and 14)
3698
       if Z80OPT3hy
3699
       else
3700
        ld a,hy
3701
        ld (SCRATCHPAD+$07),a
3702
       endif
3703
          ldax AreaObjectLength,x     ;is there something stored here already?
3704
          or a
3705
          jp p,RunAObj                ;if so, branch to do its particular sub
3706
          lda AreaObjectPageLoc      ;otherwise check to see if the object we've loaded is on the
3707
          cmpi CurrentPageLoc         ;same page as the renderer, and if so, branch
3708
          beq InitRear
3709
          ldy AreaDataOffset         ;if not, get old offset of level pointer
3710
          ldayindirect (AreaData),y           ;and reload first byte
3711
          andn ++%00001111
3712
          cmpn ++$0e                   ;row 14?
3713
          ret nz
3714
          lda BackloadingFlag        ;if so, check backloading flag
3715
         checka
3716
          bne StrAObj                ;if set, branch to render object, else leave
3717
          ret
3718
InitRear: lda BackloadingFlag        ;check backloading flag to see if it's been initialized
3719
          or a
3720
          jr z,BackColC               ;branch to column-wise check
3721
          xor a;ldan ++$00                   ;if not, initialize both backloading and 
3722
          sta BackloadingFlag        ;behind-renderer flags and leave
3723
          sta BehindAreaParserFlag
3724
         if Z80OPT3ly
3725
          ld ly,a;0;sta ObjectOffset
3726
         else
3727
          sta ObjectOffset
3728
         endif
3729
LoopCmdE: ret
3730
BackColC: ldy AreaDataOffset         ;get first byte again
3731
          ldayindirect (AreaData),y
3732
          and ++%11110000             ;mask out low nybble and move high to low
3733
          rrca
3734
          rrca
3735
          rrca
3736
          rrca
3737
          cmpi CurrentColumnPos       ;is this where we're at?
3738
          ret nz        ;if not, branch to leave
3739
StrAObj:  
3740
        ld hl,AreaDataOffset
3741
          ld a,(hl)        ;if so, load area obj offset and store in buffer
3742
        inc (hl)
3743
        inc (hl)
3744
          stax AreaObjOffsetBuffer,x
3745
        xor a
3746
        ld (AreaObjectPageSel),a
3747
RunAObj:
3748
;CY=0
3749
          ld a,(SCRATCHPAD+$00)                    ;get stored value and add offset to it
3750
       if Z80OPT3hy
3751
          add a,hy ;adci SCRATCHPAD+$07
3752
       else
3753
          adci SCRATCHPAD+$07
3754
       endif
3755
          call JumpEngine
3756
 
3757
        else ;~Z80
3758
 
3759
          ldax AreaObjectLength,x     ;check current buffer flag
3760
         checka
3761
          bmi Chk1stB
3762
          ldyx AreaObjOffsetBuffer,x  ;if not, get offset from buffer
3763
Chk1stB:  ldxn ++$10                   ;load offset of 16 for special row 15
3764
          ldayindirect (AreaData),y           ;get first byte of level object again
3765
          cmpn ++$fd
3766
          beq EndAParse              ;if end of level, leave this routine (TODO ret z)
3767
          andn ++$0f                   ;otherwise, mask out low nybble
3768
          cmpn ++$0f                   ;row 15?
3769
          beq ChkRow14               ;if so, keep the offset of 16
3770
          ldxn ++$08                   ;otherwise load offset of 8 for special row 12
3771
          cmpn ++$0c                   ;row 12?
3772
          beq ChkRow14               ;if so, keep the offset value of 8
3773
          ldxn ++$00                   ;otherwise nullify value by default
3774
ChkRow14:
3775
         stx SCRATCHPAD+$07                    ;store whatever value we just loaded here
3776
          ldx ObjectOffset           ;get object offset again
3777
          cmpn ++$0e                   ;row 14?
3778
          bne ChkRow13
3779
          ldan ++$00                   ;if so, load offset with $00
3780
          sta SCRATCHPAD+$07
3781
          ldan ++$2e                   ;and load A with another value
3782
         checka
3783
          bne NormObj                ;unconditional branch
3784
ChkRow13: cmpn ++$0d                   ;row 13?
3785
          bne ChkSRows
3786
          ldan ++$22                   ;if so, load offset with 34
3787
          sta SCRATCHPAD+$07
3788
          iny                        ;get next byte
3789
          ldayindirect (AreaData),y
3790
          andn ++%01000000             ;mask out all but d6 (page control obj bit)
3791
          beq LeavePar               ;if d6 clear, branch to leave (we handled this earlier)
3792
          ldayindirect (AreaData),y           ;otherwise, get byte again
3793
          andn ++%01111111             ;mask out d7
3794
          cmpn ++$4b                   ;check for loop command in low nybble
3795
          bne Mask2MSB               ;(plus d6 set for object other than page control)
3796
          inci LoopCommand            ;if loop command, set loop command flag
3797
Mask2MSB: andn ++%00111111             ;mask out d7 and d6
3798
          jmp NormObj                ;and jump
3799
ChkSRows: cmpn ++$0c                   ;row 12-15?
3800
              cmpcy
3801
          bcs SpecObj
3802
 
3803
          iny                        ;if not, get second byte of level object
3804
          ldayindirect (AreaData),y
3805
          andn ++%01110000             ;mask out all but d6-d4
3806
          bne LrgObj                 ;if any bits set, branch to handle large object
3807
          ldan ++$16
3808
          sta SCRATCHPAD+$07                    ;otherwise set offset of 24 for small object
3809
          ldayindirect (AreaData),y           ;reload second byte of level object
3810
          andn ++%00001111             ;mask out higher nybble and jump
3811
          jmp NormObj
3812
LrgObj:   sta SCRATCHPAD+$00                    ;store value here (branch for large objects)
3813
          cmpn ++$70                   ;check for vertical pipe object
3814
          bne NotWPipe
3815
          ldayindirect (AreaData),y           ;if not, reload second byte
3816
          andn ++%00001000             ;mask out all but d3 (usage control bit)
3817
          beq NotWPipe               ;if d3 clear, branch to get original value
3818
          ldan ++$00                   ;otherwise, nullify value for warp pipe
3819
          sta SCRATCHPAD+$00
3820
NotWPipe: lda SCRATCHPAD+$00                    ;get value and jump ahead
3821
          jmp MoveAOId
3822
SpecObj:  iny                        ;branch here for rows 12-15
3823
          ldayindirect (AreaData),y
3824
          andn ++%01110000             ;get next byte and mask out all but d6-d4
3825
MoveAOId: lsr                        ;move d6-d4 to lower nybble
3826
          lsr
3827
          lsr
3828
          lsr
3829
NormObj:  sta SCRATCHPAD+$00                    ;store value here (branch for small objects and rows 13 and 14)
3830
          ldax AreaObjectLength,x     ;is there something stored here already?
3831
         checka
3832
          bpl RunAObj                ;if so, branch to do its particular sub
3833
          lda AreaObjectPageLoc      ;otherwise check to see if the object we've loaded is on the
3834
          cmpi CurrentPageLoc         ;same page as the renderer, and if so, branch
3835
          beq InitRear
3836
          ldy AreaDataOffset         ;if not, get old offset of level pointer
3837
          ldayindirect (AreaData),y           ;and reload first byte
3838
          andn ++%00001111
3839
          cmpn ++$0e                   ;row 14?
3840
          bne LeavePar ;TODO ret nz
3841
          lda BackloadingFlag        ;if so, check backloading flag
3842
         checka
3843
          bne StrAObj                ;if set, branch to render object, else leave
3844
LeavePar: rts
3845
InitRear: lda BackloadingFlag        ;check backloading flag to see if it's been initialized
3846
         checka
3847
          beq BackColC               ;branch to column-wise check
3848
          ldan ++$00                   ;if not, initialize both backloading and 
3849
          sta BackloadingFlag        ;behind-renderer flags and leave
3850
          sta BehindAreaParserFlag
3851
          sta ObjectOffset
3852
LoopCmdE: rts
3853
BackColC: ldy AreaDataOffset         ;get first byte again
3854
          ldayindirect (AreaData),y
3855
          andn ++%11110000             ;mask out low nybble and move high to low
3856
          lsr
3857
          lsr
3858
          lsr
3859
          lsr
3860
          cmpi CurrentColumnPos       ;is this where we're at?
3861
          bne LeavePar               ;if not, branch to leave
3862
StrAObj:  lda AreaDataOffset         ;if so, load area obj offset and store in buffer
3863
          stax AreaObjOffsetBuffer,x
3864
          jsr IncAreaObjOffset       ;do sub to increment to next object data
3865
RunAObj:  lda SCRATCHPAD+$00                    ;get stored value and add offset to it
3866
          clc                        ;then use the jump engine with current contents of A
3867
          adci SCRATCHPAD+$07
3868
          jsr JumpEngine
3869
        endif
3870
 
3871
;y=AreaData offset ( GetLrgObjAttrib)
3872
;x   GetLrgObjAttrib
3873
; x   hy;SCRATCHPAD+$07
3874
 
3875
;large objects (rows $00-$0b or 00-11, d6-d4 set)
3876
      .dw VerticalPipe         ;used by warp pipes
3877
      .dw AreaStyleObject
3878
      .dw RowOfBricks
3879
      .dw RowOfSolidBlocks
3880
      .dw RowOfCoins
3881
      .dw ColumnOfBricks
3882
      .dw ColumnOfSolidBlocks
3883
      .dw VerticalPipe         ;used by decoration pipes
3884
 
3885
;objects for special row $0c or 12
3886
      .dw Hole_Empty
3887
      .dw PulleyRopeObject
3888
      .dw Bridge_High
3889
      .dw Bridge_Middle
3890
      .dw Bridge_Low
3891
      .dw Hole_Water
3892
      .dw QuestionBlockRow_High
3893
      .dw QuestionBlockRow_Low
3894
 
3895
;objects for special row $0f or 15
3896
      .dw EndlessRope
3897
      .dw BalancePlatRope
3898
      .dw CastleObject
3899
      .dw StaircaseObject
3900
      .dw ExitPipe
3901
      .dw FlagBalls_Residual
3902
 
3903
;small objects (rows $00-$0b or 00-11, d6-d4 all clear)
3904
      .dw QuestionBlock     ;power-up
3905
      .dw QuestionBlock     ;coin
3906
      .dw QuestionBlock     ;hidden, coin
3907
      .dw Hidden1UpBlock    ;hidden, 1-up
3908
      .dw BrickWithItem     ;brick, power-up
3909
      .dw BrickWithItem     ;brick, vine
3910
      .dw BrickWithItem     ;brick, star
3911
      .dw BrickWithCoins    ;brick, coins
3912
      .dw BrickWithItem     ;brick, 1-up
3913
      .dw WaterPipe
3914
      .dw EmptyBlock
3915
      .dw Jumpspring
3916
 
3917
;objects for special row $0d or 13 (d6 set)
3918
      .dw IntroPipe
3919
      .dw FlagpoleObject
3920
      .dw AxeObj
3921
      .dw ChainObj
3922
      .dw CastleBridgeObj
3923
      .dw ScrollLockObject_Warp
3924
      .dw ScrollLockObject
3925
      .dw ScrollLockObject
3926
      .dw AreaFrenzy            ;flying cheep-cheeps 
3927
      .dw AreaFrenzy            ;bullet bills or swimming cheep-cheeps
3928
      .dw AreaFrenzy            ;stop frenzy
3929
      .dw LoopCmdE ;ret
3930
 
3931
;object for special row $0e or 14
3932
      .dw AlterAreaAttributes
3933
 
3934
;-------------------------------------------------------------------------------------
3935
;(these apply to all area object subroutines in this section unless otherwise stated)
3936
;$00 - used to store offset used to find object code
3937
;$07 - starts with adder from area parser, used to store row offset
3938
 
3939
AlterAreaAttributes:
3940
         ldyx AreaObjOffsetBuffer,x ;load offset for level object data saved in buffer
3941
         iny                       ;load second byte
3942
         ldayindirect (AreaData),y
3943
         pha                       ;save in stack for now
3944
         andn ++%01000000
3945
         bne Alter2                ;branch if d6 is set
3946
         pla
3947
         pha                       ;pull and push offset to copy to A
3948
         andn ++%00001111            ;mask out high nybble and store as
3949
         sta TerrainControl        ;new terrain height type bits
3950
         pla
3951
         andn ++%00110000            ;pull and mask out all but d5 and d4
3952
         lsr                       ;move bits to lower nybble and store
3953
         lsr                       ;as new background scenery bits
3954
         lsr
3955
         lsr
3956
         sta BackgroundScenery     ;then leave
3957
         rts
3958
Alter2:  pla
3959
         andn ++%00000111            ;mask out all but 3 LSB
3960
         cmpn ++$04                  ;if four or greater, set color control bits
3961
              cmpcy
3962
         bcc SetFore               ;and nullify foreground scenery bits
3963
         sta BackgroundColorCtrl
3964
         ldan ++$00
3965
SetFore: sta ForegroundScenery     ;otherwise set new foreground scenery bits
3966
         rts
3967
 
3968
;--------------------------------
3969
 
3970
ScrollLockObject_Warp:
3971
         ldxn ++$04            ;load value of 4 for game text routine as default
3972
         lda WorldNumber     ;warp zone (4-3-2), then check world number
3973
         checka
3974
         beq WarpNum
3975
         inx                 ;if world number HIGH  1, increment for next warp zone (5)
3976
         ldy AreaType        ;check area type
3977
         dey
3978
         bne WarpNum         ;if ground area type, increment for last warp zone
3979
         inx                 ;(8-7-6) and move on
3980
WarpNum: txa
3981
         sta WarpZoneControl ;store number here to be used by warp zone routine
3982
         jsr WriteGameText   ;print text and warp zone numbers
3983
         ldan ++PiranhaPlant
3984
         jsr KillEnemies     ;load identifier for piranha plants and do sub
3985
 
3986
ScrollLockObject:
3987
      lda ScrollLock      ;invert scroll lock to turn it on
3988
      eorn ++%00000001
3989
      sta ScrollLock
3990
      rts
3991
 
3992
;--------------------------------
3993
;$00 - used to store enemy identifier in KillEnemies
3994
 
3995
KillEnemies:
3996
           sta SCRATCHPAD+$00           ;store identifier here
3997
           ldan ++$00
3998
           ldxn ++$04          ;check for identifier in enemy object buffer
3999
KillELoop: ldyx Enemy_ID,x
4000
           cpyi SCRATCHPAD+$00           ;if not found, branch
4001
           bne NoKillE
4002
           stax Enemy_Flag,x  ;if found, deactivate enemy object flag
4003
NoKillE:   dex               ;do this until all slots are checked
4004
           bpl KillELoop
4005
           rts
4006
 
4007
;--------------------------------
4008
 
4009
FrenzyIDData:
4010
      .db FlyCheepCheepFrenzy, BBill_CCheep_Frenzy, Stop_Frenzy
4011
 
4012
AreaFrenzy:  ldx SCRATCHPAD+$00               ;use area object identifier bit as offset
4013
             ldax FrenzyIDData-8,x  ;note that it starts at 8, thus weird address here
4014
             ldyn ++$05
4015
FreCompLoop: dey                   ;check regular slots of enemy object buffer
4016
             bmi ExitAFrenzy       ;if all slots checked and enemy object not found, branch to store
4017
             cmpy Enemy_ID,y    ;check for enemy object in buffer versus frenzy object
4018
             bne FreCompLoop
4019
             ldan ++$00              ;if enemy object already present, nullify queue and leave
4020
ExitAFrenzy: sta EnemyFrenzyQueue  ;store enemy into frenzy queue
4021
             rts
4022
 
4023
;--------------------------------
4024
;$06 - used by MushroomLedge to store length
4025
 
4026
AreaStyleObject:
4027
      lda AreaStyle        ;load level object style and jump to the right sub
4028
      jsr JumpEngine
4029
      .dw TreeLedge        ;also used for cloud type levels
4030
      .dw MushroomLedge
4031
      .dw BulletBillCannon
4032
 
4033
TreeLedge:
4034
          jsr GetLrgObjAttrib     ;get row and length of green ledge
4035
          ldax AreaObjectLength,x  ;check length counter for expiration
4036
         checka
4037
          beq EndTreeL  
4038
          bpl MidTreeL
4039
          tya
4040
          stax AreaObjectLength,x  ;store lower nybble into buffer flag as length of ledge
4041
          lda CurrentPageLoc
4042
          orai CurrentColumnPos    ;are we at the start of the level?
4043
          beq MidTreeL
4044
          ldan ++$16                ;render start of tree ledge
4045
          jmp NoUnder
4046
MidTreeL:
4047
        if Z80OPT3hy
4048
          ld c,hy;ldx SCRATCHPAD+$07
4049
        else
4050
          ldx SCRATCHPAD+$07
4051
        endif
4052
          ldan ++$17                ;render middle of tree ledge
4053
          stax MetatileBuffer,x    ;note that this is also used if ledge position is
4054
          ldan ++$4c                ;at the start of level for continuous effect
4055
          jmp AllUnder            ;now render the part underneath
4056
EndTreeL: ldan ++$18                ;render end of tree ledge
4057
          jmp NoUnder
4058
 
4059
MushroomLedge:
4060
          jsr ChkLrgObjLength        ;get shroom dimensions
4061
          sty SCRATCHPAD+$06                    ;store length here for now
4062
          bcc EndMushL
4063
          ldax AreaObjectLength,x     ;divide length by 2 and store elsewhere
4064
          lsr
4065
          stax MushroomLedgeHalfLen,x
4066
          ldan ++$19                   ;render start of mushroom
4067
          jmp NoUnder
4068
EndMushL: ldan ++$1b                   ;if at the end, render end of mushroom
4069
          ldyx AreaObjectLength,x
4070
         checky
4071
          beq NoUnder
4072
          ldax MushroomLedgeHalfLen,x ;get divided length and store where length
4073
          sta SCRATCHPAD+$06                    ;was stored originally
4074
        if Z80OPT3hy
4075
          ld c,hy;ldx SCRATCHPAD+$07
4076
        else
4077
          ldx SCRATCHPAD+$07
4078
        endif
4079
          ldan ++$1a
4080
          stax MetatileBuffer,x       ;render middle of mushroom
4081
          cpyi SCRATCHPAD+$06                    ;are we smack dab in the center?
4082
          bne MushLExit              ;if not, branch to leave
4083
          inx
4084
          ldan ++$4f
4085
          stax MetatileBuffer,x       ;render stem top of mushroom underneath the middle
4086
          ldan ++$50
4087
AllUnder: inx
4088
          ldyn ++$0f                   ;set $0f to render all way down
4089
          jmp RenderUnderPart       ;now render the stem of mushroom
4090
NoUnder:  
4091
        if Z80OPT3hy
4092
          ld c,hy;ldx SCRATCHPAD+$07     ;load row of ledge
4093
        else
4094
          ldx SCRATCHPAD+$07                    ;load row of ledge
4095
        endif
4096
          ldyn ++$00                   ;set 0 for no bottom on this part
4097
          jmp RenderUnderPart
4098
 
4099
;--------------------------------
4100
 
4101
;tiles used by pulleys and rope object
4102
PulleyRopeMetatiles:
4103
      .db $42, $41, $43
4104
 
4105
PulleyRopeObject:
4106
           jsr ChkLrgObjLength       ;get length of pulley/rope object
4107
           ldyn ++$00                  ;initialize metatile offset
4108
           bcs RenderPul             ;if starting, render left pulley
4109
           iny
4110
           ldax AreaObjectLength,x    ;if not at the end, render rope
4111
         checka
4112
           bne RenderPul
4113
           iny                       ;otherwise render right pulley
4114
RenderPul: lday PulleyRopeMetatiles,y
4115
           sta MetatileBuffer        ;render at the top of the screen
4116
MushLExit: rts                       ;and leave
4117
 
4118
;--------------------------------
4119
;$06 - used to store upper limit of rows for CastleObject
4120
 
4121
CastleMetatiles:
4122
      .db $00, $45, $45, $45, $00
4123
      .db $00, $48, $47, $46, $00
4124
      .db $45, $49, $49, $49, $45
4125
      .db $47, $47, $4a, $47, $47
4126
      .db $47, $47, $4b, $47, $47
4127
      .db $49, $49, $49, $49, $49
4128
      .db $47, $4a, $47, $4a, $47
4129
      .db $47, $4b, $47, $4b, $47
4130
      .db $47, $47, $47, $47, $47
4131
      .db $4a, $47, $4a, $47, $4a
4132
      .db $4b, $47, $4b, $47, $4b
4133
 
4134
CastleObject:
4135
            jsr GetLrgObjAttrib      ;save lower nybble as starting row
4136
        if Z80OPT3hy
4137
          ld hy,e;  sty SCRATCHPAD+$07                  ;if starting row is above $0a, game will crash!!!
4138
        else
4139
            sty SCRATCHPAD+$07                  ;if starting row is above $0a, game will crash!!!
4140
        endif
4141
            ldyn ++$04
4142
            jsr ChkLrgObjFixedLength ;load length of castle if not already loaded
4143
            txa                  
4144
            pha                      ;save obj buffer offset to stack
4145
            ldyx AreaObjectLength,x   ;use current length as offset for castle data
4146
        if Z80OPT3hy
4147
          ld c,hy;ldx SCRATCHPAD+$07     ;begin at starting row
4148
        else
4149
            ldx SCRATCHPAD+$07                  ;begin at starting row
4150
        endif
4151
            ldan ++$0b
4152
            sta SCRATCHPAD+$06                  ;load upper limit of number of rows to print
4153
CRendLoop:  lday CastleMetatiles,y    ;load current byte using offset
4154
            stax MetatileBuffer,x
4155
            inx                      ;store in buffer and increment buffer offset
4156
            lda SCRATCHPAD+$06
4157
         checka
4158
            beq ChkCFloor            ;have we reached upper limit yet?
4159
            iny                      ;if not, increment column-wise
4160
            iny                      ;to byte in next row
4161
            iny
4162
            iny
4163
            iny
4164
            deci SCRATCHPAD+$06                  ;move closer to upper limit
4165
ChkCFloor:  cpxn ++$0b                 ;have we reached the row just before floor?
4166
            bne CRendLoop            ;if not, go back and do another row
4167
            pla
4168
            tax                      ;get obj buffer offset from before
4169
            lda CurrentPageLoc
4170
         checka
4171
            beq ExitCastle           ;if we're at page 0, we do not need to do anything else
4172
            ldax AreaObjectLength,x   ;check length
4173
            cmpn ++$01                 ;if length almost about to expire, put brick at floor
4174
            beq PlayerStop
4175
        if Z80OPT3hy
4176
         if Z80OPT3hybug
4177
           ld c,hy;ldy SCRATCHPAD+$07                  ;check starting row for tall castle ($00) ;    !
4178
         else
4179
           ld e,hy;ldy SCRATCHPAD+$07                  ;check starting row for tall castle ($00)
4180
         endif
4181
        else
4182
            ldy SCRATCHPAD+$07                  ;check starting row for tall castle ($00)
4183
        endif
4184
         checky
4185
            bne NotTall
4186
            cmpn ++$03                 ;if found, then check to see if we're at the second column
4187
            beq PlayerStop
4188
NotTall:    cmpn ++$02                 ;if not tall castle, check to see if we're at the third column
4189
            bne ExitCastle           ;if we aren't and the castle is tall, don't create flag yet
4190
            jsr GetAreaObjXPosition  ;otherwise, obtain and save horizontal pixel coordinate
4191
            pha
4192
            jsr FindEmptyEnemySlot   ;find an empty place on the enemy object buffer
4193
            pla
4194
            stax Enemy_X_Position,x   ;then write horizontal coordinate for star flag
4195
            lda CurrentPageLoc
4196
            stax Enemy_PageLoc,x      ;set page location for star flag
4197
            ldan ++$01
4198
            stax Enemy_Y_HighPos,x    ;set vertical high byte
4199
            stax Enemy_Flag,x         ;set flag for buffer
4200
            ldan ++$90
4201
            stax Enemy_Y_Position,x   ;set vertical coordinate
4202
            ldan ++StarFlagObject      ;set star flag value in buffer itself
4203
            stax Enemy_ID,x
4204
            rts
4205
PlayerStop: ldyn ++$52                 ;put brick at floor to stop player at end of level
4206
            sty MetatileBuffer+10    ;this is only done if we're on the second column
4207
ExitCastle: rts
4208
 
4209
;--------------------------------
4210
 
4211
WaterPipe:
4212
      jsr GetLrgObjAttrib     ;get row and lower nybble
4213
      ldyx AreaObjectLength,x  ;get length (residual code, water pipe is 1 col thick)
4214
        if Z80OPT3hy
4215
      ld c,hy;ldx SCRATCHPAD+$07                 ;get row
4216
        else
4217
      ldx SCRATCHPAD+$07                 ;get row
4218
        endif
4219
      ldan ++$6b
4220
      stax MetatileBuffer,x    ;draw something here and below it
4221
      ldan ++$6c
4222
      stax MetatileBuffer+1,x
4223
      rts
4224
 
4225
;--------------------------------
4226
;$05 - used to store length of vertical shaft in RenderSidewaysPipe
4227
;$06 - used to store leftover horizontal length in RenderSidewaysPipe
4228
; and vertical length in VerticalPipe and GetPipeHeight
4229
 
4230
IntroPipe:
4231
               ldyn ++$03                 ;check if length set, if not set, set it
4232
               jsr ChkLrgObjFixedLength
4233
               ldyn ++$0a                 ;set fixed value and render the sideways part
4234
               jsr RenderSidewaysPipe
4235
               bcs NoBlankP             ;if carry flag set, not time to draw vertical pipe part
4236
               ldxn ++$06                 ;blank everything above the vertical pipe part
4237
VPipeSectLoop: ldan ++$00                 ;all the way to the top of the screen
4238
               stax MetatileBuffer,x     ;because otherwise it will look like exit pipe
4239
               dex
4240
               bpl VPipeSectLoop
4241
               lday VerticalPipeData,y   ;draw the end of the vertical pipe part
4242
               sta MetatileBuffer+7
4243
NoBlankP:      rts
4244
 
4245
SidePipeShaftData:
4246
      .db $15, $14  ;used to control whether or not vertical pipe shaft
4247
      .db $00, $00  ;is drawn, and if so, controls the metatile number
4248
SidePipeTopPart:
4249
      .db $15, $1e  ;top part of sideways part of pipe
4250
      .db $1d, $1c
4251
SidePipeBottomPart:
4252
      .db $15, $21  ;bottom part of sideways part of pipe
4253
      .db $20, $1f
4254
 
4255
ExitPipe:
4256
      ldyn ++$03                 ;check if length set, if not set, set it
4257
      jsr ChkLrgObjFixedLength
4258
      jsr GetLrgObjAttrib      ;get vertical length, then plow on through RenderSidewaysPipe
4259
 
4260
RenderSidewaysPipe:
4261
              dey                       ;decrement twice to make room for shaft at bottom
4262
              dey                       ;and store here for now as vertical length
4263
              sty SCRATCHPAD+$05
4264
              ldyx AreaObjectLength,x    ;get length left over and store here
4265
              sty SCRATCHPAD+$06
4266
              ldx SCRATCHPAD+$05                   ;get vertical length plus one, use as buffer offset
4267
              inx
4268
              lday SidePipeShaftData,y   ;check for value $00 based on horizontal offset
4269
              cmpn ++$00
4270
               cmpcy
4271
              beq DrawSidePart          ;if found, do not draw the vertical pipe shaft (CY6502=1)
4272
              ldxn ++$00
4273
              ldy SCRATCHPAD+$05                   ;init buffer offset and get vertical length
4274
              jsr RenderUnderPart       ;and render vertical shaft using tile number in A
4275
              clc                       ;clear carry flag to be used by IntroPipe
4276
DrawSidePart:
4277
                push af
4278
                ldy SCRATCHPAD+$06                   ;render side pipe part at the bottom
4279
              lday SidePipeTopPart,y
4280
              stax MetatileBuffer,x      ;note that the pipe parts are stored
4281
              lday SidePipeBottomPart,y  ;backwards horizontally
4282
              stax MetatileBuffer+1,x
4283
               pop af
4284
              rts
4285
 
4286
VerticalPipeData:
4287
      .db $11, $10 ;used by pipes that lead somewhere
4288
      .db $15, $14
4289
      .db $13, $12 ;used by decoration pipes
4290
      .db $15, $14
4291
 
4292
VerticalPipe:
4293
          jsr GetPipeHeight
4294
          lda SCRATCHPAD+$00                  ;check to see if value was nullified earlier
4295
         checka
4296
          beq WarpPipe             ;(if d3, the usage control bit of second byte, was set)
4297
          iny
4298
          iny
4299
          iny
4300
          iny                      ;add four if usage control bit was not set
4301
WarpPipe: tya                      ;save value in stack
4302
          pha
4303
          lda AreaNumber
4304
          orai WorldNumber          ;if at world 1-1, do not add piranha plant ever
4305
        if NOPIRANHAPLANT
4306
        xor a
4307
        endif
4308
          beq DrawPipe
4309
          ldyx AreaObjectLength,x   ;if on second column of pipe, branch
4310
         checky
4311
          beq DrawPipe             ;(because we only need to do this once)
4312
          jsr FindEmptyEnemySlot   ;check for an empty moving data buffer space
4313
          bcs DrawPipe             ;if not found, too many enemies, thus skip
4314
          jsr GetAreaObjXPosition  ;get horizontal pixel coordinate
4315
          clc
4316
          adcn ++$08                 ;add eight to put the piranha plant in the center
4317
         push af
4318
          stax Enemy_X_Position,x   ;store as enemy's horizontal coordinate
4319
          lda CurrentPageLoc       ;add carry to current page number
4320
         ld h,a
4321
         pop af
4322
         ld a,h
4323
          adcn ++$00
4324
          stax Enemy_PageLoc,x      ;store as enemy's page coordinate
4325
          ldan ++$01
4326
          stax Enemy_Y_HighPos,x
4327
          stax Enemy_Flag,x         ;activate enemy flag
4328
          jsr GetAreaObjYPosition  ;get piranha plant's vertical coordinate and store here
4329
          stax Enemy_Y_Position,x
4330
          ldan ++PiranhaPlant        ;write piranha plant's value into buffer
4331
          stax Enemy_ID,x
4332
          jsr InitPiranhaPlant
4333
DrawPipe: pla                      ;get value saved earlier and use as Y
4334
          tay
4335
        if Z80OPT3hy
4336
          ld c,hy;ldx SCRATCHPAD+$07                  ;get buffer offset
4337
        else
4338
          ldx SCRATCHPAD+$07                  ;get buffer offset
4339
        endif
4340
          lday VerticalPipeData,y   ;draw the appropriate pipe with the Y we loaded earlier
4341
          stax MetatileBuffer,x     ;render the top of the pipe
4342
          inx
4343
          lday VerticalPipeData+2,y ;render the rest of the pipe
4344
          ldy SCRATCHPAD+$06                  ;subtract one from length and render the part underneath
4345
          dey
4346
          jmp RenderUnderPart
4347
 
4348
GetPipeHeight:
4349
      ldyn ++$01       ;check for length loaded, if not, load
4350
      jsr ChkLrgObjFixedLength ;pipe length of 2 (horizontal)
4351
      jsr GetLrgObjAttrib
4352
      tya            ;get saved lower nybble as height
4353
      andn ++$07       ;save only the three lower bits as
4354
      sta SCRATCHPAD+$06        ;vertical length, then load Y with
4355
      ldyx AreaObjectLength,x    ;length left over
4356
      rts
4357
 
4358
FindEmptyEnemySlot:
4359
              ldxn ++$00          ;start at first enemy slot
4360
EmptyChkLoop: clc               ;clear carry flag by default
4361
              ldax Enemy_Flag,x  ;check enemy buffer for nonzero
4362
         checka
4363
              beq ExitEmptyChk  ;if zero, leave
4364
              inx
4365
              cpxn ++$05          ;if nonzero, check next value
4366
              bne EmptyChkLoop
4367
ExitEmptyChk: rts               ;if all values nonzero, carry flag is set
4368
 
4369
;--------------------------------
4370
 
4371
Hole_Water:
4372
      jsr ChkLrgObjLength   ;get low nybble and save as length
4373
      ldan ++$86              ;render waves
4374
      sta MetatileBuffer+10
4375
      ldxn ++$0b
4376
      ldyn ++$01              ;now render the water underneath
4377
      ldan ++$87
4378
      jmp RenderUnderPart
4379
 
4380
;--------------------------------
4381
 
4382
QuestionBlockRow_High:
4383
      ldan ++$03    ;start on the fourth row
4384
      jr QuestionBlockRow_go;.db $2c     ;BIT instruction opcode
4385
 
4386
QuestionBlockRow_Low:
4387
      ldan ++$07             ;start on the eighth row
4388
QuestionBlockRow_go
4389
      pha                  ;save whatever row to the stack for now
4390
      jsr ChkLrgObjLength  ;get low nybble and save as length
4391
      pla
4392
      tax                  ;render question boxes with coins
4393
      ldan ++$c0
4394
      stax MetatileBuffer,x
4395
      rts
4396
 
4397
;--------------------------------
4398
 
4399
Bridge_High:
4400
      ldan ++$06  ;start on the seventh row from top of screen
4401
      jr Bridge_go;.db $2c   ;BIT instruction opcode
4402
 
4403
Bridge_Middle:
4404
      ldan ++$07  ;start on the eighth row
4405
      jr Bridge_go;.db $2c   ;BIT instruction opcode
4406
 
4407
Bridge_Low:
4408
      ldan ++$09             ;start on the tenth row
4409
Bridge_go
4410
      pha                  ;save whatever row to the stack for now
4411
      jsr ChkLrgObjLength  ;get low nybble and save as length
4412
      pla
4413
      tax                  ;render bridge railing
4414
      ldan ++$0b
4415
      stax MetatileBuffer,x
4416
      inx
4417
      ldyn ++$00             ;now render the bridge itself
4418
      ldan ++$63
4419
      jmp RenderUnderPart
4420
 
4421
;--------------------------------
4422
 
4423
FlagBalls_Residual:
4424
      jsr GetLrgObjAttrib  ;get low nybble from object byte
4425
      ldxn ++$02             ;render flag balls on third row from top
4426
      ldan ++$6d             ;of screen downwards based on low nybble
4427
      jmp RenderUnderPart
4428
 
4429
;--------------------------------
4430
 
4431
FlagpoleObject:
4432
      ldan ++$24                 ;render flagpole ball on top
4433
      sta MetatileBuffer
4434
      ldxn ++$01                 ;now render the flagpole shaft
4435
      ldyn ++$08
4436
      ldan ++$25
4437
      jsr RenderUnderPart
4438
      ldan ++$61                 ;render solid block at the bottom
4439
      sta MetatileBuffer+10
4440
      jsr GetAreaObjXPosition
4441
      secsub                      ;get pixel coordinate of where the flagpole is,
4442
      sbcn ++$08                 ;subtract eight pixels and use as horizontal
4443
      sta Enemy_X_Position+5   ;coordinate for the flag
4444
      lda CurrentPageLoc
4445
      sbcn ++$00                 ;subtract borrow from page location and use as
4446
      sta Enemy_PageLoc+5      ;page location for the flag
4447
      ldan ++$30
4448
      sta Enemy_Y_Position+5   ;set vertical coordinate for flag
4449
      ldan ++$b0
4450
      sta FlagpoleFNum_Y_Pos   ;set initial vertical coordinate for flagpole's floatey number
4451
      ldan ++FlagpoleFlagObject
4452
      sta Enemy_ID+5           ;set flag identifier, note that identifier and coordinates
4453
      inci Enemy_Flag+5         ;use last space in enemy object buffer
4454
      rts
4455
 
4456
;--------------------------------
4457
 
4458
EndlessRope:
4459
      ldxn ++$00       ;render rope from the top to the bottom of screen
4460
      ldyn ++$0f
4461
      jmp DrawRope
4462
 
4463
BalancePlatRope:
4464
          txa                 ;save object buffer offset for now
4465
          pha
4466
          ldxn ++$01            ;blank out all from second row to the bottom
4467
          ldyn ++$0f            ;with blank used for balance platform rope
4468
          ldan ++$44
4469
          jsr RenderUnderPart
4470
          pla                 ;get back object buffer offset
4471
          tax
4472
          jsr GetLrgObjAttrib ;get vertical length from lower nybble
4473
          ldxn ++$01
4474
DrawRope: ldan ++$40            ;render the actual rope
4475
          jmp RenderUnderPart
4476
 
4477
;--------------------------------
4478
 
4479
CoinMetatileData:
4480
      .db $c3, $c2, $c2, $c2
4481
 
4482
RowOfCoins:
4483
      ldy AreaType            ;get area type
4484
      lday CoinMetatileData,y  ;load appropriate coin metatile
4485
      jmp GetRow
4486
 
4487
;--------------------------------
4488
 
4489
C_ObjectRow:
4490
      .db $06, $07, $08
4491
 
4492
C_ObjectMetatile:
4493
      .db $c5, $0c, $89
4494
 
4495
CastleBridgeObj:
4496
      ldyn ++$0c                  ;load length of 13 columns
4497
      jsr ChkLrgObjFixedLength
4498
      jmp ChainObj
4499
 
4500
AxeObj:
4501
      ldan ++$08                  ;load bowser's palette into sprite portion of palette
4502
      sta VRAM_Buffer_AddrCtrl
4503
 
4504
ChainObj:
4505
      ldy SCRATCHPAD+$00                   ;get value loaded earlier from decoder
4506
      ldxy C_ObjectRow-2,y       ;get appropriate row and metatile for object
4507
      lday C_ObjectMetatile-2,y
4508
      jmp ColObj
4509
 
4510
EmptyBlock:
4511
        jsr GetLrgObjAttrib  ;get row location
4512
       if Z80OPT3hy
4513
        ld c,hy;ldx SCRATCHPAD+$07
4514
       else
4515
        ldx SCRATCHPAD+$07
4516
       endif
4517
        ldan ++$c4
4518
ColObj: ldyn ++$00             ;column length of 1
4519
        jmp RenderUnderPart
4520
 
4521
;--------------------------------
4522
 
4523
SolidBlockMetatiles:
4524
      .db $69, $61, $61, $62
4525
 
4526
BrickMetatiles:
4527
      .db $22, $51, $52, $52
4528
      .db $88 ;used only by row of bricks object
4529
 
4530
RowOfBricks:
4531
            ldy AreaType           ;load area type obtained from area offset pointer
4532
            lda CloudTypeOverride  ;check for cloud type override
4533
         checka
4534
            beq DrawBricks
4535
            ldyn ++$04               ;if cloud type, override area type
4536
DrawBricks: lday BrickMetatiles,y   ;get appropriate metatile
4537
            jmp GetRow             ;and go render it
4538
 
4539
RowOfSolidBlocks:
4540
         ldy AreaType               ;load area type obtained from area offset pointer
4541
         lday SolidBlockMetatiles,y  ;get metatile
4542
GetRow:  pha                        ;store metatile here
4543
         jsr ChkLrgObjLength        ;get row number, load length
4544
DrawRow:
4545
       if Z80OPT3hy
4546
         ld c,hy;ldx SCRATCHPAD+$07
4547
       else
4548
         ldx SCRATCHPAD+$07
4549
       endif
4550
         ldyn ++$00                   ;set vertical height of 1
4551
         pla
4552
         jmp RenderUnderPart        ;render object
4553
 
4554
ColumnOfBricks:
4555
      ldy AreaType          ;load area type obtained from area offset
4556
      lday BrickMetatiles,y  ;get metatile (no cloud override as for row)
4557
      jmp GetRow2
4558
 
4559
ColumnOfSolidBlocks:
4560
         ldy AreaType               ;load area type obtained from area offset
4561
         lday SolidBlockMetatiles,y  ;get metatile
4562
GetRow2: pha                        ;save metatile to stack for now
4563
         jsr GetLrgObjAttrib        ;get length and row
4564
         pla                        ;restore metatile
4565
       if Z80OPT3hy
4566
         ld c,hy;ldx SCRATCHPAD+$07                    ;get starting row
4567
       else
4568
         ldx SCRATCHPAD+$07                    ;get starting row
4569
       endif
4570
         jmp RenderUnderPart        ;now render the column
4571
 
4572
;--------------------------------
4573
 
4574
BulletBillCannon:
4575
             jsr GetLrgObjAttrib      ;get row and length of bullet bill cannon
4576
       if Z80OPT3hy
4577
             ld c,hy;ldx SCRATCHPAD+$07                  ;start at first row
4578
       else
4579
             ldx SCRATCHPAD+$07                  ;start at first row
4580
       endif
4581
             ldan ++$64                 ;render bullet bill cannon
4582
             stax MetatileBuffer,x
4583
             inx
4584
             dey                      ;done yet?
4585
             bmi SetupCannon
4586
             ldan ++$65                 ;if not, render middle part
4587
             stax MetatileBuffer,x
4588
             inx
4589
             dey                      ;done yet?
4590
             bmi SetupCannon
4591
             ldan ++$66                 ;if not, render bottom until length expires
4592
             jsr RenderUnderPart
4593
SetupCannon: ldx Cannon_Offset        ;get offset for data used by cannons and whirlpools
4594
             jsr GetAreaObjYPosition  ;get proper vertical coordinate for cannon
4595
             stax Cannon_Y_Position,x  ;and store it here
4596
             lda CurrentPageLoc
4597
             stax Cannon_PageLoc,x     ;store page number for cannon here
4598
             jsr GetAreaObjXPosition  ;get proper horizontal coordinate for cannon
4599
             stax Cannon_X_Position,x  ;and store it here
4600
             inx
4601
             cpxn ++$06                 ;increment and check offset
4602
              cmpcy
4603
             bcc StrCOffset           ;if not yet reached sixth cannon, branch to save offset
4604
             ldxn ++$00                 ;otherwise initialize it
4605
StrCOffset:  stx Cannon_Offset        ;save new offset and leave
4606
             rts
4607
 
4608
;--------------------------------
4609
 
4610
StaircaseHeightData:
4611
      .db $07, $07, $06, $05, $04, $03, $02, $01, $00
4612
 
4613
StaircaseRowData:
4614
      .db $03, $03, $04, $05, $06, $07, $08, $09, $0a
4615
 
4616
StaircaseObject:
4617
           jsr ChkLrgObjLength       ;check and load length
4618
           bcc NextStair             ;if length already loaded, skip init part
4619
           ldan ++$09                  ;start past the end for the bottom
4620
           sta StaircaseControl      ;of the staircase
4621
NextStair: deci StaircaseControl      ;move onto next step (or first if starting)
4622
           ldy StaircaseControl
4623
           ldxy StaircaseRowData,y    ;get starting row and height to render
4624
           lday StaircaseHeightData,y
4625
           tay
4626
           ldan ++$61                  ;now render solid block staircase
4627
           jmp RenderUnderPart
4628
 
4629
;--------------------------------
4630
 
4631
Jumpspring:
4632
      jsr GetLrgObjAttrib
4633
      jsr FindEmptyEnemySlot      ;find empty space in enemy object buffer
4634
      jsr GetAreaObjXPosition     ;get horizontal coordinate for jumpspring
4635
      stax Enemy_X_Position,x      ;and store
4636
      lda CurrentPageLoc          ;store page location of jumpspring
4637
      stax Enemy_PageLoc,x
4638
      jsr GetAreaObjYPosition     ;get vertical coordinate for jumpspring
4639
      stax Enemy_Y_Position,x      ;and store
4640
      stax Jumpspring_FixedYPos,x  ;store as permanent coordinate here
4641
      ldan ++JumpspringObject
4642
      stax Enemy_ID,x              ;write jumpspring object to enemy object buffer
4643
      ldyn ++$01
4644
      styx Enemy_Y_HighPos,x       ;store vertical high byte
4645
      incx Enemy_Flag,x            ;set flag for enemy object buffer
4646
       if Z80OPT3hy
4647
      ld c,hy;ldx SCRATCHPAD+$07
4648
       else
4649
      ldx SCRATCHPAD+$07
4650
       endif
4651
      ldan ++$67                    ;draw metatiles in two rows where jumpspring is
4652
      stax MetatileBuffer,x
4653
      ldan ++$68
4654
      stax MetatileBuffer+1,x
4655
      rts
4656
 
4657
;--------------------------------
4658
;$07 - used to save ID of brick object
4659
 
4660
Hidden1UpBlock:
4661
      lda Hidden1UpFlag  ;if flag not set, do not render object
4662
         checka
4663
      beq ExitDecBlock
4664
      ldan ++$00           ;if set, init for the next one
4665
      sta Hidden1UpFlag
4666
      jmp BrickWithItem  ;jump to code shared with unbreakable bricks
4667
 
4668
QuestionBlock:
4669
      jsr GetAreaObjectID ;get value from level decoder routine
4670
      jmp DrawQBlk        ;go to render it
4671
 
4672
BrickWithCoins:
4673
      ldan ++$00                 ;initialize multi-coin timer flag
4674
      sta BrickCoinTimerFlag
4675
 
4676
BrickWithItem:
4677
          jsr GetAreaObjectID         ;save area object ID
4678
       if Z80OPT3hy
4679
          ld hy,e;sty SCRATCHPAD+$07              
4680
       else
4681
          sty SCRATCHPAD+$07              
4682
       endif
4683
          ldan ++$00                    ;load default adder for bricks with lines
4684
          ldy AreaType                ;check level type for ground level
4685
          dey
4686
          beq BWithL                  ;if ground type, do not start with 5
4687
          ldan ++$05                    ;otherwise use adder for bricks without lines
4688
BWithL:  
4689
       if Z80OPT3hy
4690
          ;clc                         ;add object ID to adder
4691
          add a,hy;adci SCRATCHPAD+$07
4692
       else
4693
          clc                         ;add object ID to adder
4694
          adci SCRATCHPAD+$07
4695
       endif
4696
          tay                         ;use as offset for metatile
4697
DrawQBlk: lday BrickQBlockMetatiles,y  ;get appropriate metatile for brick (question block
4698
          pha                         ;if branched to here from question block routine)
4699
          jsr GetLrgObjAttrib         ;get row from location byte
4700
          jmp DrawRow                 ;now render the object
4701
 
4702
GetAreaObjectID:
4703
              lda SCRATCHPAD+$00    ;get value saved from area parser routine
4704
              secsub
4705
              sbcn ++$00   ;possibly residual code
4706
              tay        ;save to Y
4707
ExitDecBlock: rts
4708
 
4709
;--------------------------------
4710
 
4711
HoleMetatiles:
4712
      .db $87, $00, $00, $00
4713
 
4714
Hole_Empty:
4715
            jsr ChkLrgObjLength          ;get lower nybble and save as length
4716
            bcc NoWhirlP                 ;skip this part if length already loaded
4717
            lda AreaType                 ;check for water type level
4718
         checka
4719
            bne NoWhirlP                 ;if not water type, skip this part
4720
            ldx Whirlpool_Offset         ;get offset for data used by cannons and whirlpools
4721
            jsr GetAreaObjXPosition      ;get proper vertical coordinate of where we're at
4722
            secsub
4723
            sbcn ++$10                     ;subtract 16 pixels
4724
           push af
4725
            stax Whirlpool_LeftExtent,x   ;store as left extent of whirlpool
4726
           pop af
4727
            lda CurrentPageLoc           ;get page location of where we're at
4728
            sbcn ++$00                     ;subtract borrow
4729
            stax Whirlpool_PageLoc,x      ;save as page location of whirlpool
4730
            iny
4731
            iny                          ;increment length by 2
4732
            tya
4733
            asl                          ;multiply by 16 to get size of whirlpool
4734
            asl                          ;note that whirlpool will always be
4735
            asl                          ;two blocks bigger than actual size of hole
4736
            asl                          ;and extend one block beyond each edge
4737
            stax Whirlpool_Length,x       ;save size of whirlpool here
4738
            inx
4739
            cpxn ++$05                     ;increment and check offset
4740
              cmpcy
4741
            bcc StrWOffset               ;if not yet reached fifth whirlpool, branch to save offset
4742
            ldxn ++$00                     ;otherwise initialize it
4743
StrWOffset: stx Whirlpool_Offset         ;save new offset here
4744
NoWhirlP:   ldx AreaType                 ;get appropriate metatile, then
4745
            ldax HoleMetatiles,x          ;render the hole proper
4746
            ldxn ++$08
4747
            ldyn ++$0f                     ;start at ninth row and go to bottom, run RenderUnderPart
4748
 
4749
;--------------------------------
4750
 
4751
RenderUnderPart:
4752
             sty AreaObjectHeight  ;store vertical length to render
4753
             ldyx MetatileBuffer,x  ;check current spot to see if there's something
4754
         checky
4755
             beq DrawThisRow       ;we need to keep, if nothing, go ahead
4756
             cpyn ++$17
4757
             beq WaitOneRow        ;if middle part (tree ledge), wait until next row
4758
             cpyn ++$1a
4759
             beq WaitOneRow        ;if middle part (mushroom ledge), wait until next row
4760
             cpyn ++$c0
4761
             beq DrawThisRow       ;if question block w/ coin, overwrite
4762
             cpyn ++$c0
4763
              cmpcy
4764
             bcs WaitOneRow        ;if any other metatile with palette 3, wait until next row
4765
             cpyn ++$54
4766
             bne DrawThisRow       ;if cracked rock terrain, overwrite
4767
             cmpn ++$50
4768
             beq WaitOneRow        ;if stem top of mushroom, wait until next row
4769
DrawThisRow: stax MetatileBuffer,x  ;render contents of A from routine that called this
4770
WaitOneRow:  inx
4771
             cpxn ++$0d              ;stop rendering if we're at the bottom of the screen
4772
              cmpcy
4773
             bcs ExitUPartR
4774
             ldy AreaObjectHeight  ;decrement, and stop rendering if there is no more length
4775
             dey
4776
             bpl RenderUnderPart
4777
ExitUPartR:  rts
4778
 
4779
;--------------------------------
4780
 
4781
ChkLrgObjLength:
4782
        jsr GetLrgObjAttrib     ;get row location and size (length if branched to from here)
4783
 
4784
ChkLrgObjFixedLength:
4785
        ldax AreaObjectLength,x  ;check for set length counter
4786
        clc                     ;clear carry flag for not just starting
4787
         checka
4788
        bpl LenSet              ;if counter not set, load it, otherwise leave alone
4789
        tya                     ;save length into length counter
4790
        stax AreaObjectLength,x
4791
        sec                     ;set carry flag if just starting
4792
LenSet: rts
4793
 
4794
 
4795
GetLrgObjAttrib:
4796
;x=???
4797
;y=AreaData offset
4798
      ldyx AreaObjOffsetBuffer,x ;get offset saved from area obj decoding routine
4799
      ldayindirect (AreaData),y          ;get first byte of level object
4800
      andn ++%00001111
4801
       if Z80OPT3hy
4802
      ld hy,a;sta SCRATCHPAD+$07                   ;save row location
4803
       else
4804
      sta SCRATCHPAD+$07                   ;save row location
4805
       endif
4806
      iny
4807
      ldayindirect (AreaData),y          ;get next byte, save lower nybble (length or height)
4808
      andn ++%00001111            ;as Y, then leave
4809
      tay
4810
      rts
4811
 
4812
;--------------------------------
4813
 
4814
GetAreaObjXPosition:
4815
      lda CurrentColumnPos    ;multiply current offset where we're at by 16
4816
      asl                     ;to obtain horizontal pixel coordinate
4817
      asl
4818
      asl
4819
      asl
4820
      rts
4821
 
4822
;--------------------------------
4823
 
4824
GetAreaObjYPosition:
4825
       if Z80OPT3hy
4826
      ld a,hy;lda SCRATCHPAD+$07
4827
       else
4828
      lda SCRATCHPAD+$07  
4829
       endif
4830
      asl     ;multiply value by 16
4831
      asl      ;this will give us the proper vertical pixel coordinate
4832
      asl
4833
      asl
4834
      clc
4835
      adcn ++32  ;add 32 pixels for the status bar
4836
      rts
4837
 
4838
;-------------------------------------------------------------------------------------
4839
;$06-$07 - used to store block buffer address used as indirect
4840
 
4841
        if Z80OPT
4842
        else
4843
BlockBufferAddr:
4844
      .db LOW Block_Buffer_1, LOW Block_Buffer_2
4845
      .db HIGH Block_Buffer_1, HIGH Block_Buffer_2
4846
 
4847
;a=%000hllll
4848
;out: $06$07 = BlockBufferAddr[i]+%llll
4849
GetBlockBufferAddr:
4850
     pha                      ;take value of A, save
4851
      lsr                      ;move high nybble to low
4852
      lsr
4853
      lsr
4854
      lsr
4855
      tay                      ;use nybble as pointer to high byte
4856
      lday BlockBufferAddr+2,y  ;of indirect here
4857
      sta SCRATCHPAD+$07
4858
     pla
4859
      andn ++%00001111           ;pull from stack, mask out high nybble
4860
      clc
4861
      adcy BlockBufferAddr,y    ;add to low byte
4862
      sta SCRATCHPAD+$06                  ;store here and leave
4863
      rts
4864
        endif
4865
 
4866
;-------------------------------------------------------------------------------------
4867
 
4868
;unused space
4869
      .db $ff, $ff
4870
 
4871
;-------------------------------------------------------------------------------------
4872
 
4873
AreaDataOfsLoopback:
4874
      .db $12, $36, $0e, $0e, $0e, $32, $32, $32, $0a, $26, $40
4875
 
4876
;-------------------------------------------------------------------------------------
4877
 
4878
LoadAreaPointer:
4879
             jsr FindAreaPointer  ;find it and store it here
4880
             sta AreaPointer
4881
GetAreaType: andn ++%01100000       ;mask out all but d6 and d5
4882
             asl
4883
             rol
4884
             rol
4885
             rol                  ;make %0xx00000 into %000000xx
4886
             sta AreaType         ;save 2 MSB as area type
4887
             rts
4888
 
4889
FindAreaPointer:
4890
      ldy WorldNumber        ;load offset from world variable
4891
      lday WorldAddrOffsets,y
4892
      clc                    ;add area number used to find data
4893
      adci AreaNumber
4894
      tay
4895
      lday AreaAddrOffsets,y  ;from there we have our area pointer
4896
      rts
4897
 
4898
 
4899
GetAreaDataAddrs:
4900
            lda AreaPointer          ;use 2 MSB for Y
4901
            jsr GetAreaType
4902
            tay
4903
            lda AreaPointer          ;mask out all but 5 LSB
4904
            andn ++%00011111
4905
            sta AreaAddrsLOffset     ;save as low offset
4906
            lday EnemyAddrHOffsets,y  ;load base value with 2 altered MSB,
4907
            clc                      ;then add base value to 5 LSB, result
4908
            adci AreaAddrsLOffset     ;becomes offset for level data
4909
            tay
4910
            lday EnemyDataAddrLow,y   ;use offset to load pointer
4911
            sta EnemyDataLow
4912
            lday EnemyDataAddrHigh,y
4913
            sta EnemyDataHigh
4914
            ldy AreaType             ;use area type as offset
4915
            lday AreaDataHOffsets,y   ;do the same thing but with different base value
4916
            clc
4917
            adci AreaAddrsLOffset        
4918
            tay
4919
            lday AreaDataAddrLow,y    ;use this offset to load another pointer
4920
            sta AreaDataLow
4921
            lday AreaDataAddrHigh,y
4922
            sta AreaDataHigh
4923
            ldyn ++$00                 ;load first byte of header
4924
            ldayindirect (AreaData),y    
4925
            pha                      ;save it to the stack for now
4926
            andn ++%00000111           ;save 3 LSB for foreground scenery or bg color control
4927
            cmpn ++$04
4928
              cmpcy
4929
            bcc StoreFore
4930
            sta BackgroundColorCtrl  ;if 4 or greater, save value here as bg color control
4931
            ldan ++$00
4932
StoreFore:  sta ForegroundScenery    ;if less, save value here as foreground scenery
4933
            pla                      ;pull byte from stack and push it back
4934
            pha
4935
            andn ++%00111000           ;save player entrance control bits
4936
            lsr                      ;shift bits over to LSBs
4937
            lsr
4938
            lsr
4939
            sta PlayerEntranceCtrl       ;save value here as player entrance control
4940
            pla                      ;pull byte again but do not push it back
4941
            andn ++%11000000           ;save 2 MSB for game timer setting
4942
            clc
4943
            rol                      ;rotate bits over to LSBs
4944
            rol
4945
            rol
4946
            sta GameTimerSetting     ;save value here as game timer setting
4947
            iny
4948
            ldayindirect (AreaData),y         ;load second byte of header
4949
            pha                      ;save to stack
4950
            andn ++%00001111           ;mask out all but lower nybble
4951
            sta TerrainControl
4952
            pla                      ;pull and push byte to copy it to A
4953
            pha
4954
            andn ++%00110000           ;save 2 MSB for background scenery type
4955
            lsr
4956
            lsr                      ;shift bits to LSBs
4957
            lsr
4958
            lsr
4959
            sta BackgroundScenery    ;save as background scenery
4960
            pla          
4961
            andn ++%11000000
4962
            clc
4963
            rol                      ;rotate bits over to LSBs
4964
            rol
4965
            rol
4966
            cmpn ++%00000011           ;if set to 3, store here
4967
            bne StoreStyle           ;and nullify other value
4968
            sta CloudTypeOverride    ;otherwise store value in other place
4969
            ldan ++$00
4970
StoreStyle: sta AreaStyle
4971
            lda AreaDataLow          ;increment area data address by 2 bytes
4972
            clc
4973
            adcn ++$02
4974
            sta AreaDataLow
4975
            lda AreaDataHigh
4976
            adcn ++$00
4977
            sta AreaDataHigh
4978
            rts
4979
 
4980
;-------------------------------------------------------------------------------------
4981
;GAME LEVELS DATA
4982
 
4983
WorldAddrOffsets:
4984
      .db World1Areas-AreaAddrOffsets, World2Areas-AreaAddrOffsets
4985
      .db World3Areas-AreaAddrOffsets, World4Areas-AreaAddrOffsets
4986
      .db World5Areas-AreaAddrOffsets, World6Areas-AreaAddrOffsets
4987
      .db World7Areas-AreaAddrOffsets, World8Areas-AreaAddrOffsets
4988
 
4989
AreaAddrOffsets:
4990
World1Areas: .db $25, $29, $c0, $26, $60
4991
World2Areas: .db $28, $29, $01, $27, $62
4992
World3Areas: .db $24, $35, $20, $63
4993
World4Areas: .db $22, $29, $41, $2c, $61
4994
World5Areas: .db $2a, $31, $26, $62
4995
World6Areas: .db $2e, $23, $2d, $60
4996
World7Areas: .db $33, $29, $01, $27, $64
4997
World8Areas: .db $30, $32, $21, $65
4998
 
4999
;bonus area data offsets, included here for comparison purposes
5000
;underground bonus area  - c2
5001
;cloud area 1 (day)      - 2b
5002
;cloud area 2 (night)    - 34
5003
;water area (5-2/6-2)    - 00
5004
;water area (8-4)        - 02
5005
;warp zone area (4-2)    - 2f
5006
 
5007
EnemyAddrHOffsets:
5008
      .db $1f, $06, $1c, $00
5009
 
5010
EnemyDataAddrLow:
5011
      .db LOW E_CastleArea1, LOW E_CastleArea2, LOW E_CastleArea3, LOW E_CastleArea4, LOW E_CastleArea5, LOW E_CastleArea6
5012
      .db LOW E_GroundArea1, LOW E_GroundArea2, LOW E_GroundArea3, LOW E_GroundArea4, LOW E_GroundArea5, LOW E_GroundArea6
5013
      .db LOW E_GroundArea7, LOW E_GroundArea8, LOW E_GroundArea9, LOW E_GroundArea10, LOW E_GroundArea11, LOW E_GroundArea12
5014
      .db LOW E_GroundArea13, LOW E_GroundArea14, LOW E_GroundArea15, LOW E_GroundArea16, LOW E_GroundArea17, LOW E_GroundArea18
5015
      .db LOW E_GroundArea19, LOW E_GroundArea20, LOW E_GroundArea21, LOW E_GroundArea22, LOW E_UndergroundArea1
5016
      .db LOW E_UndergroundArea2, LOW E_UndergroundArea3, LOW E_WaterArea1, LOW E_WaterArea2, LOW E_WaterArea3
5017
 
5018
EnemyDataAddrHigh:
5019
      .db HIGH E_CastleArea1, HIGH E_CastleArea2, HIGH E_CastleArea3, HIGH E_CastleArea4, HIGH E_CastleArea5, HIGH E_CastleArea6
5020
      .db HIGH E_GroundArea1, HIGH E_GroundArea2, HIGH E_GroundArea3, HIGH E_GroundArea4, HIGH E_GroundArea5, HIGH E_GroundArea6
5021
      .db HIGH E_GroundArea7, HIGH E_GroundArea8, HIGH E_GroundArea9, HIGH E_GroundArea10, HIGH E_GroundArea11, HIGH E_GroundArea12
5022
      .db HIGH E_GroundArea13, HIGH E_GroundArea14, HIGH E_GroundArea15, HIGH E_GroundArea16, HIGH E_GroundArea17, HIGH E_GroundArea18
5023
      .db HIGH E_GroundArea19, HIGH E_GroundArea20, HIGH E_GroundArea21, HIGH E_GroundArea22, HIGH E_UndergroundArea1
5024
      .db HIGH E_UndergroundArea2, HIGH E_UndergroundArea3, HIGH E_WaterArea1, HIGH E_WaterArea2, HIGH E_WaterArea3
5025
 
5026
AreaDataHOffsets:
5027
      .db $00, $03, $19, $1c
5028
 
5029
AreaDataAddrLow:
5030
      .db LOW L_WaterArea1, LOW L_WaterArea2, LOW L_WaterArea3, LOW L_GroundArea1, LOW L_GroundArea2, LOW L_GroundArea3
5031
      .db LOW L_GroundArea4, LOW L_GroundArea5, LOW L_GroundArea6, LOW L_GroundArea7, LOW L_GroundArea8, LOW L_GroundArea9
5032
      .db LOW L_GroundArea10, LOW L_GroundArea11, LOW L_GroundArea12, LOW L_GroundArea13, LOW L_GroundArea14, LOW L_GroundArea15
5033
      .db LOW L_GroundArea16, LOW L_GroundArea17, LOW L_GroundArea18, LOW L_GroundArea19, LOW L_GroundArea20, LOW L_GroundArea21
5034
      .db LOW L_GroundArea22, LOW L_UndergroundArea1, LOW L_UndergroundArea2, LOW L_UndergroundArea3, LOW L_CastleArea1
5035
      .db LOW L_CastleArea2, LOW L_CastleArea3, LOW L_CastleArea4, LOW L_CastleArea5, LOW L_CastleArea6
5036
 
5037
AreaDataAddrHigh:
5038
      .db HIGH L_WaterArea1, HIGH L_WaterArea2, HIGH L_WaterArea3, HIGH L_GroundArea1, HIGH L_GroundArea2, HIGH L_GroundArea3
5039
      .db HIGH L_GroundArea4, HIGH L_GroundArea5, HIGH L_GroundArea6, HIGH L_GroundArea7, HIGH L_GroundArea8, HIGH L_GroundArea9
5040
      .db HIGH L_GroundArea10, HIGH L_GroundArea11, HIGH L_GroundArea12, HIGH L_GroundArea13, HIGH L_GroundArea14, HIGH L_GroundArea15
5041
      .db HIGH L_GroundArea16, HIGH L_GroundArea17, HIGH L_GroundArea18, HIGH L_GroundArea19, HIGH L_GroundArea20, HIGH L_GroundArea21
5042
      .db HIGH L_GroundArea22, HIGH L_UndergroundArea1, HIGH L_UndergroundArea2, HIGH L_UndergroundArea3, HIGH L_CastleArea1
5043
      .db HIGH L_CastleArea2, HIGH L_CastleArea3, HIGH L_CastleArea4, HIGH L_CastleArea5, HIGH L_CastleArea6
5044
 
5045
;ENEMY OBJECT DATA
5046
 
5047
;level 1-4/6-4
5048
E_CastleArea1:
5049
      .db $76, $dd, $bb, $4c, $ea, $1d, $1b, $cc, $56, $5d
5050
      .db $16, $9d, $c6, $1d, $36, $9d, $c9, $1d, $04, $db
5051
      .db $49, $1d, $84, $1b, $c9, $5d, $88, $95, $0f, $08
5052
      .db $30, $4c, $78, $2d, $a6, $28, $90, $b5
5053
      .db $ff
5054
 
5055
;level 4-4
5056
E_CastleArea2:
5057
      .db $0f, $03, $56, $1b, $c9, $1b, $0f, $07, $36, $1b
5058
      .db $aa, $1b, $48, $95, $0f, $0a, $2a, $1b, $5b, $0c
5059
      .db $78, $2d, $90, $b5
5060
      .db $ff
5061
 
5062
;level 2-4/5-4
5063
E_CastleArea3:
5064
      .db $0b, $8c, $4b, $4c, $77, $5f, $eb, $0c, $bd, $db
5065
      .db $19, $9d, $75, $1d, $7d, $5b, $d9, $1d, $3d, $dd
5066
      .db $99, $1d, $26, $9d, $5a, $2b, $8a, $2c, $ca, $1b
5067
      .db $20, $95, $7b, $5c, $db, $4c, $1b, $cc, $3b, $cc
5068
      .db $78, $2d, $a6, $28, $90, $b5
5069
      .db $ff
5070
 
5071
;level 3-4
5072
E_CastleArea4:
5073
      .db $0b, $8c, $3b, $1d, $8b, $1d, $ab, $0c, $db, $1d
5074
      .db $0f, $03, $65, $1d, $6b, $1b, $05, $9d, $0b, $1b
5075
      .db $05, $9b, $0b, $1d, $8b, $0c, $1b, $8c, $70, $15
5076
      .db $7b, $0c, $db, $0c, $0f, $08, $78, $2d, $a6, $28
5077
      .db $90, $b5
5078
      .db $ff
5079
 
5080
;level 7-4
5081
E_CastleArea5:
5082
      .db $27, $a9, $4b, $0c, $68, $29, $0f, $06, $77, $1b
5083
      .db $0f, $0b, $60, $15, $4b, $8c, $78, $2d, $90, $b5
5084
      .db $ff
5085
 
5086
;level 8-4
5087
E_CastleArea6:
5088
      .db $0f, $03, $8e, $65, $e1, $bb, $38, $6d, $a8, $3e, $e5, $e7
5089
      .db $0f, $08, $0b, $02, $2b, $02, $5e, $65, $e1, $bb, $0e
5090
      .db $db, $0e, $bb, $8e, $db, $0e, $fe, $65, $ec, $0f, $0d
5091
      .db $4e, $65, $e1, $0f, $0e, $4e, $02, $e0, $0f, $10, $fe, $e5, $e1
5092
      .db $1b, $85, $7b, $0c, $5b, $95, $78, $2d, $90, $b5
5093
      .db $ff
5094
 
5095
;level 3-3
5096
E_GroundArea1:
5097
      .db $a5, $86, $e4, $28, $18, $a8, $45, $83, $69, $03
5098
      .db $c6, $29, $9b, $83, $16, $a4, $88, $24, $e9, $28
5099
      .db $05, $a8, $7b, $28, $24, $8f, $c8, $03, $e8, $03
5100
      .db $46, $a8, $85, $24, $c8, $24
5101
      .db $ff
5102
 
5103
;level 8-3
5104
E_GroundArea2:
5105
      .db $eb, $8e, $0f, $03, $fb, $05, $17, $85, $db, $8e
5106
      .db $0f, $07, $57, $05, $7b, $05, $9b, $80, $2b, $85
5107
      .db $fb, $05, $0f, $0b, $1b, $05, $9b, $05
5108
      .db $ff
5109
 
5110
;level 4-1
5111
E_GroundArea3:
5112
      .db $2e, $c2, $66, $e2, $11, $0f, $07, $02, $11, $0f, $0c
5113
      .db $12, $11
5114
      .db $ff
5115
 
5116
;level 6-2
5117
E_GroundArea4:
5118
      .db $0e, $c2, $a8, $ab, $00, $bb, $8e, $6b, $82, $de, $00, $a0
5119
      .db $33, $86, $43, $06, $3e, $b4, $a0, $cb, $02, $0f, $07
5120
      .db $7e, $42, $a6, $83, $02, $0f, $0a, $3b, $02, $cb, $37
5121
      .db $0f, $0c, $e3, $0e
5122
      .db $ff
5123
 
5124
;level 3-1
5125
E_GroundArea5:
5126
      .db $9b, $8e, $ca, $0e, $ee, $42, $44, $5b, $86, $80, $b8
5127
      .db $1b, $80, $50, $ba, $10, $b7, $5b, $00, $17, $85
5128
      .db $4b, $05, $fe, $34, $40, $b7, $86, $c6, $06, $5b, $80
5129
      .db $83, $00, $d0, $38, $5b, $8e, $8a, $0e, $a6, $00
5130
      .db $bb, $0e, $c5, $80, $f3, $00
5131
      .db $ff
5132
 
5133
;level 1-1
5134
E_GroundArea6:
5135
      .db $1e, $c2, $00, $6b, $06, $8b, $86, $63, $b7, $0f, $05
5136
      .db $03, $06, $23, $06, $4b, $b7, $bb, $00, $5b, $b7
5137
      .db $fb, $37, $3b, $b7, $0f, $0b, $1b, $37
5138
      .db $ff
5139
 
5140
;level 1-3/5-3
5141
E_GroundArea7:
5142
      .db $2b, $d7, $e3, $03, $c2, $86, $e2, $06, $76, $a5
5143
      .db $a3, $8f, $03, $86, $2b, $57, $68, $28, $e9, $28
5144
      .db $e5, $83, $24, $8f, $36, $a8, $5b, $03
5145
      .db $ff
5146
 
5147
;level 2-3/7-3
5148
E_GroundArea8:
5149
      .db $0f, $02, $78, $40, $48, $ce, $f8, $c3, $f8, $c3
5150
      .db $0f, $07, $7b, $43, $c6, $d0, $0f, $8a, $c8, $50
5151
      .db $ff
5152
 
5153
;level 2-1
5154
E_GroundArea9:
5155
      .db $85, $86, $0b, $80, $1b, $00, $db, $37, $77, $80
5156
      .db $eb, $37, $fe, $2b, $20, $2b, $80, $7b, $38, $ab, $b8
5157
      .db $77, $86, $fe, $42, $20, $49, $86, $8b, $06, $9b, $80
5158
      .db $7b, $8e, $5b, $b7, $9b, $0e, $bb, $0e, $9b, $80
5159
;end of data terminator here is also used by pipe intro area
5160
E_GroundArea10:
5161
      .db $ff
5162
 
5163
;level 5-1
5164
E_GroundArea11:
5165
      .db $0b, $80, $60, $38, $10, $b8, $c0, $3b, $db, $8e
5166
      .db $40, $b8, $f0, $38, $7b, $8e, $a0, $b8, $c0, $b8
5167
      .db $fb, $00, $a0, $b8, $30, $bb, $ee, $42, $88, $0f, $0b
5168
      .db $2b, $0e, $67, $0e
5169
      .db $ff
5170
 
5171
;cloud level used in levels 2-1 and 5-2
5172
E_GroundArea12:
5173
      .db $0a, $aa, $0e, $28, $2a, $0e, $31, $88
5174
      .db $ff
5175
 
5176
;level 4-3
5177
E_GroundArea13:
5178
      .db $c7, $83, $d7, $03, $42, $8f, $7a, $03, $05, $a4
5179
      .db $78, $24, $a6, $25, $e4, $25, $4b, $83, $e3, $03
5180
      .db $05, $a4, $89, $24, $b5, $24, $09, $a4, $65, $24
5181
      .db $c9, $24, $0f, $08, $85, $25
5182
      .db $ff
5183
 
5184
;level 6-3
5185
E_GroundArea14:
5186
      .db $cd, $a5, $b5, $a8, $07, $a8, $76, $28, $cc, $25
5187
      .db $65, $a4, $a9, $24, $e5, $24, $19, $a4, $0f, $07
5188
      .db $95, $28, $e6, $24, $19, $a4, $d7, $29, $16, $a9
5189
      .db $58, $29, $97, $29
5190
      .db $ff
5191
 
5192
;level 6-1
5193
E_GroundArea15:
5194
      .db $0f, $02, $02, $11, $0f, $07, $02, $11
5195
      .db $ff
5196
 
5197
;warp zone area used in level 4-2
5198
E_GroundArea16:
5199
      .db $ff
5200
 
5201
;level 8-1
5202
E_GroundArea17:
5203
      .db $2b, $82, $ab, $38, $de, $42, $e2, $1b, $b8, $eb
5204
      .db $3b, $db, $80, $8b, $b8, $1b, $82, $fb, $b8, $7b
5205
      .db $80, $fb, $3c, $5b, $bc, $7b, $b8, $1b, $8e, $cb
5206
      .db $0e, $1b, $8e, $0f, $0d, $2b, $3b, $bb, $b8, $eb, $82
5207
      .db $4b, $b8, $bb, $38, $3b, $b7, $bb, $02, $0f, $13
5208
      .db $1b, $00, $cb, $80, $6b, $bc
5209
      .db $ff
5210
 
5211
;level 5-2
5212
E_GroundArea18:
5213
      .db $7b, $80, $ae, $00, $80, $8b, $8e, $e8, $05, $f9, $86
5214
      .db $17, $86, $16, $85, $4e, $2b, $80, $ab, $8e, $87, $85
5215
      .db $c3, $05, $8b, $82, $9b, $02, $ab, $02, $bb, $86
5216
      .db $cb, $06, $d3, $03, $3b, $8e, $6b, $0e, $a7, $8e
5217
      .db $ff
5218
 
5219
;level 8-2
5220
E_GroundArea19:
5221
      .db $29, $8e, $52, $11, $83, $0e, $0f, $03, $9b, $0e
5222
      .db $2b, $8e, $5b, $0e, $cb, $8e, $fb, $0e, $fb, $82
5223
      .db $9b, $82, $bb, $02, $fe, $42, $e8, $bb, $8e, $0f, $0a
5224
      .db $ab, $0e, $cb, $0e, $f9, $0e, $88, $86, $a6, $06
5225
      .db $db, $02, $b6, $8e
5226
      .db $ff
5227
 
5228
;level 7-1
5229
E_GroundArea20:
5230
      .db $ab, $ce, $de, $42, $c0, $cb, $ce, $5b, $8e, $1b, $ce
5231
      .db $4b, $85, $67, $45, $0f, $07, $2b, $00, $7b, $85
5232
      .db $97, $05, $0f, $0a, $92, $02
5233
      .db $ff
5234
 
5235
;cloud level used in levels 3-1 and 6-2
5236
E_GroundArea21:
5237
      .db $0a, $aa, $0e, $24, $4a, $1e, $23, $aa
5238
      .db $ff
5239
 
5240
;level 3-2
5241
E_GroundArea22:
5242
      .db $1b, $80, $bb, $38, $4b, $bc, $eb, $3b, $0f, $04
5243
      .db $2b, $00, $ab, $38, $eb, $00, $cb, $8e, $fb, $80
5244
      .db $ab, $b8, $6b, $80, $fb, $3c, $9b, $bb, $5b, $bc
5245
      .db $fb, $00, $6b, $b8, $fb, $38
5246
      .db $ff
5247
 
5248
;level 1-2
5249
E_UndergroundArea1:
5250
      .db $0b, $86, $1a, $06, $db, $06, $de, $c2, $02, $f0, $3b
5251
      .db $bb, $80, $eb, $06, $0b, $86, $93, $06, $f0, $39
5252
      .db $0f, $06, $60, $b8, $1b, $86, $a0, $b9, $b7, $27
5253
      .db $bd, $27, $2b, $83, $a1, $26, $a9, $26, $ee, $25, $0b
5254
      .db $27, $b4
5255
      .db $ff
5256
 
5257
;level 4-2
5258
E_UndergroundArea2:
5259
      .db $0f, $02, $1e, $2f, $60, $e0, $3a, $a5, $a7, $db, $80
5260
      .db $3b, $82, $8b, $02, $fe, $42, $68, $70, $bb, $25, $a7
5261
      .db $2c, $27, $b2, $26, $b9, $26, $9b, $80, $a8, $82
5262
      .db $b5, $27, $bc, $27, $b0, $bb, $3b, $82, $87, $34
5263
      .db $ee, $25, $6b
5264
      .db $ff
5265
 
5266
;underground bonus rooms area used in many levels
5267
E_UndergroundArea3:
5268
      .db $1e, $a5, $0a, $2e, $28, $27, $2e, $33, $c7, $0f, $03, $1e, $40, $07
5269
      .db $2e, $30, $e7, $0f, $05, $1e, $24, $44, $0f, $07, $1e, $22, $6a
5270
      .db $2e, $23, $ab, $0f, $09, $1e, $41, $68, $1e, $2a, $8a, $2e, $23, $a2
5271
      .db $2e, $32, $ea
5272
      .db $ff
5273
 
5274
;water area used in levels 5-2 and 6-2
5275
E_WaterArea1:
5276
      .db $3b, $87, $66, $27, $cc, $27, $ee, $31, $87, $ee, $23, $a7
5277
      .db $3b, $87, $db, $07
5278
      .db $ff
5279
 
5280
;level 2-2/7-2
5281
E_WaterArea2:
5282
      .db $0f, $01, $2e, $25, $2b, $2e, $25, $4b, $4e, $25, $cb, $6b, $07
5283
      .db $97, $47, $e9, $87, $47, $c7, $7a, $07, $d6, $c7
5284
      .db $78, $07, $38, $87, $ab, $47, $e3, $07, $9b, $87
5285
      .db $0f, $09, $68, $47, $db, $c7, $3b, $c7
5286
      .db $ff
5287
 
5288
;water area used in level 8-4
5289
E_WaterArea3:
5290
      .db $47, $9b, $cb, $07, $fa, $1d, $86, $9b, $3a, $87
5291
      .db $56, $07, $88, $1b, $07, $9d, $2e, $65, $f0
5292
      .db $ff
5293
 
5294
;AREA OBJECT DATA
5295
 
5296
;level 1-4/6-4
5297
L_CastleArea1:
5298
      .db $9b, $07
5299
      .db $05, $32, $06, $33, $07, $34, $ce, $03, $dc, $51
5300
      .db $ee, $07, $73, $e0, $74, $0a, $7e, $06, $9e, $0a
5301
      .db $ce, $06, $e4, $00, $e8, $0a, $fe, $0a, $2e, $89
5302
      .db $4e, $0b, $54, $0a, $14, $8a, $c4, $0a, $34, $8a
5303
      .db $7e, $06, $c7, $0a, $01, $e0, $02, $0a, $47, $0a
5304
      .db $81, $60, $82, $0a, $c7, $0a, $0e, $87, $7e, $02
5305
      .db $a7, $02, $b3, $02, $d7, $02, $e3, $02, $07, $82
5306
      .db $13, $02, $3e, $06, $7e, $02, $ae, $07, $fe, $0a
5307
      .db $0d, $c4, $cd, $43, $ce, $09, $de, $0b, $dd, $42
5308
      .db $fe, $02, $5d, $c7
5309
      .db $fd
5310
 
5311
;level 4-4
5312
L_CastleArea2:
5313
      .db $5b, $07
5314
      .db $05, $32, $06, $33, $07, $34, $5e, $0a, $68, $64
5315
      .db $98, $64, $a8, $64, $ce, $06, $fe, $02, $0d, $01
5316
      .db $1e, $0e, $7e, $02, $94, $63, $b4, $63, $d4, $63
5317
      .db $f4, $63, $14, $e3, $2e, $0e, $5e, $02, $64, $35
5318
      .db $88, $72, $be, $0e, $0d, $04, $ae, $02, $ce, $08
5319
      .db $cd, $4b, $fe, $02, $0d, $05, $68, $31, $7e, $0a
5320
      .db $96, $31, $a9, $63, $a8, $33, $d5, $30, $ee, $02
5321
      .db $e6, $62, $f4, $61, $04, $b1, $08, $3f, $44, $33
5322
      .db $94, $63, $a4, $31, $e4, $31, $04, $bf, $08, $3f
5323
      .db $04, $bf, $08, $3f, $cd, $4b, $03, $e4, $0e, $03
5324
      .db $2e, $01, $7e, $06, $be, $02, $de, $06, $fe, $0a
5325
      .db $0d, $c4, $cd, $43, $ce, $09, $de, $0b, $dd, $42
5326
      .db $fe, $02, $5d, $c7
5327
      .db $fd
5328
 
5329
;level 2-4/5-4
5330
L_CastleArea3:
5331
      .db $9b, $07
5332
      .db $05, $32, $06, $33, $07, $34, $fe, $00, $27, $b1
5333
      .db $65, $32, $75, $0a, $71, $00, $b7, $31, $08, $e4
5334
      .db $18, $64, $1e, $04, $57, $3b, $bb, $0a, $17, $8a
5335
      .db $27, $3a, $73, $0a, $7b, $0a, $d7, $0a, $e7, $3a
5336
      .db $3b, $8a, $97, $0a, $fe, $08, $24, $8a, $2e, $00
5337
      .db $3e, $40, $38, $64, $6f, $00, $9f, $00, $be, $43
5338
      .db $c8, $0a, $c9, $63, $ce, $07, $fe, $07, $2e, $81
5339
      .db $66, $42, $6a, $42, $79, $0a, $be, $00, $c8, $64
5340
      .db $f8, $64, $08, $e4, $2e, $07, $7e, $03, $9e, $07
5341
      .db $be, $03, $de, $07, $fe, $0a, $03, $a5, $0d, $44
5342
      .db $cd, $43, $ce, $09, $dd, $42, $de, $0b, $fe, $02
5343
      .db $5d, $c7
5344
      .db $fd
5345
 
5346
;level 3-4
5347
L_CastleArea4:
5348
      .db $9b, $07
5349
      .db $05, $32, $06, $33, $07, $34, $fe, $06, $0c, $81
5350
      .db $39, $0a, $5c, $01, $89, $0a, $ac, $01, $d9, $0a
5351
      .db $fc, $01, $2e, $83, $a7, $01, $b7, $00, $c7, $01
5352
      .db $de, $0a, $fe, $02, $4e, $83, $5a, $32, $63, $0a
5353
      .db $69, $0a, $7e, $02, $ee, $03, $fa, $32, $03, $8a
5354
      .db $09, $0a, $1e, $02, $ee, $03, $fa, $32, $03, $8a
5355
      .db $09, $0a, $14, $42, $1e, $02, $7e, $0a, $9e, $07
5356
      .db $fe, $0a, $2e, $86, $5e, $0a, $8e, $06, $be, $0a
5357
      .db $ee, $07, $3e, $83, $5e, $07, $fe, $0a, $0d, $c4
5358
      .db $41, $52, $51, $52, $cd, $43, $ce, $09, $de, $0b
5359
      .db $dd, $42, $fe, $02, $5d, $c7
5360
      .db $fd
5361
 
5362
;level 7-4
5363
L_CastleArea5:
5364
      .db $5b, $07
5365
      .db $05, $32, $06, $33, $07, $34, $fe, $0a, $ae, $86
5366
      .db $be, $07, $fe, $02, $0d, $02, $27, $32, $46, $61
5367
      .db $55, $62, $5e, $0e, $1e, $82, $68, $3c, $74, $3a
5368
      .db $7d, $4b, $5e, $8e, $7d, $4b, $7e, $82, $84, $62
5369
      .db $94, $61, $a4, $31, $bd, $4b, $ce, $06, $fe, $02
5370
      .db $0d, $06, $34, $31, $3e, $0a, $64, $32, $75, $0a
5371
      .db $7b, $61, $a4, $33, $ae, $02, $de, $0e, $3e, $82
5372
      .db $64, $32, $78, $32, $b4, $36, $c8, $36, $dd, $4b
5373
      .db $44, $b2, $58, $32, $94, $63, $a4, $3e, $ba, $30
5374
      .db $c9, $61, $ce, $06, $dd, $4b, $ce, $86, $dd, $4b
5375
      .db $fe, $02, $2e, $86, $5e, $02, $7e, $06, $fe, $02
5376
      .db $1e, $86, $3e, $02, $5e, $06, $7e, $02, $9e, $06
5377
      .db $fe, $0a, $0d, $c4, $cd, $43, $ce, $09, $de, $0b
5378
      .db $dd, $42, $fe, $02, $5d, $c7
5379
      .db $fd
5380
 
5381
;level 8-4
5382
L_CastleArea6:
5383
      .db $5b, $06
5384
      .db $05, $32, $06, $33, $07, $34, $5e, $0a, $ae, $02
5385
      .db $0d, $01, $39, $73, $0d, $03, $39, $7b, $4d, $4b
5386
      .db $de, $06, $1e, $8a, $ae, $06, $c4, $33, $16, $fe
5387
      .db $a5, $77, $fe, $02, $fe, $82, $0d, $07, $39, $73
5388
      .db $a8, $74, $ed, $4b, $49, $fb, $e8, $74, $fe, $0a
5389
      .db $2e, $82, $67, $02, $84, $7a, $87, $31, $0d, $0b
5390
      .db $fe, $02, $0d, $0c, $39, $73, $5e, $06, $c6, $76
5391
      .db $45, $ff, $be, $0a, $dd, $48, $fe, $06, $3d, $cb
5392
      .db $46, $7e, $ad, $4a, $fe, $82, $39, $f3, $a9, $7b
5393
      .db $4e, $8a, $9e, $07, $fe, $0a, $0d, $c4, $cd, $43
5394
      .db $ce, $09, $de, $0b, $dd, $42, $fe, $02, $5d, $c7
5395
      .db $fd
5396
 
5397
;level 3-3
5398
L_GroundArea1:
5399
      .db $94, $11
5400
      .db $0f, $26, $fe, $10, $28, $94, $65, $15, $eb, $12
5401
      .db $fa, $41, $4a, $96, $54, $40, $a4, $42, $b7, $13
5402
      .db $e9, $19, $f5, $15, $11, $80, $47, $42, $71, $13
5403
      .db $80, $41, $15, $92, $1b, $1f, $24, $40, $55, $12
5404
      .db $64, $40, $95, $12, $a4, $40, $d2, $12, $e1, $40
5405
      .db $13, $c0, $2c, $17, $2f, $12, $49, $13, $83, $40
5406
      .db $9f, $14, $a3, $40, $17, $92, $83, $13, $92, $41
5407
      .db $b9, $14, $c5, $12, $c8, $40, $d4, $40, $4b, $92
5408
      .db $78, $1b, $9c, $94, $9f, $11, $df, $14, $fe, $11
5409
      .db $7d, $c1, $9e, $42, $cf, $20
5410
      .db $fd
5411
 
5412
;level 8-3
5413
L_GroundArea2:
5414
      .db $90, $b1
5415
      .db $0f, $26, $29, $91, $7e, $42, $fe, $40, $28, $92
5416
      .db $4e, $42, $2e, $c0, $57, $73, $c3, $25, $c7, $27
5417
      .db $23, $84, $33, $20, $5c, $01, $77, $63, $88, $62
5418
      .db $99, $61, $aa, $60, $bc, $01, $ee, $42, $4e, $c0
5419
      .db $69, $11, $7e, $42, $de, $40, $f8, $62, $0e, $c2
5420
      .db $ae, $40, $d7, $63, $e7, $63, $33, $a7, $37, $27
5421
      .db $43, $04, $cc, $01, $e7, $73, $0c, $81, $3e, $42
5422
      .db $0d, $0a, $5e, $40, $88, $72, $be, $42, $e7, $87
5423
      .db $fe, $40, $39, $e1, $4e, $00, $69, $60, $87, $60
5424
      .db $a5, $60, $c3, $31, $fe, $31, $6d, $c1, $be, $42
5425
      .db $ef, $20
5426
      .db $fd
5427
 
5428
;level 4-1
5429
L_GroundArea3:
5430
      .db $52, $21
5431
      .db $0f, $20, $6e, $40, $58, $f2, $93, $01, $97, $00
5432
      .db $0c, $81, $97, $40, $a6, $41, $c7, $40, $0d, $04
5433
      .db $03, $01, $07, $01, $23, $01, $27, $01, $ec, $03
5434
      .db $ac, $f3, $c3, $03, $78, $e2, $94, $43, $47, $f3
5435
      .db $74, $43, $47, $fb, $74, $43, $2c, $f1, $4c, $63
5436
      .db $47, $00, $57, $21, $5c, $01, $7c, $72, $39, $f1
5437
      .db $ec, $02, $4c, $81, $d8, $62, $ec, $01, $0d, $0d
5438
      .db $0f, $38, $c7, $07, $ed, $4a, $1d, $c1, $5f, $26
5439
      .db $fd
5440
 
5441
;level 6-2
5442
L_GroundArea4:
5443
      .db $54, $21
5444
      .db $0f, $26, $a7, $22, $37, $fb, $73, $20, $83, $07
5445
      .db $87, $02, $93, $20, $c7, $73, $04, $f1, $06, $31
5446
      .db $39, $71, $59, $71, $e7, $73, $37, $a0, $47, $04
5447
      .db $86, $7c, $e5, $71, $e7, $31, $33, $a4, $39, $71
5448
      .db $a9, $71, $d3, $23, $08, $f2, $13, $05, $27, $02
5449
      .db $49, $71, $75, $75, $e8, $72, $67, $f3, $99, $71
5450
      .db $e7, $20, $f4, $72, $f7, $31, $17, $a0, $33, $20
5451
      .db $39, $71, $73, $28, $bc, $05, $39, $f1, $79, $71
5452
      .db $a6, $21, $c3, $06, $d3, $20, $dc, $00, $fc, $00
5453
      .db $07, $a2, $13, $21, $5f, $32, $8c, $00, $98, $7a
5454
      .db $c7, $63, $d9, $61, $03, $a2, $07, $22, $74, $72
5455
      .db $77, $31, $e7, $73, $39, $f1, $58, $72, $77, $73
5456
      .db $d8, $72, $7f, $b1, $97, $73, $b6, $64, $c5, $65
5457
      .db $d4, $66, $e3, $67, $f3, $67, $8d, $c1, $cf, $26
5458
      .db $fd
5459
 
5460
;level 3-1
5461
L_GroundArea5:
5462
      .db $52, $31
5463
      .db $0f, $20, $6e, $66, $07, $81, $36, $01, $66, $00
5464
      .db $a7, $22, $08, $f2, $67, $7b, $dc, $02, $98, $f2
5465
      .db $d7, $20, $39, $f1, $9f, $33, $dc, $27, $dc, $57
5466
      .db $23, $83, $57, $63, $6c, $51, $87, $63, $99, $61
5467
      .db $a3, $06, $b3, $21, $77, $f3, $f3, $21, $f7, $2a
5468
      .db $13, $81, $23, $22, $53, $00, $63, $22, $e9, $0b
5469
      .db $0c, $83, $13, $21, $16, $22, $33, $05, $8f, $35
5470
      .db $ec, $01, $63, $a0, $67, $20, $73, $01, $77, $01
5471
      .db $83, $20, $87, $20, $b3, $20, $b7, $20, $c3, $01
5472
      .db $c7, $00, $d3, $20, $d7, $20, $67, $a0, $77, $07
5473
      .db $87, $22, $e8, $62, $f5, $65, $1c, $82, $7f, $38
5474
      .db $8d, $c1, $cf, $26
5475
      .db $fd
5476
 
5477
;level 1-1
5478
L_GroundArea6:
5479
      .db $50, $21
5480
      .db $07, $81, $47, $24, $57, $00, $63, $01, $77, $01
5481
      .db $c9, $71, $68, $f2, $e7, $73, $97, $fb, $06, $83
5482
      .db $5c, $01, $d7, $22, $e7, $00, $03, $a7, $6c, $02
5483
      .db $b3, $22, $e3, $01, $e7, $07, $47, $a0, $57, $06
5484
      .db $a7, $01, $d3, $00, $d7, $01, $07, $81, $67, $20
5485
      .db $93, $22, $03, $a3, $1c, $61, $17, $21, $6f, $33
5486
      .db $c7, $63, $d8, $62, $e9, $61, $fa, $60, $4f, $b3
5487
      .db $87, $63, $9c, $01, $b7, $63, $c8, $62, $d9, $61
5488
      .db $ea, $60, $39, $f1, $87, $21, $a7, $01, $b7, $20
5489
      .db $39, $f1, $5f, $38, $6d, $c1, $af, $26
5490
      .db $fd
5491
 
5492
;level 1-3/5-3
5493
L_GroundArea7:
5494
      .db $90, $11
5495
      .db $0f, $26, $fe, $10, $2a, $93, $87, $17, $a3, $14
5496
      .db $b2, $42, $0a, $92, $19, $40, $36, $14, $50, $41
5497
      .db $82, $16, $2b, $93, $24, $41, $bb, $14, $b8, $00
5498
      .db $c2, $43, $c3, $13, $1b, $94, $67, $12, $c4, $15
5499
      .db $53, $c1, $d2, $41, $12, $c1, $29, $13, $85, $17
5500
      .db $1b, $92, $1a, $42, $47, $13, $83, $41, $a7, $13
5501
      .db $0e, $91, $a7, $63, $b7, $63, $c5, $65, $d5, $65
5502
      .db $dd, $4a, $e3, $67, $f3, $67, $8d, $c1, $ae, $42
5503
      .db $df, $20
5504
      .db $fd
5505
 
5506
;level 2-3/7-3
5507
L_GroundArea8:
5508
      .db $90, $11
5509
      .db $0f, $26, $6e, $10, $8b, $17, $af, $32, $d8, $62
5510
      .db $e8, $62, $fc, $3f, $ad, $c8, $f8, $64, $0c, $be
5511
      .db $43, $43, $f8, $64, $0c, $bf, $73, $40, $84, $40
5512
      .db $93, $40, $a4, $40, $b3, $40, $f8, $64, $48, $e4
5513
      .db $5c, $39, $83, $40, $92, $41, $b3, $40, $f8, $64
5514
      .db $48, $e4, $5c, $39, $f8, $64, $13, $c2, $37, $65
5515
      .db $4c, $24, $63, $00, $97, $65, $c3, $42, $0b, $97
5516
      .db $ac, $32, $f8, $64, $0c, $be, $53, $45, $9d, $48
5517
      .db $f8, $64, $2a, $e2, $3c, $47, $56, $43, $ba, $62
5518
      .db $f8, $64, $0c, $b7, $88, $64, $bc, $31, $d4, $45
5519
      .db $fc, $31, $3c, $b1, $78, $64, $8c, $38, $0b, $9c
5520
      .db $1a, $33, $18, $61, $28, $61, $39, $60, $5d, $4a
5521
      .db $ee, $11, $0f, $b8, $1d, $c1, $3e, $42, $6f, $20
5522
      .db $fd
5523
 
5524
;level 2-1
5525
L_GroundArea9:
5526
      .db $52, $31
5527
      .db $0f, $20, $6e, $40, $f7, $20, $07, $84, $17, $20
5528
      .db $4f, $34, $c3, $03, $c7, $02, $d3, $22, $27, $e3
5529
      .db $39, $61, $e7, $73, $5c, $e4, $57, $00, $6c, $73
5530
      .db $47, $a0, $53, $06, $63, $22, $a7, $73, $fc, $73
5531
      .db $13, $a1, $33, $05, $43, $21, $5c, $72, $c3, $23
5532
      .db $cc, $03, $77, $fb, $ac, $02, $39, $f1, $a7, $73
5533
      .db $d3, $04, $e8, $72, $e3, $22, $26, $f4, $bc, $02
5534
      .db $8c, $81, $a8, $62, $17, $87, $43, $24, $a7, $01
5535
      .db $c3, $04, $08, $f2, $97, $21, $a3, $02, $c9, $0b
5536
      .db $e1, $69, $f1, $69, $8d, $c1, $cf, $26
5537
      .db $fd
5538
 
5539
;pipe intro area
5540
L_GroundArea10:
5541
      .db $38, $11
5542
      .db $0f, $26, $ad, $40, $3d, $c7
5543
      .db $fd
5544
 
5545
;level 5-1
5546
L_GroundArea11:
5547
      .db $95, $b1
5548
      .db $0f, $26, $0d, $02, $c8, $72, $1c, $81, $38, $72
5549
      .db $0d, $05, $97, $34, $98, $62, $a3, $20, $b3, $06
5550
      .db $c3, $20, $cc, $03, $f9, $91, $2c, $81, $48, $62
5551
      .db $0d, $09, $37, $63, $47, $03, $57, $21, $8c, $02
5552
      .db $c5, $79, $c7, $31, $f9, $11, $39, $f1, $a9, $11
5553
      .db $6f, $b4, $d3, $65, $e3, $65, $7d, $c1, $bf, $26
5554
      .db $fd
5555
 
5556
;cloud level used in levels 2-1 and 5-2
5557
L_GroundArea12:
5558
      .db $00, $c1
5559
      .db $4c, $00, $f4, $4f, $0d, $02, $02, $42, $43, $4f
5560
      .db $52, $c2, $de, $00, $5a, $c2, $4d, $c7
5561
      .db $fd
5562
 
5563
;level 4-3
5564
L_GroundArea13:
5565
      .db $90, $51
5566
      .db $0f, $26, $ee, $10, $0b, $94, $33, $14, $42, $42
5567
      .db $77, $16, $86, $44, $02, $92, $4a, $16, $69, $42
5568
      .db $73, $14, $b0, $00, $c7, $12, $05, $c0, $1c, $17
5569
      .db $1f, $11, $36, $12, $8f, $14, $91, $40, $1b, $94
5570
      .db $35, $12, $34, $42, $60, $42, $61, $12, $87, $12
5571
      .db $96, $40, $a3, $14, $1c, $98, $1f, $11, $47, $12
5572
      .db $9f, $15, $cc, $15, $cf, $11, $05, $c0, $1f, $15
5573
      .db $39, $12, $7c, $16, $7f, $11, $82, $40, $98, $12
5574
      .db $df, $15, $16, $c4, $17, $14, $54, $12, $9b, $16
5575
      .db $28, $94, $ce, $01, $3d, $c1, $5e, $42, $8f, $20
5576
      .db $fd
5577
 
5578
;level 6-3
5579
L_GroundArea14:
5580
      .db $97, $11
5581
      .db $0f, $26, $fe, $10, $2b, $92, $57, $12, $8b, $12
5582
      .db $c0, $41, $f7, $13, $5b, $92, $69, $0b, $bb, $12
5583
      .db $b2, $46, $19, $93, $71, $00, $17, $94, $7c, $14
5584
      .db $7f, $11, $93, $41, $bf, $15, $fc, $13, $ff, $11
5585
      .db $2f, $95, $50, $42, $51, $12, $58, $14, $a6, $12
5586
      .db $db, $12, $1b, $93, $46, $43, $7b, $12, $8d, $49
5587
      .db $b7, $14, $1b, $94, $49, $0b, $bb, $12, $fc, $13
5588
      .db $ff, $12, $03, $c1, $2f, $15, $43, $12, $4b, $13
5589
      .db $77, $13, $9d, $4a, $15, $c1, $a1, $41, $c3, $12
5590
      .db $fe, $01, $7d, $c1, $9e, $42, $cf, $20
5591
      .db $fd
5592
 
5593
;level 6-1
5594
L_GroundArea15:
5595
      .db $52, $21
5596
      .db $0f, $20, $6e, $44, $0c, $f1, $4c, $01, $aa, $35
5597
      .db $d9, $34, $ee, $20, $08, $b3, $37, $32, $43, $04
5598
      .db $4e, $21, $53, $20, $7c, $01, $97, $21, $b7, $07
5599
      .db $9c, $81, $e7, $42, $5f, $b3, $97, $63, $ac, $02
5600
      .db $c5, $41, $49, $e0, $58, $61, $76, $64, $85, $65
5601
      .db $94, $66, $a4, $22, $a6, $03, $c8, $22, $dc, $02
5602
      .db $68, $f2, $96, $42, $13, $82, $17, $02, $af, $34
5603
      .db $f6, $21, $fc, $06, $26, $80, $2a, $24, $36, $01
5604
      .db $8c, $00, $ff, $35, $4e, $a0, $55, $21, $77, $20
5605
      .db $87, $07, $89, $22, $ae, $21, $4c, $82, $9f, $34
5606
      .db $ec, $01, $03, $e7, $13, $67, $8d, $4a, $ad, $41
5607
      .db $0f, $a6
5608
      .db $fd
5609
 
5610
;warp zone area used in level 4-2
5611
L_GroundArea16:
5612
      .db $10, $51
5613
      .db $4c, $00, $c7, $12, $c6, $42, $03, $92, $02, $42
5614
      .db $29, $12, $63, $12, $62, $42, $69, $14, $a5, $12
5615
      .db $a4, $42, $e2, $14, $e1, $44, $f8, $16, $37, $c1
5616
      .db $8f, $38, $02, $bb, $28, $7a, $68, $7a, $a8, $7a
5617
      .db $e0, $6a, $f0, $6a, $6d, $c5
5618
      .db $fd
5619
 
5620
;level 8-1
5621
L_GroundArea17:
5622
      .db $92, $31
5623
      .db $0f, $20, $6e, $40, $0d, $02, $37, $73, $ec, $00
5624
      .db $0c, $80, $3c, $00, $6c, $00, $9c, $00, $06, $c0
5625
      .db $c7, $73, $06, $83, $28, $72, $96, $40, $e7, $73
5626
      .db $26, $c0, $87, $7b, $d2, $41, $39, $f1, $c8, $f2
5627
      .db $97, $e3, $a3, $23, $e7, $02, $e3, $07, $f3, $22
5628
      .db $37, $e3, $9c, $00, $bc, $00, $ec, $00, $0c, $80
5629
      .db $3c, $00, $86, $21, $a6, $06, $b6, $24, $5c, $80
5630
      .db $7c, $00, $9c, $00, $29, $e1, $dc, $05, $f6, $41
5631
      .db $dc, $80, $e8, $72, $0c, $81, $27, $73, $4c, $01
5632
      .db $66, $74, $0d, $11, $3f, $35, $b6, $41, $2c, $82
5633
      .db $36, $40, $7c, $02, $86, $40, $f9, $61, $39, $e1
5634
      .db $ac, $04, $c6, $41, $0c, $83, $16, $41, $88, $f2
5635
      .db $39, $f1, $7c, $00, $89, $61, $9c, $00, $a7, $63
5636
      .db $bc, $00, $c5, $65, $dc, $00, $e3, $67, $f3, $67
5637
      .db $8d, $c1, $cf, $26
5638
      .db $fd
5639
 
5640
;level 5-2
5641
L_GroundArea18:
5642
      .db $55, $b1
5643
      .db $0f, $26, $cf, $33, $07, $b2, $15, $11, $52, $42
5644
      .db $99, $0b, $ac, $02, $d3, $24, $d6, $42, $d7, $25
5645
      .db $23, $84, $cf, $33, $07, $e3, $19, $61, $78, $7a
5646
      .db $ef, $33, $2c, $81, $46, $64, $55, $65, $65, $65
5647
      .db $ec, $74, $47, $82, $53, $05, $63, $21, $62, $41
5648
      .db $96, $22, $9a, $41, $cc, $03, $b9, $91, $39, $f1
5649
      .db $63, $26, $67, $27, $d3, $06, $fc, $01, $18, $e2
5650
      .db $d9, $07, $e9, $04, $0c, $86, $37, $22, $93, $24
5651
      .db $87, $84, $ac, $02, $c2, $41, $c3, $23, $d9, $71
5652
      .db $fc, $01, $7f, $b1, $9c, $00, $a7, $63, $b6, $64
5653
      .db $cc, $00, $d4, $66, $e3, $67, $f3, $67, $8d, $c1
5654
      .db $cf, $26
5655
      .db $fd
5656
 
5657
;level 8-2
5658
L_GroundArea19:
5659
      .db $50, $b1
5660
      .db $0f, $26, $fc, $00, $1f, $b3, $5c, $00, $65, $65
5661
      .db $74, $66, $83, $67, $93, $67, $dc, $73, $4c, $80
5662
      .db $b3, $20, $c9, $0b, $c3, $08, $d3, $2f, $dc, $00
5663
      .db $2c, $80, $4c, $00, $8c, $00, $d3, $2e, $ed, $4a
5664
      .db $fc, $00, $d7, $a1, $ec, $01, $4c, $80, $59, $11
5665
      .db $d8, $11, $da, $10, $37, $a0, $47, $04, $99, $11
5666
      .db $e7, $21, $3a, $90, $67, $20, $76, $10, $77, $60
5667
      .db $87, $07, $d8, $12, $39, $f1, $ac, $00, $e9, $71
5668
      .db $0c, $80, $2c, $00, $4c, $05, $c7, $7b, $39, $f1
5669
      .db $ec, $00, $f9, $11, $0c, $82, $6f, $34, $f8, $11
5670
      .db $fa, $10, $7f, $b2, $ac, $00, $b6, $64, $cc, $01
5671
      .db $e3, $67, $f3, $67, $8d, $c1, $cf, $26
5672
      .db $fd
5673
 
5674
;level 7-1
5675
L_GroundArea20:
5676
      .db $52, $b1
5677
      .db $0f, $20, $6e, $45, $39, $91, $b3, $04, $c3, $21
5678
      .db $c8, $11, $ca, $10, $49, $91, $7c, $73, $e8, $12
5679
      .db $88, $91, $8a, $10, $e7, $21, $05, $91, $07, $30
5680
      .db $17, $07, $27, $20, $49, $11, $9c, $01, $c8, $72
5681
      .db $23, $a6, $27, $26, $d3, $03, $d8, $7a, $89, $91
5682
      .db $d8, $72, $39, $f1, $a9, $11, $09, $f1, $63, $24
5683
      .db $67, $24, $d8, $62, $28, $91, $2a, $10, $56, $21
5684
      .db $70, $04, $79, $0b, $8c, $00, $94, $21, $9f, $35
5685
      .db $2f, $b8, $3d, $c1, $7f, $26
5686
      .db $fd
5687
 
5688
;cloud level used in levels 3-1 and 6-2
5689
L_GroundArea21:
5690
      .db $06, $c1
5691
      .db $4c, $00, $f4, $4f, $0d, $02, $06, $20, $24, $4f
5692
      .db $35, $a0, $36, $20, $53, $46, $d5, $20, $d6, $20
5693
      .db $34, $a1, $73, $49, $74, $20, $94, $20, $b4, $20
5694
      .db $d4, $20, $f4, $20, $2e, $80, $59, $42, $4d, $c7
5695
      .db $fd
5696
 
5697
;level 3-2
5698
L_GroundArea22:
5699
      .db $96, $31
5700
      .db $0f, $26, $0d, $03, $1a, $60, $77, $42, $c4, $00
5701
      .db $c8, $62, $b9, $e1, $d3, $06, $d7, $07, $f9, $61
5702
      .db $0c, $81, $4e, $b1, $8e, $b1, $bc, $01, $e4, $50
5703
      .db $e9, $61, $0c, $81, $0d, $0a, $84, $43, $98, $72
5704
      .db $0d, $0c, $0f, $38, $1d, $c1, $5f, $26
5705
      .db $fd
5706
 
5707
;level 1-2
5708
L_UndergroundArea1:
5709
      .db $48, $0f
5710
      .db $0e, $01, $5e, $02, $a7, $00, $bc, $73, $1a, $e0
5711
      .db $39, $61, $58, $62, $77, $63, $97, $63, $b8, $62
5712
      .db $d6, $07, $f8, $62, $19, $e1, $75, $52, $86, $40
5713
      .db $87, $50, $95, $52, $93, $43, $a5, $21, $c5, $52
5714
      .db $d6, $40, $d7, $20, $e5, $06, $e6, $51, $3e, $8d
5715
      .db $5e, $03, $67, $52, $77, $52, $7e, $02, $9e, $03
5716
      .db $a6, $43, $a7, $23, $de, $05, $fe, $02, $1e, $83
5717
      .db $33, $54, $46, $40, $47, $21, $56, $04, $5e, $02
5718
      .db $83, $54, $93, $52, $96, $07, $97, $50, $be, $03
5719
      .db $c7, $23, $fe, $02, $0c, $82, $43, $45, $45, $24
5720
      .db $46, $24, $90, $08, $95, $51, $78, $fa, $d7, $73
5721
      .db $39, $f1, $8c, $01, $a8, $52, $b8, $52, $cc, $01
5722
      .db $5f, $b3, $97, $63, $9e, $00, $0e, $81, $16, $24
5723
      .db $66, $04, $8e, $00, $fe, $01, $08, $d2, $0e, $06
5724
      .db $6f, $47, $9e, $0f, $0e, $82, $2d, $47, $28, $7a
5725
      .db $68, $7a, $a8, $7a, $ae, $01, $de, $0f, $6d, $c5
5726
      .db $fd
5727
 
5728
;level 4-2
5729
L_UndergroundArea2:
5730
      .db $48, $0f
5731
      .db $0e, $01, $5e, $02, $bc, $01, $fc, $01, $2c, $82
5732
      .db $41, $52, $4e, $04, $67, $25, $68, $24, $69, $24
5733
      .db $ba, $42, $c7, $04, $de, $0b, $b2, $87, $fe, $02
5734
      .db $2c, $e1, $2c, $71, $67, $01, $77, $00, $87, $01
5735
      .db $8e, $00, $ee, $01, $f6, $02, $03, $85, $05, $02
5736
      .db $13, $21, $16, $02, $27, $02, $2e, $02, $88, $72
5737
      .db $c7, $20, $d7, $07, $e4, $76, $07, $a0, $17, $06
5738
      .db $48, $7a, $76, $20, $98, $72, $79, $e1, $88, $62
5739
      .db $9c, $01, $b7, $73, $dc, $01, $f8, $62, $fe, $01
5740
      .db $08, $e2, $0e, $00, $6e, $02, $73, $20, $77, $23
5741
      .db $83, $04, $93, $20, $ae, $00, $fe, $0a, $0e, $82
5742
      .db $39, $71, $a8, $72, $e7, $73, $0c, $81, $8f, $32
5743
      .db $ae, $00, $fe, $04, $04, $d1, $17, $04, $26, $49
5744
      .db $27, $29, $df, $33, $fe, $02, $44, $f6, $7c, $01
5745
      .db $8e, $06, $bf, $47, $ee, $0f, $4d, $c7, $0e, $82
5746
      .db $68, $7a, $ae, $01, $de, $0f, $6d, $c5
5747
      .db $fd
5748
 
5749
;underground bonus rooms area used in many levels
5750
L_UndergroundArea3:
5751
      .db $48, $01
5752
      .db $0e, $01, $00, $5a, $3e, $06, $45, $46, $47, $46
5753
      .db $53, $44, $ae, $01, $df, $4a, $4d, $c7, $0e, $81
5754
      .db $00, $5a, $2e, $04, $37, $28, $3a, $48, $46, $47
5755
      .db $c7, $07, $ce, $0f, $df, $4a, $4d, $c7, $0e, $81
5756
      .db $00, $5a, $33, $53, $43, $51, $46, $40, $47, $50
5757
      .db $53, $04, $55, $40, $56, $50, $62, $43, $64, $40
5758
      .db $65, $50, $71, $41, $73, $51, $83, $51, $94, $40
5759
      .db $95, $50, $a3, $50, $a5, $40, $a6, $50, $b3, $51
5760
      .db $b6, $40, $b7, $50, $c3, $53, $df, $4a, $4d, $c7
5761
      .db $0e, $81, $00, $5a, $2e, $02, $36, $47, $37, $52
5762
      .db $3a, $49, $47, $25, $a7, $52, $d7, $04, $df, $4a
5763
      .db $4d, $c7, $0e, $81, $00, $5a, $3e, $02, $44, $51
5764
      .db $53, $44, $54, $44, $55, $24, $a1, $54, $ae, $01
5765
      .db $b4, $21, $df, $4a, $e5, $07, $4d, $c7
5766
      .db $fd
5767
 
5768
;water area used in levels 5-2 and 6-2
5769
L_WaterArea1:
5770
      .db $41, $01
5771
      .db $b4, $34, $c8, $52, $f2, $51, $47, $d3, $6c, $03
5772
      .db $65, $49, $9e, $07, $be, $01, $cc, $03, $fe, $07
5773
      .db $0d, $c9, $1e, $01, $6c, $01, $62, $35, $63, $53
5774
      .db $8a, $41, $ac, $01, $b3, $53, $e9, $51, $26, $c3
5775
      .db $27, $33, $63, $43, $64, $33, $ba, $60, $c9, $61
5776
      .db $ce, $0b, $e5, $09, $ee, $0f, $7d, $ca, $7d, $47
5777
      .db $fd
5778
 
5779
;level 2-2/7-2
5780
L_WaterArea2:
5781
      .db $41, $01
5782
      .db $b8, $52, $ea, $41, $27, $b2, $b3, $42, $16, $d4
5783
      .db $4a, $42, $a5, $51, $a7, $31, $27, $d3, $08, $e2
5784
      .db $16, $64, $2c, $04, $38, $42, $76, $64, $88, $62
5785
      .db $de, $07, $fe, $01, $0d, $c9, $23, $32, $31, $51
5786
      .db $98, $52, $0d, $c9, $59, $42, $63, $53, $67, $31
5787
      .db $14, $c2, $36, $31, $87, $53, $17, $e3, $29, $61
5788
      .db $30, $62, $3c, $08, $42, $37, $59, $40, $6a, $42
5789
      .db $99, $40, $c9, $61, $d7, $63, $39, $d1, $58, $52
5790
      .db $c3, $67, $d3, $31, $dc, $06, $f7, $42, $fa, $42
5791
      .db $23, $b1, $43, $67, $c3, $34, $c7, $34, $d1, $51
5792
      .db $43, $b3, $47, $33, $9a, $30, $a9, $61, $b8, $62
5793
      .db $be, $0b, $d5, $09, $de, $0f, $0d, $ca, $7d, $47
5794
      .db $fd
5795
 
5796
;water area used in level 8-4
5797
L_WaterArea3:
5798
      .db $49, $0f
5799
      .db $1e, $01, $39, $73, $5e, $07, $ae, $0b, $1e, $82
5800
      .db $6e, $88, $9e, $02, $0d, $04, $2e, $0b, $45, $09
5801
      .db $4e, $0f, $ed, $47
5802
      .db $fd
5803
 
5804
;-------------------------------------------------------------------------------------
5805
 
5806
       if Z80==0
5807
;unused space
5808
      .db $ff
5809
       endif
5810
 
5811
;-------------------------------------------------------------------------------------
5812
 
5813
;indirect jump routine called when
5814
;$0770 is set to 1
5815
GameMode:
5816
      lda OperMode_Task
5817
      jsr JumpEngine
5818
 
5819
      .dw InitializeArea
5820
      .dw ScreenRoutines
5821
      .dw SecondaryGameSetup
5822
      .dw GameCoreRoutine
5823
 
5824
;-------------------------------------------------------------------------------------
5825
 
5826
GameCoreRoutine:
5827
      ldx CurrentPlayer          ;get which player is on the screen
5828
      ldax SavedJoypadBits,x      ;use appropriate player's controller bits
5829
       ;or a
5830
       ;jr nz,$
5831
      sta SavedJoypadBits        ;as the master controller bits
5832
      jsr GameRoutines           ;execute one of many possible subs ;9907t (3 Goomba + 2  + )
5833
      lda OperMode_Task          ;check major task of operating mode
5834
      cmpn ++$03                   ;if we are supposed to be here,
5835
              cmpcy
5836
      bcs GameEngine             ;branch to the game engine itself
5837
      rts
5838
 
5839
GameEngine:
5840
              jsr ProcFireball_Bubble    ;process fireballs and air bubbles
5841
              ldxn ++$00
5842
ProcELoop:    stx ObjectOffset           ;put incremented offset in X as enemy object offset
5843
              jsr EnemiesAndLoopsCore    ;process enemy objects  ;8639+8388+9593+999+999+404t (3 Goomba + 2  + ) ;<------------
5844
              jsr FloateyNumbersRoutine  ;process floatey numbers ;73+941+73+73+73+73t (3 Goomba + 2  + )
5845
              inx
5846
              cpxn ++$06                   ;do these two subroutines until the whole buffer is done
5847
              bne ProcELoop
5848
              jsr GetPlayerOffscreenBits ;get offscreen bits for player object ;726t (3 Goomba + 2  + )
5849
              jsr RelativePlayerPosition ;get relative coordinates for player object ;228t (3 Goomba + 2  + )
174 demige 5850
           if 0;Z80
5851
            ld hl,(logicframe)
5852
            dec l
5853
            call z,PlayerGfxHandler ;     (  ) ;  -        
5854
           else
171 demige 5855
              jsr PlayerGfxHandler       ;draw the player                               ;3074t (3 Goomba + 2  + ) ;<--------------
174 demige 5856
           endif
171 demige 5857
              jsr BlockObjMT_Updater     ;replace block objects with metatiles if necessary ;250t (3 Goomba + 2  + )
5858
              ldxn ++$01
5859
              stx ObjectOffset           ;set offset for second
5860
              jsr BlockObjectsCore       ;process second block object ;101t (3 Goomba + 2  + )
5861
              dex
5862
              stx ObjectOffset           ;set offset for first
5863
              jsr BlockObjectsCore       ;process first block object ;101t (3 Goomba + 2  + )
5864
              jsr MiscObjectsCore        ;process misc objects (hammer, jumping coins) ;3249t (3 Goomba + 2  + ) ;<---------------
5865
              jsr ProcessCannons         ;process bullet bill cannons ;431t (3 Goomba + 2  + )
5866
              jsr ProcessWhirlpools      ;process whirlpools         ;58t (3 Goomba + 2  + )
5867
              jsr FlagpoleRoutine        ;process the flagpole       ;96t (3 Goomba + 2  + )
5868
              jsr RunGameTimer           ;count down the game timer ;174t (3 Goomba + 2  + )
5869
              jsr ColorRotation          ;cycle one of the background colors ;57t (3 Goomba + 2  + )
5870
              lda Player_Y_HighPos
5871
              cmpn ++$02                   ;if player is below the screen, don't bother with the music
5872
              bpl NoChgMus
5873
              lda StarInvincibleTimer    ;if star mario invincibility timer at zero,
5874
         checka
5875
              beq ClrPlrPal              ;skip this part
5876
              cmpn ++$04
5877
              bne NoChgMus               ;if not yet at a certain point, continue
5878
              lda IntervalTimerControl   ;if interval timer not yet expired,
5879
         checka
5880
              bne NoChgMus               ;branch ahead, don't bother with the music
5881
              jsr GetAreaMusic           ;to re-attain appropriate level music
5882
NoChgMus:     ldy StarInvincibleTimer    ;get invincibility timer
5883
              lda FrameCounter           ;get frame counter
5884
              cpyn ++$08                   ;if timer still above certain point,
5885
              cmpcy
5886
              bcs CycleTwo               ;branch to cycle player's palette quickly
5887
              lsr                        ;otherwise, divide by 8 to cycle every eighth frame
5888
              lsr
5889
CycleTwo:     lsr                        ;if branched here, divide by 2 to cycle every other frame
5890
              jsr CyclePlayerPalette     ;do sub to cycle the palette (note: shares fire flower code)
5891
              jmp SaveAB                 ;then skip this sub to finish up the game engine
5892
ClrPlrPal:    jsr ResetPalStar           ;do sub to clear player's palette bits in attributes
5893
SaveAB:       lda A_B_Buttons            ;save current A and B button
5894
              sta PreviousA_B_Buttons    ;into temp variable to be used on next frame
5895
              ldan ++$00
5896
              sta Left_Right_Buttons     ;nullify left and right buttons temp variable
5897
UpdScrollVar: lda VRAM_Buffer_AddrCtrl
5898
              cmpn ++$06                   ;if vram address controller set to 6 (one of two $0341s) (VRAM_Buffer2)
5899
              beq ExitEng                ;then branch to leave
5900
              lda AreaParserTaskNum      ;otherwise check number of tasks
5901
         checka
5902
              bne RunParser
5903
              lda ScrollThirtyTwo        ;get horizontal scroll in 0-31 or $00-$20 range
5904
              cmpn ++$20                   ;check to see if exceeded $21
5905
              bmi ExitEng                ;branch to leave if not
5906
              lda ScrollThirtyTwo
5907
              sbcn ++$20                   ;otherwise subtract $20 to set appropriately
5908
              sta ScrollThirtyTwo        ;and store
5909
              ldan ++$00                   ;reset vram buffer offset used in conjunction with
5910
              sta VRAM_Buffer2_Offset    ;level graphics buffer at $0341-$035f
5911
RunParser:    jsr AreaParserTaskHandler  ;update the name table with more level graphics
5912
ExitEng:      rts                        ;and after all that, we're finally done!
5913
 
5914
;-------------------------------------------------------------------------------------
5915
 
5916
ScrollHandler:
5917
            lda Player_X_Scroll       ;load value saved here
5918
            clc
5919
            adci Platform_X_Scroll     ;add value used by left/right platforms
5920
            sta Player_X_Scroll       ;save as new value here to impose force on scroll
5921
            lda ScrollLock            ;check scroll lock flag
5922
         checka
5923
            bne InitScrlAmt           ;skip a bunch of code here if set
5924
            lda Player_Pos_ForScroll
5925
            cmpn ++$50                  ;check player's horizontal screen position
5926
              cmpcy
5927
            bcc InitScrlAmt           ;if less than 80 pixels to the right, branch
5928
            lda SideCollisionTimer    ;if timer related to player's side collision
5929
         checka
5930
            bne InitScrlAmt           ;not expired, branch
5931
            ldy Player_X_Scroll       ;get value and decrement by one
5932
            dey                       ;if value originally set to zero or otherwise
5933
            bmi InitScrlAmt           ;negative for left movement, branch
5934
            iny
5935
            cpyn ++$02                  ;if value $01, branch and do not decrement
5936
              cmpcy
5937
            bcc ChkNearMid
5938
            dey                       ;otherwise decrement by one
5939
ChkNearMid: lda Player_Pos_ForScroll
5940
            cmpn ++$70                  ;check player's horizontal screen position
5941
              cmpcy
5942
            bcc ScrollScreen          ;if less than 112 pixels to the right, branch
5943
            ldy Player_X_Scroll       ;otherwise get original value undecremented
5944
 
5945
ScrollScreen:
5946
              tya
5947
              sta ScrollAmount          ;save value here
5948
              clc
5949
              adci ScrollThirtyTwo       ;add to value already set here
5950
              sta ScrollThirtyTwo       ;save as new value here
5951
              tya
5952
              clc
5953
              adci ScreenLeft_X_Pos      ;add to left side coordinate
5954
              sta ScreenLeft_X_Pos      ;save as new left side coordinate
5955
              sta HorizontalScroll      ;save here also
5956
              lda ScreenLeft_PageLoc
5957
              adcn ++$00                  ;add carry to page location for left
5958
              sta ScreenLeft_PageLoc    ;side of the screen
5959
              andn ++$01                  ;get LSB of page location
5960
              sta SCRATCHPAD+$00                   ;save as temp variable for PPU register 1 mirror
5961
              lda Mirror_PPU_CTRL_REG1  ;get PPU register 1 mirror
5962
              andn ++%11111110            ;save all bits except d0
5963
              orai SCRATCHPAD+$00                   ;get saved bit here and save in PPU register 1
5964
              sta Mirror_PPU_CTRL_REG1  ;mirror to be used to set name table later
5965
              jsr GetScreenPosition     ;figure out where the right side is
5966
              ldan ++$08
5967
              sta ScrollIntervalTimer   ;set scroll timer (residual, not used elsewhere)
5968
              jmp ChkPOffscr            ;skip this part
5969
InitScrlAmt:  ldan ++$00
5970
              sta ScrollAmount          ;initialize value here
5971
ChkPOffscr:   ldxn ++$00                  ;set X for player offset
5972
              jsr GetXOffscreenBits     ;get horizontal offscreen bits for player
5973
              sta SCRATCHPAD+$00                   ;save them here
5974
              ldyn ++$00                  ;load default offset (left side)
5975
              asl                       ;if d7 of offscreen bits are set, ;TODO >>4  GetXOffscreenBits
5976
              bcs KeepOnscr             ;branch with default offset
5977
              iny                         ;otherwise use different offset (right side)
5978
              lda SCRATCHPAD+$00
5979
              andn ++%00100000              ;check offscreen bits for d5 set ;TODO >>4  GetXOffscreenBits
5980
              beq InitPlatScrl            ;if not set, branch ahead of this part
5981
KeepOnscr:    lday ScreenEdge_X_Pos,y      ;get left or right side coordinate based on offset
5982
              secsub
5983
              sbcy X_SubtracterData,y      ;subtract amount based on offset
5984
              sta Player_X_Position       ;store as player position to prevent movement further
5985
              ldaykeepcy ScreenEdge_PageLoc,y    ;get left or right page location based on offset
5986
              sbcn ++$00                    ;subtract borrow
5987
              sta Player_PageLoc          ;save as player's page location
5988
              lda Left_Right_Buttons      ;check saved controller bits
5989
              cmpy OffscrJoypadBitsData,y  ;against bits based on offset
5990
              beq InitPlatScrl            ;if not equal, branch
5991
              ldan ++$00
5992
              sta Player_X_Speed          ;otherwise nullify horizontal speed of player
5993
InitPlatScrl: ldan ++$00                    ;nullify platform force imposed on scroll
5994
              sta Platform_X_Scroll
5995
              rts
5996
 
5997
X_SubtracterData:
5998
      .db $00, $10
5999
 
6000
OffscrJoypadBitsData:
6001
      .db $01, $02
6002
 
6003
;-------------------------------------------------------------------------------------
6004
 
6005
GetScreenPosition:
6006
      lda ScreenLeft_X_Pos    ;get coordinate of screen's left boundary
6007
      clc
6008
      adcn ++$ff                ;add 255 pixels
6009
      sta ScreenRight_X_Pos   ;store as coordinate of screen's right boundary
6010
      lda ScreenLeft_PageLoc  ;get page number where left boundary is
6011
      adcn ++$00                ;add carry from before
6012
      sta ScreenRight_PageLoc ;store as page number where right boundary is
6013
      rts
6014
 
6015
;-------------------------------------------------------------------------------------
6016
 
6017
GameRoutines:
6018
      lda GameEngineSubroutine  ;run routine based on number (a few of these routines are   
6019
      jsr JumpEngine            ;merely placeholders as conditions for other routines)
6020
 
6021
      .dw Entrance_GameTimerSetup
6022
      .dw Vine_AutoClimb
6023
      .dw SideExitPipeEntry
6024
      .dw VerticalPipeEntry
6025
      .dw FlagpoleSlide
6026
      .dw PlayerEndLevel
6027
      .dw PlayerLoseLife
6028
      .dw PlayerEntrance
6029
      .dw PlayerCtrlRoutine
6030
      .dw PlayerChangeSize
6031
      .dw PlayerInjuryBlink
6032
      .dw PlayerDeath
6033
      .dw PlayerFireFlower
6034
 
6035
;-------------------------------------------------------------------------------------
6036
 
6037
PlayerEntrance:
6038
            lda AltEntranceControl    ;check for mode of alternate entry
6039
            cmpn ++$02
6040
            beq EntrMode2             ;if found, branch to enter from pipe or with vine
6041
            ldan ++$00      
6042
            ldy Player_Y_Position     ;if vertical position above a certain
6043
            cpyn ++$30                  ;point, nullify controller bits and continue
6044
              cmpcy
6045
            bcc AutoControlPlayer     ;with player movement code, do not return
6046
            lda PlayerEntranceCtrl    ;check player entry bits from header
6047
            cmpn ++$06
6048
            beq ChkBehPipe            ;if set to 6 or 7, execute pipe intro code
6049
            cmpn ++$07                  ;otherwise branch to normal entry
6050
            bne PlayerRdy
6051
ChkBehPipe: lda Player_SprAttrib      ;check for sprite attributes
6052
         checka
6053
            bne IntroEntr             ;branch if found
6054
            ldan ++$01
6055
            jmp AutoControlPlayer     ;force player to walk to the right
6056
IntroEntr:  jsr EnterSidePipe         ;execute sub to move player to the right
6057
            deci ChangeAreaTimer       ;decrement timer for change of area
6058
            bne ExitEntr              ;branch to exit if not yet expired
6059
            inci DisableIntermediate   ;set flag to skip world and lives display
6060
            jmp NextArea              ;jump to increment to next area and set modes
6061
EntrMode2:  lda JoypadOverride        ;if controller override bits set here,
6062
         checka
6063
            bne VineEntr              ;branch to enter with vine
6064
            ldan ++$ff                  ;otherwise, set value here then execute sub
6065
            jsr MovePlayerYAxis       ;to move player upwards (note $ff = -1)
6066
            lda Player_Y_Position     ;check to see if player is at a specific coordinate
6067
            cmpn ++$91                  ;if player risen to a certain point (this requires pipes
6068
              cmpcy
6069
            bcc PlayerRdy             ;to be at specific height to look/function right) branch
6070
            rts                       ;to the last part, otherwise leave
6071
VineEntr:   lda VineHeight
6072
            cmpn ++$60                  ;check vine height
6073
            bne ExitEntr              ;if vine not yet reached maximum height, branch to leave
6074
            lda Player_Y_Position     ;get player's vertical coordinate
6075
            cmpn ++$99                  ;check player's vertical coordinate against preset value
6076
              cmpcy
6077
            ldyn ++$00                  ;load default values to be written to 
6078
            ldan ++$01                  ;this value moves player to the right off the vine
6079
            bcc OffVine               ;if vertical coordinate LOW  preset value, use defaults
6080
            ldan ++$03
6081
            sta Player_State          ;otherwise set player state to climbing
6082
            iny                       ;increment value in Y
6083
            ldan ++$08                  ;set block in block buffer to cover hole, then 
6084
            sta Block_Buffer_1+$b4    ;use same value to force player to climb
6085
OffVine:    sty DisableCollisionDet   ;set collision detection disable flag
6086
            jsr AutoControlPlayer     ;use contents of A to move player up or right, execute sub
6087
            lda Player_X_Position
6088
            cmpn ++$48                  ;check player's horizontal position
6089
              cmpcy
6090
            bcc ExitEntr              ;if not far enough to the right, branch to leave
6091
PlayerRdy:  ldan ++$08                  ;set routine to be executed by game engine next frame
6092
            sta GameEngineSubroutine
6093
            ldan ++$01                  ;set to face player to the right
6094
            sta PlayerFacingDir
6095
            lsr                       ;init A
6096
            sta AltEntranceControl    ;init mode of entry
6097
            sta DisableCollisionDet   ;init collision detection disable flag
6098
            sta JoypadOverride        ;nullify controller override bits
6099
ExitEntr:   rts                       ;leave!
6100
 
6101
;-------------------------------------------------------------------------------------
6102
;$07 - used to hold upper limit of high byte when player falls down hole
6103
 
6104
AutoControlPlayer:
6105
      sta SavedJoypadBits         ;override controller bits with contents of A if executing here
6106
 
6107
PlayerCtrlRoutine:
6108
            lda GameEngineSubroutine    ;check task here
6109
            cmpn ++$0b                    ;if certain value is set, branch to skip controller bit loading (playerdeath)
6110
            beq SizeChk
6111
            lda AreaType                ;are we in a water type area?    1???
6112
         checka
6113
            bne SaveJoyp                ;if not, branch
6114
            ldy Player_Y_HighPos
6115
            dey                         ;if not in vertical area between
6116
            bne DisJoyp                 ;status bar and bottom, branch
6117
            lda Player_Y_Position
6118
            cmpn ++$d0                    ;if nearing the bottom of the screen or
6119
              cmpcy
6120
            bcc SaveJoyp                ;not in the vertical area between status bar or bottom,
6121
DisJoyp:    ldan ++$00                    ;disable controller bits
6122
            sta SavedJoypadBits
6123
SaveJoyp:   lda SavedJoypadBits         ;otherwise store A and B buttons in $0a
6124
            andn ++%11000000
6125
            sta A_B_Buttons
6126
            lda SavedJoypadBits         ;store left and right buttons in $0c
6127
            andn ++%00000011
6128
            sta Left_Right_Buttons
6129
            lda SavedJoypadBits         ;store up and down buttons in $0b
6130
            andn ++%00001100
6131
            sta Up_Down_Buttons
6132
            andn ++%00000100              ;check for pressing down
6133
            beq SizeChk                 ;if not, branch
6134
            lda Player_State            ;check player's state
6135
         checka
6136
            bne SizeChk                 ;if not on the ground, branch
6137
            ldy Left_Right_Buttons      ;check left and right
6138
         checky
6139
            beq SizeChk                 ;if neither pressed, branch
6140
            ldan ++$00
6141
            sta Left_Right_Buttons      ;if pressing down while on the ground,
6142
            sta Up_Down_Buttons         ;nullify directional bits
6143
SizeChk:    jsr PlayerMovementSubs      ;run movement subroutines
6144
            ldyn ++$01                    ;is player small?
6145
            lda PlayerSize
6146
         checka
6147
            bne ChkMoveDir
6148
            ldyn ++$00                    ;check for if crouching
6149
            lda CrouchingFlag
6150
         checka
6151
            beq ChkMoveDir              ;if not, branch ahead
6152
            ldyn ++$02                    ;if big and crouching, load y with 2
6153
ChkMoveDir: sty Player_BoundBoxCtrl     ;set contents of Y as player's bounding box size control
6154
            ldan ++$01                    ;set moving direction to right by default
6155
            ldy Player_X_Speed          ;check player's horizontal speed
6156
         checky
6157
            beq PlayerSubs              ;if not moving at all horizontally, skip this part
6158
            bpl SetMoveDir              ;if moving to the right, use default moving direction
6159
            asl                         ;otherwise change to move to the left
6160
SetMoveDir: sta Player_MovingDir        ;set moving direction
6161
PlayerSubs: jsr ScrollHandler           ;move the screen if necessary
6162
            jsr GetPlayerOffscreenBits  ;get player's offscreen bits
6163
            jsr RelativePlayerPosition  ;get coordinates relative to the screen
6164
            ldxn ++$00                    ;set offset for player object
6165
            jsr BoundingBoxCore         ;get player's bounding box coordinates
6166
            jsr PlayerBGCollision       ;do collision detection and process
6167
            lda Player_Y_Position
6168
            cmpn ++$40                    ;check to see if player is higher than 64th pixel
6169
              cmpcy
6170
            bcc PlayerHole              ;if so, branch ahead
6171
            lda GameEngineSubroutine
6172
            cmpn ++$05                    ;if running end-of-level routine, branch ahead
6173
            beq PlayerHole
6174
            cmpn ++$07                    ;if running player entrance routine, branch ahead
6175
            beq PlayerHole
6176
            cmpn ++$04                    ;if running routines $00-$03, branch ahead
6177
              cmpcy
6178
            bcc PlayerHole
6179
            lda Player_SprAttrib
6180
            andn ++%11011111              ;otherwise nullify player's
6181
            sta Player_SprAttrib        ;background priority flag
6182
PlayerHole: lda Player_Y_HighPos        ;check player's vertical high byte
6183
            cmpn ++$02                    ;for below the screen
6184
            bmi ExitCtrl                ;branch to leave if not that far down
6185
            ldxn ++$01
6186
            stx ScrollLock              ;set scroll lock
6187
            ldyn ++$04
6188
            sty SCRATCHPAD+$07                     ;set value here
6189
            ldxn ++$00                    ;use X as flag, and clear for cloud level
6190
            ldy GameTimerExpiredFlag    ;check game timer expiration flag
6191
         checky
6192
            bne HoleDie                 ;if set, branch
6193
            ldy CloudTypeOverride       ;check for cloud type override
6194
         checky
6195
            bne ChkHoleX                ;skip to last part if found
6196
HoleDie:    inx                         ;set flag in X for player death
6197
            ldy GameEngineSubroutine
6198
            cpyn ++$0b                    ;check for some other routine running (playerdeath)
6199
            beq ChkHoleX                ;if so, branch ahead
6200
            ldy DeathMusicLoaded        ;check value here
6201
         checky
6202
            bne HoleBottom              ;if already set, branch to next part
6203
            iny
6204
            sty EventMusicQueue         ;otherwise play death music
6205
            sty DeathMusicLoaded        ;and set value here
6206
HoleBottom: ldyn ++$06
6207
            sty SCRATCHPAD+$07                     ;change value here
6208
ChkHoleX:   cmpi SCRATCHPAD+$07                     ;compare vertical high byte with value set here
6209
            bmi ExitCtrl                ;if less, branch to leave
6210
            dex                         ;otherwise decrement flag in X
6211
            bmi CloudExit               ;if flag was clear, branch to set modes and other values
6212
            ldy EventMusicBuffer        ;check to see if music is still playing
6213
         checky
6214
            bne ExitCtrl                ;branch to leave if so
6215
            ldan ++$06                    ;otherwise set to run lose life routine
6216
            sta GameEngineSubroutine    ;on next frame
6217
ExitCtrl:   rts                         ;leave
6218
 
6219
CloudExit:
6220
      ldan ++$00
6221
      sta JoypadOverride      ;clear controller override bits if any are set
6222
      jsr SetEntr             ;do sub to set secondary mode
6223
      inci AltEntranceControl  ;set mode of entry to 3
6224
      rts
6225
 
6226
;-------------------------------------------------------------------------------------
6227
 
6228
Vine_AutoClimb:
6229
           lda Player_Y_HighPos   ;check to see whether player reached position
6230
         checka
6231
           bne AutoClimb          ;above the status bar yet and if so, set modes
6232
           lda Player_Y_Position
6233
           cmpn ++$e4
6234
              cmpcy
6235
           bcc SetEntr
6236
AutoClimb: ldan ++%00001000         ;set controller bits override to up
6237
           sta JoypadOverride
6238
           ldyn ++$03               ;set player state to climbing
6239
           sty Player_State
6240
           jmp AutoControlPlayer
6241
SetEntr:   ldan ++$02               ;set starting position to override
6242
           sta AltEntranceControl
6243
           jmp ChgAreaMode        ;set modes
6244
 
6245
;-------------------------------------------------------------------------------------
6246
 
6247
VerticalPipeEntry:
6248
      ldan ++$01             ;set 1 as movement amount
6249
      jsr MovePlayerYAxis  ;do sub to move player downwards
6250
      jsr ScrollHandler    ;do sub to scroll screen with saved force if necessary
6251
      ldyn ++$00             ;load default mode of entry
6252
      lda WarpZoneControl  ;check warp zone control variable/flag
6253
         checka
6254
      bne ChgAreaPipe      ;if set, branch to use mode 0
6255
      iny
6256
      lda AreaType         ;check for castle level type
6257
      cmpn ++$03
6258
      bne ChgAreaPipe      ;if not castle type level, use mode 1
6259
      iny
6260
      jmp ChgAreaPipe      ;otherwise use mode 2
6261
 
6262
MovePlayerYAxis:
6263
      clc
6264
      adci Player_Y_Position ;add contents of A to player position
6265
      sta Player_Y_Position
6266
      rts
6267
 
6268
;-------------------------------------------------------------------------------------
6269
 
6270
SideExitPipeEntry:
6271
             jsr EnterSidePipe         ;execute sub to move player to the right
6272
             ldyn ++$02
6273
ChgAreaPipe: deci ChangeAreaTimer       ;decrement timer for change of area
6274
             bne ExitCAPipe
6275
             sty AltEntranceControl    ;when timer expires set mode of alternate entry
6276
ChgAreaMode: inci DisableScreenFlag     ;set flag to disable screen output
6277
             ldan ++$00
6278
             sta OperMode_Task         ;set secondary mode of operation
6279
             sta Sprite0HitDetectFlag  ;disable sprite 0 check
6280
ExitCAPipe:  rts                       ;leave
6281
 
6282
EnterSidePipe:
6283
           ldan ++$08               ;set player's horizontal speed
6284
           sta Player_X_Speed
6285
           ldyn ++$01               ;set controller right button by default
6286
           lda Player_X_Position  ;mask out higher nybble of player's
6287
           andn ++%00001111         ;horizontal position
6288
           bne RightPipe
6289
           sta Player_X_Speed     ;if lower nybble = 0, set as horizontal speed
6290
           tay                    ;and nullify controller bit override here
6291
RightPipe: tya                    ;use contents of Y to
6292
           jsr AutoControlPlayer  ;execute player control routine with ctrl bits nulled
6293
           rts
6294
 
6295
;-------------------------------------------------------------------------------------
6296
 
6297
PlayerChangeSize:
6298
             lda TimerControl    ;check master timer control
6299
             cmpn ++$f8            ;for specific moment in time
6300
             bne EndChgSize      ;branch if before or after that point
6301
             jmp InitChangeSize  ;otherwise run code to get growing/shrinking going
6302
EndChgSize:  cmpn ++$c4            ;check again for another specific moment
6303
             bne ExitChgSize     ;and branch to leave if before or after that point
6304
             jsr DonePlayerTask  ;otherwise do sub to init timer control and set routine
6305
ExitChgSize: rts                 ;and then leave
6306
 
6307
;-------------------------------------------------------------------------------------
6308
 
6309
PlayerInjuryBlink:
6310
           lda TimerControl       ;check master timer control
6311
           cmpn ++$f0               ;for specific moment in time
6312
              cmpcy
6313
           bcs ExitBlink          ;branch if before that point
6314
           cmpn ++$c8               ;check again for another specific point
6315
           beq DonePlayerTask     ;branch if at that point, and not before or after
6316
           jmp PlayerCtrlRoutine  ;otherwise run player control routine
6317
ExitBlink: bne ExitBoth           ;do unconditional branch to leave
6318
 
6319
InitChangeSize:
6320
          ldy PlayerChangeSizeFlag  ;if growing/shrinking flag already set
6321
         checky
6322
          bne ExitBoth              ;then branch to leave
6323
          sty PlayerAnimCtrl        ;otherwise initialize player's animation frame control
6324
          inci PlayerChangeSizeFlag  ;set growing/shrinking flag
6325
          lda PlayerSize
6326
          eorn ++$01                  ;invert player's size
6327
          sta PlayerSize
6328
ExitBoth: rts                       ;leave
6329
 
6330
;-------------------------------------------------------------------------------------
6331
;$00 - used in CyclePlayerPalette to store current palette to cycle
6332
 
6333
PlayerDeath:
6334
      lda TimerControl       ;check master timer control
6335
      cmpn ++$f0               ;for specific moment in time
6336
              cmpcy
6337
      bcs ExitDeath          ;branch to leave if before that point
6338
      jmp PlayerCtrlRoutine  ;otherwise run player control routine
6339
 
6340
DonePlayerTask:
6341
      ldan ++$00
6342
      sta TimerControl          ;initialize master timer control to continue timers
6343
      ldan ++$08
6344
      sta GameEngineSubroutine  ;set player control routine to run next frame
6345
      rts                       ;leave
6346
 
6347
PlayerFireFlower:
6348
      lda TimerControl       ;check master timer control
6349
      cmpn ++$c0               ;for specific moment in time
6350
      beq ResetPalFireFlower ;branch if at moment, not before or after
6351
      lda FrameCounter       ;get frame counter
6352
      lsr
6353
      lsr                    ;divide by four to change every four frames
6354
 
6355
CyclePlayerPalette:
180 demige 6356
        if Z80MARIOCYCLECOLOR
6357
        ld hl,(curpalette)
6358
        ld e,12*2
6359
        add hl,de
6360
        ld a,(hl)
6361
        xor 0xf3
6362
        ld (hl),a
6363
        inc hl
6364
        ld (hl),a
6365
        inc hl
6366
        inc hl
6367
        inc hl
6368
        ld a,(hl)
6369
        xor 0xf3
6370
        ld (hl),a
6371
        inc hl
6372
        ld (hl),a
6373
        else
171 demige 6374
      andn ++$03              ;mask out all but d1-d0 (previously d3-d2)
6375
      sta SCRATCHPAD+$00               ;store result here to use as palette bits
6376
      lda Player_SprAttrib  ;get player attributes
6377
      andn ++%11111100        ;save any other bits but palette bits
6378
      orai SCRATCHPAD+$00               ;add palette bits
6379
      sta Player_SprAttrib  ;store as new player attributes
180 demige 6380
        endif
171 demige 6381
      rts                   ;and leave
6382
 
6383
ResetPalFireFlower:
6384
      jsr DonePlayerTask    ;do sub to init timer control and run player control routine
6385
 
6386
ResetPalStar:
180 demige 6387
        if Z80MARIOCYCLECOLOR
6388
        if 1
6389
        jp GetPlayerColors
6390
        else
6391
        ld hl,(curpalette)
6392
        ld e,12*2
6393
        add hl,de
6394
        ld a,(hl)
6395
        xor 0xf3
6396
        ld (hl),a
6397
        inc hl
6398
        ld (hl),a
6399
        inc hl
6400
        inc hl
6401
        inc hl
6402
        ld a,(hl)
6403
        xor 0xf3
6404
        ld (hl),a
6405
        inc hl
6406
        ld (hl),a
6407
        ret
6408
        endif
6409
        else
171 demige 6410
      lda Player_SprAttrib  ;get player attributes
6411
      andn ++%11111100        ;mask out palette bits to force palette 0
6412
      sta Player_SprAttrib  ;store as new player attributes
6413
      rts                   ;and leave
180 demige 6414
        endif
171 demige 6415
 
6416
ExitDeath:
6417
      rts          ;leave from death routine
6418
 
6419
;-------------------------------------------------------------------------------------
6420
 
6421
FlagpoleSlide:
6422
             lda Enemy_ID+5           ;check special use enemy slot
6423
             cmpn ++FlagpoleFlagObject  ;for flagpole flag object
6424
             bne NoFPObj              ;if not found, branch to something residual
6425
             lda FlagpoleSoundQueue   ;load flagpole sound
6426
             sta Square1SoundQueue    ;into square 1's sfx queue
6427
             ldan ++$00
6428
             sta FlagpoleSoundQueue   ;init flagpole sound queue
6429
             ldy Player_Y_Position
6430
             cpyn ++$9e                 ;check to see if player has slid down
6431
              cmpcy
6432
             bcs SlidePlayer          ;far enough, and if so, branch with no controller bits set
6433
             ldan ++$04                 ;otherwise force player to climb down (to slide)
6434
SlidePlayer: jmp AutoControlPlayer    ;jump to player control routine
6435
NoFPObj:     inci GameEngineSubroutine ;increment to next routine (this may
6436
             rts                      ;be residual code)
6437
 
6438
;-------------------------------------------------------------------------------------
6439
 
6440
Hidden1UpCoinAmts:
6441
      .db $15, $23, $16, $1b, $17, $18, $23, $63
6442
 
6443
PlayerEndLevel:
231 alone 6444
        if MUSICONINT ;:       MUSICONINT=0
6445
     ;YIELD
6446
     ;ld b,0
6447
     ;ld d,b
6448
     halt
6449
        ;ld hl,0xffff
6450
        ;ld (EventMusicQueue_noint),hl
6451
        ld hl,SoundEngine
6452
        ld (soundenginepatch),hl
6453
        ld a,0x21
6454
        ld (soundenginecall),a
6455
        endif
171 demige 6456
          ldan ++$01                  ;force player to walk to the right
6457
          jsr AutoControlPlayer
6458
          lda Player_Y_Position     ;check player's vertical position
6459
          cmpn ++$ae
6460
              cmpcy
6461
          bcc ChkStop               ;if player is not yet off the flagpole, skip this part
6462
          lda ScrollLock            ;if scroll lock not set, branch ahead to next part
6463
         checka
6464
          beq ChkStop               ;because we only need to do this part once
6465
          ldan ++EndOfLevelMusic
6466
          sta EventMusicQueue       ;load win level music in event music queue
6467
          ldan ++$00
6468
          sta ScrollLock            ;turn off scroll lock to skip this part later
6469
ChkStop:  lda Player_CollisionBits  ;get player collision bits
6470
          lsr                       ;check for d0 set
6471
          bcs RdyNextA              ;if d0 set, skip to next part
6472
          lda StarFlagTaskControl   ;if star flag task control already set,
6473
         checka
6474
          bne InCastle              ;go ahead with the rest of the code
6475
          inci StarFlagTaskControl   ;otherwise set task control now (this gets ball rolling!)
6476
InCastle: ldan ++%00100000            ;set player's background priority bit to
6477
          sta Player_SprAttrib      ;give illusion of being inside the castle
6478
RdyNextA: lda StarFlagTaskControl
6479
          cmpn ++$05                  ;if star flag task control not yet set
6480
          bne ExitNA                ;beyond last valid task number, branch to leave
6481
          inci LevelNumber           ;increment level number used for game logic
6482
          lda LevelNumber
6483
          cmpn ++$03                  ;check to see if we have yet reached level -4
6484
          bne NextArea              ;and skip this last part here if not
6485
          ldy WorldNumber           ;get world number as offset
6486
          lda CoinTallyFor1Ups      ;check third area coin tally for bonus 1-ups
6487
          cmpy Hidden1UpCoinAmts,y   ;against minimum value, if player has not collected
6488
              cmpcy
6489
          bcc NextArea              ;at least this number of coins, leave flag clear
6490
          inci Hidden1UpFlag         ;otherwise set hidden 1-up box control flag
6491
NextArea: inci AreaNumber            ;increment area number used for address loader
6492
          jsr LoadAreaPointer       ;get new level pointer
6493
          inci FetchNewGameTimerFlag ;set flag to load new game timer
6494
          jsr ChgAreaMode           ;do sub to set secondary mode, disable screen and sprite 0
6495
          sta HalfwayPage           ;reset halfway page to 0 (beginning)
6496
          ldan ++Silence
6497
          sta EventMusicQueue       ;silence music and leave
6498
ExitNA:   rts
6499
 
6500
;-------------------------------------------------------------------------------------
6501
 
6502
PlayerMovementSubs:
6503
           ldan ++$00                  ;set A to init crouch flag by default
6504
           ldy PlayerSize            ;is player small?
6505
         checky
6506
           bne SetCrouch             ;if so, branch
6507
           lda Player_State          ;check state of player
6508
         checka
6509
           bne ProcMove              ;if not on the ground, branch
6510
           lda Up_Down_Buttons       ;load controller bits for up and down
6511
           andn ++%00000100            ;single out bit for down button
6512
SetCrouch: sta CrouchingFlag         ;store value in crouch flag
6513
ProcMove:  jsr PlayerPhysicsSub      ;run sub related to jumping and swimming
6514
           lda PlayerChangeSizeFlag  ;if growing/shrinking flag set,
6515
         checka
6516
           bne NoMoveSub             ;branch to leave
6517
           lda Player_State
6518
           cmpn ++$03                  ;get player state
6519
           beq MoveSubs              ;if climbing, branch ahead, leave timer unset
6520
           ldyn ++$18
6521
           sty ClimbSideTimer        ;otherwise reset timer now
6522
MoveSubs:  jsr JumpEngine
6523
 
6524
      .dw OnGroundStateSub
6525
      .dw JumpSwimSub
6526
      .dw FallingSub
6527
      .dw ClimbingSub
6528
 
6529
NoMoveSub: rts
6530
 
6531
;-------------------------------------------------------------------------------------
6532
;$00 - used by ClimbingSub to store high vertical adder
6533
 
6534
OnGroundStateSub:
6535
         jsr GetPlayerAnimSpeed     ;do a sub to set animation frame timing
6536
         lda Left_Right_Buttons
6537
         checka
6538
         beq GndMove                ;if left/right controller bits not set, skip instruction
6539
         ;jr $ ;     left,right
6540
         sta PlayerFacingDir        ;otherwise set new facing direction
6541
GndMove: jsr ImposeFriction         ;do a sub to impose friction on player's walk/run
6542
         jsr MovePlayerHorizontally ;do another sub to move player horizontally
6543
         sta Player_X_Scroll        ;set returned value as player's movement speed for scroll
6544
         rts
6545
 
6546
;--------------------------------
6547
 
6548
FallingSub:
6549
      lda VerticalForceDown
6550
      sta VerticalForce      ;dump vertical movement force for falling into main one
6551
      jmp LRAir              ;movement force, then skip ahead to process left/right movement
6552
 
6553
;--------------------------------
6554
 
6555
JumpSwimSub:
6556
          ldy Player_Y_Speed         ;if player's vertical speed zero
6557
         checky
6558
          bpl DumpFall               ;or moving downwards, branch to falling
6559
          lda A_B_Buttons
6560
          andn ++A_Button              ;check to see if A button is being pressed
6561
          andi PreviousA_B_Buttons    ;and was pressed in previous frame
6562
          bne ProcSwim               ;if so, branch elsewhere
6563
          lda JumpOrigin_Y_Position  ;get vertical position player jumped from
6564
          secsub
6565
          sbci Player_Y_Position      ;subtract current from original vertical coordinate
6566
          cmpi DiffToHaltJump         ;compare to value set here to see if player is in mid-jump
6567
              cmpcy
6568
          bcc ProcSwim               ;or just starting to jump, if just starting, skip ahead
6569
DumpFall: lda VerticalForceDown      ;otherwise dump falling into main fractional
6570
          sta VerticalForce
6571
ProcSwim: lda SwimmingFlag           ;if swimming flag not set, ;   0???
6572
         checka
6573
          beq LRAir                  ;branch ahead to last part
6574
          jsr GetPlayerAnimSpeed     ;do a sub to get animation frame timing
6575
          lda Player_Y_Position
6576
          cmpn ++$14                   ;check vertical position against preset value
6577
              cmpcy
6578
          bcs LRWater                ;if not yet reached a certain position, branch ahead
6579
          ldan ++$18
6580
          sta VerticalForce          ;otherwise set fractional
6581
LRWater:  lda Left_Right_Buttons     ;check left/right controller bits (check for swimming)
6582
         checka
6583
          beq LRAir                  ;if not pressing any, skip
6584
          sta PlayerFacingDir        ;otherwise set facing direction accordingly
6585
;    FallingSub
6586
LRAir:    lda Left_Right_Buttons     ;check left/right controller bits (check for jumping/falling)
6587
         checka
6588
          beq JSMove                 ;if not pressing any, skip
6589
          jsr ImposeFriction         ;otherwise process horizontal movement
6590
JSMove:   jsr MovePlayerHorizontally ;do a sub to move player horizontally
6591
          sta Player_X_Scroll        ;set player's speed here, to be used for scroll later
6592
          lda GameEngineSubroutine
6593
          cmpn ++$0b                   ;check for specific routine selected (playerdeath)
6594
          bne ExitMov1               ;branch if not set to run
6595
          ldan ++$28
6596
          sta VerticalForce          ;otherwise set fractional
6597
ExitMov1: jmp MovePlayerVertically   ;jump to move player vertically, then leave
6598
 
6599
;--------------------------------
6600
 
6601
ClimbAdderLow:
6602
      .db $0e, $04, $fc, $f2
6603
ClimbAdderHigh:
6604
      .db $00, $00, $ff, $ff
6605
 
6606
ClimbingSub:
6607
             lda Player_YMF_Dummy
6608
             clc                      ;add movement force to dummy variable
6609
             adci Player_Y_MoveForce   ;save with carry
6610
             sta Player_YMF_Dummy
6611
             ldyn ++$00                 ;set default adder here
6612
             lda Player_Y_Speed       ;get player's vertical speed
6613
         checka
6614
             bpl MoveOnVine           ;if not moving upwards, branch
6615
             dey                      ;otherwise set adder to $ff
6616
MoveOnVine:  sty SCRATCHPAD+$00                  ;store adder here
6617
             adci Player_Y_Position    ;add carry to player's vertical position
6618
             sta Player_Y_Position    ;and store to move player up or down
6619
             lda Player_Y_HighPos
6620
             adci SCRATCHPAD+$00                  ;add carry to player's page location
6621
             sta Player_Y_HighPos     ;and store
6622
             lda Left_Right_Buttons   ;compare left/right controller bits
6623
             andi Player_CollisionBits ;to collision flag
6624
             beq InitCSTimer          ;if not set, skip to end
6625
             ldy ClimbSideTimer       ;otherwise check timer 
6626
         checky
6627
             bne ExitCSub             ;if timer not expired, branch to leave
6628
             ldyn ++$18
6629
             sty ClimbSideTimer       ;otherwise set timer now
6630
             ldxn ++$00                 ;set default offset here
6631
             ldy PlayerFacingDir      ;get facing direction
6632
             lsr                      ;move right button controller bit to carry
6633
             bcs ClimbFD              ;if controller right pressed, branch ahead
6634
             inx
6635
             inx                      ;otherwise increment offset by 2 bytes
6636
ClimbFD:     dey                      ;check to see if facing right
6637
             beq CSetFDir             ;if so, branch, do not increment
6638
             inx                      ;otherwise increment by 1 byte
6639
CSetFDir:    lda Player_X_Position
6640
             clc                      ;add or subtract from player's horizontal position
6641
             adcx ClimbAdderLow,x      ;using value here as adder and X as offset
6642
             sta Player_X_Position
6643
             lda Player_PageLoc       ;add or subtract carry or borrow using value here
6644
             adcx ClimbAdderHigh,x     ;from the player's page location
6645
             sta Player_PageLoc
6646
             lda Left_Right_Buttons   ;get left/right controller bits again
6647
             eorn ++%00000011           ;invert them and store them while player
6648
             sta PlayerFacingDir      ;is on vine to face player in opposite direction
6649
ExitCSub:    rts                      ;then leave
6650
InitCSTimer: sta ClimbSideTimer       ;initialize timer here
6651
             rts
6652
 
6653
;-------------------------------------------------------------------------------------
6654
;$00 - used to store offset to friction data
6655
 
6656
JumpMForceData:
6657
      .db $20, $20, $1e, $28, $28, $0d, $04
6658
 
6659
FallMForceData:
6660
      .db $70, $70, $60, $90, $90, $0a, $09
6661
 
6662
PlayerYSpdData:
6663
      .db $fc, $fc, $fc, $fb, $fb, $fe, $ff
6664
 
6665
InitMForceData:
6666
      .db $00, $00, $00, $00, $00, $80, $00
6667
 
6668
MaxLeftXSpdData:
6669
      .db $d8, $e8, $f0
6670
 
6671
MaxRightXSpdData:
6672
      .db $28, $18, $10
6673
      .db $0c ;used for pipe intros
6674
 
6675
FrictionData:
6676
      .db $e4, $98, $d0
6677
 
6678
Climb_Y_SpeedData:
6679
      .db $00, $ff, $01
6680
 
6681
Climb_Y_MForceData:
6682
      .db $00, $20, $ff
6683
 
6684
PlayerPhysicsSub:
6685
           lda Player_State          ;check player state
6686
           cmpn ++$03
6687
           bne CheckForJumping       ;if not climbing, branch
6688
           ldyn ++$00
6689
           lda Up_Down_Buttons       ;get controller bits for up/down
6690
           andi Player_CollisionBits  ;check against player's collision detection bits
6691
           beq ProcClimb             ;if not pressing up or down, branch
6692
           iny
6693
           andn ++%00001000            ;check for pressing up
6694
           bne ProcClimb
6695
           iny
6696
ProcClimb: ldxy Climb_Y_MForceData,y  ;load value here
6697
           stx Player_Y_MoveForce    ;store as vertical movement force
6698
           ldan ++$08                  ;load default animation timing
6699
           ldxy Climb_Y_SpeedData,y   ;load some other value here
6700
           stx Player_Y_Speed        ;store as vertical speed
6701
         checkx
6702
           bmi SetCAnim              ;if climbing down, use default animation timing value
6703
           lsr                       ;otherwise divide timer setting by 2
6704
SetCAnim:  sta PlayerAnimTimerSet    ;store animation timer setting and leave
6705
           rts
6706
 
6707
CheckForJumping:
6708
        lda JumpspringAnimCtrl    ;if jumpspring animating, 
6709
         checka
6710
        bne NoJump                ;skip ahead to something else
6711
        lda A_B_Buttons           ;check for A button press
6712
        andn ++A_Button
6713
        beq NoJump                ;if not, branch to something else
6714
        andi PreviousA_B_Buttons   ;if button not pressed in previous frame, branch
6715
        beq ProcJumping
6716
NoJump: jmp X_Physics             ;otherwise, jump to something else
6717
 
6718
ProcJumping:
6719
           lda Player_State           ;check player state
6720
         checka
6721
           beq InitJS                 ;if on the ground, branch
6722
           lda SwimmingFlag           ;if swimming flag not set, jump to do something else
6723
         checka
6724
           beq NoJump                 ;to prevent midair jumping, otherwise continue
6725
           lda JumpSwimTimer          ;if jump/swim timer nonzero, branch
6726
         checka
6727
           bne InitJS
6728
           lda Player_Y_Speed         ;check player's vertical speed
6729
         checka
6730
           bpl InitJS                 ;if player's vertical speed motionless or down, branch
6731
           jmp X_Physics              ;if timer at zero and player still rising, do not swim
6732
InitJS:    ldan ++$20                   ;set jump/swim timer
6733
           sta JumpSwimTimer
6734
           ldyn ++$00                   ;initialize vertical force and dummy variable
6735
           sty Player_YMF_Dummy
6736
           sty Player_Y_MoveForce
6737
           lda Player_Y_HighPos       ;get vertical high and low bytes of jump origin
6738
           sta JumpOrigin_Y_HighPos   ;and store them next to each other here
6739
           lda Player_Y_Position
6740
           sta JumpOrigin_Y_Position
6741
           ldan ++$01                   ;set player state to jumping/swimming
6742
           sta Player_State
6743
           lda Player_XSpeedAbsolute  ;check value related to walking/running speed
6744
           cmpn ++$09
6745
              cmpcy
6746
           bcc ChkWtr                 ;branch if below certain values, increment Y
6747
           iny                        ;for each amount equal or exceeded
6748
           cmpn ++$10
6749
              cmpcy
6750
           bcc ChkWtr
6751
           iny
6752
           cmpn ++$19
6753
              cmpcy
6754
           bcc ChkWtr
6755
           iny
6756
           cmpn ++$1c
6757
              cmpcy
6758
           bcc ChkWtr                 ;note that for jumping, range is 0-4 for Y
6759
           iny
6760
ChkWtr:    ldan ++$01                   ;set value here (apparently always set to 1)
6761
           sta DiffToHaltJump
6762
           lda SwimmingFlag           ;if swimming flag disabled, branch
6763
         checka
6764
           beq GetYPhy
6765
           ldyn ++$05                   ;otherwise set Y to 5, range is 5-6
6766
           lda Whirlpool_Flag         ;if whirlpool flag not set, branch
6767
         checka
6768
           beq GetYPhy
6769
           iny                        ;otherwise increment to 6
6770
GetYPhy:   lday JumpMForceData,y       ;store appropriate jump/swim
6771
           sta VerticalForce          ;data here
6772
           lday FallMForceData,y
6773
           sta VerticalForceDown
6774
           lday InitMForceData,y
6775
           sta Player_Y_MoveForce
6776
           lday PlayerYSpdData,y
6777
           sta Player_Y_Speed
6778
           lda SwimmingFlag           ;if swimming flag disabled, branch
6779
         checka
6780
           beq PJumpSnd
6781
           ldan ++Sfx_EnemyStomp        ;load swim/goomba stomp sound into
6782
           sta Square1SoundQueue      ;square 1's sfx queue
6783
           lda Player_Y_Position
6784
           cmpn ++$14                   ;check vertical low byte of player position
6785
              cmpcy
6786
           bcs X_Physics              ;if below a certain point, branch
6787
           ldan ++$00                   ;otherwise reset player's vertical speed
6788
           sta Player_Y_Speed         ;and jump to something else to keep player
6789
           jmp X_Physics              ;from swimming above water level
6790
PJumpSnd:  ldan ++Sfx_BigJump           ;load big mario's jump sound by default
6791
           ldy PlayerSize             ;is mario big?
6792
         checky
6793
           beq SJumpSnd
6794
           ldan ++Sfx_SmallJump         ;if not, load small mario's jump sound
6795
SJumpSnd:  sta Square1SoundQueue      ;store appropriate jump sound in square 1 sfx queue
6796
X_Physics: ldyn ++$00
6797
           sty SCRATCHPAD+$00                    ;init value here
6798
           lda Player_State           ;if mario is on the ground, branch
6799
         checka
6800
           beq ProcPRun
6801
           lda Player_XSpeedAbsolute  ;check something that seems to be related
6802
           cmpn ++$19                   ;to mario's speed
6803
              cmpcy
6804
           bcs GetXPhy                ;if => $19 branch here
6805
           bcc ChkRFast               ;if not branch elsewhere
6806
ProcPRun:  iny                        ;if mario on the ground, increment Y
6807
           lda AreaType               ;check area type
6808
         checka
6809
           beq ChkRFast               ;if water type, branch
6810
           dey                        ;decrement Y by default for non-water type area
6811
           lda Left_Right_Buttons     ;get left/right controller bits
6812
           cmpi Player_MovingDir       ;check against moving direction
6813
           bne ChkRFast               ;if controller bits <> moving direction, skip this part
6814
           lda A_B_Buttons            ;check for b button pressed
6815
           andn ++B_Button
6816
           bne SetRTmr                ;if pressed, skip ahead to set timer
6817
           lda RunningTimer           ;check for running timer set
6818
         checka
6819
           bne GetXPhy                ;if set, branch
6820
ChkRFast:  iny                        ;if running timer not set or level type is water, 
6821
           inci SCRATCHPAD+$00                    ;increment Y again and temp variable in memory
6822
           lda RunningSpeed
6823
         checka
6824
           bne FastXSp                ;if running speed set here, branch
6825
           lda Player_XSpeedAbsolute
6826
           cmpn ++$21                   ;otherwise check player's walking/running speed
6827
              cmpcy
6828
           bcc GetXPhy                ;if less than a certain amount, branch ahead
6829
FastXSp:   inci SCRATCHPAD+$00                    ;if running speed set or speed => $21 increment $00
6830
           jmp GetXPhy                ;and jump ahead
6831
SetRTmr:   ldan ++$0a                   ;if b button pressed, set running timer
6832
           sta RunningTimer
6833
GetXPhy:   lday MaxLeftXSpdData,y      ;get maximum speed to the left
6834
           sta MaximumLeftSpeed
6835
           lda GameEngineSubroutine   ;check for specific routine running
6836
           cmpn ++$07                   ;(player entrance)
6837
           bne GetXPhy2               ;if not running, skip and use old value of Y
6838
           ldyn ++$03                   ;otherwise set Y to 3
6839
GetXPhy2:  lday MaxRightXSpdData,y     ;get maximum speed to the right
6840
           sta MaximumRightSpeed
6841
           ldy SCRATCHPAD+$00                    ;get other value in memory
6842
           lday FrictionData,y         ;get value using value in memory as offset
6843
           sta FrictionAdderLow
6844
           ldan ++$00
6845
           sta FrictionAdderHigh      ;init something here
6846
           lda PlayerFacingDir
6847
           cmpi Player_MovingDir       ;check facing direction against moving direction
6848
           beq ExitPhy                ;if the same, branch to leave
6849
           asli FrictionAdderLow       ;otherwise shift d7 of friction adder low into carry
6850
           roli FrictionAdderHigh      ;then rotate carry onto d0 of friction adder high
6851
ExitPhy:   rts                        ;and then leave
6852
 
6853
;-------------------------------------------------------------------------------------
6854
 
6855
PlayerAnimTmrData:
6856
      .db $02, $04, $07
6857
 
6858
GetPlayerAnimSpeed:
6859
            ldyn ++$00                   ;initialize offset in Y
6860
            lda Player_XSpeedAbsolute  ;check player's walking/running speed
6861
            cmpn ++$1c                   ;against preset amount
6862
              cmpcy
6863
            bcs SetRunSpd              ;if greater than a certain amount, branch ahead
6864
            iny                        ;otherwise increment Y
6865
            cmpn ++$0e                   ;compare against lower amount
6866
              cmpcy
6867
            bcs ChkSkid                ;if greater than this but not greater than first, skip increment
6868
            iny                        ;otherwise increment Y again
6869
ChkSkid:    lda SavedJoypadBits        ;get controller bits
6870
            andn ++%01111111             ;mask out A button
6871
            beq SetAnimSpd             ;if no other buttons pressed, branch ahead of all this
6872
            andn ++$03                   ;mask out all others except left and right
6873
            cmpi Player_MovingDir       ;check against moving direction
6874
            bne ProcSkid               ;if left/right controller bits <>  moving direction, branch
6875
            ldan ++$00                   ;otherwise set zero value here
6876
SetRunSpd:  sta RunningSpeed           ;store zero or running speed here
6877
            jmp SetAnimSpd
6878
ProcSkid:   lda Player_XSpeedAbsolute  ;check player's walking/running speed
6879
            cmpn ++$0b                   ;against one last amount
6880
              cmpcy
6881
            bcs SetAnimSpd             ;if greater than this amount, branch
6882
            lda PlayerFacingDir
6883
            sta Player_MovingDir       ;otherwise use facing direction to set moving direction
6884
            ldan ++$00
6885
            sta Player_X_Speed         ;nullify player's horizontal speed
6886
            sta Player_X_MoveForce     ;and dummy variable for player (  X-)
6887
SetAnimSpd: lday PlayerAnimTmrData,y    ;get animation timer setting using Y as offset
6888
            sta PlayerAnimTimerSet
6889
            rts
6890
 
6891
;-------------------------------------------------------------------------------------
6892
 
6893
ImposeFriction:
6894
           andi Player_CollisionBits  ;perform AND between left/right controller bits and collision flag
6895
           cmpn ++$00                  ;then compare to zero (this instruction is redundant)
6896
           bne JoypFrict             ;if any bits set, branch to next part
6897
           lda Player_X_Speed
6898
         checka
6899
           beq SetAbsSpd             ;if player has no horizontal speed, branch ahead to last part
6900
           bpl RghtFrict             ;if player moving to the right, branch to slow
6901
           bmi LeftFrict             ;otherwise logic dictates player moving left, branch to slow
6902
JoypFrict: lsr                       ;put right controller bit into carry
6903
           bcc RghtFrict             ;if left button pressed, carry = 0, thus branch
6904
LeftFrict: lda Player_X_MoveForce    ;load value set here (  X-)
6905
           clc
6906
           adci FrictionAdderLow      ;add to it another value set here (???      !)
6907
           sta Player_X_MoveForce    ;store here (  X-)
6908
           lda Player_X_Speed
6909
           adci FrictionAdderHigh     ;add value plus carry to horizontal speed
6910
           sta Player_X_Speed        ;set as new horizontal speed
6911
           cmpi MaximumRightSpeed     ;compare against maximum value for right movement
6912
           bmi XSpdSign              ;if horizontal speed greater negatively, branch
6913
           lda MaximumRightSpeed     ;otherwise set preset value as horizontal speed
6914
           sta Player_X_Speed        ;thus slowing the player's left movement down
6915
           jmp SetAbsSpd             ;skip to the end
6916
RghtFrict: lda Player_X_MoveForce    ;load value set here (  X-)
6917
           secsub
6918
           sbci FrictionAdderLow      ;subtract from it another value set here (???      !)
6919
           sta Player_X_MoveForce    ;store here (  X-)
6920
           lda Player_X_Speed
6921
           sbci FrictionAdderHigh     ;subtract value plus borrow from horizontal speed
6922
           sta Player_X_Speed        ;set as new horizontal speed
6923
           cmpi MaximumLeftSpeed      ;compare against maximum value for left movement
6924
           bpl XSpdSign              ;if horizontal speed greater positively, branch
6925
           lda MaximumLeftSpeed      ;otherwise set preset value as horizontal speed
6926
           sta Player_X_Speed        ;thus slowing the player's right movement down
6927
XSpdSign:  cmpn ++$00                  ;if player not moving or moving to the right,
6928
           bpl SetAbsSpd             ;branch and leave horizontal speed value unmodified
6929
           eorn ++$ff
6930
           clc                       ;otherwise get two's compliment to get absolute
6931
           adcn ++$01                  ;unsigned walking/running speed
6932
SetAbsSpd: sta Player_XSpeedAbsolute ;store walking/running speed here and leave
6933
           rts
6934
 
6935
;-------------------------------------------------------------------------------------
6936
;$00 - used to store downward movement force in FireballObjCore
6937
;$02 - used to store maximum vertical speed in FireballObjCore
6938
;$07 - used to store pseudorandom bit in BubbleCheck
6939
 
6940
ProcFireball_Bubble:
6941
      lda PlayerStatus           ;check player's status
6942
      cmpn ++$02
6943
              cmpcy
6944
      bcc ProcAirBubbles         ;if not fiery, branch
6945
      lda A_B_Buttons
6946
      andn ++B_Button              ;check for b button pressed
6947
      beq ProcFireballs          ;branch if not pressed
6948
      andi PreviousA_B_Buttons
6949
      bne ProcFireballs          ;if button pressed in previous frame, branch
6950
      lda FireballCounter        ;load fireball counter
6951
      andn ++%00000001             ;get LSB and use as offset for buffer
6952
      tax
6953
      ldax Fireball_State,x       ;load fireball state
6954
         checka
6955
      bne ProcFireballs          ;if not inactive, branch
6956
      ldy Player_Y_HighPos       ;if player too high or too low, branch
6957
      dey
6958
      bne ProcFireballs
6959
      lda CrouchingFlag          ;if player crouching, branch
6960
         checka
6961
      bne ProcFireballs
6962
      lda Player_State           ;if player's state = climbing, branch
6963
      cmpn ++$03
6964
      beq ProcFireballs
6965
      ldan ++Sfx_Fireball          ;play fireball sound effect
6966
      sta Square1SoundQueue
6967
      ldan ++$02                   ;load state
6968
      stax Fireball_State,x
6969
      ldy PlayerAnimTimerSet     ;copy animation frame timer setting
6970
      sty FireballThrowingTimer  ;into fireball throwing timer
6971
      dey
6972
      sty PlayerAnimTimer        ;decrement and store in player's animation timer
6973
      inci FireballCounter        ;increment fireball counter
6974
 
6975
ProcFireballs:
6976
      ldxn ++$00
6977
      jsr FireballObjCore  ;process first fireball object
6978
      ldxn ++$01
6979
      jsr FireballObjCore  ;process second fireball object, then do air bubbles
6980
 
6981
ProcAirBubbles:
6982
          lda AreaType                ;if not water type level, skip the rest of this
6983
         checka
6984
          bne BublExit
6985
          ldxn ++$02                    ;otherwise load counter and use as offset
6986
BublLoop: stx ObjectOffset            ;store offset
6987
          jsr BubbleCheck             ;check timers and coordinates, create air bubble
6988
          jsr RelativeBubblePosition  ;get relative coordinates
6989
          jsr GetBubbleOffscreenBits  ;get offscreen information
6990
          jsr DrawBubble              ;draw the air bubble
6991
          dex
6992
          bpl BublLoop                ;do this until all three are handled
6993
BublExit: rts                         ;then leave
6994
 
6995
FireballXSpdData:
6996
      .db $40, $c0
6997
 
6998
FireballObjCore:
6999
         stx ObjectOffset             ;store offset as current object
7000
         ldax Fireball_State,x         ;check for d7 = 1
7001
         asl
7002
         bcs FireballExplosion        ;if so, branch to get relative coordinates and draw explosion
7003
         ldyx Fireball_State,x         ;if fireball inactive, branch to leave
7004
         checky
7005
         beq NoFBall
7006
         dey                          ;if fireball state set to 1, skip this part and just run it
7007
         beq RunFB
7008
         lda Player_X_Position        ;get player's horizontal position
7009
        or a
7010
         adcn ++$04                     ;add four pixels and store as fireball's horizontal position
7011
        push af
7012
         stax Fireball_X_Position,x
7013
        pop af
7014
         lda Player_PageLoc           ;get player's page location
7015
         adcn ++$00                     ;add carry and store as fireball's page location
7016
         stax Fireball_PageLoc,x
7017
         lda Player_Y_Position        ;get player's vertical position and store
7018
         stax Fireball_Y_Position,x
7019
         ldan ++$01                     ;set high byte of vertical position
7020
         stax Fireball_Y_HighPos,x
7021
         ldy PlayerFacingDir          ;get player's facing direction
7022
         dey                          ;decrement to use as offset here
7023
         lday FireballXSpdData,y       ;set horizontal speed of fireball accordingly
7024
         stax Fireball_X_Speed,x
7025
         ldan ++$04                     ;set vertical speed of fireball
7026
         stax Fireball_Y_Speed,x
7027
         ldan ++$07
7028
         stax Fireball_BoundBoxCtrl,x  ;set bounding box size control for fireball
7029
         decx Fireball_State,x         ;decrement state to 1 to skip this part from now on
7030
RunFB:   txa                          ;add 7 to offset to use
7031
         clc                          ;as fireball offset for next routines
7032
         adcn ++$07
7033
         tax
7034
         ldan ++$50                     ;set downward movement force here
7035
         sta SCRATCHPAD+$00
7036
         ldan ++$03                     ;set maximum speed here
7037
         sta SCRATCHPAD+$02
7038
         ldan ++$00
7039
         jsr ImposeGravity            ;do sub here to impose gravity on fireball and move vertically
7040
         jsr MoveObjectHorizontally   ;do another sub to move it horizontally
7041
         ldx ObjectOffset             ;return fireball offset to X
7042
         jsr RelativeFireballPosition ;get relative coordinates
7043
         jsr GetFireballOffscreenBits ;get offscreen information
7044
         jsr GetFireballBoundBox      ;get bounding box coordinates
7045
         jsr FireballBGCollision      ;do fireball to background collision detection
7046
         lda FBall_OffscreenBits      ;get fireball offscreen bits
7047
         andn ++%11001100               ;mask out certain bits
7048
         bne EraseFB                  ;if any bits still set, branch to kill fireball
7049
         jsr FireballEnemyCollision   ;do fireball to enemy collision detection and deal with collisions
7050
         jmp DrawFireball             ;draw fireball appropriately and leave
7051
EraseFB: ldan ++$00                     ;erase fireball state
7052
         stax Fireball_State,x
7053
NoFBall: rts                          ;leave
7054
 
7055
FireballExplosion:
7056
      jsr RelativeFireballPosition
7057
      jmp DrawExplosion_Fireball
7058
 
7059
BubbleCheck:
7060
      ldax PseudoRandomBitReg+1,x  ;get part of LSFR
7061
      andn ++$01
7062
      sta SCRATCHPAD+$07                     ;store pseudorandom bit here
7063
      ldax Bubble_Y_Position,x     ;get vertical coordinate for air bubble
7064
      cmpn ++$f8                    ;if offscreen coordinate not set,
7065
      bne MoveBubl                ;branch to move air bubble
7066
      lda AirBubbleTimer          ;if air bubble timer not expired,
7067
         checka
7068
      bne ExitBubl                ;branch to leave, otherwise create new air bubble
7069
 
7070
SetupBubble:
7071
          ldyn ++$00                 ;load default value here
7072
          lda PlayerFacingDir      ;get player's facing direction
7073
          lsr                      ;move d0 to carry
7074
          bcc PosBubl              ;branch to use default value if facing left
7075
          ldyn ++$08                 ;otherwise load alternate value here
7076
PosBubl:  tya                      ;use value loaded as adder
7077
          adci Player_X_Position    ;add to player's horizontal position
7078
         push af
7079
          stax Bubble_X_Position,x  ;save as horizontal position for airbubble
7080
         pop af
7081
          lda Player_PageLoc
7082
          adcn ++$00                 ;add carry to player's page location
7083
          stax Bubble_PageLoc,x     ;save as page location for airbubble
7084
          lda Player_Y_Position
7085
          clc                      ;add eight pixels to player's vertical position
7086
          adcn ++$08
7087
          stax Bubble_Y_Position,x  ;save as vertical position for air bubble
7088
          ldan ++$01
7089
          stax Bubble_Y_HighPos,x   ;set vertical high byte for air bubble
7090
          ldy SCRATCHPAD+$07                  ;get pseudorandom bit, use as offset
7091
          lday BubbleTimerData,y    ;get data for air bubble timer
7092
          sta AirBubbleTimer       ;set air bubble timer
7093
MoveBubl: ldy SCRATCHPAD+$07                  ;get pseudorandom bit again, use as offset
7094
          ldax Bubble_YMF_Dummy,x
7095
          secsub                      ;subtract pseudorandom amount from dummy variable
7096
          sbcy Bubble_MForceData,y
7097
               push af
7098
          stax Bubble_YMF_Dummy,x   ;save dummy variable
7099
          ldax Bubble_Y_Position,x
7100
               ld h,a
7101
               pop af
7102
               ld a,h
7103
          sbcn ++$00                 ;subtract borrow from airbubble's vertical coordinate
7104
          cmpn ++$20                 ;if below the status bar,
7105
              cmpcy
7106
          bcs Y_Bubl               ;branch to go ahead and use to move air bubble upwards
7107
          ldan ++$f8                 ;otherwise set offscreen coordinate
7108
Y_Bubl:   stax Bubble_Y_Position,x  ;store as new vertical coordinate for air bubble
7109
ExitBubl: rts                      ;leave
7110
 
7111
Bubble_MForceData:
7112
      .db $ff, $50
7113
 
7114
BubbleTimerData:
7115
      .db $40, $20
7116
 
7117
;-------------------------------------------------------------------------------------
7118
 
7119
RunGameTimer:
7120
           lda OperMode               ;get primary mode of operation
7121
         checka
7122
           beq ExGTimer               ;branch to leave if in title screen mode
7123
           lda GameEngineSubroutine
7124
           cmpn ++$08                   ;if routine number less than eight running,
7125
              cmpcy
7126
           bcc ExGTimer               ;branch to leave
7127
           cmpn ++$0b                   ;if running death routine,
7128
           beq ExGTimer               ;branch to leave
7129
           lda Player_Y_HighPos
7130
           cmpn ++$02                   ;if player below the screen,
7131
              cmpcy
7132
           bcs ExGTimer               ;branch to leave regardless of level type
7133
           lda GameTimerCtrlTimer     ;if game timer control not yet expired,
7134
         checka
7135
           bne ExGTimer               ;branch to leave
7136
           lda GameTimerDisplay
7137
           orai GameTimerDisplay+1     ;otherwise check game timer digits
7138
           orai GameTimerDisplay+2
7139
           beq TimeUpOn               ;if game timer digits at 000, branch to time-up code
7140
           ldy GameTimerDisplay       ;otherwise check first digit
7141
           dey                        ;if first digit not on 1,
7142
           bne ResGTCtrl              ;branch to reset game timer control
7143
           lda GameTimerDisplay+1     ;otherwise check second and third digits
7144
           orai GameTimerDisplay+2
7145
           bne ResGTCtrl              ;if timer not at 100, branch to reset game timer control
7146
           ldan ++TimeRunningOutMusic
7147
           sta EventMusicQueue        ;otherwise load time running out music
7148
ResGTCtrl: ldan ++$18                   ;reset game timer control
7149
           sta GameTimerCtrlTimer
7150
           ldyn ++$23                   ;set offset for last digit
7151
           ldan ++$ff                   ;set value to decrement game timer digit
7152
           sta DigitModifier+5
7153
           jsr DigitsMathRoutine      ;do sub to decrement game timer slowly
7154
           ldan ++$a4                   ;set status nybbles to update game timer display
7155
           jmp PrintStatusBarNumbers  ;do sub to update the display
7156
TimeUpOn:  sta PlayerStatus           ;init player status (note A will always be zero here)
7157
           jsr ForceInjury            ;do sub to kill the player (note player is small here)
7158
           inci GameTimerExpiredFlag   ;set game timer expiration flag
7159
ExGTimer:  rts                        ;leave
7160
 
7161
;-------------------------------------------------------------------------------------
7162
 
7163
WarpZoneObject:
7164
      lda ScrollLock         ;check for scroll lock flag
7165
         checka
7166
      beq ExGTimer           ;branch if not set to leave
7167
      lda Player_Y_Position  ;check to see if player's vertical coordinate has
7168
      andi Player_Y_HighPos   ;same bits set as in vertical high byte (why?)
7169
      bne ExGTimer           ;if so, branch to leave
7170
      sta ScrollLock         ;otherwise nullify scroll lock flag
7171
      inci WarpZoneControl    ;increment warp zone flag to make warp pipes for warp zone
7172
      jmp EraseEnemyObject   ;kill this object
7173
 
7174
;-------------------------------------------------------------------------------------
7175
;$00 - used in WhirlpoolActivate to store whirlpool length / 2, page location of center of whirlpool
7176
;and also to store movement force exerted on player
7177
;$01 - used in ProcessWhirlpools to store page location of right extent of whirlpool
7178
;and in WhirlpoolActivate to store center of whirlpool
7179
;$02 - used in ProcessWhirlpools to store right extent of whirlpool and in
7180
;WhirlpoolActivate to store maximum vertical speed
7181
 
7182
ProcessWhirlpools:
7183
        lda AreaType                ;check for water type level
7184
         checka
7185
        bne ExitWh                  ;branch to leave if not found
7186
        sta Whirlpool_Flag          ;otherwise initialize whirlpool flag
7187
        lda TimerControl            ;if master timer control set,
7188
         checka
7189
        bne ExitWh                  ;branch to leave
7190
        ldyn ++$04                    ;otherwise start with last whirlpool data
7191
WhLoop: lday Whirlpool_LeftExtent,y  ;get left extent of whirlpool
7192
        clc
7193
        adcy Whirlpool_Length,y      ;add length of whirlpool
7194
        sta SCRATCHPAD+$02                     ;store result as right extent here
7195
        ldaykeepcy Whirlpool_PageLoc,y     ;get page location
7196
         checka
7197
        beq NextWh                  ;if none or page 0, branch to get next data
7198
        adcn ++$00                    ;add carry
7199
        sta SCRATCHPAD+$01                     ;store result as page location of right extent here
7200
        lda Player_X_Position       ;get player's horizontal position
7201
        secsub
7202
        sbcy Whirlpool_LeftExtent,y  ;subtract left extent
7203
        lda Player_PageLoc          ;get player's page location
7204
        sbcy Whirlpool_PageLoc,y     ;subtract borrow
7205
        bmi NextWh                  ;if player too far left, branch to get next data
7206
        lda SCRATCHPAD+$02                     ;otherwise get right extent
7207
        secsub
7208
        sbci Player_X_Position       ;subtract player's horizontal coordinate
7209
        lda SCRATCHPAD+$01                     ;get right extent's page location
7210
        sbci Player_PageLoc          ;subtract borrow
7211
        bpl WhirlpoolActivate       ;if player within right extent, branch to whirlpool code
7212
NextWh: dey                         ;move onto next whirlpool data
7213
        bpl WhLoop                  ;do this until all whirlpools are checked
7214
ExitWh: rts                         ;leave
7215
 
7216
WhirlpoolActivate:
7217
        lday Whirlpool_Length,y      ;get length of whirlpool
7218
        lsr                         ;divide by 2
7219
        sta SCRATCHPAD+$00                     ;save here
7220
        lday Whirlpool_LeftExtent,y  ;get left extent of whirlpool
7221
        clc
7222
        adci SCRATCHPAD+$00                     ;add length divided by 2
7223
        sta SCRATCHPAD+$01                     ;save as center of whirlpool
7224
        ldaykeepcy Whirlpool_PageLoc,y     ;get page location
7225
        adcn ++$00                    ;add carry
7226
        sta SCRATCHPAD+$00                     ;save as page location of whirlpool center
7227
        lda FrameCounter            ;get frame counter
7228
        lsr                         ;shift d0 into carry (to run on every other frame)
7229
        bcc WhPull                  ;if d0 not set, branch to last part of code
7230
        lda SCRATCHPAD+$01                     ;get center
7231
        secsub
7232
        sbci Player_X_Position       ;subtract player's horizontal coordinate
7233
        lda SCRATCHPAD+$00                     ;get page location of center
7234
        sbci Player_PageLoc          ;subtract borrow
7235
        bpl LeftWh                  ;if player to the left of center, branch
7236
        lda Player_X_Position       ;otherwise slowly pull player left, towards the center
7237
        secsub
7238
        sbcn ++$01                    ;subtract one pixel
7239
        sta Player_X_Position       ;set player's new horizontal coordinate
7240
        lda Player_PageLoc
7241
        sbcn ++$00                    ;subtract borrow
7242
        jmp SetPWh                  ;jump to set player's new page location
7243
LeftWh: lda Player_CollisionBits    ;get player's collision bits
7244
        lsr                         ;shift d0 into carry
7245
        bcc WhPull                  ;if d0 not set, branch
7246
        lda Player_X_Position       ;otherwise slowly pull player right, towards the center
7247
        clc
7248
        adcn ++$01                    ;add one pixel
7249
        sta Player_X_Position       ;set player's new horizontal coordinate
7250
        lda Player_PageLoc
7251
        adcn ++$00                    ;add carry
7252
SetPWh: sta Player_PageLoc          ;set player's new page location
7253
WhPull: ldan ++$10
7254
        sta SCRATCHPAD+$00                     ;set vertical movement force
7255
        ldan ++$01
7256
        sta Whirlpool_Flag          ;set whirlpool flag to be used later
7257
        sta SCRATCHPAD+$02                     ;also set maximum vertical speed
7258
        lsr
7259
        tax                         ;set X for player offset
7260
        jmp ImposeGravity           ;jump to put whirlpool effect on player vertically, do not return
7261
 
7262
;-------------------------------------------------------------------------------------
7263
 
7264
FlagpoleScoreMods:
7265
      .db $05, $02, $08, $04, $01
7266
 
7267
FlagpoleScoreDigits:
7268
      .db $03, $03, $04, $04, $04
7269
 
7270
FlagpoleRoutine:
7271
           ldxn ++$05                  ;set enemy object offset
7272
           stx ObjectOffset          ;to special use slot
7273
           ldax Enemy_ID,x
7274
           cmpn ++FlagpoleFlagObject   ;if flagpole flag not found,
7275
           bne ExitFlagP             ;branch to leave
7276
           lda GameEngineSubroutine
7277
           cmpn ++$04                  ;if flagpole slide routine not running,
7278
           bne SkipScore             ;branch to near the end of code
7279
           lda Player_State
7280
           cmpn ++$03                  ;if player state not climbing,
7281
           bne SkipScore             ;branch to near the end of code
7282
           ldax Enemy_Y_Position,x    ;check flagpole flag's vertical coordinate
7283
           cmpn ++$aa                  ;if flagpole flag down to a certain point,
7284
              cmpcy
7285
           bcs GiveFPScr             ;branch to end the level
7286
           lda Player_Y_Position     ;check player's vertical coordinate
7287
           cmpn ++$a2                  ;if player down to a certain point,
7288
              cmpcy
7289
           bcs GiveFPScr             ;branch to end the level
7290
           ldax Enemy_YMF_Dummy,x
7291
          or a
7292
           adcn ++$ff                  ;add movement amount to dummy variable
7293
          push af
7294
           stax Enemy_YMF_Dummy,x     ;save dummy variable
7295
           ldax Enemy_Y_Position,x    ;get flag's vertical coordinate
7296
          ld h,a
7297
          pop af
7298
          ld a,h
7299
           adcn ++$01                  ;add 1 plus carry to move flag, and
7300
           stax Enemy_Y_Position,x    ;store vertical coordinate
7301
           lda FlagpoleFNum_YMFDummy
7302
           secsub                       ;subtract movement amount from dummy variable
7303
           sbcn ++$ff
7304
           sta FlagpoleFNum_YMFDummy ;save dummy variable
7305
           lda FlagpoleFNum_Y_Pos
7306
           sbcn ++$01                  ;subtract one plus borrow to move floatey number,
7307
           sta FlagpoleFNum_Y_Pos    ;and store vertical coordinate here
7308
SkipScore: jmp FPGfx                 ;jump to skip ahead and draw flag and floatey number
7309
GiveFPScr: ldy FlagpoleScore         ;get score offset from earlier (when player touched flagpole)
7310
           lday FlagpoleScoreMods,y   ;get amount to award player points
7311
           ldxy FlagpoleScoreDigits,y ;get digit with which to award points
7312
           stax DigitModifier,x       ;store in digit modifier
7313
           jsr AddToScore            ;do sub to award player points depending on height of collision
7314
           ldan ++$05
7315
           sta GameEngineSubroutine  ;set to run end-of-level subroutine on next frame
7316
FPGfx:     jsr GetEnemyOffscreenBits ;get offscreen information
7317
           jsr RelativeEnemyPosition ;get relative coordinates
7318
           jsr FlagpoleGfxHandler    ;draw flagpole flag and floatey number
7319
ExitFlagP: rts
7320
 
7321
;-------------------------------------------------------------------------------------
7322
 
7323
Jumpspring_Y_PosData:
7324
      .db $08, $10, $08, $00
7325
 
7326
JumpspringHandler:
7327
           jsr GetEnemyOffscreenBits   ;get offscreen information
7328
           lda TimerControl            ;check master timer control
7329
         checka
7330
           bne DrawJSpr                ;branch to last section if set
7331
           lda JumpspringAnimCtrl      ;check jumpspring frame control
7332
         checka
7333
           beq DrawJSpr                ;branch to last section if not set
7334
           tay
7335
           dey                         ;subtract one from frame control,
7336
           tya                         ;the only way a poor nmos 6502 can
7337
           andn ++%00000010              ;mask out all but d1, original value still in Y
7338
           bne DownJSpr                ;if set, branch to move player up
7339
           inci Player_Y_Position
7340
           inci Player_Y_Position       ;move player's vertical position down two pixels
7341
           jmp PosJSpr                 ;skip to next part
7342
DownJSpr:  deci Player_Y_Position       ;move player's vertical position up two pixels
7343
           deci Player_Y_Position
7344
PosJSpr:   ldax Jumpspring_FixedYPos,x  ;get permanent vertical position
7345
           clc
7346
           adcy Jumpspring_Y_PosData,y  ;add value using frame control as offset
7347
           stax Enemy_Y_Position,x      ;store as new vertical position
7348
           cpyn ++$01                    ;check frame control offset (second frame is $00)
7349
              cmpcy
7350
           bcc BounceJS                ;if offset not yet at third frame ($01), skip to next part
7351
           lda A_B_Buttons
7352
           andn ++A_Button               ;check saved controller bits for A button press
7353
           beq BounceJS                ;skip to next part if A not pressed
7354
           andi PreviousA_B_Buttons     ;check for A button pressed in previous frame
7355
           bne BounceJS                ;skip to next part if so
7356
           ldan ++$f4
7357
           sta JumpspringForce         ;otherwise write new jumpspring force here
7358
BounceJS:  cpyn ++$03                    ;check frame control offset again
7359
           bne DrawJSpr                ;skip to last part if not yet at fifth frame ($03)
7360
           lda JumpspringForce
7361
           sta Player_Y_Speed          ;store jumpspring force as player's new vertical speed
7362
           ldan ++$00
7363
           sta JumpspringAnimCtrl      ;initialize jumpspring frame control
7364
DrawJSpr:  jsr RelativeEnemyPosition   ;get jumpspring's relative coordinates
7365
           jsr EnemyGfxHandler         ;draw jumpspring
7366
           jsr OffscreenBoundsCheck    ;check to see if we need to kill it
7367
           lda JumpspringAnimCtrl      ;if frame control at zero, don't bother
7368
         checka
7369
           beq ExJSpring               ;trying to animate it, just leave
7370
           lda JumpspringTimer
7371
         checka
7372
           bne ExJSpring               ;if jumpspring timer not expired yet, leave
7373
           ldan ++$04
7374
           sta JumpspringTimer         ;otherwise initialize jumpspring timer
7375
           inci JumpspringAnimCtrl      ;increment frame control to animate jumpspring
7376
ExJSpring: rts                         ;leave
7377
 
7378
;-------------------------------------------------------------------------------------
7379
 
7380
Setup_Vine:
7381
        ldan ++VineObject          ;load identifier for vine object
7382
        stax Enemy_ID,x           ;store in buffer
7383
        ldan ++$01
7384
        stax Enemy_Flag,x         ;set flag for enemy object buffer
7385
        lday Block_PageLoc,y
7386
        stax Enemy_PageLoc,x      ;copy page location from previous object
7387
        lday Block_X_Position,y
7388
        stax Enemy_X_Position,x   ;copy horizontal coordinate from previous object
7389
        lday Block_Y_Position,y
7390
        stax Enemy_Y_Position,x   ;copy vertical coordinate from previous object
7391
        ldy VineFlagOffset       ;load vine flag/offset to next available vine slot
7392
         checky
7393
        bne NextVO               ;if set at all, don't bother to store vertical
7394
        sta VineStart_Y_Position ;otherwise store vertical coordinate here
7395
NextVO: txa                      ;store object offset to next available vine slot
7396
        stay VineObjOffset,y      ;using vine flag as offset
7397
        inci VineFlagOffset       ;increment vine flag offset
7398
        ldan ++Sfx_GrowVine
7399
        sta Square2SoundQueue    ;load vine grow sound
7400
        rts
7401
 
7402
;-------------------------------------------------------------------------------------
7403
;$06-$07 - used as address to block buffer data
7404
;$02 - used as vertical high nybble of block buffer offset
7405
 
7406
VineHeightData:
7407
      .db $30, $60
7408
 
7409
VineObjectHandler:
7410
           cpxn ++$05                  ;check enemy offset for special use slot
7411
           bne ExitVH                ;if not in last slot, branch to leave
7412
           ldy VineFlagOffset
7413
           dey                       ;decrement vine flag in Y, use as offset
7414
           lda VineHeight
7415
           cmpy VineHeightData,y      ;if vine has reached certain height,
7416
           beq RunVSubs              ;branch ahead to skip this part
7417
           lda FrameCounter          ;get frame counter
7418
           lsr                       ;shift d1 into carry
7419
           lsr
7420
           bcc RunVSubs              ;if d1 not set (2 frames every 4) skip this part
7421
           lda Enemy_Y_Position+5
7422
          or a
7423
           sbcn ++$01                  ;subtract vertical position of vine
7424
           sta Enemy_Y_Position+5    ;one pixel every frame it's time
7425
           inci VineHeight            ;increment vine height
7426
RunVSubs:  lda VineHeight            ;if vine still very small,
7427
           cmpn ++$08                  ;branch to leave
7428
              cmpcy
7429
           bcc ExitVH
7430
           jsr RelativeEnemyPosition ;get relative coordinates of vine,
7431
           jsr GetEnemyOffscreenBits ;and any offscreen bits
7432
           ldyn ++$00                  ;initialize offset used in draw vine sub
7433
VDrawLoop: jsr DrawVine              ;draw vine
7434
           iny                       ;increment offset
7435
           cpyi VineFlagOffset        ;if offset in Y and offset here
7436
           bne VDrawLoop             ;do not yet match, loop back to draw more vine
7437
           lda Enemy_OffscreenBits
7438
           andn ++%00001100            ;mask offscreen bits
7439
           beq WrCMTile              ;if none of the saved offscreen bits set, skip ahead
7440
           dey                       ;otherwise decrement Y to get proper offset again
7441
KillVine:  ldxy VineObjOffset,y       ;get enemy object offset for this vine object
7442
           jsr EraseEnemyObject      ;kill this vine object
7443
           dey                       ;decrement Y
7444
           bpl KillVine              ;if any vine objects left, loop back to kill it
7445
           sta VineFlagOffset        ;initialize vine flag/offset
7446
           sta VineHeight            ;initialize vine height
7447
WrCMTile:  lda VineHeight            ;check vine height
7448
           cmpn ++$20                  ;if vine small (less than 32 pixels tall)
7449
              cmpcy
7450
           bcc ExitVH                ;then branch ahead to leave
7451
           ldxn ++$06                  ;set offset in X to last enemy slot
7452
           ldan ++$01                  ;set A to obtain horizontal in $04, but we don't care
7453
           ldyn ++$1b                  ;set Y to offset to get block at ($04, $10) of coordinates
7454
           jsr BlockBufferCollision  ;do a sub to get block buffer address set, return contents
7455
           ldy SCRATCHPAD+$02
7456
           cpyn ++$d0                  ;if vertical high nybble offset beyond extent of
7457
              cmpcy
7458
           bcs ExitVH                ;current block buffer, branch to leave, do not write
7459
           ldayindirect (SCRATCHPAD+$06),y               ;otherwise check contents of block buffer at 
7460
         checka
7461
           bne ExitVH                ;current offset, if not empty, branch to leave
7462
           ldan ++$26
7463
           stayindirect (SCRATCHPAD+$06),y               ;otherwise, write climbing metatile to block buffer
7464
ExitVH:    ldx ObjectOffset          ;get enemy object offset and leave
7465
           rts
7466
 
7467
;-------------------------------------------------------------------------------------
7468
 
7469
CannonBitmasks:
7470
      .db %00001111, %00000111
7471
 
7472
ProcessCannons:
7473
           lda AreaType                ;get area type
7474
         checka
7475
           beq ExCannon                ;if water type area, branch to leave
7476
           ldxn ++$02
7477
ThreeSChk: stx ObjectOffset            ;start at third enemy slot
7478
           ldax Enemy_Flag,x            ;check enemy buffer flag
7479
         checka
7480
           bne Chk_BB                  ;if set, branch to check enemy
7481
           ldax PseudoRandomBitReg+1,x  ;otherwise get part of LSFR
7482
           ldy SecondaryHardMode       ;get secondary hard mode flag, use as offset
7483
           andy CannonBitmasks,y        ;mask out bits of LSFR as decided by flag
7484
           cmpn ++$06                    ;check to see if lower nybble is above certain value
7485
              cmpcy
7486
           bcs Chk_BB                  ;if so, branch to check enemy
7487
           tay                         ;transfer masked contents of LSFR to Y as pseudorandom offset
7488
           lday Cannon_PageLoc,y        ;get page location
7489
         checka
7490
           beq Chk_BB                  ;if not set or on page 0, branch to check enemy
7491
           lday Cannon_Timer,y          ;get cannon timer
7492
         checka
7493
           beq FireCannon              ;if expired, branch to fire cannon
7494
          scf
7495
           sbcn ++$00                    ;otherwise subtract borrow (note carry will always be clear here)
7496
           stay Cannon_Timer,y          ;to count timer down
7497
           jmp Chk_BB                  ;then jump ahead to check enemy
7498
 
7499
FireCannon:
7500
          lda TimerControl           ;if master timer control set,
7501
         checka
7502
          bne Chk_BB                 ;branch to check enemy
7503
          ldan ++$0e                   ;otherwise we start creating one
7504
          stay Cannon_Timer,y         ;first, reset cannon timer
7505
          lday Cannon_PageLoc,y       ;get page location of cannon
7506
          stax Enemy_PageLoc,x        ;save as page location of bullet bill
7507
          lday Cannon_X_Position,y    ;get horizontal coordinate of cannon
7508
          stax Enemy_X_Position,x     ;save as horizontal coordinate of bullet bill
7509
          lday Cannon_Y_Position,y    ;get vertical coordinate of cannon
7510
          secsub
7511
          sbcn ++$08                   ;subtract eight pixels (because enemies are 24 pixels tall)
7512
          stax Enemy_Y_Position,x     ;save as vertical coordinate of bullet bill
7513
          ldan ++$01
7514
          stax Enemy_Y_HighPos,x      ;set vertical high byte of bullet bill
7515
          stax Enemy_Flag,x           ;set buffer flag
7516
          lsr                        ;shift right once to init A
7517
          stax Enemy_State,x          ;then initialize enemy's state
7518
          ldan ++$09
7519
          stax Enemy_BoundBoxCtrl,x   ;set bounding box size control for bullet bill
7520
          ldan ++BulletBill_CannonVar
7521
          stax Enemy_ID,x             ;load identifier for bullet bill (cannon variant)
7522
          jmp Next3Slt               ;move onto next slot
7523
Chk_BB:   ldax Enemy_ID,x             ;check enemy identifier for bullet bill (cannon variant)
7524
          cmpn ++BulletBill_CannonVar
7525
          bne Next3Slt               ;if not found, branch to get next slot
7526
          jsr OffscreenBoundsCheck   ;otherwise, check to see if it went offscreen
7527
          ldax Enemy_Flag,x           ;check enemy buffer flag
7528
         checka
7529
          beq Next3Slt               ;if not set, branch to get next slot
7530
          jsr GetEnemyOffscreenBits  ;otherwise, get offscreen information
7531
          jsr BulletBillHandler      ;then do sub to handle bullet bill
7532
Next3Slt: dex                        ;move onto next slot
7533
          bpl ThreeSChk              ;do this until first three slots are checked
7534
ExCannon: rts                        ;then leave
7535
 
7536
;--------------------------------
7537
 
7538
BulletBillXSpdData:
7539
      .db $18, $e8
7540
 
7541
BulletBillHandler:
7542
           lda TimerControl          ;if master timer control set,
7543
         checka
7544
           bne RunBBSubs             ;branch to run subroutines except movement sub
7545
           ldax Enemy_State,x
7546
         checka
7547
           bne ChkDSte               ;if bullet bill's state set, branch to check defeated state
7548
           lda Enemy_OffscreenBits   ;otherwise load offscreen bits
7549
           andn ++%00001100            ;mask out bits
7550
           cmpn ++%00001100            ;check to see if all bits are set
7551
           beq KillBB                ;if so, branch to kill this object
7552
           ldyn ++$01                  ;set to move right by default
7553
           jsr PlayerEnemyDiff       ;get horizontal difference between player and bullet bill
7554
           bmi SetupBB               ;if enemy to the left of player, branch
7555
           iny                       ;otherwise increment to move left
7556
SetupBB:  
7557
         push af
7558
           styx Enemy_MovingDir,x     ;set bullet bill's moving direction
7559
           dey                       ;decrement to use as offset
7560
           lday BulletBillXSpdData,y  ;get horizontal speed based on moving direction
7561
           stax Enemy_X_Speed,x       ;and store it
7562
           lda SCRATCHPAD+$00                   ;get horizontal difference
7563
         ld h,a
7564
         pop af
7565
         ld a,h
7566
           adcn ++$28                  ;add 40 pixels
7567
           cmpn ++$50                  ;if less than a certain amount, player is too close
7568
              cmpcy
7569
           bcc KillBB                ;to cannon either on left or right side, thus branch
7570
           ldan ++$01
7571
           stax Enemy_State,x         ;otherwise set bullet bill's state
7572
           ldan ++$0a
7573
           stax EnemyFrameTimer,x     ;set enemy frame timer
7574
           ldan ++Sfx_Blast
7575
           sta Square2SoundQueue     ;play fireworks/gunfire sound
7576
ChkDSte:   ldax Enemy_State,x         ;check enemy state for d5 set
7577
           andn ++%00100000
7578
           beq BBFly                 ;if not set, skip to move horizontally
7579
           jsr MoveD_EnemyVertically ;otherwise do sub to move bullet bill vertically
7580
BBFly:     jsr MoveEnemyHorizontally ;do sub to move bullet bill horizontally
7581
RunBBSubs: jsr GetEnemyOffscreenBits ;get offscreen information
7582
           jsr RelativeEnemyPosition ;get relative coordinates
7583
           jsr GetEnemyBoundBox      ;get bounding box coordinates
7584
           jsr PlayerEnemyCollision  ;handle player to enemy collisions
7585
           jmp EnemyGfxHandler       ;draw the bullet bill and leave
7586
KillBB:    jsr EraseEnemyObject      ;kill bullet bill and leave
7587
           rts
7588
 
7589
;-------------------------------------------------------------------------------------
7590
 
7591
HammerEnemyOfsData:
7592
      .db $04, $04, $04, $05, $05, $05
7593
      .db $06, $06, $06
7594
 
7595
HammerXSpdData:
7596
      .db $10, $f0
7597
 
7598
SpawnHammerObj:
7599
          lda PseudoRandomBitReg+1 ;get pseudorandom bits from
7600
          andn ++%00000111           ;second part of LSFR
7601
          bne SetMOfs              ;if any bits are set, branch and use as offset
7602
          lda PseudoRandomBitReg+1
7603
          andn ++%00001000           ;get d3 from same part of LSFR
7604
SetMOfs:  tay                      ;use either d3 or d2-d0 for offset here
7605
          lday Misc_State,y         ;if any values loaded in
7606
         checka
7607
          bne NoHammer             ;$2a-$32 where offset is then leave with carry clear
7608
          ldxy HammerEnemyOfsData,y ;get offset of enemy slot to check using Y as offset
7609
          ldax Enemy_Flag,x         ;check enemy buffer flag at offset
7610
         checka
7611
          bne NoHammer             ;if buffer flag set, branch to leave with carry clear
7612
          ldx ObjectOffset         ;get original enemy object offset
7613
          txa
7614
          stay HammerEnemyOffset,y  ;save here
7615
          ldan ++$90
7616
          stay Misc_State,y         ;save hammer's state here
7617
          ldan ++$07
7618
          stay Misc_BoundBoxCtrl,y  ;set something else entirely, here
7619
          sec                      ;return with carry set
7620
          rts
7621
NoHammer: ldx ObjectOffset         ;get original enemy object offset
7622
          clc                      ;return with carry clear
7623
          rts
7624
 
7625
;--------------------------------
7626
;$00 - used to set downward force
7627
;$01 - used to set upward force (residual)
7628
;$02 - used to set maximum speed
7629
 
7630
ProcHammerObj:
7631
          lda TimerControl           ;if master timer control set
7632
         checka
7633
          bne RunHSubs               ;skip all of this code and go to last subs at the end
7634
          ldax Misc_State,x           ;otherwise get hammer's state
7635
          andn ++%01111111             ;mask out d7
7636
          ldyx HammerEnemyOffset,x    ;get enemy object offset that spawned this hammer
7637
          cmpn ++$02                   ;check hammer's state
7638
              cmpcy
7639
          beq SetHSpd                ;if currently at 2, branch
7640
          bcs SetHPos                ;if greater than 2, branch elsewhere
7641
          txa
7642
          clc                        ;add 13 bytes to use
7643
          adcn ++$0d                   ;proper misc object
7644
          tax                        ;return offset to X
7645
          ldan ++$10
7646
          sta SCRATCHPAD+$00                    ;set downward movement force
7647
          ldan ++$0f
7648
          sta SCRATCHPAD+$01                    ;set upward movement force (not used)
7649
          ldan ++$04
7650
          sta SCRATCHPAD+$02                    ;set maximum vertical speed
7651
          ldan ++$00                   ;set A to impose gravity on hammer
7652
          jsr ImposeGravity          ;do sub to impose gravity on hammer and move vertically
7653
          jsr MoveObjectHorizontally ;do sub to move it horizontally
7654
          ldx ObjectOffset           ;get original misc object offset
7655
          jmp RunAllH                ;branch to essential subroutines
7656
SetHSpd:  ldan ++$fe
7657
          stax Misc_Y_Speed,x         ;set hammer's vertical speed
7658
          lday Enemy_State,y          ;get enemy object state
7659
          andn ++%11110111             ;mask out d3
7660
          stay Enemy_State,y          ;store new state
7661
          ldxy Enemy_MovingDir,y      ;get enemy's moving direction
7662
          dex                        ;decrement to use as offset
7663
          ldax HammerXSpdData,x       ;get proper speed to use based on moving direction
7664
          ldx ObjectOffset           ;reobtain hammer's buffer offset
7665
          stax Misc_X_Speed,x         ;set hammer's horizontal speed
7666
SetHPos:  decx Misc_State,x           ;decrement hammer's state
7667
          lday Enemy_X_Position,y     ;get enemy's horizontal position
7668
          clc
7669
          adcn ++$02                   ;set position 2 pixels to the right
7670
         push af
7671
          stax Misc_X_Position,x      ;store as hammer's horizontal position
7672
          lday Enemy_PageLoc,y        ;get enemy's page location
7673
         ld h,a
7674
         pop af
7675
         ld a,h
7676
          adcn ++$00                   ;add carry
7677
          stax Misc_PageLoc,x         ;store as hammer's page location
7678
          lday Enemy_Y_Position,y     ;get enemy's vertical position
7679
          secsub
7680
          sbcn ++$0a                   ;move position 10 pixels upward
7681
          stax Misc_Y_Position,x      ;store as hammer's vertical position
7682
          ldan ++$01
7683
          stax Misc_Y_HighPos,x       ;set hammer's vertical high byte
7684
         checka
7685
          bne RunHSubs               ;unconditional branch to skip first routine
7686
RunAllH:  jsr PlayerHammerCollision  ;handle collisions
7687
RunHSubs: jsr GetMiscOffscreenBits   ;get offscreen information
7688
          jsr RelativeMiscPosition   ;get relative coordinates
7689
          jsr GetMiscBoundBox        ;get bounding box coordinates
7690
          jsr DrawHammer             ;draw the hammer
7691
          rts                        ;and we are done here
7692
 
7693
;-------------------------------------------------------------------------------------
7694
;$02 - used to store vertical high nybble offset from block buffer routine
7695
;$06 - used to store low byte of block buffer address
7696
 
7697
CoinBlock:
7698
      jsr FindEmptyMiscSlot   ;set offset for empty or last misc object buffer slot
7699
;CY = 1(no subtract borrow)???
7700
      ldax Block_PageLoc,x     ;get page location of block object
7701
      stay Misc_PageLoc,y      ;store as page location of misc object
7702
      ldax Block_X_Position,x  ;get horizontal coordinate of block object
7703
      oran ++$05                ;add 5 pixels
7704
      stay Misc_X_Position,y   ;store as horizontal coordinate of misc object
7705
      ldax Block_Y_Position,x  ;get vertical coordinate of block object
7706
     or a ;???
7707
      sbcn ++$10                ;subtract 16 pixels
7708
      stay Misc_Y_Position,y   ;store as vertical coordinate of misc object
7709
      jmp JCoinC              ;jump to rest of code as applies to this misc object
7710
 
7711
SetupJumpCoin:
7712
        jsr FindEmptyMiscSlot  ;set offset for empty or last misc object buffer slot
7713
        ldax Block_PageLoc2,x   ;get page location saved earlier
7714
        stay Misc_PageLoc,y     ;and save as page location for misc object
7715
        lda SCRATCHPAD+$06                ;get low byte of block buffer offset
7716
        asl
7717
        asl                    ;multiply by 16 to use lower nybble
7718
        asl
7719
        asl
7720
       push af
7721
        oran ++$05               ;add five pixels
7722
        stay Misc_X_Position,y  ;save as horizontal coordinate for misc object
7723
        lda SCRATCHPAD+$02                ;get vertical high nybble offset from earlier
7724
       ld h,a
7725
       pop af
7726
       ld a,h
7727
        adcn ++$20               ;add 32 pixels for the status bar
7728
        stay Misc_Y_Position,y  ;store as vertical coordinate
7729
JCoinC: ldan ++$fb
7730
        stay Misc_Y_Speed,y     ;set vertical speed
7731
        ldan ++$01
7732
        stay Misc_Y_HighPos,y   ;set vertical high byte
7733
        stay Misc_State,y       ;set state for misc object
7734
        sta Square2SoundQueue  ;load coin grab sound
7735
        stx ObjectOffset       ;store current control bit as misc object offset 
7736
        jsr GiveOneCoin        ;update coin tally on the screen and coin amount variable
7737
        inci CoinTallyFor1Ups   ;increment coin tally used to activate 1-up block flag
7738
        rts
7739
 
7740
FindEmptyMiscSlot:
7741
           ldyn ++$08                ;start at end of misc objects buffer
7742
FMiscLoop: lday Misc_State,y        ;get misc object state
7743
         checka
7744
           beq UseMiscS            ;branch if none found to use current offset
7745
           dey                     ;decrement offset
7746
           cpyn ++$05                ;do this for three slots
7747
           bne FMiscLoop           ;do this until all slots are checked
7748
           ldyn ++$08                ;if no empty slots found, use last slot
7749
UseMiscS:  sty JumpCoinMiscOffset  ;store offset of misc object buffer here (residual)
7750
           rts
7751
 
7752
;-------------------------------------------------------------------------------------
7753
 
7754
MiscObjectsCore:
7755
          ldxn ++$08          ;set at end of misc object buffer
7756
MiscLoop: stx ObjectOffset  ;store misc object offset here
7757
          ldax Misc_State,x  ;check misc object state
7758
         checka
7759
          beq MiscLoopBack  ;branch to check next slot
7760
          asl               ;otherwise shift d7 into carry
7761
          bcc ProcJumpCoin  ;if d7 not set, jumping coin, thus skip to rest of code here
7762
          jsr ProcHammerObj ;otherwise go to process hammer,
7763
          jmp MiscLoopBack  ;then check next slot
7764
 
7765
;--------------------------------
7766
;$00 - used to set downward force
7767
;$01 - used to set upward force (residual)
7768
;$02 - used to set maximum speed
7769
 
7770
ProcJumpCoin:
7771
           ldyx Misc_State,x          ;check misc object state
7772
           dey                       ;decrement to see if it's set to 1
7773
           beq JCoinRun              ;if so, branch to handle jumping coin
7774
           incx Misc_State,x          ;otherwise increment state to either start off or as timer
7775
           ldax Misc_X_Position,x     ;get horizontal coordinate for misc object
7776
           clc                       ;whether its jumping coin (state 0 only) or floatey number
7777
           adci ScrollAmount          ;add current scroll speed
7778
          push af
7779
           stax Misc_X_Position,x     ;store as new horizontal coordinate
7780
           ldax Misc_PageLoc,x        ;get page location
7781
          ld h,a
7782
          pop af
7783
          ld a,h
7784
           adcn ++$00                  ;add carry
7785
           stax Misc_PageLoc,x        ;store as new page location
7786
           ldax Misc_State,x
7787
           cmpn ++$30                  ;check state of object for preset value
7788
           bne RunJCSubs             ;if not yet reached, branch to subroutines
7789
           ldan ++$00
7790
           stax Misc_State,x          ;otherwise nullify object state
7791
           jmp MiscLoopBack          ;and move onto next slot
7792
JCoinRun:  txa            
7793
           clc                       ;add 13 bytes to offset for next subroutine
7794
           adcn ++$0d
7795
           tax
7796
           ldan ++$50                  ;set downward movement amount
7797
           sta SCRATCHPAD+$00
7798
           ldan ++$06                  ;set maximum vertical speed
7799
           sta SCRATCHPAD+$02
7800
           lsr                       ;divide by 2 and set
7801
           sta SCRATCHPAD+$01                   ;as upward movement amount (apparently residual)
7802
           ldan ++$00                  ;set A to impose gravity on jumping coin
7803
           jsr ImposeGravity         ;do sub to move coin vertically and impose gravity on it
7804
           ldx ObjectOffset          ;get original misc object offset
7805
           ldax Misc_Y_Speed,x        ;check vertical speed
7806
           cmpn ++$05
7807
           bne RunJCSubs             ;if not moving downward fast enough, keep state as-is
7808
           incx Misc_State,x          ;otherwise increment state to change to floatey number
7809
RunJCSubs: jsr RelativeMiscPosition  ;get relative coordinates
7810
           jsr GetMiscOffscreenBits  ;get offscreen information
7811
           jsr GetMiscBoundBox       ;get bounding box coordinates (why?)
7812
           jsr JCoinGfxHandler       ;draw the coin or floatey number
7813
 
7814
MiscLoopBack:
7815
           dex                       ;decrement misc object offset
7816
           bpl MiscLoop              ;loop back until all misc objects handled
7817
           rts                       ;then leave
7818
 
7819
;-------------------------------------------------------------------------------------
7820
 
7821
CoinTallyOffsets:
7822
      .db $17, $1d
7823
 
7824
ScoreOffsets:
7825
      .db $0b, $11
7826
 
7827
StatusBarNybbles:
7828
      .db $02, $13
7829
 
7830
GiveOneCoin:
7831
      ldan ++$01               ;set digit modifier to add 1 coin
7832
      sta DigitModifier+5    ;to the current player's coin tally
7833
      ldx CurrentPlayer      ;get current player on the screen
7834
      ldyx CoinTallyOffsets,x ;get offset for player's coin tally
7835
      jsr DigitsMathRoutine  ;update the coin tally
7836
      inci CoinTally          ;increment onscreen player's coin amount
7837
      lda CoinTally
7838
      cmpn ++100               ;does player have 100 coins yet?
7839
      bne CoinPoints         ;if not, skip all of this
7840
      ldan ++$00
7841
      sta CoinTally          ;otherwise, reinitialize coin amount
7842
      inci NumberofLives      ;give the player an extra life
7843
      ldan ++Sfx_ExtraLife
7844
      sta Square2SoundQueue  ;play 1-up sound
7845
 
7846
CoinPoints:
7847
      ldan ++$02               ;set digit modifier to award
7848
      sta DigitModifier+4    ;200 points to the player
7849
 
7850
AddToScore:
7851
      ldx CurrentPlayer      ;get current player
7852
      ldyx ScoreOffsets,x     ;get offset for player's score
7853
      jsr DigitsMathRoutine  ;update the score internally with value in digit modifier
7854
 
7855
GetSBNybbles:
7856
      ldy CurrentPlayer      ;get current player
7857
      lday StatusBarNybbles,y ;get nybbles based on player, use to update score and coins
7858
 
7859
UpdateNumber:
7860
        jsr PrintStatusBarNumbers ;print status bar numbers based on nybbles, whatever they be
7861
        ldy VRAM_Buffer1_Offset  
7862
        lday VRAM_Buffer1-6,y      ;check highest digit of score
7863
         checka
7864
        bne NoZSup                ;if zero, overwrite with space tile for zero suppression
7865
        ldan ++$24
7866
        stay VRAM_Buffer1-6,y
7867
NoZSup: ldx ObjectOffset          ;get enemy object buffer offset
7868
        rts
7869
 
7870
;-------------------------------------------------------------------------------------
7871
 
7872
SetupPowerUp:
7873
           ;jr $
7874
           ldan ++PowerUpObject        ;load power-up identifier into
7875
           sta Enemy_ID+5            ;special use slot of enemy object buffer
7876
           ldax Block_PageLoc,x       ;store page location of block object
7877
           sta Enemy_PageLoc+5       ;as page location of power-up object
7878
           ldax Block_X_Position,x    ;store horizontal coordinate of block object
7879
           sta Enemy_X_Position+5    ;as horizontal coordinate of power-up object
7880
           ldan ++$01
7881
           sta Enemy_Y_HighPos+5     ;set vertical high byte of power-up object
7882
           ldax Block_Y_Position,x    ;get vertical coordinate of block object
7883
           secsub
7884
           sbcn ++$08                  ;subtract 8 pixels
7885
           sta Enemy_Y_Position+5    ;and use as vertical coordinate of power-up object
7886
PwrUpJmp:  ldan ++$01                  ;this is a residual jump point in enemy object jump table
7887
           sta Enemy_State+5         ;set power-up object's state
7888
           sta Enemy_Flag+5          ;set buffer flag
7889
           ldan ++$03
7890
           sta Enemy_BoundBoxCtrl+5  ;set bounding box size control for power-up object
7891
           lda PowerUpType
7892
           cmpn ++$02                  ;check currently loaded power-up type
7893
              cmpcy
7894
           bcs PutBehind             ;if star or 1-up, branch ahead
7895
           lda PlayerStatus          ;otherwise check player's current status
7896
           cmpn ++$02
7897
              cmpcy
7898
           bcc StrType               ;if player not fiery (<2), use status as power-up type
7899
           ;jr $
7900
           lsr                       ;otherwise shift right to force fire flower type
7901
StrType:   sta PowerUpType           ;store type here
7902
PutBehind: ldan ++%00100000
7903
           sta Enemy_SprAttrib+5     ;set background priority bit
7904
           ldan ++Sfx_GrowPowerUp
7905
           sta Square2SoundQueue     ;load power-up reveal sound and leave
7906
           rts
7907
 
7908
;-------------------------------------------------------------------------------------
7909
 
7910
PowerUpObjHandler:
7911
        ;jr $
7912
         ldxn ++$05                   ;set object offset for last slot in enemy object buffer
7913
         stx ObjectOffset
7914
         lda Enemy_State+5          ;check power-up object's state
7915
         checka
7916
         beq ExitPUp                ;if not set, branch to leave
7917
         asl                        ;shift to check if d7 was set in object state
7918
         bcc GrowThePowerUp         ;if not set, branch ahead to skip this part
7919
         lda TimerControl           ;if master timer control set,
7920
         checka
7921
         bne RunPUSubs              ;branch ahead to enemy object routines
7922
         lda PowerUpType            ;check power-up type
7923
         checka
7924
         beq ShroomM                ;if normal mushroom, branch ahead to move it
7925
         cmpn ++$03
7926
         beq ShroomM                ;if 1-up mushroom, branch ahead to move it
7927
         cmpn ++$02
7928
         bne RunPUSubs              ;if not star, branch elsewhere to skip movement
7929
         jsr MoveJumpingEnemy       ;otherwise impose gravity on star power-up and make it jump
7930
         jsr EnemyJump              ;note that green paratroopa shares the same code here 
7931
         jmp RunPUSubs              ;then jump to other power-up subroutines
7932
ShroomM: jsr MoveNormalEnemy        ;do sub to make mushrooms move
7933
         jsr EnemyToBGCollisionDet  ;deal with collisions
7934
         jmp RunPUSubs              ;run the other subroutines
7935
 
7936
GrowThePowerUp:
7937
           lda FrameCounter           ;get frame counter
7938
           andn ++$03                   ;mask out all but 2 LSB
7939
           bne ChkPUSte               ;if any bits set here, branch
7940
           deci Enemy_Y_Position+5     ;otherwise decrement vertical coordinate slowly
7941
           lda Enemy_State+5          ;load power-up object state
7942
           inci Enemy_State+5          ;increment state for next frame (to make power-up rise)
7943
           cmpn ++$11                   ;if power-up object state not yet past 16th pixel,
7944
              cmpcy
7945
           bcc ChkPUSte               ;branch ahead to last part here
7946
           ldan ++$10
7947
           stax Enemy_X_Speed,x        ;otherwise set horizontal speed
7948
           ldan ++%10000000
7949
           sta Enemy_State+5          ;and then set d7 in power-up object's state
7950
           asl                        ;shift once to init A
7951
           sta Enemy_SprAttrib+5      ;initialize background priority bit set here
7952
           rol                        ;rotate A to set right moving direction
7953
           stax Enemy_MovingDir,x      ;set moving direction
7954
ChkPUSte:  lda Enemy_State+5          ;check power-up object's state
7955
           cmpn ++$06                   ;for if power-up has risen enough
7956
              cmpcy
7957
           bcc ExitPUp                ;if not, don't even bother running these routines
7958
RunPUSubs: jsr RelativeEnemyPosition  ;get coordinates relative to screen
7959
           jsr GetEnemyOffscreenBits  ;get offscreen bits
7960
           jsr GetEnemyBoundBox       ;get bounding box coordinates
7961
           jsr DrawPowerUp            ;draw the power-up object
7962
           jsr PlayerEnemyCollision   ;check for collision with player
7963
           jsr OffscreenBoundsCheck   ;check to see if it went offscreen
7964
ExitPUp:   rts                        ;and we're done
7965
 
7966
;-------------------------------------------------------------------------------------
7967
;These apply to all routines in this section unless otherwise noted:
7968
;$00 - used to store metatile from block buffer routine
7969
;$02 - used to store vertical high nybble offset from block buffer routine
7970
;$05 - used to store metatile stored in A at beginning of PlayerHeadCollision
7971
;$06-$07 - used as block buffer address indirect
7972
 
7973
BlockYPosAdderData:
7974
      .db $04, $12
7975
 
7976
PlayerHeadCollision:
7977
           pha                      ;store metatile number to stack
7978
           ldan ++$11                 ;load unbreakable block object state by default
7979
           ldx SprDataOffset_Ctrl   ;load offset control bit here
7980
           ldy PlayerSize           ;check player's size
7981
         checky
7982
           bne DBlockSte            ;if small, branch
7983
           ldan ++$12                 ;otherwise load breakable block object state
7984
DBlockSte: stax Block_State,x        ;store into block object buffer
7985
           jsr DestroyBlockMetatile ;store blank metatile in vram buffer to write to name table
7986
           ldx SprDataOffset_Ctrl   ;load offset control bit
7987
           lda SCRATCHPAD+$02                  ;get vertical high nybble offset used in block buffer routine
7988
           stax Block_Orig_YPos,x    ;set as vertical coordinate for block object
7989
           tay
7990
           lda SCRATCHPAD+$06                  ;get low byte of block buffer address used in same routine
7991
           stax Block_BBuf_Low,x     ;save as offset here to be used later
7992
           ldayindirect (SCRATCHPAD+$06),y              ;get contents of block buffer at old address at $06, $07
7993
           jsr BlockBumpedChk       ;do a sub to check which block player bumped head on
7994
           sta SCRATCHPAD+$00                  ;store metatile here
7995
           ldy PlayerSize           ;check player's size
7996
         checky
7997
           bne ChkBrick             ;if small, use metatile itself as contents of A
7998
           tya                      ;otherwise init A (note: big = 0)
7999
ChkBrick:  bcc PutMTileB            ;if no match was found in previous sub, skip ahead
8000
        ;jr $ ; ,    
8001
           ldyn ++$11                 ;otherwise load unbreakable state into block object buffer
8002
           styx Block_State,x        ;note this applies to both player sizes
8003
           ldan ++$c4                 ;load empty block metatile into A for now
8004
           ldy SCRATCHPAD+$00                  ;get metatile from before
8005
           cpyn ++$58                 ;is it brick with coins (with line)?
8006
           beq StartBTmr            ;if so, branch
8007
           cpyn ++$5d                 ;is it brick with coins (without line)?
8008
           bne PutMTileB            ;if not, branch ahead to store empty block metatile
8009
StartBTmr: lda BrickCoinTimerFlag   ;check brick coin timer flag
8010
         checka
8011
           bne ContBTmr             ;if set, timer expired or counting down, thus branch
8012
           ldan ++$0b
8013
           sta BrickCoinTimer       ;if not set, set brick coin timer
8014
           inci BrickCoinTimerFlag   ;and set flag linked to it
8015
ContBTmr:  lda BrickCoinTimer       ;check brick coin timer
8016
         checka
8017
           bne PutOldMT             ;if not yet expired, branch to use current metatile
8018
           ldyn ++$c4                 ;otherwise use empty block metatile
8019
PutOldMT:  tya                      ;put metatile into A
8020
PutMTileB: stax Block_Metatile,x     ;store whatever metatile be appropriate here
8021
           jsr InitBlock_XY_Pos     ;get block object horizontal coordinates saved
8022
           ldy SCRATCHPAD+$02                  ;get vertical high nybble offset
8023
           ldan ++$23
8024
           stayindirect (SCRATCHPAD+$06),y              ;write blank metatile $23 to block buffer
8025
           ldan ++$10
8026
           sta BlockBounceTimer     ;set block bounce timer
8027
           pla                      ;pull original metatile from stack
8028
           sta SCRATCHPAD+$05                  ;and save here
8029
           ldyn ++$00                 ;set default offset
8030
           lda CrouchingFlag        ;is player crouching?
8031
         checka
8032
           bne SmallBP              ;if so, branch to increment offset
8033
           lda PlayerSize           ;is player big?
8034
         checka
8035
           beq BigBP                ;if so, branch to use default offset
8036
SmallBP:   iny                      ;increment for small or big and crouching
8037
BigBP:     lda Player_Y_Position    ;get player's vertical coordinate
8038
           clc
8039
           adcy BlockYPosAdderData,y ;add value determined by size
8040
           andn ++$f0                 ;mask out low nybble to get 16-pixel correspondence
8041
           stax Block_Y_Position,x   ;save as vertical coordinate for block object
8042
           ldyx Block_State,x        ;get block object state
8043
           cpyn ++$11
8044
           beq Unbreak              ;if set to value loaded for unbreakable, branch
8045
           jsr BrickShatter         ;execute code for breakable brick
8046
           jmp InvOBit              ;skip subroutine to do last part of code here
8047
Unbreak:   jsr BumpBlock            ;execute code for unbreakable brick or question block
8048
InvOBit:   lda SprDataOffset_Ctrl   ;invert control bit used by block objects
8049
           eorn ++$01                 ;and floatey numbers
8050
           sta SprDataOffset_Ctrl
8051
           rts                      ;leave!
8052
 
8053
;--------------------------------
8054
 
8055
InitBlock_XY_Pos:
8056
      lda Player_X_Position   ;get player's horizontal coordinate
8057
      clc
8058
      adcn ++$08                ;add eight pixels
8059
     push af
8060
      andn ++$f0                ;mask out low nybble to give 16-pixel correspondence
8061
      stax Block_X_Position,x  ;save as horizontal coordinate for block object
8062
     pop af
8063
      lda Player_PageLoc
8064
      adcn ++$00                ;add carry to page location of player
8065
      stax Block_PageLoc,x     ;save as page location of block object
8066
      stax Block_PageLoc2,x    ;save elsewhere to be used later
8067
      lda Player_Y_HighPos
8068
      stax Block_Y_HighPos,x   ;save vertical high byte of player into
8069
      rts                     ;vertical high byte of block object and leave
8070
 
8071
;--------------------------------
8072
 
8073
BumpBlock:
8074
           jsr CheckTopOfBlock     ;check to see if there's a coin directly above this block
8075
           ldan ++Sfx_Bump
8076
           sta Square1SoundQueue   ;play bump sound
8077
           ldan ++$00
8078
           stax Block_X_Speed,x     ;initialize horizontal speed for block object
8079
           stax Block_Y_MoveForce,x ;init fractional movement force
8080
           sta Player_Y_Speed      ;init player's vertical speed
8081
           ldan ++$fe
8082
           stax Block_Y_Speed,x     ;set vertical speed for block object
8083
           lda SCRATCHPAD+$05                 ;get original metatile from stack
8084
           jsr BlockBumpedChk      ;do a sub to check which block player bumped head on
8085
           bcc ExitBlockChk        ;if no match was found, branch to leave
8086
           tya                     ;move block number to A
8087
           cmpn ++$09                ;if block number was within 0-8 range,
8088
              cmpcy
8089
           bcc BlockCode           ;branch to use current number
8090
              cmpcy
8091
           sbcn ++$05                ;otherwise subtract 5 for second set to get proper number
8092
BlockCode: jsr JumpEngine          ;run appropriate subroutine depending on block number
8093
 
8094
      .dw MushFlowerBlock
8095
      .dw CoinBlock
8096
      .dw CoinBlock
8097
      .dw ExtraLifeMushBlock
8098
      .dw MushFlowerBlock
8099
      .dw VineBlock
8100
      .dw StarBlock
8101
      .dw CoinBlock
8102
      .dw ExtraLifeMushBlock
8103
 
8104
;--------------------------------
8105
 
8106
MushFlowerBlock:
8107
      ldan ++$00       ;load mushroom/fire flower into power-up type
8108
      jr bonusblock_go;.db $2c        ;BIT instruction opcode
8109
 
8110
StarBlock:
8111
      ldan ++$02       ;load star into power-up type
8112
      jr bonusblock_go;.db $2c        ;BIT instruction opcode
8113
 
8114
ExtraLifeMushBlock:
8115
      ldan ++$03         ;load 1-up mushroom into power-up type
8116
bonusblock_go
8117
      sta SCRATCHPAD+$39          ;store correct power-up type
8118
      jmp SetupPowerUp
8119
 
8120
VineBlock:
8121
      ldxn ++$05                ;load last slot for enemy object buffer
8122
      ldy SprDataOffset_Ctrl  ;get control bit
8123
      jsr Setup_Vine          ;set up vine object
8124
 
8125
ExitBlockChk:
8126
      rts                     ;leave
8127
 
8128
;--------------------------------
8129
 
8130
BrickQBlockMetatiles:
8131
      .db $c1, $c0, $5f, $60 ;used by question blocks
8132
 
8133
      ;these two sets are functionally identical, but look different
8134
      .db $55, $56, $57, $58, $59 ;used by ground level types
8135
      .db $5a, $5b, $5c, $5d, $5e ;used by other level types
8136
 
8137
BlockBumpedChk:
8138
             ldyn ++$0d                    ;start at end of metatile data
8139
BumpChkLoop: cmpy BrickQBlockMetatiles,y  ;check to see if current metatile matches
8140
             beq MatchBump               ;metatile found in block buffer, branch if so
8141
             dey                         ;otherwise move onto next metatile
8142
             bpl BumpChkLoop             ;do this until all metatiles are checked
8143
             clc                         ;if none match, return with carry clear
8144
            if Z80
8145
             rts
8146
MatchBump:
8147
             scf
8148
             ret
8149
            else
8150
MatchBump:   rts                         ;note carry is set if found match
8151
            endif
8152
 
8153
;--------------------------------
8154
 
8155
BrickShatter:
8156
      jsr CheckTopOfBlock    ;check to see if there's a coin directly above this block
8157
      ldan ++Sfx_BrickShatter
8158
      stax Block_RepFlag,x    ;set flag for block object to immediately replace metatile
8159
      sta NoiseSoundQueue    ;load brick shatter sound
8160
      jsr SpawnBrickChunks   ;create brick chunk objects
8161
      ldan ++$fe
8162
      sta Player_Y_Speed     ;set vertical speed for player
8163
      ldan ++$05
8164
      sta DigitModifier+5    ;set digit modifier to give player 50 points
8165
      jsr AddToScore         ;do sub to update the score
8166
      ldx SprDataOffset_Ctrl ;load control bit and leave
8167
      rts
8168
 
8169
;--------------------------------
8170
 
8171
CheckTopOfBlock:
8172
       ldx SprDataOffset_Ctrl  ;load control bit
8173
       ldy SCRATCHPAD+$02                 ;get vertical high nybble offset used in block buffer
8174
         checky
8175
       beq TopEx               ;branch to leave if set to zero, because we're at the top
8176
       tya                     ;otherwise set to A
8177
       secsub
8178
       sbcn ++$10                ;subtract $10 to move up one row in the block buffer
8179
       sta SCRATCHPAD+$02                 ;store as new vertical high nybble offset
8180
       tay
8181
       ldayindirect (SCRATCHPAD+$06),y             ;get contents of block buffer in same column, one row up
8182
       cmpn ++$c2                ;is it a coin? (not underwater)
8183
       bne TopEx               ;if not, branch to leave
8184
       ldan ++$00
8185
       stayindirect (SCRATCHPAD+$06),y             ;otherwise put blank metatile where coin was
8186
       jsr RemoveCoin_Axe      ;write blank metatile to vram buffer
8187
       ldx SprDataOffset_Ctrl  ;get control bit
8188
       jsr SetupJumpCoin       ;create jumping coin object and update coin variables
8189
TopEx: rts                     ;leave!
8190
 
8191
;--------------------------------
8192
 
8193
SpawnBrickChunks:
8194
      ldax Block_X_Position,x     ;set horizontal coordinate of block object
8195
      stax Block_Orig_XPos,x      ;as original horizontal coordinate here
8196
      ldan ++$f0
8197
      stax Block_X_Speed,x        ;set horizontal speed for brick chunk objects
8198
      stax Block_X_Speed+2,x
8199
      ldan ++$fa
8200
      stax Block_Y_Speed,x        ;set vertical speed for one
8201
      ldan ++$fc
8202
      stax Block_Y_Speed+2,x      ;set lower vertical speed for the other
8203
      ldan ++$00
8204
      stax Block_Y_MoveForce,x    ;init fractional movement force for both
8205
      stax Block_Y_MoveForce+2,x
8206
      ldax Block_PageLoc,x
8207
      stax Block_PageLoc+2,x      ;copy page location
8208
      ldax Block_X_Position,x
8209
      stax Block_X_Position+2,x   ;copy horizontal coordinate
8210
      ldax Block_Y_Position,x
8211
      clc                        ;add 8 pixels to vertical coordinate
8212
      adcn ++$08                   ;and save as vertical coordinate for one of them
8213
      stax Block_Y_Position+2,x
8214
      ldan ++$fa
8215
      stax Block_Y_Speed,x        ;set vertical speed...again??? (redundant)
8216
      rts
8217
 
8218
;-------------------------------------------------------------------------------------
8219
 
8220
BlockObjectsCore:
8221
        ldax Block_State,x           ;get state of block object
8222
         checka
8223
        beq UpdSte                  ;if not set, branch to leave
8224
        andn ++$0f                    ;mask out high nybble
8225
        pha                         ;push to stack
8226
        tay                         ;put in Y for now
8227
        txa
8228
        clc
8229
        adcn ++$09                    ;add 9 bytes to offset (note two block objects are created
8230
        tax                         ;when using brick chunks, but only one offset for both) ;   #9  misc objects ( ???)
8231
        dey                         ;decrement Y to check for solid block state
8232
        beq BouncingBlockHandler    ;branch if found, otherwise continue for brick chunks
8233
        jsr ImposeGravityBlock      ;do sub to impose gravity on one block object object
8234
        jsr MoveObjectHorizontally  ;do another sub to move horizontally
8235
        txa
8236
        clc                         ;move onto next block object
8237
        adcn ++$02
8238
        tax
8239
        jsr ImposeGravityBlock      ;do sub to impose gravity on other block object
8240
        jsr MoveObjectHorizontally  ;do another sub to move horizontally
8241
        ldx ObjectOffset            ;get block object offset used for both
8242
        jsr RelativeBlockPosition   ;get relative coordinates
8243
        jsr GetBlockOffscreenBits   ;get offscreen information
8244
        jsr DrawBrickChunks         ;draw the brick chunks
8245
        pla                         ;get lower nybble of saved state
8246
        ldyx Block_Y_HighPos,x       ;check vertical high byte of block object
8247
         checky
8248
        beq UpdSte                  ;if above the screen, branch to kill it
8249
        pha                         ;otherwise save state back into stack
8250
        ldan ++$f0
8251
        cmpx Block_Y_Position+2,x    ;check to see if bottom block object went
8252
              cmpcy
8253
        bcs ChkTop                  ;to the bottom of the screen, and branch if not
8254
        stax Block_Y_Position+2,x    ;otherwise set offscreen coordinate
8255
ChkTop: ldax Block_Y_Position,x      ;get top block object's vertical coordinate
8256
        cmpn ++$f0                    ;see if it went to the bottom of the screen
8257
        plakeepcy                         ;pull block object state from stack
8258
              cmpcy
8259
        bcc UpdSte                  ;if not, branch to save state
8260
        bcs KillBlock               ;otherwise do unconditional branch to kill it
8261
 
8262
BouncingBlockHandler:
8263
           jsr ImposeGravityBlock     ;do sub to impose gravity on block object
8264
           ldx ObjectOffset           ;get block object offset
8265
           jsr RelativeBlockPosition  ;get relative coordinates
8266
           jsr GetBlockOffscreenBits  ;get offscreen information
8267
           jsr DrawBlock              ;draw the block
8268
           ldax Block_Y_Position,x     ;get vertical coordinate
8269
           andn ++$0f                   ;mask out high nybble
8270
           cmpn ++$05                   ;check to see if low nybble wrapped around
8271
              cmpcy
8272
           plakeepcy                        ;pull state from stack
8273
           bcs UpdSte                 ;if still above amount, not time to kill block yet, thus branch
8274
           ldan ++$01
8275
           stax Block_RepFlag,x        ;otherwise set flag to replace metatile
8276
KillBlock: ldan ++$00                   ;if branched here, nullify object state
8277
UpdSte:    stax Block_State,x          ;store contents of A in block object state
8278
           rts
8279
 
8280
;-------------------------------------------------------------------------------------
8281
;$02 - used to store offset to block buffer
8282
;$06-$07 - used to store block buffer address
8283
 
8284
BlockObjMT_Updater:
8285
            ldxn ++$01                  ;set offset to start with second block object
8286
UpdateLoop: stx ObjectOffset          ;set offset here
8287
            lda VRAM_Buffer1          ;if vram buffer already being used here,
8288
         checka
8289
            bne NextBUpd              ;branch to move onto next block object
8290
            ldax Block_RepFlag,x       ;if flag for block object already clear,
8291
         checka
8292
            beq NextBUpd              ;branch to move onto next block object
8293
            ldax Block_BBuf_Low,x      ;get low byte of block buffer
8294
            sta SCRATCHPAD+$06                   ;store into block buffer address
8295
            ldan ++$05
8296
            sta SCRATCHPAD+$07                   ;set high byte of block buffer address
8297
            ldax Block_Orig_YPos,x     ;get original vertical coordinate of block object
8298
            sta SCRATCHPAD+$02                   ;store here and use as offset to block buffer
8299
            tay
8300
            ldax Block_Metatile,x      ;get metatile to be written
8301
            stayindirect (SCRATCHPAD+$06),y               ;write it to the block buffer
8302
            jsr ReplaceBlockMetatile  ;do sub to replace metatile where block object is
8303
            ldan ++$00
8304
            stax Block_RepFlag,x       ;clear block object flag
8305
NextBUpd:   dex                       ;decrement block object offset
8306
            bpl UpdateLoop            ;do this until both block objects are dealt with
8307
            rts                       ;then leave
8308
 
8309
;-------------------------------------------------------------------------------------
8310
;$00 - used to store high nybble of horizontal speed as adder
8311
;$01 - used to store low nybble of horizontal speed
8312
;$02 - used to store adder to page location
8313
 
8314
MoveEnemyHorizontally:
8315
      inx                         ;increment offset for enemy offset
8316
      jsr MoveObjectHorizontally  ;position object horizontally according to
8317
      ldx ObjectOffset            ;counters, return with saved value in A,
8318
      rts                         ;put enemy offset back in X and leave
8319
 
8320
MovePlayerHorizontally:
8321
      lda JumpspringAnimCtrl  ;if jumpspring currently animating,
8322
        if Z80OPT
8323
      or a
8324
      ret nz                ;branch to leave
8325
        else
8326
      checka
8327
      bne ExXMove             ;branch to leave
8328
        endif
8329
      tax                     ;otherwise set zero for offset to use player's stuff
8330
 
8331
MoveObjectHorizontally:
8332
;PageLoc_XPosition_XMoveforce += 16*Xspeed (signed)
8333
;out: a= X-    (   ?  - ?)
8334
;CY  
8335
;  y
8336
;    SCRATCHPAD+0,1,2
8337
        if Z80OPT
8338
          ld ix,SprObject_X_Speed
8339
          add ix,bc
8340
          ld a,(ix)
8341
          add a,a
8342
          ld l,a
8343
          sbc a,a
8344
          ld h,a ; 
8345
          ld e,a ; 
8346
          add hl,hl
8347
          add hl,hl
8348
          add hl,hl
8349
          ld a,l
8350
          ld d,h
8351
          ld hl,SprObject_X_MoveForce
8352
          add hl,bc
8353
          add a,(hl) ;get whatever number's here (  X-)  ;add low nybble moved to high
8354
          ld (hl),a ;store result here (  X-)
8355
          ld a,(ix+SprObject_X_Position-SprObject_X_Speed)
8356
          ld l,a
8357
          adc a,d        ;add carry plus saved value (high nybble moved to low
8358
          ld d,b;0
8359
          ld h,a ;plus $f0 if necessary) to object's horizontal position
8360
          ld a,(ix+SprObject_PageLoc-SprObject_X_Speed)
8361
          adc a,e                                           ;add carry plus other saved value to the
8362
          ld (ix+SprObject_PageLoc-SprObject_X_Speed),a     ;object's page location and save
8363
          ld a,h
8364
          sub l;(ix+SprObject_X_Position-SprObject_X_Speed) ;(  X-   )
8365
          ld (ix+SprObject_X_Position-SprObject_X_Speed),h
8366
          ret
8367
        else ;~Z80
8368
          ldax SprObject_X_Speed,x     ;get currently saved value (horizontal
8369
          asl                         ;speed, secondary counter, whatever)
8370
          asl                         ;and move low nybble to high
8371
          asl
8372
          asl
8373
          sta SCRATCHPAD+$01                     ;store result here
8374
          ldax SprObject_X_Speed,x     ;get saved value again
8375
          lsr                         ;move high nybble to low
8376
          lsr
8377
          lsr
8378
          lsr
8379
          cmpn ++$08                    ;if < 8, branch, do not change
8380
              cmpcy
8381
          bcc SaveXSpd
8382
          oran ++%11110000              ;otherwise alter high nybble ( )
8383
SaveXSpd: sta SCRATCHPAD+$00                     ;save result here
8384
          ldyn ++$00                    ;load default Y value here
8385
          cmpn ++$00                    ;if result positive, leave Y alone
8386
          bpl UseAdder
8387
          dey                         ;otherwise decrement Y
8388
UseAdder: sty SCRATCHPAD+$02                     ;save Y here (   0/-1)
8389
          ldax SprObject_X_MoveForce,x ;get whatever number's here (  X-)
8390
          clc
8391
          adci SCRATCHPAD+$01                     ;add low nybble moved to high
8392
         push af
8393
          stax SprObject_X_MoveForce,x ;store result here (  X-)
8394
         pop af
8395
          ldan ++$00                    ;init A
8396
          rol                         ;rotate carry into d0
8397
       pha                         ;push onto stack (       X-)
8398
          ror                         ;rotate d0 back onto carry
8399
          ldaxkeepcy SprObject_X_Position,x
8400
          adci SCRATCHPAD+$00                     ;add carry plus saved value (high nybble moved to low
8401
         push af
8402
          stax SprObject_X_Position,x  ;plus $f0 if necessary) to object's horizontal position
8403
          ldax SprObject_PageLoc,x
8404
         ld h,a
8405
         pop af
8406
         ld a,h
8407
          adci SCRATCHPAD+$02                     ;add carry plus other saved value to the
8408
          stax SprObject_PageLoc,x     ;object's page location and save
8409
       pla
8410
          clc                         ;pull old carry from stack (      X-) and add
8411
          adci SCRATCHPAD+$00                     ;to high nybble moved to low (  X-   )
8412
ExXMove:  rts                         ;and leave
8413
        endif
8414
 
8415
;-------------------------------------------------------------------------------------
8416
;$00 - used for downward force
8417
;$01 - used for upward force
8418
;$02 - used for maximum vertical speed
8419
 
8420
MovePlayerVertically:
8421
         ldxn ++$00                ;set X for player offset
8422
         lda TimerControl
8423
         checka
8424
         bne NoJSChk             ;if master timer control set, branch ahead
8425
         lda JumpspringAnimCtrl  ;otherwise check to see if jumpspring is animating
8426
        if Z80OPT
8427
         or a
8428
         ret nz ;branch to leave if so
8429
        else
8430
         checka
8431
         bne ExXMove             ;branch to leave if so
8432
        endif
8433
NoJSChk: lda VerticalForce       ;dump vertical force 
8434
         sta SCRATCHPAD+$00
8435
         ldan ++$04                ;set maximum vertical speed here
8436
         jmp ImposeGravitySprObj ;then jump to move player vertically
8437
 
8438
;--------------------------------
8439
 
8440
MoveD_EnemyVertically:
8441
      ldyn ++$3d           ;set quick movement amount downwards
8442
      ldax Enemy_State,x  ;then check enemy state
8443
      cmpn ++$05           ;if not set to unique state for spiny's egg, go ahead
8444
      bne ContVMove      ;and use, otherwise set different movement amount, continue on
8445
 
8446
MoveFallingPlatform:
8447
           ldyn ++$20       ;set movement amount
8448
ContVMove: jmp SetHiMax   ;jump to skip the rest of this
8449
 
8450
;--------------------------------
8451
 
8452
MoveRedPTroopaDown:
8453
      ldyn ++$00            ;set Y to move downwards
8454
      jmp MoveRedPTroopa  ;skip to movement routine
8455
 
8456
MoveRedPTroopaUp:
8457
      ldyn ++$01            ;set Y to move upwards
8458
 
8459
MoveRedPTroopa:
8460
      inx                 ;increment X for enemy offset
8461
      ldan ++$03
8462
      sta SCRATCHPAD+$00             ;set downward movement amount here
8463
      ldan ++$06
8464
      sta SCRATCHPAD+$01             ;set upward movement amount here
8465
      ldan ++$02
8466
      sta SCRATCHPAD+$02             ;set maximum speed here
8467
      tya                 ;set movement direction in A, and
8468
      jmp RedPTroopaGrav  ;jump to move this thing
8469
 
8470
;--------------------------------
8471
 
8472
MoveDropPlatform:
8473
      ldyn ++$7f      ;set movement amount for drop platform
8474
         checky
8475
      bne SetMdMax  ;skip ahead of other value set here
8476
 
8477
MoveEnemySlowVert:
8478
          ldyn ++$0f         ;set movement amount for bowser/other objects
8479
SetMdMax: ldan ++$02         ;set maximum speed in A
8480
         checka
8481
          bne SetXMoveAmt  ;unconditional branch
8482
 
8483
;--------------------------------
8484
 
8485
MoveJ_EnemyVertically:
8486
             ldyn ++$1c                ;set movement amount for podoboo/other objects
8487
SetHiMax:    ldan ++$03                ;set maximum speed in A
8488
SetXMoveAmt: sty SCRATCHPAD+$00                 ;set movement amount here
8489
             inx                     ;increment X for enemy offset
8490
             jsr ImposeGravitySprObj ;do a sub to move enemy object downwards
8491
             ldx ObjectOffset        ;get enemy object buffer offset and leave
8492
             rts
8493
 
8494
;--------------------------------
8495
 
8496
MaxSpdBlockData:
8497
      .db $06, $08
8498
 
8499
ResidualGravityCode:
8500
      ldyn ++$00       ;this part appears to be residual,
8501
      jr ImposeGravityBlock_go;.db $2c        ;no code branches or jumps to it...
8502
 
8503
ImposeGravityBlock:
8504
      ldyn ++$01       ;set offset for maximum speed
8505
ImposeGravityBlock_go
8506
      ldan ++$50       ;set movement amount here
8507
      sta SCRATCHPAD+$00
8508
      lday MaxSpdBlockData,y    ;get maximum speed
8509
 
8510
ImposeGravitySprObj:
8511
      sta SCRATCHPAD+$02            ;set maximum speed here
8512
      ldan ++$00           ;set value to move downwards
8513
      jmp ImposeGravity  ;jump to the code that actually moves it
8514
 
8515
;--------------------------------
8516
 
8517
MovePlatformDown:
8518
      ldan ++$00    ;save value to stack (if branching here, execute next
8519
      jr MovePlatform_go;.db $2c     ;part as BIT instruction)
8520
 
8521
MovePlatformUp:
8522
           ldan ++$01        ;save value to stack
8523
MovePlatform_go
8524
           pha
8525
           ldyx Enemy_ID,x  ;get enemy object identifier
8526
           inx             ;increment offset for enemy object
8527
           ldan ++$05        ;load default value here
8528
           cpyn ++$29        ;residual comparison, object ++29 never executes
8529
           bne SetDplSpd   ;this code, thus unconditional branch here
8530
           ldan ++$09        ;residual code
8531
SetDplSpd: sta SCRATCHPAD+$00         ;save downward movement amount here
8532
           ldan ++$0a        ;save upward movement amount here
8533
           sta SCRATCHPAD+$01
8534
           ldan ++$03        ;save maximum vertical speed here
8535
           sta SCRATCHPAD+$02
8536
           pla             ;get value from stack
8537
           tay             ;use as Y, then move onto code shared by red koopa
8538
 
8539
RedPTroopaGrav:
8540
      jsr ImposeGravity  ;do a sub to move object gradually
8541
      ldx ObjectOffset   ;get enemy object offset and leave
8542
      rts
8543
 
8544
;-------------------------------------------------------------------------------------
8545
;$00 - used for downward force
8546
;$01 - used for upward force
8547
;$07 - used as adder for vertical position
8548
 
8549
ImposeGravity:
8550
         pha                          ;push value to stack
8551
         ldax SprObject_YMF_Dummy,x
8552
         clc                          ;add value in movement force to contents of dummy variable
8553
         adcx SprObject_Y_MoveForce,x
8554
          push af
8555
         stax SprObject_YMF_Dummy,x
8556
         ldyn ++$00                     ;set Y to zero by default
8557
         ldax SprObject_Y_Speed,x      ;get current vertical speed
8558
          ld h,a
8559
          pop af
8560
          ld a,h
8561
         checka
8562
         bpl AlterYP                  ;if currently moving downwards, do not decrement Y
8563
         dey                          ;otherwise decrement Y
8564
AlterYP: sty SCRATCHPAD+$07                      ;store Y here
8565
         adcx SprObject_Y_Position,x   ;add vertical position to vertical speed plus carry
8566
          push af
8567
         stax SprObject_Y_Position,x   ;store as new vertical position
8568
         ldax SprObject_Y_HighPos,x
8569
          ld h,a
8570
          pop af
8571
          ld a,h
8572
         adci SCRATCHPAD+$07                      ;add carry plus contents of $07 to vertical high byte
8573
         stax SprObject_Y_HighPos,x    ;store as new vertical high byte
8574
         ldax SprObject_Y_MoveForce,x
8575
         clc
8576
         adci SCRATCHPAD+$00                      ;add downward movement amount to contents of $0433
8577
          push af
8578
         stax SprObject_Y_MoveForce,x
8579
         ldax SprObject_Y_Speed,x      ;add carry to vertical speed and store
8580
          ld h,a
8581
          pop af
8582
          ld a,h
8583
         adcn ++$00
8584
         stax SprObject_Y_Speed,x
8585
         cmpi SCRATCHPAD+$02                      ;compare to maximum speed
8586
         bmi ChkUpM                   ;if less than preset value, skip this part
8587
         ldax SprObject_Y_MoveForce,x
8588
         cmpn ++$80                     ;if less positively than preset maximum, skip this part
8589
              cmpcy
8590
         bcc ChkUpM
8591
         lda SCRATCHPAD+$02
8592
         stax SprObject_Y_Speed,x      ;keep vertical speed within maximum value
8593
         ldan ++$00
8594
         stax SprObject_Y_MoveForce,x  ;clear fractional
8595
ChkUpM:  pla                          ;get value from stack
8596
         checka
8597
         beq ExVMove                  ;if set to zero, branch to leave
8598
         lda SCRATCHPAD+$02
8599
         eorn ++%11111111               ;otherwise get two's compliment of maximum speed
8600
         tay
8601
         iny
8602
         sty SCRATCHPAD+$07                      ;store two's compliment here
8603
         ldax SprObject_Y_MoveForce,x
8604
         secsub                          ;subtract upward movement amount from contents
8605
         sbci SCRATCHPAD+$01                      ;of movement force, note that $01 is twice as large as $00,
8606
          push af
8607
         stax SprObject_Y_MoveForce,x  ;thus it effectively undoes add we did earlier
8608
         ldax SprObject_Y_Speed,x
8609
          ld h,a
8610
          pop af
8611
          ld a,h
8612
         sbcn ++$00                     ;subtract borrow from vertical speed and store
8613
         stax SprObject_Y_Speed,x
8614
         cmpi SCRATCHPAD+$07                      ;compare vertical speed to two's compliment
8615
         bpl ExVMove                  ;if less negatively than preset maximum, skip this part
8616
         ldax SprObject_Y_MoveForce,x
8617
         cmpn ++$80                     ;check if fractional part is above certain amount,
8618
              cmpcy
8619
         bcs ExVMove                  ;and if so, branch to leave
8620
         lda SCRATCHPAD+$07
8621
         stax SprObject_Y_Speed,x      ;keep vertical speed within maximum value
8622
         ldan ++$ff
8623
         stax SprObject_Y_MoveForce,x  ;clear fractional
8624
ExVMove: rts                          ;leave!
8625
 
8626
;-------------------------------------------------------------------------------------
8627
 
8628
EnemiesAndLoopsCore:
8629
            ldax Enemy_Flag,x         ;check data here for MSB set
8630
            pha                      ;save in stack
8631
            asl
8632
            bcs ChkBowserF           ;if MSB set in enemy flag, branch ahead of jumps
8633
            pla                      ;get from stack
8634
         checka
8635
            beq ChkAreaTsk           ;if data zero, branch
8636
            jmp RunEnemyObjectsCore  ;otherwise, jump to run enemy subroutines
8637
ChkAreaTsk: lda AreaParserTaskNum    ;check number of tasks to perform
8638
            andn ++$07
8639
            cmpn ++$07                 ;if at a specific task, jump and leave
8640
            beq ExitELCore
8641
            jmp ProcLoopCommand      ;otherwise, jump to process loop command/load enemies
8642
ChkBowserF: pla                      ;get data from stack
8643
            andn ++%00001111           ;mask out high nybble
8644
            tay
8645
            lday Enemy_Flag,y         ;use as pointer and load same place with different offset
8646
         checka
8647
            bne ExitELCore
8648
            stax Enemy_Flag,x         ;if second enemy flag not set, also clear first one
8649
ExitELCore: rts
8650
 
8651
;--------------------------------
8652
 
8653
;loop command data
8654
LoopCmdWorldNumber:
8655
      .db $03, $03, $06, $06, $06, $06, $06, $06, $07, $07, $07
8656
 
8657
LoopCmdPageNumber:
8658
      .db $05, $09, $04, $05, $06, $08, $09, $0a, $06, $0b, $10
8659
 
8660
LoopCmdYPosition:
8661
      .db $40, $b0, $b0, $80, $40, $40, $80, $40, $f0, $f0, $f0
8662
 
8663
ExecGameLoopback:
8664
      lda Player_PageLoc        ;send player back four pages
8665
      secsub
8666
      sbcn ++$04
8667
      sta Player_PageLoc
8668
      lda CurrentPageLoc        ;send current page back four pages
8669
      secsub
8670
      sbcn ++$04
8671
      sta CurrentPageLoc
8672
      lda ScreenLeft_PageLoc    ;subtract four from page location
8673
      secsub                       ;of screen's left border
8674
      sbcn ++$04
8675
      sta ScreenLeft_PageLoc
8676
      lda ScreenRight_PageLoc   ;do the same for the page location
8677
      secsub                       ;of screen's right border
8678
      sbcn ++$04
8679
      sta ScreenRight_PageLoc
8680
      lda AreaObjectPageLoc     ;subtract four from page control
8681
      secsub                       ;for area objects
8682
      sbcn ++$04
8683
      sta AreaObjectPageLoc
8684
      ldan ++$00                  ;initialize page select for both
8685
      sta EnemyObjectPageSel    ;area and enemy objects
8686
      sta AreaObjectPageSel
8687
      sta EnemyDataOffset       ;initialize enemy object data offset
8688
      sta EnemyObjectPageLoc    ;and enemy object page control
8689
      lday AreaDataOfsLoopback,y ;adjust area object offset based on
8690
      sta AreaDataOffset        ;which loop command we encountered
8691
      rts
8692
 
8693
ProcLoopCommand:
8694
          lda LoopCommand           ;check if loop command was found
8695
         checka
8696
          beq ChkEnemyFrenzy
8697
          lda CurrentColumnPos      ;check to see if we're still on the first page
8698
         checka
8699
          bne ChkEnemyFrenzy        ;if not, do not loop yet
8700
          ldyn ++$0b                  ;start at the end of each set of loop data
8701
FindLoop: dey
8702
          bmi ChkEnemyFrenzy        ;if all data is checked and not match, do not loop
8703
          lda WorldNumber           ;check to see if one of the world numbers
8704
          cmpy LoopCmdWorldNumber,y  ;matches our current world number
8705
          bne FindLoop
8706
          lda CurrentPageLoc        ;check to see if one of the page numbers
8707
          cmpy LoopCmdPageNumber,y   ;matches the page we're currently on
8708
          bne FindLoop
8709
          lda Player_Y_Position     ;check to see if the player is at the correct position
8710
          cmpy LoopCmdYPosition,y    ;if not, branch to check for world 7
8711
          bne WrongChk
8712
          lda Player_State          ;check to see if the player is
8713
          cmpn ++$00                  ;on solid ground (i.e. not jumping or falling)
8714
          bne WrongChk              ;if not, player fails to pass loop, and loopback
8715
          lda WorldNumber           ;are we in world 7? (check performed on correct
8716
          cmpn ++World7               ;vertical position and on solid ground)
8717
          bne InitMLp               ;if not, initialize flags used there, otherwise
8718
          inci MultiLoopCorrectCntr  ;increment counter for correct progression
8719
IncMLoop: inci MultiLoopPassCntr     ;increment master multi-part counter
8720
          lda MultiLoopPassCntr     ;have we done all three parts?
8721
          cmpn ++$03
8722
          bne InitLCmd              ;if not, skip this part
8723
          lda MultiLoopCorrectCntr  ;if so, have we done them all correctly?
8724
          cmpn ++$03
8725
          beq InitMLp               ;if so, branch past unnecessary check here
8726
          bne DoLpBack              ;unconditional branch if previous branch fails
8727
WrongChk: lda WorldNumber           ;are we in world 7? (check performed on
8728
          cmpn ++World7               ;incorrect vertical position or not on solid ground)
8729
          beq IncMLoop
8730
DoLpBack: jsr ExecGameLoopback      ;if player is not in right place, loop back
8731
          jsr KillAllEnemies
8732
InitMLp:  ldan ++$00                  ;initialize counters used for multi-part loop commands
8733
          sta MultiLoopPassCntr
8734
          sta MultiLoopCorrectCntr
8735
InitLCmd: ldan ++$00                  ;initialize loop command flag
8736
          sta LoopCommand
8737
 
8738
;--------------------------------
8739
 
8740
ChkEnemyFrenzy:
8741
      lda EnemyFrenzyQueue  ;check for enemy object in frenzy queue
8742
         checka
8743
      beq ProcessEnemyData  ;if not, skip this part
8744
      stax Enemy_ID,x        ;store as enemy object identifier here
8745
      ldan ++$01
8746
      stax Enemy_Flag,x      ;activate enemy object flag
8747
      ldan ++$00
8748
      stax Enemy_State,x     ;initialize state and frenzy queue
8749
      sta EnemyFrenzyQueue
8750
      jmp InitEnemyObject   ;and then jump to deal with this enemy
8751
 
8752
;--------------------------------
8753
;$06 - used to hold page location of extended right boundary
8754
;$07 - used to hold high nybble of position of extended right boundary
8755
 
8756
ProcessEnemyData:
8757
        ldy EnemyDataOffset      ;get offset of enemy object data
8758
        ldayindirect (EnemyData),y        ;load first byte
8759
        cmpn ++$ff                 ;check for EOD terminator
8760
        bne CheckEndofBuffer
8761
        jmp CheckFrenzyBuffer    ;if found, jump to check frenzy buffer, otherwise
8762
 
8763
CheckEndofBuffer:
8764
        andn ++%00001111           ;check for special row $0e
8765
        cmpn ++$0e
8766
        beq CheckRightBounds     ;if found, branch, otherwise
8767
        cpxn ++$05                 ;check for end of buffer
8768
              cmpcy
8769
        bcc CheckRightBounds     ;if not at end of buffer, branch
8770
        iny
8771
        ldayindirect (EnemyData),y        ;check for specific value here
8772
        andn ++%00111111           ;not sure what this was intended for, exactly
8773
        cmpn ++$2e                 ;this part is quite possibly residual code
8774
        beq CheckRightBounds     ;but it has the effect of keeping enemies out of
8775
        rts                      ;the sixth slot
8776
 
8777
CheckRightBounds:
8778
        lda ScreenRight_X_Pos    ;add 48 to pixel coordinate of right boundary
8779
        clc
8780
        adcn ++$30
8781
          push af
8782
        andn ++%11110000           ;store high nybble
8783
        sta SCRATCHPAD+$07
8784
        lda ScreenRight_PageLoc  ;add carry to page location of right boundary
8785
          ld h,a
8786
          pop af
8787
          ld a,h
8788
        adcn ++$00
8789
        sta SCRATCHPAD+$06                  ;store page location + carry
8790
        ldy EnemyDataOffset
8791
        iny
8792
        ldayindirect (EnemyData),y        ;if MSB of enemy object is clear, branch to check for row $0f
8793
        asl
8794
        bcc CheckPageCtrlRow
8795
        lda EnemyObjectPageSel   ;if page select already set, do not set again
8796
         checka
8797
        bne CheckPageCtrlRow
8798
        inci EnemyObjectPageSel   ;otherwise, if MSB is set, set page select 
8799
        inci EnemyObjectPageLoc   ;and increment page control
8800
 
8801
CheckPageCtrlRow:
8802
        dey
8803
        ldayindirect (EnemyData),y        ;reread first byte
8804
        andn ++$0f
8805
        cmpn ++$0f                 ;check for special row $0f
8806
        bne PositionEnemyObj     ;if not found, branch to position enemy object
8807
        lda EnemyObjectPageSel   ;if page select set,
8808
         checka
8809
        bne PositionEnemyObj     ;branch without reading second byte
8810
        iny
8811
        ldayindirect (EnemyData),y        ;otherwise, get second byte, mask out 2 MSB
8812
        andn ++%00111111
8813
        sta EnemyObjectPageLoc   ;store as page control for enemy object data
8814
        inci EnemyDataOffset      ;increment enemy object data offset 2 bytes
8815
        inci EnemyDataOffset
8816
        inci EnemyObjectPageSel   ;set page select for enemy object data and 
8817
        jmp ProcLoopCommand      ;jump back to process loop commands again
8818
 
8819
PositionEnemyObj:
8820
        lda EnemyObjectPageLoc   ;store page control as page location
8821
        stax Enemy_PageLoc,x      ;for enemy object
8822
        ldayindirect (EnemyData),y        ;get first byte of enemy object
8823
        andn ++%11110000
8824
        stax Enemy_X_Position,x   ;store column position
8825
        cmpi ScreenRight_X_Pos    ;check column position against right boundary
8826
        ldaxkeepcy Enemy_PageLoc,x      ;without subtracting, then subtract borrow
8827
        sbci ScreenRight_PageLoc  ;from page location
8828
              cmpcy
8829
        bcs CheckRightExtBounds  ;if enemy object beyond or at boundary, branch
8830
        ldayindirect (EnemyData),y
8831
        andn ++%00001111           ;check for special row $0e
8832
        cmpn ++$0e                 ;if found, jump elsewhere
8833
        beq ParseRow0e
8834
        jmp CheckThreeBytes      ;if not found, unconditional jump
8835
 
8836
CheckRightExtBounds:
8837
        lda SCRATCHPAD+$07                  ;check right boundary + 48 against
8838
        cmpx Enemy_X_Position,x   ;column position without subtracting,
8839
        lda SCRATCHPAD+$06                  ;then subtract borrow from page control temp
8840
        sbcx Enemy_PageLoc,x      ;plus carry
8841
              cmpcy
8842
        bcc CheckFrenzyBuffer    ;if enemy object beyond extended boundary, branch
8843
        ldan ++$01                 ;store value in vertical high byte
8844
        stax Enemy_Y_HighPos,x
8845
        ldayindirect (EnemyData),y        ;get first byte again
8846
        asl                      ;multiply by four to get the vertical
8847
        asl                      ;coordinate
8848
        asl
8849
        asl
8850
        stax Enemy_Y_Position,x
8851
        cmpn ++$e0                 ;do one last check for special row $0e
8852
        beq ParseRow0e           ;(necessary if branched to $c1cb)
8853
        iny
8854
        ldayindirect (EnemyData),y        ;get second byte of object
8855
        andn ++%01000000           ;check to see if hard mode bit is set
8856
        beq CheckForEnemyGroup   ;if not, branch to check for group enemy objects
8857
        lda SecondaryHardMode    ;if set, check to see if secondary hard mode flag
8858
         checka
8859
        beq Inc2B                ;is on, and if not, branch to skip this object completely
8860
 
8861
CheckForEnemyGroup:
8862
        ldayindirect (EnemyData),y      ;get second byte and mask out 2 MSB
8863
        andn ++%00111111
8864
        cmpn ++$37               ;check for value below $37
8865
              cmpcy
8866
        bcc BuzzyBeetleMutate
8867
        cmpn ++$3f               ;if $37 or greater, check for value
8868
              cmpcy
8869
        bcc DoGroup            ;below $3f, branch if below $3f
8870
 
8871
BuzzyBeetleMutate:
8872
        cmpn ++Goomba          ;if below $37, check for goomba
8873
        bne StrID            ;value ($3f or more always fails)
8874
        ldy PrimaryHardMode  ;check if primary hard mode flag is set
8875
         checky
8876
        beq StrID            ;and if so, change goomba to buzzy beetle
8877
        ldan ++BuzzyBeetle
8878
StrID:  stax Enemy_ID,x       ;store enemy object number into buffer
8879
        ldan ++$01
8880
        stax Enemy_Flag,x     ;set flag for enemy in buffer
8881
        jsr InitEnemyObject
8882
        ldax Enemy_Flag,x     ;check to see if flag is set
8883
         checka
8884
        bne Inc2B            ;if not, leave, otherwise branch
8885
        rts
8886
 
8887
CheckFrenzyBuffer:
8888
        lda EnemyFrenzyBuffer    ;if enemy object stored in frenzy buffer
8889
         checka
8890
        bne StrFre               ;then branch ahead to store in enemy object buffer
8891
        lda VineFlagOffset       ;otherwise check vine flag offset
8892
        cmpn ++$01
8893
        bne ExEPar               ;if other value LOW HIGH  1, leave
8894
        ldan ++VineObject          ;otherwise put vine in enemy identifier
8895
StrFre: stax Enemy_ID,x           ;store contents of frenzy buffer into enemy identifier value
8896
 
8897
InitEnemyObject:
8898
        ldan ++$00                 ;initialize enemy state
8899
        stax Enemy_State,x
8900
        jsr CheckpointEnemyID    ;jump ahead to run jump engine and subroutines
8901
ExEPar: rts                      ;then leave
8902
 
8903
DoGroup:
8904
        jmp HandleGroupEnemies   ;handle enemy group objects
8905
 
8906
ParseRow0e:
8907
        iny                      ;increment Y to load third byte of object
8908
        iny
8909
        ldayindirect (EnemyData),y
8910
        lsr                      ;move 3 MSB to the bottom, effectively
8911
        lsr                      ;making %xxx00000 into %00000xxx
8912
        lsr
8913
        lsr
8914
        lsr
8915
        cmpi WorldNumber          ;is it the same world number as we're on?
8916
        bne NotUse               ;if not, do not use (this allows multiple uses
8917
        dey                      ;of the same area, like the underground bonus areas)
8918
        ldayindirect (EnemyData),y        ;otherwise, get second byte and use as offset
8919
        sta AreaPointer          ;to addresses for level and enemy object data
8920
        iny
8921
        ldayindirect (EnemyData),y        ;get third byte again, and this time mask out
8922
        andn ++%00011111           ;the 3 MSB from before, save as page number to be
8923
        sta EntrancePage         ;used upon entry to area, if area is entered
8924
NotUse: jmp Inc3B
8925
 
8926
CheckThreeBytes:
8927
        ldy EnemyDataOffset      ;load current offset for enemy object data
8928
        ldayindirect (EnemyData),y        ;get first byte
8929
        andn ++%00001111           ;check for special row $0e
8930
        cmpn ++$0e
8931
        bne Inc2B
8932
Inc3B:  inci EnemyDataOffset      ;if row = $0e, increment three bytes
8933
Inc2B:  inci EnemyDataOffset      ;otherwise increment two bytes
8934
        inci EnemyDataOffset
8935
        ldan ++$00                 ;init page select for enemy objects
8936
        sta EnemyObjectPageSel
8937
        ldx ObjectOffset         ;reload current offset in enemy buffers
8938
        rts                      ;and leave
8939
 
8940
CheckpointEnemyID:
8941
        ldax Enemy_ID,x
8942
        cmpn ++$15                     ;check enemy object identifier for $15 or greater
8943
              cmpcy
8944
        bcs InitEnemyRoutines        ;and branch straight to the jump engine if found
8945
        tay                          ;save identifier in Y register for now
8946
        ldax Enemy_Y_Position,x
8947
         or a
8948
        adcn ++$08                     ;add eight pixels to what will eventually be the
8949
        stax Enemy_Y_Position,x       ;enemy object's vertical coordinate ($00-$14 only)
8950
        ldan ++$01
8951
        stax EnemyOffscrBitsMasked,x  ;set offscreen masked bit
8952
        tya                          ;get identifier back and use as offset for jump engine
8953
 
8954
InitEnemyRoutines:
8955
        jsr JumpEngine
8956
 
8957
;jump engine table for newly loaded enemy objects
8958
 
8959
      .dw InitNormalEnemy  ;for objects $00-$0f
8960
      .dw InitNormalEnemy
8961
      .dw InitNormalEnemy
8962
      .dw InitRedKoopa
8963
      .dw NoInitCode
8964
      .dw InitHammerBro
8965
      .dw InitGoomba
8966
      .dw InitBloober
8967
      .dw InitBulletBill
8968
      .dw NoInitCode
8969
      .dw InitCheepCheep
8970
      .dw InitCheepCheep
8971
      .dw InitPodoboo
8972
      .dw InitPiranhaPlant
8973
      .dw InitJumpGPTroopa
8974
      .dw InitRedPTroopa
8975
 
8976
      .dw InitHorizFlySwimEnemy  ;for objects $10-$1f
8977
      .dw InitLakitu
8978
      .dw InitEnemyFrenzy
8979
      .dw NoInitCode
8980
      .dw InitEnemyFrenzy
8981
      .dw InitEnemyFrenzy
8982
      .dw InitEnemyFrenzy
8983
      .dw InitEnemyFrenzy
8984
      .dw EndFrenzy
8985
      .dw NoInitCode
8986
      .dw NoInitCode
8987
      .dw InitShortFirebar
8988
      .dw InitShortFirebar
8989
      .dw InitShortFirebar
8990
      .dw InitShortFirebar
8991
      .dw InitLongFirebar
8992
 
8993
      .dw NoInitCode ;for objects $20-$2f
8994
      .dw NoInitCode
8995
      .dw NoInitCode
8996
      .dw NoInitCode
8997
      .dw InitBalPlatform
8998
      .dw InitVertPlatform
8999
      .dw LargeLiftUp
9000
      .dw LargeLiftDown
9001
      .dw InitHoriPlatform
9002
      .dw InitDropPlatform
9003
      .dw InitHoriPlatform
9004
      .dw PlatLiftUp
9005
      .dw PlatLiftDown
9006
      .dw InitBowser
9007
      .dw PwrUpJmp   ;possibly dummy value
9008
      .dw Setup_Vine
9009
 
9010
      .dw NoInitCode ;for objects $30-$36
9011
      .dw NoInitCode
9012
      .dw NoInitCode
9013
      .dw NoInitCode
9014
      .dw NoInitCode
9015
      .dw InitRetainerObj
9016
      .dw EndOfEnemyInitCode
9017
 
9018
;-------------------------------------------------------------------------------------
9019
 
9020
NoInitCode:
9021
      rts               ;this executed when enemy object has no init code
9022
 
9023
;--------------------------------
9024
 
9025
InitGoomba:
9026
      jsr InitNormalEnemy  ;set appropriate horizontal speed
9027
      jmp SmallBBox        ;set $09 as bounding box control, set other values
9028
 
9029
;--------------------------------
9030
 
9031
InitPodoboo:
9032
      ldan ++$02                  ;set enemy position to below
9033
      stax Enemy_Y_HighPos,x     ;the bottom of the screen
9034
      stax Enemy_Y_Position,x
9035
      lsr
9036
      stax EnemyIntervalTimer,x  ;set timer for enemy
9037
      lsr
9038
      stax Enemy_State,x         ;initialize enemy state, then jump to use
9039
      jmp SmallBBox             ;$09 as bounding box size and set other things
9040
 
9041
;--------------------------------
9042
 
9043
InitRetainerObj:
9044
      ldan ++$b8                ;set fixed vertical position for
9045
      stax Enemy_Y_Position,x  ;princess/mushroom retainer object
9046
      rts
9047
 
9048
;--------------------------------
9049
 
9050
NormalXSpdData:
9051
      .db $f8, $f4
9052
 
9053
InitNormalEnemy:
9054
         ldyn ++$01              ;load offset of 1 by default
9055
         lda PrimaryHardMode   ;check for primary hard mode flag set
9056
         checka
9057
         bne GetESpd
9058
         dey                   ;if not set, decrement offset
9059
GetESpd: lday NormalXSpdData,y  ;get appropriate horizontal speed
9060
SetESpd: stax Enemy_X_Speed,x   ;store as speed for enemy object
9061
         jmp TallBBox          ;branch to set bounding box control and other data
9062
 
9063
;--------------------------------
9064
 
9065
InitRedKoopa:
9066
      jsr InitNormalEnemy   ;load appropriate horizontal speed
9067
      ldan ++$01              ;set enemy state for red koopa troopa $03
9068
      stax Enemy_State,x
9069
      rts
9070
 
9071
;--------------------------------
9072
 
9073
HBroWalkingTimerData:
9074
      .db $80, $50
9075
 
9076
InitHammerBro:
9077
      ldan ++$00                    ;init horizontal speed and timer used by hammer bro
9078
      stax HammerThrowingTimer,x   ;apparently to time hammer throwing
9079
      stax Enemy_X_Speed,x
9080
      ldy SecondaryHardMode       ;get secondary hard mode flag
9081
      lday HBroWalkingTimerData,y
9082
      stax EnemyIntervalTimer,x    ;set value as delay for hammer bro to walk left
9083
      ldan ++$0b                    ;set specific value for bounding box size control
9084
      jmp SetBBox
9085
 
9086
;--------------------------------
9087
 
9088
InitHorizFlySwimEnemy:
9089
      ldan ++$00        ;initialize horizontal speed
9090
      jmp SetESpd
9091
 
9092
;--------------------------------
9093
 
9094
InitBloober:
9095
           ldan ++$00               ;initialize horizontal speed
9096
           stax BlooperMoveSpeed,x
9097
SmallBBox: ldan ++$09               ;set specific bounding box size control
9098
         checka
9099
           bne SetBBox            ;unconditional branch
9100
 
9101
;--------------------------------
9102
 
9103
InitRedPTroopa:
9104
;CY = 0 after JumpEngine ???
9105
        or a ;???
9106
        push af
9107
          ldyn ++$30                    ;load central position adder for 48 pixels down
9108
          ldax Enemy_Y_Position,x      ;set vertical coordinate into location to
9109
          stax RedPTroopaOrigXPos,x    ;be used as original vertical coordinate
9110
        ld h,a
9111
        pop af
9112
        ld a,h
9113
         checka
9114
          bpl GetCent                 ;if vertical coordinate LOW  $80
9115
          ldyn ++$e0                    ;if =HIGH  $80, load position adder for 32 pixels up
9116
GetCent:  tya                         ;send central position adder to A
9117
          adcx Enemy_Y_Position,x      ;add to current vertical coordinate
9118
          stax RedPTroopaCenterYPos,x  ;store as central vertical coordinate
9119
TallBBox: ldan ++$03                    ;set specific bounding box size control
9120
SetBBox:  stax Enemy_BoundBoxCtrl,x    ;set bounding box control here
9121
          ldan ++$02                    ;set moving direction for left
9122
          stax Enemy_MovingDir,x
9123
InitVStf: ldan ++$00                    ;initialize vertical speed
9124
          stax Enemy_Y_Speed,x         ;and movement force
9125
          stax Enemy_Y_MoveForce,x
9126
          rts
9127
 
9128
;--------------------------------
9129
 
9130
InitBulletBill:
9131
      ldan ++$02                  ;set moving direction for left
9132
      stax Enemy_MovingDir,x
9133
      ldan ++$09                  ;set bounding box control for $09
9134
      stax Enemy_BoundBoxCtrl,x
9135
      rts
9136
 
9137
;--------------------------------
9138
 
9139
InitCheepCheep:
9140
      jsr SmallBBox              ;set vertical bounding box, speed, init others
9141
      ldax PseudoRandomBitReg,x   ;check one portion of LSFR
9142
      andn ++%00010000             ;get d4 from it
9143
      stax CheepCheepMoveMFlag,x  ;save as movement flag of some sort
9144
      ldax Enemy_Y_Position,x
9145
      stax CheepCheepOrigYPos,x   ;save original vertical coordinate here
9146
      rts
9147
 
9148
;--------------------------------
9149
 
9150
InitLakitu:
9151
      lda EnemyFrenzyBuffer      ;check to see if an enemy is already in
9152
         checka
9153
      bne KillLakitu             ;the frenzy buffer, and branch to kill lakitu if so
9154
 
9155
SetupLakitu:
9156
      ldan ++$00                   ;erase counter for lakitu's reappearance
9157
      sta LakituReappearTimer
9158
      jsr InitHorizFlySwimEnemy  ;set $03 as bounding box, set other attributes
9159
      jmp TallBBox2              ;set $03 as bounding box again (not necessary) and leave
9160
 
9161
KillLakitu:
9162
      jmp EraseEnemyObject
9163
 
9164
;--------------------------------
9165
;$01-$03 - used to hold pseudorandom difference adjusters
9166
 
9167
PRDiffAdjustData:
9168
      .db $26, $2c, $32, $38
9169
      .db $20, $22, $24, $26
9170
      .db $13, $14, $15, $16
9171
 
9172
LakituAndSpinyHandler:
9173
          lda FrenzyEnemyTimer    ;if timer here not expired, leave
9174
         checka
9175
          bne ExLSHand
9176
          cpxn ++$05                ;if we are on the special use slot, leave
9177
              cmpcy
9178
          bcs ExLSHand
9179
          ldan ++$80                ;set timer
9180
          sta FrenzyEnemyTimer
9181
          ldyn ++$04                ;start with the last enemy slot
9182
ChkLak:   lday Enemy_ID,y          ;check all enemy slots to see
9183
          cmpn ++Lakitu             ;if lakitu is on one of them
9184
          beq CreateSpiny         ;if so, branch out of this loop
9185
          dey                     ;otherwise check another slot
9186
          bpl ChkLak              ;loop until all slots are checked
9187
          inci LakituReappearTimer ;increment reappearance timer
9188
          lda LakituReappearTimer
9189
          cmpn ++$07                ;check to see if we're up to a certain value yet
9190
              cmpcy
9191
          bcc ExLSHand            ;if not, leave
9192
          ldxn ++$04                ;start with the last enemy slot again
9193
ChkNoEn:  ldax Enemy_Flag,x        ;check enemy buffer flag for non-active enemy slot
9194
         checka
9195
          beq CreateL             ;branch out of loop if found
9196
          dex                     ;otherwise check next slot
9197
          bpl ChkNoEn             ;branch until all slots are checked
9198
          bmi RetEOfs             ;if no empty slots were found, branch to leave
9199
CreateL:  ldan ++$00                ;initialize enemy state
9200
          stax Enemy_State,x
9201
          ldan ++Lakitu             ;create lakitu enemy object
9202
          stax Enemy_ID,x
9203
          jsr SetupLakitu         ;do a sub to set up lakitu
9204
          ldan ++$20
9205
          jsr PutAtRightExtent    ;finish setting up lakitu
9206
RetEOfs:  ldx ObjectOffset        ;get enemy object buffer offset again and leave
9207
ExLSHand: rts
9208
 
9209
;--------------------------------
9210
 
9211
CreateSpiny:
9212
          lda Player_Y_Position      ;if player above a certain point, branch to leave
9213
          cmpn ++$2c
9214
              cmpcy
9215
          bcc ExLSHand
9216
          lday Enemy_State,y          ;if lakitu is not in normal state, branch to leave
9217
         checka
9218
          bne ExLSHand
9219
          lday Enemy_PageLoc,y        ;store horizontal coordinates (high and low) of lakitu
9220
          stax Enemy_PageLoc,x        ;into the coordinates of the spiny we're going to create
9221
          lday Enemy_X_Position,y
9222
          stax Enemy_X_Position,x
9223
          ldan ++$01                   ;put spiny within vertical screen unit
9224
          stax Enemy_Y_HighPos,x
9225
          lday Enemy_Y_Position,y     ;put spiny eight pixels above where lakitu is
9226
          secsub
9227
          sbcn ++$08
9228
          stax Enemy_Y_Position,x
9229
          ldax PseudoRandomBitReg,x   ;get 2 LSB of LSFR and save to Y
9230
          andn ++%00000011
9231
          tay
9232
          ldxn ++$02
9233
DifLoop:  lday PRDiffAdjustData,y     ;get three values and save them
9234
          stax SCRATCHPAD+$01,x                  ;to $01-$03
9235
          iny
9236
          iny                        ;increment Y four bytes for each value
9237
          iny
9238
          iny
9239
          dex                        ;decrement X for each one
9240
          bpl DifLoop                ;loop until all three are written
9241
          ldx ObjectOffset           ;get enemy object buffer offset
9242
          jsr PlayerLakituDiff       ;move enemy, change direction, get value - difference
9243
          ldy Player_X_Speed         ;check player's horizontal speed
9244
          cpyn ++$08
9245
              cmpcy
9246
          bcs SetSpSpd               ;if moving faster than a certain amount, branch elsewhere
9247
          tay                        ;otherwise save value in A to Y for now
9248
          ldax PseudoRandomBitReg+1,x
9249
          andn ++%00000011             ;get one of the LSFR parts and save the 2 LSB
9250
          beq UsePosv                ;branch if neither bits are set
9251
          tya
9252
          eorn ++%11111111             ;otherwise get two's compliment of Y
9253
          tay
9254
          iny
9255
UsePosv:  tya                        ;put value from A in Y back to A (they will be lost anyway)
9256
SetSpSpd: jsr SmallBBox              ;set bounding box control, init attributes, lose contents of A
9257
          ldyn ++$02
9258
          stax Enemy_X_Speed,x        ;set horizontal speed to zero because previous contents
9259
          cmpn ++$00                   ;of A were lost...branch here will never be taken for
9260
          bmi SpinyRte               ;the same reason
9261
          dey
9262
SpinyRte: styx Enemy_MovingDir,x      ;set moving direction to the right
9263
          ldan ++$fd
9264
          stax Enemy_Y_Speed,x        ;set vertical speed to move upwards
9265
          ldan ++$01
9266
          stax Enemy_Flag,x           ;enable enemy object by setting flag
9267
          ldan ++$05
9268
          stax Enemy_State,x          ;put spiny in egg state and leave
9269
ChpChpEx: rts
9270
 
9271
;--------------------------------
9272
 
9273
FirebarSpinSpdData:
9274
      .db $28, $38, $28, $38, $28
9275
 
9276
FirebarSpinDirData:
9277
      .db $00, $00, $10, $10, $00
9278
 
9279
InitLongFirebar:
9280
      jsr DuplicateEnemyObj       ;create enemy object for long firebar
9281
 
9282
InitShortFirebar:
9283
      ldan ++$00                    ;initialize low byte of spin state
9284
      stax FirebarSpinState_Low,x
9285
      ldax Enemy_ID,x              ;subtract $1b from enemy identifier
9286
      secsub                         ;to get proper offset for firebar data
9287
      sbcn ++$1b
9288
      tay
9289
      lday FirebarSpinSpdData,y    ;get spinning speed of firebar
9290
      stax FirebarSpinSpeed,x
9291
      lday FirebarSpinDirData,y    ;get spinning direction of firebar
9292
      stax FirebarSpinDirection,x
9293
      ldax Enemy_Y_Position,x
9294
      clc                         ;add four pixels to vertical coordinate
9295
      adcn ++$04
9296
      stax Enemy_Y_Position,x
9297
      ldax Enemy_X_Position,x
9298
      clc                         ;add four pixels to horizontal coordinate
9299
      adcn ++$04
9300
          push af
9301
      stax Enemy_X_Position,x
9302
      ldax Enemy_PageLoc,x
9303
          ld h,a
9304
          pop af
9305
          ld a,h
9306
      adcn ++$00                    ;add carry to page location
9307
      stax Enemy_PageLoc,x
9308
      jmp TallBBox2               ;set bounding box control (not used) and leave
9309
 
9310
;--------------------------------
9311
;$00-$01 - used to hold pseudorandom bits
9312
 
9313
FlyCCXPositionData:
9314
      .db $80, $30, $40, $80
9315
      .db $30, $50, $50, $70
9316
      .db $20, $40, $80, $a0
9317
      .db $70, $40, $90, $68
9318
 
9319
FlyCCXSpeedData:
9320
      .db $0e, $05, $06, $0e
9321
      .db $1c, $20, $10, $0c
9322
      .db $1e, $22, $18, $14
9323
 
9324
FlyCCTimerData:
9325
      .db $10, $60, $20, $48
9326
 
9327
InitFlyingCheepCheep:
9328
         lda FrenzyEnemyTimer       ;if timer here not expired yet, branch to leave
9329
         checka
9330
         bne ChpChpEx
9331
         jsr SmallBBox              ;jump to set bounding box size $09 and init other values
9332
         ldax PseudoRandomBitReg+1,x
9333
         andn ++%00000011             ;set pseudorandom offset here
9334
         tay
9335
         lday FlyCCTimerData,y       ;load timer with pseudorandom offset
9336
         sta FrenzyEnemyTimer
9337
         ldyn ++$03                   ;load Y with default value
9338
         lda SecondaryHardMode
9339
         checka
9340
         beq MaxCC                  ;if secondary hard mode flag not set, do not increment Y
9341
         iny                        ;otherwise, increment Y to allow as many as four onscreen
9342
MaxCC:   sty SCRATCHPAD+$00                    ;store whatever pseudorandom bits are in Y
9343
         cpxi SCRATCHPAD+$00                    ;compare enemy object buffer offset with Y
9344
              cmpcy
9345
         bcs ChpChpEx               ;if X =HIGH  Y, branch to leave
9346
         ldax PseudoRandomBitReg,x
9347
         andn ++%00000011             ;get last two bits of LSFR, first part
9348
         sta SCRATCHPAD+$00                    ;and store in two places
9349
         sta SCRATCHPAD+$01
9350
         ldan ++$fb                   ;set vertical speed for cheep-cheep
9351
         stax Enemy_Y_Speed,x
9352
         ldan ++$00                   ;load default value
9353
         ldy Player_X_Speed         ;check player's horizontal speed
9354
         checky
9355
         beq GSeed                  ;if player not moving left or right, skip this part
9356
         ldan ++$04
9357
         cpyn ++$19                   ;if moving to the right but not very quickly,
9358
              cmpcy
9359
         bcc GSeed                  ;do not change A
9360
         asl                        ;otherwise, multiply A by 2
9361
GSeed:   pha                        ;save to stack
9362
         clc
9363
         adci SCRATCHPAD+$00                    ;add to last two bits of LSFR we saved earlier
9364
         sta SCRATCHPAD+$00                    ;save it there
9365
         ldax PseudoRandomBitReg+1,x
9366
         andn ++%00000011             ;if neither of the last two bits of second LSFR set,
9367
         beq RSeed                  ;skip this part and save contents of $00
9368
         ldax PseudoRandomBitReg+2,x
9369
         andn ++%00001111             ;otherwise overwrite with lower nybble of
9370
         sta SCRATCHPAD+$00                    ;third LSFR part
9371
RSeed:   pla                        ;get value from stack we saved earlier
9372
         clc
9373
         adci SCRATCHPAD+$01                    ;add to last two bits of LSFR we saved in other place
9374
         tay                        ;use as pseudorandom offset here
9375
         lday FlyCCXSpeedData,y      ;get horizontal speed using pseudorandom offset
9376
         stax Enemy_X_Speed,x
9377
         ldan ++$01                   ;set to move towards the right
9378
         stax Enemy_MovingDir,x
9379
         lda Player_X_Speed         ;if player moving left or right, branch ahead of this part
9380
         checka
9381
         bne D2XPos1
9382
         ldy SCRATCHPAD+$00                    ;get first LSFR or third LSFR lower nybble
9383
         tya                        ;and check for d1 set
9384
         andn ++%00000010
9385
         beq D2XPos1                ;if d1 not set, branch
9386
         ldax Enemy_X_Speed,x
9387
         eorn ++$ff                   ;if d1 set, change horizontal speed
9388
         clc                        ;into two's compliment, thus moving in the opposite
9389
         adcn ++$01                   ;direction
9390
         stax Enemy_X_Speed,x
9391
         incx Enemy_MovingDir,x      ;increment to move towards the left
9392
D2XPos1: tya                        ;get first LSFR or third LSFR lower nybble again
9393
         andn ++%00000010
9394
         beq D2XPos2                ;check for d1 set again, branch again if not set
9395
         lda Player_X_Position      ;get player's horizontal position
9396
         clc
9397
         adcy FlyCCXPositionData,y   ;if d1 set, add value obtained from pseudorandom offset
9398
          push af
9399
         stax Enemy_X_Position,x     ;and save as enemy's horizontal position
9400
          pop af
9401
         lda Player_PageLoc         ;get player's page location
9402
         adcn ++$00                   ;add carry and jump past this part
9403
         jmp FinCCSt
9404
D2XPos2: lda Player_X_Position      ;get player's horizontal position
9405
         secsub
9406
         sbcy FlyCCXPositionData,y   ;if d1 not set, subtract value obtained from pseudorandom
9407
          push af
9408
         stax Enemy_X_Position,x     ;offset and save as enemy's horizontal position
9409
          pop af
9410
         lda Player_PageLoc         ;get player's page location
9411
         sbcn ++$00                   ;subtract borrow
9412
FinCCSt: stax Enemy_PageLoc,x        ;save as enemy's page location
9413
         ldan ++$01
9414
         stax Enemy_Flag,x           ;set enemy's buffer flag
9415
         stax Enemy_Y_HighPos,x      ;set enemy's high vertical byte
9416
         ldan ++$f8
9417
         stax Enemy_Y_Position,x     ;put enemy below the screen, and we are done
9418
         rts
9419
 
9420
;--------------------------------
9421
 
9422
InitBowser:
9423
      jsr DuplicateEnemyObj     ;jump to create another bowser object
9424
      stx BowserFront_Offset    ;save offset of first here
9425
      ldan ++$00
9426
      sta BowserBodyControls    ;initialize bowser's body controls
9427
      sta BridgeCollapseOffset  ;and bridge collapse offset
9428
      ldax Enemy_X_Position,x
9429
      sta BowserOrigXPos        ;store original horizontal position here
9430
      ldan ++$df
9431
      sta BowserFireBreathTimer ;store something here
9432
      stax Enemy_MovingDir,x     ;and in moving direction
9433
      ldan ++$20
9434
      sta BowserFeetCounter     ;set bowser's feet timer and in enemy timer
9435
      stax EnemyFrameTimer,x
9436
      ldan ++$05
9437
      sta BowserHitPoints       ;give bowser 5 hit points
9438
      lsr
9439
      sta BowserMovementSpeed   ;set default movement speed here
9440
      rts
9441
 
9442
;--------------------------------
9443
 
9444
DuplicateEnemyObj:
9445
        ldyn ++$ff                ;start at beginning of enemy slots
9446
FSLoop: iny                     ;increment one slot
9447
        lday Enemy_Flag,y        ;check enemy buffer flag for empty slot
9448
         checka
9449
        bne FSLoop              ;if set, branch and keep checking
9450
        sty DuplicateObj_Offset ;otherwise set offset here
9451
        txa                     ;transfer original enemy buffer offset
9452
        oran ++%10000000          ;store with d7 set as flag in new enemy
9453
        stay Enemy_Flag,y        ;slot as well as enemy offset
9454
        ldax Enemy_PageLoc,x
9455
        stay Enemy_PageLoc,y     ;copy page location and horizontal coordinates
9456
        ldax Enemy_X_Position,x  ;from original enemy to new enemy
9457
        stay Enemy_X_Position,y
9458
        ldan ++$01
9459
        stax Enemy_Flag,x        ;set flag as normal for original enemy
9460
        stay Enemy_Y_HighPos,y   ;set high vertical byte for new enemy
9461
        ldax Enemy_Y_Position,x
9462
        stay Enemy_Y_Position,y  ;copy vertical coordinate from original to new
9463
FlmEx:  rts                     ;and then leave
9464
 
9465
;--------------------------------
9466
 
9467
FlameYPosData:
9468
      .db $90, $80, $70, $90
9469
 
9470
FlameYMFAdderData:
9471
      .db $ff, $01
9472
 
9473
InitBowserFlame:
9474
        lda FrenzyEnemyTimer        ;if timer not expired yet, branch to leave
9475
         checka
9476
        bne FlmEx
9477
        stax Enemy_Y_MoveForce,x     ;reset something here
9478
        lda NoiseSoundQueue
9479
        oran ++Sfx_BowserFlame        ;load bowser's flame sound into queue
9480
        sta NoiseSoundQueue
9481
        ldy BowserFront_Offset      ;get bowser's buffer offset
9482
        lday Enemy_ID,y              ;check for bowser
9483
        cmpn ++Bowser
9484
        beq SpawnFromMouth          ;branch if found
9485
        jsr SetFlameTimer           ;get timer data based on flame counter
9486
        clc
9487
        adcn ++$20                    ;add 32 frames by default
9488
        ldy SecondaryHardMode
9489
         checky
9490
        beq SetFrT                  ;if secondary mode flag not set, use as timer setting
9491
        secsub
9492
        sbcn ++$10                    ;otherwise subtract 16 frames for secondary hard mode
9493
SetFrT: sta FrenzyEnemyTimer        ;set timer accordingly
9494
        ldax PseudoRandomBitReg,x
9495
        andn ++%00000011              ;get 2 LSB from first part of LSFR
9496
        stax BowserFlamePRandomOfs,x ;set here
9497
        tay                         ;use as offset
9498
        lday FlameYPosData,y         ;load vertical position based on pseudorandom offset
9499
 
9500
PutAtRightExtent:
9501
      stax Enemy_Y_Position,x    ;set vertical position
9502
      lda ScreenRight_X_Pos
9503
      clc
9504
      adcn ++$20                  ;place enemy 32 pixels beyond right side of screen
9505
       push af
9506
      stax Enemy_X_Position,x
9507
       pop af
9508
      lda ScreenRight_PageLoc
9509
      adcn ++$00                  ;add carry
9510
      stax Enemy_PageLoc,x
9511
      jmp FinishFlame           ;skip this part to finish setting values
9512
 
9513
SpawnFromMouth:
9514
       lday Enemy_X_Position,y    ;get bowser's horizontal position
9515
       secsub
9516
       sbcn ++$0e                  ;subtract 14 pixels
9517
       stax Enemy_X_Position,x    ;save as flame's horizontal position
9518
       lday Enemy_PageLoc,y
9519
       stax Enemy_PageLoc,x       ;copy page location from bowser to flame
9520
       lday Enemy_Y_Position,y
9521
       clc                       ;add 8 pixels to bowser's vertical position
9522
       adcn ++$08
9523
       stax Enemy_Y_Position,x    ;save as flame's vertical position
9524
       ldax PseudoRandomBitReg,x
9525
       andn ++%00000011            ;get 2 LSB from first part of LSFR
9526
       stax Enemy_YMF_Dummy,x     ;save here
9527
       tay                       ;use as offset
9528
       lday FlameYPosData,y       ;get value here using bits as offset
9529
       ldyn ++$00                  ;load default offset
9530
       cmpx Enemy_Y_Position,x    ;compare value to flame's current vertical position
9531
              cmpcy
9532
       bcc SetMF                 ;if less, do not increment offset
9533
       iny                       ;otherwise increment now
9534
SetMF: lday FlameYMFAdderData,y   ;get value here and save
9535
       stax Enemy_Y_MoveForce,x   ;to vertical movement force
9536
       ldan ++$00
9537
       sta EnemyFrenzyBuffer     ;clear enemy frenzy buffer
9538
 
9539
FinishFlame:
9540
      ldan ++$08                 ;set $08 for bounding box control
9541
      stax Enemy_BoundBoxCtrl,x
9542
      ldan ++$01                 ;set high byte of vertical and
9543
      stax Enemy_Y_HighPos,x    ;enemy buffer flag
9544
      stax Enemy_Flag,x
9545
      lsr
9546
      stax Enemy_X_MoveForce,x  ;initialize horizontal movement force (  X-), and
9547
      stax Enemy_State,x        ;enemy state
9548
      rts
9549
 
9550
;--------------------------------
9551
 
9552
FireworksXPosData:
9553
      .db $00, $30, $60, $60, $00, $20
9554
 
9555
FireworksYPosData:
9556
      .db $60, $40, $70, $40, $60, $30
9557
 
9558
InitFireworks:
9559
          lda FrenzyEnemyTimer         ;if timer not expired yet, branch to leave
9560
         checka
9561
          bne ExitFWk
9562
          ldan ++$20                     ;otherwise reset timer
9563
          sta FrenzyEnemyTimer
9564
          deci FireworksCounter         ;decrement for each explosion
9565
          ldyn ++$06                     ;start at last slot
9566
StarFChk: dey
9567
          lday Enemy_ID,y               ;check for presence of star flag object
9568
          cmpn ++StarFlagObject          ;if there isn't a star flag object,
9569
          bne StarFChk                 ;routine goes into infinite loop = crash
9570
          lday Enemy_X_Position,y
9571
          secsub                          ;get horizontal coordinate of star flag object, then
9572
          sbcn ++$30                     ;subtract 48 pixels from it and save to
9573
          pha                          ;the stack
9574
          ldaykeepcy Enemy_PageLoc,y
9575
          sbcn ++$00                     ;subtract the carry from the page location
9576
          sta SCRATCHPAD+$00                      ;of the star flag object
9577
          lda FireworksCounter         ;get fireworks counter
9578
          clc
9579
          adcy Enemy_State,y            ;add state of star flag object (possibly not necessary)
9580
          tay                          ;use as offset
9581
          pla                          ;get saved horizontal coordinate of star flag - 48 pixels
9582
          clc
9583
          adcy FireworksXPosData,y      ;add number based on offset of fireworks counter
9584
           push af
9585
          stax Enemy_X_Position,x       ;store as the fireworks object horizontal coordinate
9586
           pop af
9587
          lda SCRATCHPAD+$00
9588
          adcn ++$00                     ;add carry and store as page location for
9589
          stax Enemy_PageLoc,x          ;the fireworks object
9590
          lday FireworksYPosData,y      ;get vertical position using same offset
9591
          stax Enemy_Y_Position,x       ;and store as vertical coordinate for fireworks object
9592
          ldan ++$01
9593
          stax Enemy_Y_HighPos,x        ;store in vertical high byte
9594
          stax Enemy_Flag,x             ;and activate enemy buffer flag
9595
          lsr
9596
          stax ExplosionGfxCounter,x    ;initialize explosion counter
9597
          ldan ++$08
9598
          stax ExplosionTimerCounter,x  ;set explosion timing counter
9599
ExitFWk:  rts
9600
 
9601
;--------------------------------
9602
 
9603
Bitmasks:
9604
      .db %00000001, %00000010, %00000100, %00001000, %00010000, %00100000, %01000000, %10000000
9605
 
9606
Enemy17YPosData:
9607
      .db $40, $30, $90, $50, $20, $60, $a0, $70
9608
 
9609
SwimCC_IDData:
9610
      .db $0a, $0b
9611
 
9612
BulletBillCheepCheep:
9613
         lda FrenzyEnemyTimer      ;if timer not expired yet, branch to leave
9614
         checka
9615
         bne ExF17
9616
         lda AreaType              ;are we in a water-type level?
9617
         checka
9618
         bne DoBulletBills         ;if not, branch elsewhere
9619
         cpxn ++$03                  ;are we past third enemy slot?
9620
              cmpcy
9621
         bcs ExF17                 ;if so, branch to leave
9622
         ldyn ++$00                  ;load default offset
9623
         ldax PseudoRandomBitReg,x
9624
         cmpn ++$aa                  ;check first part of LSFR against preset value
9625
              cmpcy
9626
         bcc ChkW2                 ;if less than preset, do not increment offset
9627
         iny                       ;otherwise increment
9628
ChkW2:   lda WorldNumber           ;check world number
9629
         cmpn ++World2
9630
         beq Get17ID               ;if we're on world 2, do not increment offset
9631
         iny                       ;otherwise increment
9632
Get17ID: tya
9633
         andn ++%00000001            ;mask out all but last bit of offset
9634
         tay
9635
         lday SwimCC_IDData,y       ;load identifier for cheep-cheeps
9636
Set17ID: stax Enemy_ID,x            ;store whatever's in A as enemy identifier
9637
         lda BitMFilter
9638
         cmpn ++$ff                  ;if not all bits set, skip init part and compare bits
9639
         bne GetRBit
9640
         ldan ++$00                  ;initialize vertical position filter
9641
         sta BitMFilter
9642
GetRBit: ldax PseudoRandomBitReg,x  ;get first part of LSFR
9643
         andn ++%00000111            ;mask out all but 3 LSB
9644
ChkRBit: tay                       ;use as offset
9645
         lday Bitmasks,y            ;load bitmask
9646
         biti BitMFilter            ;perform AND on filter without changing it
9647
         beq AddFBit
9648
         iny                       ;increment offset
9649
         tya
9650
         andn ++%00000111            ;mask out all but 3 LSB thus keeping it 0-7
9651
         jmp ChkRBit               ;do another check
9652
AddFBit: orai BitMFilter            ;add bit to already set bits in filter
9653
         sta BitMFilter            ;and store
9654
         lday Enemy17YPosData,y     ;load vertical position using offset
9655
         jsr PutAtRightExtent      ;set vertical position and other values
9656
         stax Enemy_YMF_Dummy,x     ;initialize dummy variable
9657
         ldan ++$20                  ;set timer
9658
         sta FrenzyEnemyTimer
9659
         jmp CheckpointEnemyID     ;process our new enemy object
9660
 
9661
DoBulletBills:
9662
          ldyn ++$ff                   ;start at beginning of enemy slots
9663
BB_SLoop: iny                        ;move onto the next slot
9664
          cpyn ++$05                   ;branch to play sound if we've done all slots
9665
              cmpcy
9666
          bcs FireBulletBill
9667
          lday Enemy_Flag,y           ;if enemy buffer flag not set,
9668
         checka
9669
          beq BB_SLoop               ;loop back and check another slot
9670
          lday Enemy_ID,y
9671
          cmpn ++BulletBill_FrenzyVar  ;check enemy identifier for
9672
          bne BB_SLoop               ;bullet bill object (frenzy variant)
9673
ExF17:    rts                        ;if found, leave
9674
 
9675
FireBulletBill:
9676
      lda Square2SoundQueue
9677
      oran ++Sfx_Blast            ;play fireworks/gunfire sound
9678
      sta Square2SoundQueue
9679
      ldan ++BulletBill_FrenzyVar ;load identifier for bullet bill object
9680
         checka
9681
      bne Set17ID               ;unconditional branch
9682
 
9683
;--------------------------------
9684
;$00 - used to store Y position of group enemies
9685
;$01 - used to store enemy ID
9686
;$02 - used to store page location of right side of screen
9687
;$03 - used to store X position of right side of screen
9688
 
9689
HandleGroupEnemies:
9690
        ldyn ++$00                  ;load value for green koopa troopa
9691
        secsub
9692
        sbcn ++$37                  ;subtract $37 from second byte read
9693
        pha                       ;save result in stack for now
9694
        cmpn ++$04                  ;was byte in $3b-$3e range?
9695
              cmpcy
9696
        bcs SnglID                ;if so, branch
9697
        pha                       ;save another copy to stack
9698
        ldyn ++Goomba               ;load value for goomba enemy
9699
        lda PrimaryHardMode       ;if primary hard mode flag not set,
9700
         checka
9701
        beq PullID                ;branch, otherwise change to value
9702
        ldyn ++BuzzyBeetle          ;for buzzy beetle
9703
PullID: pla                       ;get second copy from stack
9704
SnglID: sty SCRATCHPAD+$01                   ;save enemy id here
9705
        ldyn ++$b0                  ;load default y coordinate
9706
        andn ++$02                  ;check to see if d1 was set
9707
        beq SetYGp                ;if so, move y coordinate up,
9708
        ldyn ++$70                  ;otherwise branch and use default
9709
SetYGp: sty SCRATCHPAD+$00                   ;save y coordinate here
9710
        lda ScreenRight_PageLoc   ;get page number of right edge of screen
9711
        sta SCRATCHPAD+$02                   ;save here
9712
        lda ScreenRight_X_Pos     ;get pixel coordinate of right edge
9713
        sta SCRATCHPAD+$03                   ;save here
9714
        ldyn ++$02                  ;load two enemies by default
9715
        pla                       ;get first copy from stack
9716
        lsr                       ;check to see if d0 was set
9717
        bcc CntGrp                ;if not, use default value
9718
        iny                       ;otherwise increment to three enemies
9719
CntGrp: sty NumberofGroupEnemies  ;save number of enemies here
9720
GrLoop: ldxn ++$ff                  ;start at beginning of enemy buffers
9721
GSltLp: inx                       ;increment and branch if past
9722
        cpxn ++$05                  ;end of buffers
9723
              cmpcy
9724
        bcs NextED
9725
        ldax Enemy_Flag,x          ;check to see if enemy is already
9726
         checka
9727
        bne GSltLp                ;stored in buffer, and branch if so
9728
        lda SCRATCHPAD+$01
9729
        stax Enemy_ID,x            ;store enemy object identifier
9730
        lda SCRATCHPAD+$02
9731
        stax Enemy_PageLoc,x       ;store page location for enemy object
9732
        lda SCRATCHPAD+$03
9733
        stax Enemy_X_Position,x    ;store x coordinate for enemy object
9734
        clc
9735
        adcn ++$18                  ;add 24 pixels for next enemy
9736
        sta SCRATCHPAD+$03
9737
        lda SCRATCHPAD+$02                   ;add carry to page location for
9738
        adcn ++$00                  ;next enemy
9739
        sta SCRATCHPAD+$02
9740
        lda SCRATCHPAD+$00                   ;store y coordinate for enemy object
9741
        stax Enemy_Y_Position,x
9742
        ldan ++$01                  ;activate flag for buffer, and
9743
        stax Enemy_Y_HighPos,x     ;put enemy within the screen vertically
9744
        stax Enemy_Flag,x
9745
        jsr CheckpointEnemyID     ;process each enemy object separately
9746
        deci NumberofGroupEnemies  ;do this until we run out of enemy objects
9747
        bne GrLoop
9748
NextED: jmp Inc2B                 ;jump to increment data offset and leave
9749
 
9750
;--------------------------------
9751
 
9752
InitPiranhaPlant:
9753
      ldan ++$01                     ;set initial speed
9754
      stax PiranhaPlant_Y_Speed,x
9755
      lsr
9756
      stax Enemy_State,x            ;initialize enemy state and what would normally
9757
      stax PiranhaPlant_MoveFlag,x  ;be used as vertical speed, but not in this case
9758
      ldax Enemy_Y_Position,x
9759
      stax PiranhaPlantDownYPos,x   ;save original vertical coordinate here
9760
      secsub
9761
      sbcn ++$18
9762
      stax PiranhaPlantUpYPos,x     ;save original vertical coordinate - 24 pixels here
9763
      ldan ++$09
9764
      jmp SetBBox2                 ;set specific value for bounding box control ;   #9  misc objects ( ???)
9765
 
9766
;--------------------------------
9767
 
9768
InitEnemyFrenzy:
9769
      ldax Enemy_ID,x        ;load enemy identifier
9770
      sta EnemyFrenzyBuffer ;save in enemy frenzy buffer
9771
      secsub
9772
      sbcn ++$12              ;subtract 12 and use as offset for jump engine
9773
      jsr JumpEngine
9774
 
9775
;frenzy object jump table
9776
      .dw LakituAndSpinyHandler
9777
      .dw NoFrenzyCode
9778
      .dw InitFlyingCheepCheep
9779
      .dw InitBowserFlame
9780
      .dw InitFireworks
9781
      .dw BulletBillCheepCheep
9782
 
9783
;--------------------------------
9784
 
9785
NoFrenzyCode:
9786
      rts
9787
 
9788
;--------------------------------
9789
 
9790
EndFrenzy:
9791
           ldyn ++$05               ;start at last slot
9792
LakituChk: lday Enemy_ID,y         ;check enemy identifiers
9793
           cmpn ++Lakitu            ;for lakitu
9794
           bne NextFSlot
9795
           ldan ++$01               ;if found, set state
9796
           stay Enemy_State,y
9797
NextFSlot: dey                    ;move onto the next slot
9798
           bpl LakituChk          ;do this until all slots are checked
9799
           ldan ++$00
9800
           sta EnemyFrenzyBuffer  ;empty enemy frenzy buffer
9801
           stax Enemy_Flag,x       ;disable enemy buffer flag for this object
9802
           rts
9803
 
9804
;--------------------------------
9805
 
9806
InitJumpGPTroopa:
9807
           ldan ++$02                  ;set for movement to the left
9808
           stax Enemy_MovingDir,x
9809
           ldan ++$f8                  ;set horizontal speed
9810
           stax Enemy_X_Speed,x
9811
TallBBox2: ldan ++$03                  ;set specific value for bounding box control
9812
SetBBox2:  stax Enemy_BoundBoxCtrl,x  ;set bounding box control then leave
9813
           rts
9814
 
9815
;--------------------------------
9816
 
9817
InitBalPlatform:
9818
        decx Enemy_Y_Position,x    ;raise vertical position by two pixels
9819
        decx Enemy_Y_Position,x
9820
        ldy SecondaryHardMode     ;if secondary hard mode flag not set,
9821
         checky
9822
        bne AlignP                ;branch ahead
9823
        ldyn ++$02                  ;otherwise set value here
9824
        jsr PosPlatform           ;do a sub to add or subtract pixels
9825
AlignP: ldyn ++$ff                  ;set default value here for now
9826
        lda BalPlatformAlignment  ;get current balance platform alignment
9827
        stax Enemy_State,x         ;set platform alignment to object state here
9828
         checka
9829
        bpl SetBPA                ;if old alignment $ff, put $ff as alignment for negative
9830
        txa                       ;if old contents already $ff, put
9831
        tay                       ;object offset as alignment to make next positive
9832
SetBPA: sty BalPlatformAlignment  ;store whatever value's in Y here
9833
        ldan ++$00
9834
        stax Enemy_MovingDir,x     ;init moving direction
9835
        tay                       ;init Y
9836
        jsr PosPlatform           ;do a sub to add 8 pixels, then run shared code here
9837
 
9838
;--------------------------------
9839
 
9840
InitDropPlatform:
9841
      ldan ++$ff
9842
      stax PlatformCollisionFlag,x  ;set some value here
9843
      jmp CommonPlatCode           ;then jump ahead to execute more code
9844
 
9845
;--------------------------------
9846
 
9847
InitHoriPlatform:
9848
      ldan ++$00
9849
      stax XMoveSecondaryCounter,x  ;init one of the moving counters
9850
      jmp CommonPlatCode           ;jump ahead to execute more code
9851
 
9852
;--------------------------------
9853
 
9854
InitVertPlatform:
9855
       ldyn ++$40                    ;set default value here
9856
       ldax Enemy_Y_Position,x      ;check vertical position
9857
         checka
9858
       bpl SetYO                   ;if above a certain point, skip this part
9859
       eorn ++$ff
9860
       clc                         ;otherwise get two's compliment
9861
       adcn ++$01
9862
       ldyn ++$c0                    ;get alternate value to add to vertical position
9863
SetYO: stax YPlatformTopYPos,x      ;save as top vertical position
9864
       tya
9865
       clc                         ;load value from earlier, add number of pixels 
9866
       adcx Enemy_Y_Position,x      ;to vertical position
9867
       stax YPlatformCenterYPos,x   ;save result as central vertical position
9868
 
9869
;--------------------------------
9870
 
9871
CommonPlatCode:
9872
        jsr InitVStf              ;do a sub to init certain other values 
9873
SPBBox: ldan ++$05                  ;set default bounding box size control
9874
        ldy AreaType
9875
        cpyn ++$03                  ;check for castle-type level
9876
        beq CasPBB                ;use default value if found
9877
        ldy SecondaryHardMode     ;otherwise check for secondary hard mode flag
9878
         checky
9879
        bne CasPBB                ;if set, use default value
9880
        ldan ++$06                  ;use alternate value if not castle or secondary not set
9881
CasPBB: stax Enemy_BoundBoxCtrl,x  ;set bounding box size control here and leave
9882
        rts
9883
 
9884
;--------------------------------
9885
 
9886
LargeLiftUp:
9887
      jsr PlatLiftUp       ;execute code for platforms going up
9888
      jmp LargeLiftBBox    ;overwrite bounding box for large platforms
9889
 
9890
LargeLiftDown:
9891
      jsr PlatLiftDown     ;execute code for platforms going down
9892
 
9893
LargeLiftBBox:
9894
      jmp SPBBox           ;jump to overwrite bounding box size control
9895
 
9896
;--------------------------------
9897
 
9898
PlatLiftUp:
9899
      ldan ++$10                 ;set movement amount here
9900
      stax Enemy_Y_MoveForce,x
9901
      ldan ++$ff                 ;set moving speed for platforms going up
9902
      stax Enemy_Y_Speed,x
9903
      jmp CommonSmallLift      ;skip ahead to part we should be executing
9904
 
9905
;--------------------------------
9906
 
9907
PlatLiftDown:
9908
      ldan ++$f0                 ;set movement amount here
9909
      stax Enemy_Y_MoveForce,x
9910
      ldan ++$00                 ;set moving speed for platforms going down
9911
      stax Enemy_Y_Speed,x
9912
 
9913
;--------------------------------
9914
 
9915
CommonSmallLift:
9916
      ldyn ++$01
9917
      jsr PosPlatform           ;do a sub to add 12 pixels due to preset value  
9918
      ldan ++$04
9919
      stax Enemy_BoundBoxCtrl,x  ;set bounding box control for small platforms
9920
      rts
9921
 
9922
;--------------------------------
9923
 
9924
PlatPosDataLow:
9925
      .db $08,$0c,$f8
9926
 
9927
PlatPosDataHigh:
9928
      .db $00,$00,$ff
9929
 
9930
PosPlatform:
9931
      ldax Enemy_X_Position,x  ;get horizontal coordinate
9932
      clc
9933
      adcy PlatPosDataLow,y    ;add or subtract pixels depending on offset
9934
          push af
9935
      stax Enemy_X_Position,x  ;store as new horizontal coordinate
9936
      ldax Enemy_PageLoc,x
9937
          ld h,a
9938
          pop af
9939
          ld a,h
9940
      adcy PlatPosDataHigh,y   ;add or subtract page location depending on offset
9941
      stax Enemy_PageLoc,x     ;store as new page location
9942
      rts                     ;and go back
9943
 
9944
;--------------------------------
9945
 
9946
EndOfEnemyInitCode:
9947
      rts
9948
 
9949
;-------------------------------------------------------------------------------------
9950
 
9951
RunEnemyObjectsCore:
9952
        ;jr $
9953
       ldx ObjectOffset  ;get offset for enemy object buffer
9954
       ldan ++$00          ;load value 0 for jump engine by default
9955
       ldyx Enemy_ID,x
9956
       cpyn ++$15          ;if enemy object LOW  $15, use default value
9957
              cmpcy
9958
       bcc JmpEO
9959
       tya               ;otherwise subtract $14 from the value and use
9960
              cmpcy
9961
       sbcn ++$14          ;as value for jump engine
9962
JmpEO: jsr JumpEngine
9963
 
9964
      .dw RunNormalEnemies  ;for objects $00-$14
9965
 
9966
      .dw RunBowserFlame    ;for objects $15-$1f
9967
      .dw RunFireworks
9968
      .dw NoRunCode
9969
      .dw NoRunCode
9970
      .dw NoRunCode
9971
      .dw NoRunCode
9972
      .dw RunFirebarObj
9973
      .dw RunFirebarObj
9974
      .dw RunFirebarObj
9975
      .dw RunFirebarObj
9976
      .dw RunFirebarObj
9977
 
9978
      .dw RunFirebarObj     ;for objects $20-$2f
9979
      .dw RunFirebarObj
9980
      .dw RunFirebarObj
9981
      .dw NoRunCode
9982
      .dw RunLargePlatform
9983
      .dw RunLargePlatform
9984
      .dw RunLargePlatform
9985
      .dw RunLargePlatform
9986
      .dw RunLargePlatform
9987
      .dw RunLargePlatform
9988
      .dw RunLargePlatform
9989
      .dw RunSmallPlatform
9990
      .dw RunSmallPlatform
9991
      .dw RunBowser
9992
      .dw PowerUpObjHandler
9993
      .dw VineObjectHandler
9994
 
9995
      .dw NoRunCode         ;for objects $30-$35
9996
      .dw RunStarFlagObj
9997
      .dw JumpspringHandler
9998
      .dw NoRunCode
9999
      .dw WarpZoneObject
10000
      .dw RunRetainerObj
10001
 
10002
;--------------------------------
10003
 
10004
NoRunCode:
10005
      rts
10006
 
10007
;--------------------------------
10008
 
10009
RunRetainerObj:
10010
      jsr GetEnemyOffscreenBits
10011
      jsr RelativeEnemyPosition
10012
      jmp EnemyGfxHandler
10013
 
10014
;--------------------------------
10015
 
10016
RunNormalEnemies:
10017
;TODO   
10018
          ldan ++$00                  ;init sprite attributes
10019
          stax Enemy_SprAttrib,x
10020
          ;jr $
10021
          jsr GetEnemyOffscreenBits ;1589t (497 opt)
10022
          jsr RelativeEnemyPosition ;316t (274 opt)
174 demige 10023
         if Z80
10024
logicframe=$+1
10025
            ld l,0
10026
            dec l
10027
            call z,EnemyGfxHandler ;     (  )
10028
         else
10029
          jsr EnemyGfxHandler ;4939t ( 3   768t) (3280 opt) <----- TODO  ,      ?
10030
         endif
171 demige 10031
          jsr GetEnemyBoundBox ;631t (452 opt)
10032
          jsr EnemyToBGCollisionDet ;3500t ( ChkUnderEnemy (cc46) = 1193t, BlockBufferChk_Enemy (cf18) = 1159t) (2058 opt) <-----
10033
          jsr EnemiesCollision ;45/230t (   ) (209 opt)
10034
          jsr PlayerEnemyCollision ;230t (58 opt)
10035
          ldy TimerControl          ;if master timer control set, skip to last routine
10036
         checky
10037
          bne SkipMove
10038
          jsr EnemyMovementSubs ;1408t (833 opt)
10039
SkipMove: jmp OffscreenBoundsCheck
10040
 
10041
EnemyMovementSubs:
10042
      ldax Enemy_ID,x
10043
      jsr JumpEngine
10044
 
10045
      .dw MoveNormalEnemy      ;only objects $00-$14 use this table
10046
      .dw MoveNormalEnemy
10047
      .dw MoveNormalEnemy
10048
      .dw MoveNormalEnemy
10049
      .dw MoveNormalEnemy
10050
      .dw ProcHammerBro
10051
      .dw MoveNormalEnemy
10052
      .dw MoveBloober
10053
      .dw MoveBulletBill
10054
      .dw NoMoveCode
10055
      .dw MoveSwimmingCheepCheep
10056
      .dw MoveSwimmingCheepCheep
10057
      .dw MovePodoboo
10058
      .dw MovePiranhaPlant
10059
      .dw MoveJumpingEnemy
10060
      .dw ProcMoveRedPTroopa
10061
      .dw MoveFlyGreenPTroopa
10062
      .dw MoveLakitu
10063
      .dw MoveNormalEnemy
10064
      .dw NoMoveCode   ;dummy
10065
      .dw MoveFlyingCheepCheep
10066
 
10067
;--------------------------------
10068
 
10069
NoMoveCode:
10070
      rts
10071
 
10072
;--------------------------------
10073
 
10074
RunBowserFlame:
10075
      jsr ProcBowserFlame
10076
      jsr GetEnemyOffscreenBits
10077
      jsr RelativeEnemyPosition
10078
      jsr GetEnemyBoundBox
10079
      jsr PlayerEnemyCollision
10080
      jmp OffscreenBoundsCheck
10081
 
10082
;--------------------------------
10083
 
10084
RunFirebarObj:
10085
      jsr ProcFirebar
10086
      jmp OffscreenBoundsCheck
10087
 
10088
;--------------------------------
10089
 
10090
RunSmallPlatform:
10091
      jsr GetEnemyOffscreenBits
10092
      jsr RelativeEnemyPosition
10093
      jsr SmallPlatformBoundBox
10094
      jsr SmallPlatformCollision
10095
      jsr RelativeEnemyPosition
10096
      jsr DrawSmallPlatform
10097
      jsr MoveSmallPlatform
10098
      jmp OffscreenBoundsCheck
10099
 
10100
;--------------------------------
10101
 
10102
RunLargePlatform:
10103
        jsr GetEnemyOffscreenBits
10104
        jsr RelativeEnemyPosition
10105
        jsr LargePlatformBoundBox
10106
        jsr LargePlatformCollision
10107
        lda TimerControl             ;if master timer control set,
10108
         checka
10109
        bne SkipPT                   ;skip subroutine tree
10110
        jsr LargePlatformSubroutines
10111
SkipPT: jsr RelativeEnemyPosition
10112
        jsr DrawLargePlatform
10113
        jmp OffscreenBoundsCheck
10114
 
10115
;--------------------------------
10116
 
10117
LargePlatformSubroutines:
10118
      ldax Enemy_ID,x  ;subtract $24 to get proper offset for jump table
10119
      secsub
10120
      sbcn ++$24
10121
      jsr JumpEngine
10122
 
10123
      .dw BalancePlatform   ;table used by objects $24-$2a
10124
      .dw YMovingPlatform
10125
      .dw MoveLargeLiftPlat
10126
      .dw MoveLargeLiftPlat
10127
      .dw XMovingPlatform
10128
      .dw DropPlatform
10129
      .dw RightPlatform
10130
 
10131
;-------------------------------------------------------------------------------------
10132
 
10133
EraseEnemyObject:
10134
;TODO ix
10135
      ldan ++$00                 ;clear all enemy object variables
10136
      stax Enemy_Flag,x
10137
      stax Enemy_ID,x
10138
      stax Enemy_State,x
10139
      stax FloateyNum_Control,x
10140
      stax EnemyIntervalTimer,x
10141
      stax ShellChainCounter,x
10142
      stax Enemy_SprAttrib,x
10143
      stax EnemyFrameTimer,x
10144
      rts
10145
 
10146
;-------------------------------------------------------------------------------------
10147
 
10148
MovePodoboo:
10149
      ldax EnemyIntervalTimer,x   ;check enemy timer
10150
         checka
10151
      bne PdbM                   ;branch to move enemy if not expired
10152
      jsr InitPodoboo            ;otherwise set up podoboo again
10153
      ldax PseudoRandomBitReg+1,x ;get part of LSFR
10154
      oran ++%10000000             ;set d7
10155
      stax Enemy_Y_MoveForce,x    ;store as movement force
10156
      andn ++%00001111             ;mask out high nybble
10157
      oran ++$06                   ;set for at least six intervals
10158
      stax EnemyIntervalTimer,x   ;store as new enemy timer
10159
      ldan ++$f9
10160
      stax Enemy_Y_Speed,x        ;set vertical speed to move podoboo upwards
10161
PdbM: jmp MoveJ_EnemyVertically  ;branch to impose gravity on podoboo
10162
 
10163
;--------------------------------
10164
;$00 - used in HammerBroJumpCode as bitmask
10165
 
10166
HammerThrowTmrData:
10167
      .db $30, $1c
10168
 
10169
XSpeedAdderData:
10170
      .db $00, $e8, $00, $18
10171
 
10172
RevivedXSpeed:
10173
      .db $08, $f8, $0c, $f4
10174
 
10175
ProcHammerBro:
10176
       ldax Enemy_State,x          ;check hammer bro's enemy state for d5 set
10177
       andn ++%00100000
10178
       beq ChkJH                  ;if not set, go ahead with code
10179
       jmp MoveDefeatedEnemy      ;otherwise jump to something else
10180
ChkJH: ldax HammerBroJumpTimer,x   ;check jump timer
10181
         checka
10182
       beq HammerBroJumpCode      ;if expired, branch to jump
10183
       decx HammerBroJumpTimer,x   ;otherwise decrement jump timer
10184
       lda Enemy_OffscreenBits
10185
       andn ++%00001100             ;check offscreen bits
10186
       bne MoveHammerBroXDir      ;if hammer bro a little offscreen, skip to movement code
10187
       ldax HammerThrowingTimer,x  ;check hammer throwing timer
10188
         checka
10189
       bne DecHT                  ;if not expired, skip ahead, do not throw hammer
10190
       ldy SecondaryHardMode      ;otherwise get secondary hard mode flag
10191
       lday HammerThrowTmrData,y   ;get timer data using flag as offset
10192
       stax HammerThrowingTimer,x  ;set as new timer
10193
       jsr SpawnHammerObj         ;do a sub here to spawn hammer object
10194
       bcc DecHT                  ;if carry clear, hammer not spawned, skip to decrement timer
10195
       ldax Enemy_State,x
10196
       oran ++%00001000             ;set d3 in enemy state for hammer throw
10197
       stax Enemy_State,x
10198
       jmp MoveHammerBroXDir      ;jump to move hammer bro
10199
DecHT: decx HammerThrowingTimer,x  ;decrement timer
10200
       jmp MoveHammerBroXDir      ;jump to move hammer bro
10201
 
10202
HammerBroJumpLData:
10203
      .db $20, $37
10204
 
10205
HammerBroJumpCode:
10206
       ldax Enemy_State,x           ;get hammer bro's enemy state
10207
       andn ++%00000111              ;mask out all but 3 LSB
10208
       cmpn ++$01                    ;check for d0 set (for jumping)
10209
       beq MoveHammerBroXDir       ;if set, branch ahead to moving code
10210
       ldan ++$00                    ;load default value here
10211
       sta SCRATCHPAD+$00                     ;save into temp variable for now
10212
       ldyn ++$fa                    ;set default vertical speed
10213
       ldax Enemy_Y_Position,x      ;check hammer bro's vertical coordinate
10214
         checka
10215
       bmi SetHJ                   ;if on the bottom half of the screen, use current speed
10216
       ldyn ++$fd                    ;otherwise set alternate vertical speed
10217
       cmpn ++$70                    ;check to see if hammer bro is above the middle of screen
10218
              cmpcy
10219
       inci SCRATCHPAD+$00                     ;increment preset value to $01
10220
       bcc SetHJ                   ;if above the middle of the screen, use current speed and $01
10221
       deci SCRATCHPAD+$00                     ;otherwise return value to $00
10222
       ldax PseudoRandomBitReg+1,x  ;get part of LSFR, mask out all but LSB
10223
       andn ++$01
10224
       bne SetHJ                   ;if d0 of LSFR set, branch and use current speed and $00
10225
       ldyn ++$fa                    ;otherwise reset to default vertical speed
10226
SetHJ: styx Enemy_Y_Speed,x         ;set vertical speed for jumping
10227
       ldax Enemy_State,x           ;set d0 in enemy state for jumping
10228
       oran ++$01
10229
       stax Enemy_State,x
10230
       lda SCRATCHPAD+$00                     ;load preset value here to use as bitmask
10231
       andx PseudoRandomBitReg+2,x  ;and do bit-wise comparison with part of LSFR
10232
       tay                         ;then use as offset
10233
       lda SecondaryHardMode       ;check secondary hard mode flag
10234
         checka
10235
       bne HJump
10236
       tay                         ;if secondary hard mode flag clear, set offset to 0
10237
HJump: lday HammerBroJumpLData,y    ;get jump length timer data using offset from before
10238
       stax EnemyFrameTimer,x       ;save in enemy timer
10239
       ldax PseudoRandomBitReg+1,x
10240
       oran ++%11000000              ;get contents of part of LSFR, set d7 and d6, then
10241
       stax HammerBroJumpTimer,x    ;store in jump timer
10242
 
10243
MoveHammerBroXDir:
10244
         ldyn ++$fc                  ;move hammer bro a little to the left
10245
         lda FrameCounter
10246
         andn ++%01000000            ;change hammer bro's direction every 64 frames
10247
         bne Shimmy
10248
         ldyn ++$04                  ;if d6 set in counter, move him a little to the right
10249
Shimmy:  styx Enemy_X_Speed,x       ;store horizontal speed
10250
         ldyn ++$01                  ;set to face right by default
10251
         jsr PlayerEnemyDiff       ;get horizontal difference between player and hammer bro
10252
         bmi SetShim               ;if enemy to the left of player, skip this part
10253
         iny                       ;set to face left
10254
         ldax EnemyIntervalTimer,x  ;check walking timer
10255
         checka
10256
         bne SetShim               ;if not yet expired, skip to set moving direction
10257
         ldan ++$f8
10258
         stax Enemy_X_Speed,x       ;otherwise, make the hammer bro walk left towards player
10259
SetShim: styx Enemy_MovingDir,x     ;set moving direction
10260
 
10261
MoveNormalEnemy:
10262
       ldyn ++$00                   ;init Y to leave horizontal movement as-is 
10263
       ldax Enemy_State,x
10264
       andn ++%01000000             ;check enemy state for d6 set, if set skip
10265
       bne FallE                  ;to move enemy vertically, then horizontally if necessary
10266
       ldax Enemy_State,x
10267
       asl                        ;check enemy state for d7 set
10268
       bcs SteadM                 ;if set, branch to move enemy horizontally
10269
       ldax Enemy_State,x
10270
       andn ++%00100000             ;check enemy state for d5 set
10271
       bne MoveDefeatedEnemy      ;if set, branch to move defeated enemy object
10272
       ldax Enemy_State,x
10273
       andn ++%00000111             ;check d2-d0 of enemy state for any set bits
10274
       beq SteadM                 ;if enemy in normal state, branch to move enemy horizontally
10275
       cmpn ++$05
10276
       beq FallE                  ;if enemy in state used by spiny's egg, go ahead here
10277
       cmpn ++$03
10278
              cmpcy
10279
       bcs ReviveStunned          ;if enemy in states $03 or $04, skip ahead to yet another part
10280
FallE: jsr MoveD_EnemyVertically  ;do a sub here to move enemy downwards
10281
       ldyn ++$00
10282
       ldax Enemy_State,x          ;check for enemy state $02
10283
       cmpn ++$02
10284
       beq MEHor                  ;if found, branch to move enemy horizontally
10285
       andn ++%01000000             ;check for d6 set
10286
       beq SteadM                 ;if not set, branch to something else
10287
       ldax Enemy_ID,x
10288
       cmpn ++PowerUpObject         ;check for power-up object
10289
       beq SteadM
10290
       bne SlowM                  ;if any other object where d6 set, jump to set Y
10291
MEHor: jmp MoveEnemyHorizontally  ;jump here to move enemy horizontally for LOW HIGH  $2e and d6 set
10292
 
10293
SlowM:  ldyn ++$01                  ;if branched here, increment Y to slow horizontal movement
10294
SteadM: ldax Enemy_X_Speed,x       ;get current horizontal speed
10295
      pha                       ;save to stack
10296
         checka
10297
        bpl AddHS                 ;if not moving or moving right, skip, leave Y alone
10298
        iny
10299
        iny                       ;otherwise increment Y to next data
10300
AddHS:  clc
10301
        adcy XSpeedAdderData,y     ;add value here to slow enemy down if necessary
10302
        stax Enemy_X_Speed,x       ;save as horizontal speed temporarily
10303
        jsr MoveEnemyHorizontally ;then do a sub to move horizontally
10304
      pla
10305
        stax Enemy_X_Speed,x       ;get old horizontal speed from stack and return to
10306
        rts                       ;original memory location, then leave
10307
 
10308
ReviveStunned:
10309
         ldax EnemyIntervalTimer,x  ;if enemy timer not expired yet,
10310
         checka
10311
         bne ChkKillGoomba         ;skip ahead to something else
10312
         stax Enemy_State,x         ;otherwise initialize enemy state to normal
10313
         lda FrameCounter
10314
         andn ++$01                  ;get d0 of frame counter
10315
         tay                       ;use as Y and increment for movement direction
10316
         iny
10317
         styx Enemy_MovingDir,x     ;store as pseudorandom movement direction
10318
         dey                       ;decrement for use as pointer
10319
         lda PrimaryHardMode       ;check primary hard mode flag
10320
         checka
10321
         beq SetRSpd               ;if not set, use pointer as-is
10322
         iny
10323
         iny                       ;otherwise increment 2 bytes to next data
10324
SetRSpd: lday RevivedXSpeed,y       ;load and store new horizontal speed
10325
         stax Enemy_X_Speed,x       ;and leave
10326
         rts
10327
 
10328
MoveDefeatedEnemy:
10329
      jsr MoveD_EnemyVertically      ;execute sub to move defeated enemy downwards
10330
      jmp MoveEnemyHorizontally      ;now move defeated enemy horizontally
10331
 
10332
ChkKillGoomba:
10333
        cmpn ++$0e              ;check to see if enemy timer has reached
10334
        bne NKGmba            ;a certain point, and branch to leave if not
10335
        ldax Enemy_ID,x
10336
        cmpn ++Goomba           ;check for goomba object
10337
        bne NKGmba            ;branch if not found
10338
        jsr EraseEnemyObject  ;otherwise, kill this goomba object
10339
NKGmba: rts                   ;leave!
10340
 
10341
;--------------------------------
10342
 
10343
MoveJumpingEnemy:
10344
      jsr MoveJ_EnemyVertically  ;do a sub to impose gravity on green paratroopa
10345
      jmp MoveEnemyHorizontally  ;jump to move enemy horizontally
10346
 
10347
;--------------------------------
10348
 
10349
ProcMoveRedPTroopa:
10350
          ldax Enemy_Y_Speed,x
10351
          orax Enemy_Y_MoveForce,x     ;check for any vertical force or speed
10352
          bne MoveRedPTUpOrDown       ;branch if any found
10353
          stax Enemy_YMF_Dummy,x       ;initialize something here
10354
          ldax Enemy_Y_Position,x      ;check current vs. original vertical coordinate
10355
          cmpx RedPTroopaOrigXPos,x
10356
              cmpcy
10357
          bcs MoveRedPTUpOrDown       ;if current =HIGH  original, skip ahead to more code
10358
          lda FrameCounter            ;get frame counter
10359
          andn ++%00000111              ;mask out all but 3 LSB
10360
          bne NoIncPT                 ;if any bits set, branch to leave
10361
          incx Enemy_Y_Position,x      ;otherwise increment red paratroopa's vertical position
10362
NoIncPT:  rts                         ;leave
10363
 
10364
MoveRedPTUpOrDown:
10365
          ldax Enemy_Y_Position,x      ;check current vs. central vertical coordinate
10366
          cmpx RedPTroopaCenterYPos,x
10367
              cmpcy
10368
          bcc MovPTDwn                ;if current LOW  central, jump to move downwards
10369
          jmp MoveRedPTroopaUp        ;otherwise jump to move upwards
10370
MovPTDwn: jmp MoveRedPTroopaDown      ;move downwards
10371
 
10372
;--------------------------------
10373
;$00 - used to store adder for movement, also used as adder for platform
10374
;$01 - used to store maximum value for secondary counter
10375
 
10376
MoveFlyGreenPTroopa:
10377
        jsr XMoveCntr_GreenPTroopa ;do sub to increment primary and secondary counters
10378
        jsr MoveWithXMCntrs        ;do sub to move green paratroopa accordingly, and horizontally
10379
        ldyn ++$01                   ;set Y to move green paratroopa down
10380
        lda FrameCounter
10381
        andn ++%00000011             ;check frame counter 2 LSB for any bits set
10382
        bne NoMGPT                 ;branch to leave if set to move up/down every fourth frame
10383
        lda FrameCounter
10384
        andn ++%01000000             ;check frame counter for d6 set
10385
        bne YSway                  ;branch to move green paratroopa down if set
10386
        ldyn ++$ff                   ;otherwise set Y to move green paratroopa up
10387
YSway:  sty SCRATCHPAD+$00                    ;store adder here
10388
        ldax Enemy_Y_Position,x
10389
        clc                        ;add or subtract from vertical position
10390
        adci SCRATCHPAD+$00                    ;to give green paratroopa a wavy flight
10391
        stax Enemy_Y_Position,x
10392
NoMGPT: rts                        ;leave!
10393
 
10394
XMoveCntr_GreenPTroopa:
10395
         ldan ++$13                    ;load preset maximum value for secondary counter
10396
 
10397
XMoveCntr_Platform:
10398
         sta SCRATCHPAD+$01                     ;store value here
10399
         lda FrameCounter
10400
         andn ++%00000011              ;branch to leave if not on
10401
         bne NoIncXM                 ;every fourth frame
10402
         ldyx XMoveSecondaryCounter,x ;get secondary counter
10403
         ldax XMovePrimaryCounter,x   ;get primary counter
10404
         lsr
10405
         bcs DecSeXM                 ;if d0 of primary counter set, branch elsewhere
10406
         cpyi SCRATCHPAD+$01                     ;compare secondary counter to preset maximum value
10407
         beq IncPXM                  ;if equal, branch ahead of this part
10408
         incx XMoveSecondaryCounter,x ;increment secondary counter and leave
10409
NoIncXM: rts
10410
IncPXM:  incx XMovePrimaryCounter,x   ;increment primary counter and leave
10411
         rts
10412
DecSeXM: tya                         ;put secondary counter in A
10413
         checka
10414
         beq IncPXM                  ;if secondary counter at zero, branch back
10415
         decx XMoveSecondaryCounter,x ;otherwise decrement secondary counter and leave
10416
         rts
10417
 
10418
MoveWithXMCntrs:
10419
         ldax XMoveSecondaryCounter,x  ;save secondary counter to stack
10420
         pha
10421
         ldyn ++$01                     ;set value here by default
10422
         ldax XMovePrimaryCounter,x
10423
         andn ++%00000010               ;if d1 of primary counter is
10424
         bne XMRight                  ;set, branch ahead of this part here
10425
         ldax XMoveSecondaryCounter,x
10426
         eorn ++$ff                     ;otherwise change secondary
10427
         clc                          ;counter to two's compliment
10428
         adcn ++$01
10429
         stax XMoveSecondaryCounter,x
10430
         ldyn ++$02                     ;load alternate value here
10431
XMRight: styx Enemy_MovingDir,x        ;store as moving direction
10432
         jsr MoveEnemyHorizontally
10433
         sta SCRATCHPAD+$00                      ;save value obtained from sub here (  X-     )
10434
         pla                          ;get secondary counter from stack
10435
         stax XMoveSecondaryCounter,x  ;and return to original place
10436
         rts
10437
 
10438
;--------------------------------
10439
 
10440
BlooberBitmasks:
10441
      .db %00111111, %00000011
10442
 
10443
MoveBloober:
10444
        ldax Enemy_State,x
10445
        andn ++%00100000             ;check enemy state for d5 set
10446
        bne MoveDefeatedBloober    ;branch if set to move defeated bloober
10447
        ldy SecondaryHardMode      ;use secondary hard mode flag as offset
10448
        ldax PseudoRandomBitReg+1,x ;get LSFR
10449
        andy BlooberBitmasks,y      ;mask out bits in LSFR using bitmask loaded with offset
10450
        bne BlooberSwim            ;if any bits set, skip ahead to make swim
10451
        txa
10452
        lsr                        ;check to see if on second or fourth slot (1 or 3)
10453
        bcc FBLeft                 ;if not, branch to figure out moving direction
10454
        ldy Player_MovingDir       ;otherwise, load player's moving direction and
10455
        bcs SBMDir                 ;do an unconditional branch to set
10456
FBLeft: ldyn ++$02                   ;set left moving direction by default
10457
        jsr PlayerEnemyDiff        ;get horizontal difference between player and bloober
10458
        bpl SBMDir                 ;if enemy to the right of player, keep left
10459
        dey                        ;otherwise decrement to set right moving direction
10460
SBMDir: styx Enemy_MovingDir,x      ;set moving direction of bloober, then continue on here
10461
 
10462
BlooberSwim:
10463
       jsr ProcSwimmingB        ;execute sub to make bloober swim characteristically
10464
       ldax Enemy_Y_Position,x   ;get vertical coordinate
10465
       secsub
10466
       sbcx Enemy_Y_MoveForce,x  ;subtract movement force
10467
       cmpn ++$20                 ;check to see if position is above edge of status bar
10468
              cmpcy
10469
       bcc SwimX                ;if so, don't do it
10470
       stax Enemy_Y_Position,x   ;otherwise, set new vertical position, make bloober swim
10471
SwimX: ldyx Enemy_MovingDir,x    ;check moving direction
10472
       dey
10473
       bne LeftSwim             ;if moving to the left, branch to second part
10474
       ldax Enemy_X_Position,x
10475
       clc                      ;add movement speed to horizontal coordinate
10476
       adcx BlooperMoveSpeed,x
10477
          push af
10478
       stax Enemy_X_Position,x   ;store result as new horizontal coordinate
10479
       ldax Enemy_PageLoc,x
10480
          ld h,a
10481
          pop af
10482
          ld a,h
10483
       adcn ++$00                 ;add carry to page location
10484
       stax Enemy_PageLoc,x      ;store as new page location and leave
10485
       rts
10486
 
10487
LeftSwim:
10488
      ldax Enemy_X_Position,x
10489
      secsub                      ;subtract movement speed from horizontal coordinate
10490
      sbcx BlooperMoveSpeed,x
10491
          push af
10492
      stax Enemy_X_Position,x   ;store result as new horizontal coordinate
10493
      ldax Enemy_PageLoc,x
10494
          ld h,a
10495
          pop af
10496
          ld a,h
10497
      sbcn ++$00                 ;subtract borrow from page location
10498
      stax Enemy_PageLoc,x      ;store as new page location and leave
10499
      rts
10500
 
10501
MoveDefeatedBloober:
10502
      jmp MoveEnemySlowVert    ;jump to move defeated bloober downwards
10503
 
10504
ProcSwimmingB:
10505
        ldax BlooperMoveCounter,x  ;get enemy's movement counter
10506
        andn ++%00000010            ;check for d1 set
10507
        bne ChkForFloatdown       ;branch if set
10508
        lda FrameCounter
10509
        andn ++%00000111            ;get 3 LSB of frame counter
10510
        pha                       ;and save it to the stack
10511
        ldax BlooperMoveCounter,x  ;get enemy's movement counter
10512
        lsr                       ;check for d0 set
10513
        bcs SlowSwim              ;branch if set
10514
        pla                       ;pull 3 LSB of frame counter from the stack
10515
         checka
10516
        bne BSwimE                ;branch to leave, execute code only every eighth frame
10517
        ldax Enemy_Y_MoveForce,x
10518
        clc                       ;add to movement force to speed up swim
10519
        adcn ++$01
10520
        stax Enemy_Y_MoveForce,x   ;set movement force
10521
        stax BlooperMoveSpeed,x    ;set as movement speed
10522
        cmpn ++$02
10523
        bne BSwimE                ;if certain horizontal speed, branch to leave
10524
        incx BlooperMoveCounter,x  ;otherwise increment movement counter
10525
BSwimE: rts
10526
 
10527
SlowSwim:
10528
       pla                      ;pull 3 LSB of frame counter from the stack
10529
         checka
10530
       bne NoSSw                ;branch to leave, execute code only every eighth frame
10531
       ldax Enemy_Y_MoveForce,x
10532
       secsub                      ;subtract from movement force to slow swim
10533
       sbcn ++$01
10534
       stax Enemy_Y_MoveForce,x  ;set movement force
10535
       stax BlooperMoveSpeed,x   ;set as movement speed
10536
         checka
10537
       bne NoSSw                ;if any speed, branch to leave
10538
       incx BlooperMoveCounter,x ;otherwise increment movement counter
10539
       ldan ++$02
10540
       stax EnemyIntervalTimer,x ;set enemy's timer
10541
NoSSw: rts                      ;leave
10542
 
10543
ChkForFloatdown:
10544
      ldax EnemyIntervalTimer,x ;get enemy timer
10545
         checka
10546
      beq ChkNearPlayer        ;branch if expired
10547
 
10548
Floatdown:
10549
      lda FrameCounter        ;get frame counter
10550
      lsr                     ;check for d0 set
10551
      bcs NoFD                ;branch to leave on every other frame
10552
      incx Enemy_Y_Position,x  ;otherwise increment vertical coordinate
10553
NoFD: rts                     ;leave
10554
 
10555
ChkNearPlayer:
10556
;CY=0??? after JumpEngine
10557
      ldax Enemy_Y_Position,x    ;get vertical coordinate
10558
     or a ;???
10559
      adcn ++$10                  ;add sixteen pixels
10560
      cmpi Player_Y_Position     ;compare result with player's vertical coordinate
10561
              cmpcy
10562
      bcc Floatdown             ;if modified vertical less than player's, branch
10563
      ldan ++$00
10564
      stax BlooperMoveCounter,x  ;otherwise nullify movement counter
10565
      rts
10566
 
10567
;--------------------------------
10568
 
10569
MoveBulletBill:
10570
         ldax Enemy_State,x          ;check bullet bill's enemy object state for d5 set
10571
         andn ++%00100000
10572
         beq NotDefB                ;if not set, continue with movement code
10573
         jmp MoveJ_EnemyVertically  ;otherwise jump to move defeated bullet bill downwards
10574
NotDefB: ldan ++$e8                   ;set bullet bill's horizontal speed
10575
         stax Enemy_X_Speed,x        ;and move it accordingly (note: this bullet bill
10576
         jmp MoveEnemyHorizontally  ;object occurs in frenzy object $17, not from cannons)
10577
 
10578
;--------------------------------
10579
;$02 - used to hold preset values
10580
;$03 - used to hold enemy state
10581
 
10582
SwimCCXMoveData:
10583
      .db $40, $80
10584
      .db $04, $04 ;residual data, not used
10585
 
10586
MoveSwimmingCheepCheep:
10587
        ldax Enemy_State,x         ;check cheep-cheep's enemy object state
10588
        andn ++%00100000            ;for d5 set
10589
        beq CCSwim                ;if not set, continue with movement code
10590
        jmp MoveEnemySlowVert     ;otherwise jump to move defeated cheep-cheep downwards
10591
CCSwim: sta SCRATCHPAD+$03                   ;save enemy state in $03
10592
        ldax Enemy_ID,x            ;get enemy identifier
10593
        secsub
10594
        sbcn ++$0a                  ;subtract ten for cheep-cheep identifiers
10595
        tay                       ;use as offset
10596
        lday SwimCCXMoveData,y     ;load value here
10597
        sta SCRATCHPAD+$02
10598
        ldax Enemy_X_MoveForce,x   ;load horizontal force (  X-)
10599
        secsub
10600
        sbci SCRATCHPAD+$02                   ;subtract preset value from horizontal force
10601
          push af
10602
        stax Enemy_X_MoveForce,x   ;store as new horizontal force (  X-)
10603
        ldax Enemy_X_Position,x    ;get horizontal coordinate
10604
          ld h,a
10605
          pop af
10606
          ld a,h
10607
        sbcn ++$00                  ;subtract borrow (thus moving it slowly)
10608
          push af
10609
        stax Enemy_X_Position,x    ;and save as new horizontal coordinate
10610
        ldax Enemy_PageLoc,x
10611
          ld h,a
10612
          pop af
10613
          ld a,h
10614
        sbcn ++$00                  ;subtract borrow again, this time from the
10615
        stax Enemy_PageLoc,x       ;page location, then save
10616
        ldan ++$20
10617
        sta SCRATCHPAD+$02                   ;save new value here
10618
        cpxn ++$02                  ;check enemy object offset
10619
              cmpcy
10620
        bcc ExSwCC                ;if in first or second slot, branch to leave
10621
        ldax CheepCheepMoveMFlag,x ;check movement flag
10622
        cmpn ++$10                  ;if movement speed set to $00,
10623
              cmpcy
10624
        bcc CCSwimUpwards         ;branch to move upwards
10625
        ldax Enemy_YMF_Dummy,x
10626
        clc
10627
        adci SCRATCHPAD+$02                   ;add preset value to dummy variable to get carry
10628
          push af
10629
        stax Enemy_YMF_Dummy,x     ;and save dummy
10630
        ldax Enemy_Y_Position,x    ;get vertical coordinate
10631
          ld h,a
10632
          pop af
10633
          ld a,h
10634
        adci SCRATCHPAD+$03                   ;add carry to it plus enemy state to slowly move it downwards
10635
          push af
10636
        stax Enemy_Y_Position,x    ;save as new vertical coordinate
10637
        ldax Enemy_Y_HighPos,x
10638
          ld h,a
10639
          pop af
10640
          ld a,h
10641
        adcn ++$00                  ;add carry to page location and
10642
        jmp ChkSwimYPos           ;jump to end of movement code
10643
 
10644
CCSwimUpwards:
10645
        ldax Enemy_YMF_Dummy,x
10646
        secsub
10647
        sbci SCRATCHPAD+$02                   ;subtract preset value to dummy variable to get borrow
10648
          push af
10649
        stax Enemy_YMF_Dummy,x     ;and save dummy
10650
        ldax Enemy_Y_Position,x    ;get vertical coordinate
10651
          ld h,a
10652
          pop af
10653
          ld a,h
10654
        sbci SCRATCHPAD+$03                   ;subtract borrow to it plus enemy state to slowly move it upwards
10655
          push af
10656
        stax Enemy_Y_Position,x    ;save as new vertical coordinate
10657
        ldax Enemy_Y_HighPos,x
10658
          ld h,a
10659
          pop af
10660
          ld a,h
10661
        sbcn ++$00                  ;subtract borrow from page location
10662
 
10663
ChkSwimYPos:
10664
        stax Enemy_Y_HighPos,x     ;save new page location here
10665
        ldyn ++$00                  ;load movement speed to upwards by default
10666
        ldax Enemy_Y_Position,x    ;get vertical coordinate
10667
        secsub
10668
        sbcx CheepCheepOrigYPos,x  ;subtract original coordinate from current
10669
        bpl YPDiff                ;if result positive, skip to next part
10670
        ldyn ++$10                  ;otherwise load movement speed to downwards
10671
        eorn ++$ff
10672
        clc                       ;get two's compliment of result
10673
        adcn ++$01                  ;to obtain total difference of original vs. current
10674
YPDiff: cmpn ++$0f                  ;if difference between original vs. current vertical
10675
              cmpcy
10676
        bcc ExSwCC                ;coordinates LOW  15 pixels, leave movement speed alone
10677
        tya
10678
        stax CheepCheepMoveMFlag,x ;otherwise change movement speed
10679
ExSwCC: rts                       ;leave
10680
 
10681
;--------------------------------
10682
;$00 - used as counter for firebar parts
10683
;$01 - used for oscillated high byte of spin state or to hold horizontal adder
10684
;$02 - used for oscillated high byte of spin state or to hold vertical adder
10685
;$03 - used for mirror data
10686
;$04 - used to store player's sprite 1 X coordinate
10687
;$05 - used to evaluate mirror data
10688
;$06 - used to store either screen X coordinate or sprite data offset
10689
;$07 - used to store screen Y coordinate
10690
;$ed - used to hold maximum length of firebar
10691
;$ef - used to hold high byte of spinstate
10692
 
10693
;horizontal adder is at first byte + high byte of spinstate,
10694
;vertical adder is same + 8 bytes, two's compliment
10695
;if greater than $08 for proper oscillation
10696
FirebarPosLookupTbl:
10697
      .db $00, $01, $03, $04, $05, $06, $07, $07, $08
10698
      .db $00, $03, $06, $09, $0b, $0d, $0e, $0f, $10
10699
      .db $00, $04, $09, $0d, $10, $13, $16, $17, $18
10700
      .db $00, $06, $0c, $12, $16, $1a, $1d, $1f, $20
10701
      .db $00, $07, $0f, $16, $1c, $21, $25, $27, $28
10702
      .db $00, $09, $12, $1b, $21, $27, $2c, $2f, $30
10703
      .db $00, $0b, $15, $1f, $27, $2e, $33, $37, $38
10704
      .db $00, $0c, $18, $24, $2d, $35, $3b, $3e, $40
10705
      .db $00, $0e, $1b, $28, $32, $3b, $42, $46, $48
10706
      .db $00, $0f, $1f, $2d, $38, $42, $4a, $4e, $50
10707
      .db $00, $11, $22, $31, $3e, $49, $51, $56, $58
10708
 
10709
FirebarMirrorData:
10710
      .db $01, $03, $02, $00
10711
 
10712
FirebarTblOffsets:
10713
      .db $00, $09, $12, $1b, $24, $2d
10714
      .db $36, $3f, $48, $51, $5a, $63
10715
 
10716
FirebarYPos:
10717
      .db $0c, $18
10718
 
10719
ProcFirebar:
10720
          jsr GetEnemyOffscreenBits   ;get offscreen information
10721
          lda Enemy_OffscreenBits     ;check for d3 set
10722
          andn ++%00001000              ;if so, branch to leave
10723
          bne SkipFBar
10724
          lda TimerControl            ;if master timer control set, branch
10725
         checka
10726
          bne SusFbar                 ;ahead of this part
10727
          ldax FirebarSpinSpeed,x      ;load spinning speed of firebar
10728
          jsr FirebarSpin             ;modify current spinstate
10729
          andn ++%00011111              ;mask out all but 5 LSB
10730
          stax FirebarSpinState_High,x ;and store as new high byte of spinstate
10731
SusFbar:  ldax FirebarSpinState_High,x ;get high byte of spinstate
10732
          ldyx Enemy_ID,x              ;check enemy identifier
10733
          cpyn ++$1f
10734
              cmpcy
10735
          bcc SetupGFB                ;if LOW  $1f (long firebar), branch
10736
          cmpn ++$08                    ;check high byte of spinstate
10737
          beq SkpFSte                 ;if eight, branch to change
10738
          cmpn ++$18
10739
          bne SetupGFB                ;if not at twenty-four branch to not change
10740
SkpFSte:  clc
10741
          adcn ++$01                    ;add one to spinning thing to avoid horizontal state
10742
          stax FirebarSpinState_High,x
10743
SetupGFB: sta SCRATCHPAD+$ef                     ;save high byte of spinning thing, modified or otherwise
10744
          jsr RelativeEnemyPosition   ;get relative coordinates to screen
10745
          jsr GetFirebarPosition      ;do a sub here (residual, too early to be used now)
10746
          ldyx Enemy_SprDataOffset,x   ;get OAM data offset
10747
          lda Enemy_Rel_YPos          ;get relative vertical coordinate
10748
          stay Sprite_Y_Position,y     ;store as Y in OAM data
10749
          sta SCRATCHPAD+$07                     ;also save here
10750
          lda Enemy_Rel_XPos          ;get relative horizontal coordinate
10751
          stay Sprite_X_Position,y     ;store as X in OAM data
10752
          sta SCRATCHPAD+$06                     ;also save here
10753
          ldan ++$01
10754
          sta SCRATCHPAD+$00                     ;set $01 value here (not necessary)
10755
          jsr FirebarCollision        ;draw fireball part and do collision detection
10756
          ldyn ++$05                    ;load value for short firebars by default
10757
          ldax Enemy_ID,x
10758
          cmpn ++$1f                    ;are we doing a long firebar?
10759
              cmpcy
10760
          bcc SetMFbar                ;no, branch then
10761
          ldyn ++$0b                    ;otherwise load value for long firebars
10762
SetMFbar: sty SCRATCHPAD+$ed                     ;store maximum value for length of firebars
10763
          ldan ++$00
10764
          sta SCRATCHPAD+$00                     ;initialize counter here
10765
DrawFbar: lda SCRATCHPAD+$ef                     ;load high byte of spinstate
10766
          jsr GetFirebarPosition      ;get fireball position data depending on firebar part
10767
          jsr DrawFirebar_Collision   ;position it properly, draw it and do collision detection
10768
          lda SCRATCHPAD+$00                     ;check which firebar part
10769
          cmpn ++$04
10770
          bne NextFbar
10771
          ldy DuplicateObj_Offset     ;if we arrive at fifth firebar part,
10772
          lday Enemy_SprDataOffset,y   ;get offset from long firebar and load OAM data offset
10773
          sta SCRATCHPAD+$06                     ;using long firebar offset, then store as new one here
10774
NextFbar: inci SCRATCHPAD+$00                     ;move onto the next firebar part
10775
          lda SCRATCHPAD+$00
10776
          cmpi SCRATCHPAD+$ed                     ;if we end up at the maximum part, go on and leave
10777
              cmpcy
10778
          bcc DrawFbar                ;otherwise go back and do another
10779
SkipFBar: rts
10780
 
10781
DrawFirebar_Collision:
10782
         lda SCRATCHPAD+$03                  ;store mirror data elsewhere
10783
         sta SCRATCHPAD+$05          
10784
         ldy SCRATCHPAD+$06                  ;load OAM data offset for firebar
10785
         lda SCRATCHPAD+$01                  ;load horizontal adder we got from position loader
10786
         lsri SCRATCHPAD+$05                  ;shift LSB of mirror data
10787
         bcs AddHA                ;if carry was set, skip this part
10788
         eorn ++$ff
10789
         adcn ++$01                 ;otherwise get two's compliment of horizontal adder
10790
AddHA:   clc                      ;add horizontal coordinate relative to screen to
10791
         adci Enemy_Rel_XPos       ;horizontal adder, modified or otherwise
10792
         stay Sprite_X_Position,y  ;store as X coordinate here
10793
         sta SCRATCHPAD+$06                  ;store here for now, note offset is saved in Y still
10794
         cmpi Enemy_Rel_XPos       ;compare X coordinate of sprite to original X of firebar
10795
              cmpcy
10796
         bcs SubtR1               ;if sprite coordinate =HIGH  original coordinate, branch
10797
         lda Enemy_Rel_XPos
10798
         secsub                      ;otherwise subtract sprite X from the
10799
         sbci SCRATCHPAD+$06                  ;original one and skip this part
10800
         jmp ChkFOfs
10801
SubtR1:  secsub                      ;subtract original X from the
10802
         sbci Enemy_Rel_XPos       ;current sprite X
10803
ChkFOfs: cmpn ++$59                 ;if difference of coordinates within a certain range,
10804
              cmpcy
10805
         bcc VAHandl              ;continue by handling vertical adder
10806
         ldan ++$f8                 ;otherwise, load offscreen Y coordinate
10807
         checka
10808
         bne SetVFbr              ;and unconditionally branch to move sprite offscreen
10809
VAHandl: lda Enemy_Rel_YPos       ;if vertical relative coordinate offscreen,
10810
         cmpn ++$f8                 ;skip ahead of this part and write into sprite Y coordinate
10811
         beq SetVFbr
10812
         lda SCRATCHPAD+$02                  ;load vertical adder we got from position loader
10813
         lsri SCRATCHPAD+$05                  ;shift LSB of mirror data one more time
10814
         bcs AddVA                ;if carry was set, skip this part
10815
         eorn ++$ff
10816
         adcn ++$01                 ;otherwise get two's compliment of second part
10817
AddVA:   clc                      ;add vertical coordinate relative to screen to 
10818
         adci Enemy_Rel_YPos       ;the second data, modified or otherwise
10819
SetVFbr: stay Sprite_Y_Position,y  ;store as Y coordinate here
10820
         sta SCRATCHPAD+$07                  ;also store here for now
10821
 
10822
FirebarCollision:
10823
         jsr DrawFirebar          ;run sub here to draw current tile of firebar
10824
         tya                      ;return OAM data offset and save
10825
         pha                      ;to the stack for now
10826
         lda StarInvincibleTimer  ;if star mario invincibility timer
10827
         orai TimerControl         ;or master timer controls set
10828
         bne NoColFB              ;then skip all of this
10829
         sta SCRATCHPAD+$05                  ;otherwise initialize counter
10830
         ldy Player_Y_HighPos
10831
         dey                      ;if player's vertical high byte offscreen,
10832
         bne NoColFB              ;skip all of this
10833
         ldy Player_Y_Position    ;get player's vertical position
10834
         lda PlayerSize           ;get player's size
10835
         checka
10836
         bne AdjSm                ;if player small, branch to alter variables
10837
         lda CrouchingFlag
10838
         checka
10839
         beq BigJp                ;if player big and not crouching, jump ahead
10840
AdjSm:   inci SCRATCHPAD+$05                  ;if small or big but crouching, execute this part
10841
         inci SCRATCHPAD+$05                  ;first increment our counter twice (setting $02 as flag)
10842
         tya
10843
         clc                      ;then add 24 pixels to the player's
10844
         adcn ++$18                 ;vertical coordinate
10845
         tay
10846
BigJp:   tya                      ;get vertical coordinate, altered or otherwise, from Y
10847
FBCLoop: secsub                      ;subtract vertical position of firebar
10848
         sbci SCRATCHPAD+$07                  ;from the vertical coordinate of the player
10849
         bpl ChkVFBD              ;if player lower on the screen than firebar, 
10850
         eorn ++$ff                 ;skip two's compliment part
10851
         clc                      ;otherwise get two's compliment
10852
         adcn ++$01
10853
ChkVFBD: cmpn ++$08                 ;if difference =HIGH  8 pixels, skip ahead of this part
10854
              cmpcy
10855
         bcs Chk2Ofs
10856
         lda SCRATCHPAD+$06                  ;if firebar on far right on the screen, skip this,
10857
         cmpn ++$f0                 ;because, really, what's the point?
10858
              cmpcy
10859
         bcs Chk2Ofs
10860
         lda Sprite_X_Position+4  ;get OAM X coordinate for sprite ++1
10861
         clc
10862
         adcn ++$04                 ;add four pixels
10863
         sta SCRATCHPAD+$04                  ;store here
10864
         secsub                      ;subtract horizontal coordinate of firebar
10865
         sbci SCRATCHPAD+$06                  ;from the X coordinate of player's sprite 1
10866
         bpl ChkFBCl              ;if modded X coordinate to the right of firebar
10867
         eorn ++$ff                 ;skip two's compliment part
10868
         clc                      ;otherwise get two's compliment
10869
         adcn ++$01
10870
ChkFBCl: cmpn ++$08                 ;if difference LOW  8 pixels, collision, thus branch
10871
              cmpcy
10872
         bcc ChgSDir              ;to process
10873
Chk2Ofs: lda SCRATCHPAD+$05                  ;if value of $02 was set earlier for whatever reason,
10874
         cmpn ++$02                 ;branch to increment OAM offset and leave, no collision
10875
         beq NoColFB
10876
         ldy SCRATCHPAD+$05                  ;otherwise get temp here and use as offset
10877
         lda Player_Y_Position
10878
         clc
10879
         adcy FirebarYPos,y        ;add value loaded with offset to player's vertical coordinate
10880
         inci SCRATCHPAD+$05                  ;then increment temp and jump back
10881
         jmp FBCLoop
10882
ChgSDir: ldxn ++$01                 ;set movement direction by default
10883
         lda SCRATCHPAD+$04                  ;if OAM X coordinate of player's sprite 1
10884
         cmpi SCRATCHPAD+$06                  ;is greater than horizontal coordinate of firebar
10885
              cmpcy
10886
         bcs SetSDir              ;then do not alter movement direction
10887
         inx                      ;otherwise increment it
10888
SetSDir: stx Enemy_MovingDir      ;store movement direction here
10889
         ldxn ++$00
10890
         lda SCRATCHPAD+$00                  ;save value written to $00 to stack
10891
         pha
10892
         jsr InjurePlayer         ;perform sub to hurt or kill player
10893
         pla
10894
         sta SCRATCHPAD+$00                  ;get value of $00 from stack
10895
NoColFB: pla                      ;get OAM data offset
10896
         clc                      ;add four to it and save
10897
         adcn ++$04
10898
         sta SCRATCHPAD+$06
10899
         ldx ObjectOffset         ;get enemy object buffer offset and leave
10900
         rts
10901
 
10902
GetFirebarPosition:
10903
           pha                        ;save high byte of spinstate to the stack
10904
           andn ++%00001111             ;mask out low nybble
10905
           cmpn ++$09
10906
              cmpcy
10907
           bcc GetHAdder              ;if lower than $09, branch ahead
10908
           eorn ++%00001111             ;otherwise get two's compliment to oscillate
10909
           clc
10910
           adcn ++$01
10911
GetHAdder: sta SCRATCHPAD+$01                    ;store result, modified or not, here
10912
           ldy SCRATCHPAD+$00                    ;load number of firebar ball where we're at
10913
           lday FirebarTblOffsets,y    ;load offset to firebar position data
10914
           clc
10915
           adci SCRATCHPAD+$01                    ;add oscillated high byte of spinstate
10916
           tay                        ;to offset here and use as new offset
10917
           lday FirebarPosLookupTbl,y  ;get data here and store as horizontal adder
10918
           sta SCRATCHPAD+$01
10919
           pla                        ;pull whatever was in A from the stack
10920
           pha                        ;save it again because we still need it
10921
           clc
10922
           adcn ++$08                   ;add eight this time, to get vertical adder
10923
           andn ++%00001111             ;mask out high nybble
10924
           cmpn ++$09                   ;if lower than $09, branch ahead
10925
              cmpcy
10926
           bcc GetVAdder
10927
           eorn ++%00001111             ;otherwise get two's compliment
10928
           clc
10929
           adcn ++$01
10930
GetVAdder: sta SCRATCHPAD+$02                    ;store result here
10931
           ldy SCRATCHPAD+$00
10932
           lday FirebarTblOffsets,y    ;load offset to firebar position data again
10933
           clc
10934
           adci SCRATCHPAD+$02                    ;this time add value in $02 to offset here and use as offset
10935
           tay
10936
           lday FirebarPosLookupTbl,y  ;get data here and store as vertica adder
10937
           sta SCRATCHPAD+$02
10938
           pla                        ;pull out whatever was in A one last time
10939
           lsr                        ;divide by eight or shift three to the right
10940
           lsr
10941
           lsr
10942
           tay                        ;use as offset
10943
           lday FirebarMirrorData,y    ;load mirroring data here
10944
           sta SCRATCHPAD+$03                    ;store
10945
           rts
10946
 
10947
;--------------------------------
10948
 
10949
PRandomSubtracter:
10950
      .db $f8, $a0, $70, $bd, $00
10951
 
10952
FlyCCBPriority:
10953
      .db $20, $20, $20, $00, $00
10954
 
10955
MoveFlyingCheepCheep:
10956
        ldax Enemy_State,x          ;check cheep-cheep's enemy state
10957
        andn ++%00100000             ;for d5 set
10958
        beq FlyCC                  ;branch to continue code if not set
10959
        ldan ++$00
10960
        stax Enemy_SprAttrib,x      ;otherwise clear sprite attributes
10961
        jmp MoveJ_EnemyVertically  ;and jump to move defeated cheep-cheep downwards
10962
FlyCC:  jsr MoveEnemyHorizontally  ;move cheep-cheep horizontally based on speed and force
10963
        ldyn ++$0d                   ;set vertical movement amount
10964
        ldan ++$05                   ;set maximum speed
10965
        jsr SetXMoveAmt            ;branch to impose gravity on flying cheep-cheep
10966
        ldax Enemy_Y_MoveForce,x
10967
        lsr                        ;get vertical movement force and
10968
        lsr                        ;move high nybble to low
10969
        lsr
10970
        lsr
10971
        tay                        ;save as offset (note this tends to go into reach of code)
10972
        ldax Enemy_Y_Position,x     ;get vertical position
10973
        secsub                        ;subtract pseudorandom value based on offset from position
10974
        sbcy PRandomSubtracter,y
10975
        bpl AddCCF                  ;if result within top half of screen, skip this part
10976
        eorn ++$ff
10977
        clc                        ;otherwise get two's compliment
10978
        adcn ++$01
10979
AddCCF: cmpn ++$08                   ;if result or two's compliment greater than eight,
10980
              cmpcy
10981
        bcs BPGet                  ;skip to the end without changing movement force
10982
        ldax Enemy_Y_MoveForce,x
10983
        clc
10984
        adcn ++$10                   ;otherwise add to it
10985
        stax Enemy_Y_MoveForce,x
10986
        lsr                        ;move high nybble to low again
10987
        lsr
10988
        lsr
10989
        lsr
10990
        tay
10991
BPGet:  lday FlyCCBPriority,y       ;load bg priority data and store (this is very likely
10992
        stax Enemy_SprAttrib,x      ;broken or residual code, value is overwritten before
10993
        rts                        ;drawing it next frame), then leave
10994
 
10995
;--------------------------------
10996
;$00 - used to hold horizontal difference
10997
;$01-$03 - used to hold difference adjusters
10998
 
10999
LakituDiffAdj:
11000
      .db $15, $30, $40
11001
 
11002
MoveLakitu:
11003
         ldax Enemy_State,x          ;check lakitu's enemy state
11004
         andn ++%00100000             ;for d5 set
11005
         beq ChkLS                  ;if not set, continue with code
11006
         jmp MoveD_EnemyVertically  ;otherwise jump to move defeated lakitu downwards
11007
ChkLS:   ldax Enemy_State,x          ;if lakitu's enemy state not set at all,
11008
         checka
11009
         beq Fr12S                  ;go ahead and continue with code
11010
         ldan ++$00
11011
         stax LakituMoveDirection,x  ;otherwise initialize moving direction to move to left
11012
         sta EnemyFrenzyBuffer      ;initialize frenzy buffer
11013
         ldan ++$10
11014
         checka
11015
         bne SetLSpd                ;load horizontal speed and do unconditional branch
11016
Fr12S:   ldan ++Spiny
11017
         sta EnemyFrenzyBuffer      ;set spiny identifier in frenzy buffer
11018
         ldyn ++$02
11019
LdLDa:   lday LakituDiffAdj,y        ;load values
11020
         stay SCRATCHPAD+$0001,y                ;store in zero page
11021
         dey
11022
         bpl LdLDa                  ;do this until all values are stired
11023
         jsr PlayerLakituDiff       ;execute sub to set speed and create spinys
11024
SetLSpd: stax LakituMoveSpeed,x      ;set movement speed returned from sub
11025
         ldyn ++$01                   ;set moving direction to right by default
11026
         ldax LakituMoveDirection,x
11027
         andn ++$01                   ;get LSB of moving direction
11028
         bne SetLMov                ;if set, branch to the end to use moving direction
11029
         ldax LakituMoveSpeed,x
11030
         eorn ++$ff                   ;get two's compliment of moving speed
11031
         clc
11032
         adcn ++$01
11033
         stax LakituMoveSpeed,x      ;store as new moving speed
11034
         iny                        ;increment moving direction to left
11035
SetLMov: styx Enemy_MovingDir,x      ;store moving direction
11036
         jmp MoveEnemyHorizontally  ;move lakitu horizontally
11037
 
11038
PlayerLakituDiff:
11039
           ldyn ++$00                   ;set Y for default value
11040
           jsr PlayerEnemyDiff        ;get horizontal difference between enemy and player
11041
           bpl ChkLakDif              ;branch if enemy is to the right of the player
11042
           iny                        ;increment Y for left of player
11043
           lda SCRATCHPAD+$00
11044
           eorn ++$ff                   ;get two's compliment of low byte of horizontal difference
11045
           clc
11046
           adcn ++$01                   ;store two's compliment as horizontal difference
11047
           sta SCRATCHPAD+$00
11048
ChkLakDif: lda SCRATCHPAD+$00                    ;get low byte of horizontal difference
11049
           cmpn ++$3c                   ;if within a certain distance of player, branch
11050
              cmpcy
11051
           bcc ChkPSpeed
11052
           ldan ++$3c                   ;otherwise set maximum distance
11053
           sta SCRATCHPAD+$00
11054
           ldax Enemy_ID,x             ;check if lakitu is in our current enemy slot
11055
           cmpn ++Lakitu
11056
           bne ChkPSpeed              ;if not, branch elsewhere
11057
           tya                        ;compare contents of Y, now in A
11058
           cmpx LakituMoveDirection,x  ;to what is being used as horizontal movement direction
11059
           beq ChkPSpeed              ;if moving toward the player, branch, do not alter
11060
           ldax LakituMoveDirection,x  ;if moving to the left beyond maximum distance,
11061
         checka
11062
           beq SetLMovD               ;branch and alter without delay
11063
           decx LakituMoveSpeed,x      ;decrement horizontal speed
11064
           ldax LakituMoveSpeed,x      ;if horizontal speed not yet at zero, branch to leave
11065
         checka
11066
           bne ExMoveLak
11067
SetLMovD:  tya                        ;set horizontal direction depending on horizontal
11068
           stax LakituMoveDirection,x  ;difference between enemy and player if necessary
11069
ChkPSpeed: lda SCRATCHPAD+$00
11070
           andn ++%00111100             ;mask out all but four bits in the middle
11071
           lsr                        ;divide masked difference by four
11072
           lsr
11073
           sta SCRATCHPAD+$00                    ;store as new value
11074
           ldyn ++$00                   ;init offset
11075
           lda Player_X_Speed
11076
         checka
11077
           beq SubDifAdj              ;if player not moving horizontally, branch
11078
           lda ScrollAmount
11079
         checka
11080
           beq SubDifAdj              ;if scroll speed not set, branch to same place
11081
           iny                        ;otherwise increment offset
11082
           lda Player_X_Speed
11083
           cmpn ++$19                   ;if player not running, branch
11084
              cmpcy
11085
           bcc ChkSpinyO
11086
           lda ScrollAmount
11087
           cmpn ++$02                   ;if scroll speed below a certain amount, branch
11088
              cmpcy
11089
           bcc ChkSpinyO              ;to same place
11090
           iny                        ;otherwise increment once more
11091
ChkSpinyO: ldax Enemy_ID,x             ;check for spiny object
11092
           cmpn ++Spiny
11093
           bne ChkEmySpd              ;branch if not found
11094
           lda Player_X_Speed         ;if player not moving, skip this part
11095
         checka
11096
           bne SubDifAdj
11097
ChkEmySpd: ldax Enemy_Y_Speed,x        ;check vertical speed
11098
         checka
11099
           bne SubDifAdj              ;branch if nonzero
11100
           ldyn ++$00                   ;otherwise reinit offset
11101
SubDifAdj: lday SCRATCHPAD+$0001,y                ;get one of three saved values from earlier
11102
           ldy SCRATCHPAD+$00                    ;get saved horizontal difference
11103
SPixelLak: secsub                        ;subtract one for each pixel of horizontal difference
11104
           sbcn ++$01                   ;from one of three saved values
11105
           dey
11106
           bpl SPixelLak              ;branch until all pixels are subtracted, to adjust difference
11107
ExMoveLak: rts                        ;leave!!!
11108
 
11109
;-------------------------------------------------------------------------------------
11110
;$04-$05 - used to store name table address in little endian order
11111
 
11112
BridgeCollapseData:
11113
      .db $1a ;axe
11114
      .db $58 ;chain
11115
      .db $98, $96, $94, $92, $90, $8e, $8c ;bridge
11116
      .db $8a, $88, $86, $84, $82, $80
11117
 
11118
BridgeCollapse:
11119
       ldx BowserFront_Offset    ;get enemy offset for bowser
11120
       ldax Enemy_ID,x            ;check enemy object identifier for bowser
11121
       cmpn ++Bowser               ;if not found, branch ahead,
11122
       bne SetM2                 ;metatile removal not necessary
11123
       stx ObjectOffset          ;store as enemy offset here
11124
       ldax Enemy_State,x         ;if bowser in normal state, skip all of this
11125
         checka
11126
       beq RemoveBridge
11127
       andn ++%01000000            ;if bowser's state has d6 clear, skip to silence music
11128
       beq SetM2
11129
       ldax Enemy_Y_Position,x    ;check bowser's vertical coordinate
11130
       cmpn ++$e0                  ;if bowser not yet low enough, skip this part ahead
11131
              cmpcy
11132
       bcc MoveD_Bowser
11133
SetM2: ldan ++Silence              ;silence music
11134
       sta EventMusicQueue
11135
       inci OperMode_Task         ;move onto next secondary mode in autoctrl mode
11136
       jmp KillAllEnemies        ;jump to empty all enemy slots and then leave  
11137
 
11138
MoveD_Bowser:
11139
       jsr MoveEnemySlowVert     ;do a sub to move bowser downwards
11140
       jmp BowserGfxHandler      ;jump to draw bowser's front and rear, then leave
11141
 
11142
RemoveBridge:
11143
         deci BowserFeetCounter     ;decrement timer to control bowser's feet
11144
         bne NoBFall               ;if not expired, skip all of this
11145
         ldan ++$04
11146
         sta BowserFeetCounter     ;otherwise, set timer now
11147
         lda BowserBodyControls
11148
         eorn ++$01                  ;invert bit to control bowser's feet
11149
         sta BowserBodyControls
11150
         ldan ++$22                  ;put high byte of name table address here for now
11151
         sta SCRATCHPAD+$05
11152
         ldy BridgeCollapseOffset  ;get bridge collapse offset here
11153
         lday BridgeCollapseData,y  ;load low byte of name table address and store here
11154
         sta SCRATCHPAD+$04
11155
         ldy VRAM_Buffer1_Offset   ;increment vram buffer offset
11156
         iny
11157
         ldxn ++$0c                  ;set offset for tile data for sub to draw blank metatile
11158
         jsr RemBridge             ;do sub here to remove bowser's bridge metatiles
11159
         ldx ObjectOffset          ;get enemy offset
11160
         jsr MoveVOffset           ;set new vram buffer offset
11161
         ldan ++Sfx_Blast            ;load the fireworks/gunfire sound into the square 2 sfx
11162
         sta Square2SoundQueue     ;queue while at the same time loading the brick
11163
         ldan ++Sfx_BrickShatter     ;shatter sound into the noise sfx queue thus
11164
         sta NoiseSoundQueue       ;producing the unique sound of the bridge collapsing 
11165
         inci BridgeCollapseOffset  ;increment bridge collapse offset
11166
         lda BridgeCollapseOffset
11167
         cmpn ++$0f                  ;if bridge collapse offset has not yet reached
11168
         bne NoBFall               ;the end, go ahead and skip this part
11169
         jsr InitVStf              ;initialize whatever vertical speed bowser has
11170
         ldan ++%01000000
11171
         stax Enemy_State,x         ;set bowser's state to one of defeated states (d6 set)
11172
         ldan ++Sfx_BowserFall
11173
         sta Square2SoundQueue     ;play bowser defeat sound
11174
NoBFall: jmp BowserGfxHandler      ;jump to code that draws bowser
11175
 
11176
;--------------------------------
11177
 
11178
PRandomRange:
11179
      .db $21, $41, $11, $31
11180
 
11181
RunBowser:
11182
      ldax Enemy_State,x       ;if d5 in enemy state is not set
11183
      andn ++%00100000          ;then branch elsewhere to run bowser
11184
      beq BowserControl
11185
      ldax Enemy_Y_Position,x  ;otherwise check vertical position
11186
      cmpn ++$e0                ;if above a certain point, branch to move defeated bowser
11187
              cmpcy
11188
      bcc MoveD_Bowser        ;otherwise proceed to KillAllEnemies
11189
 
11190
KillAllEnemies:
11191
          ldxn ++$04              ;start with last enemy slot
11192
KillLoop: jsr EraseEnemyObject  ;branch to kill enemy objects
11193
          dex                   ;move onto next enemy slot
11194
          bpl KillLoop          ;do this until all slots are emptied
11195
          sta EnemyFrenzyBuffer ;empty frenzy buffer
11196
          ldx ObjectOffset      ;get enemy object offset and leave
11197
          rts
11198
 
11199
BowserControl:
11200
           ldan ++$00
11201
           sta EnemyFrenzyBuffer      ;empty frenzy buffer
11202
           lda TimerControl           ;if master timer control not set,
11203
         checka
11204
           beq ChkMouth               ;skip jump and execute code here
11205
           jmp SkipToFB               ;otherwise, jump over a bunch of code
11206
ChkMouth:  lda BowserBodyControls     ;check bowser's mouth
11207
         checka
11208
           bpl FeetTmr                ;if bit clear, go ahead with code here
11209
           jmp HammerChk              ;otherwise skip a whole section starting here
11210
FeetTmr:   deci BowserFeetCounter      ;decrement timer to control bowser's feet
11211
           bne ResetMDr               ;if not expired, skip this part
11212
           ldan ++$20                   ;otherwise, reset timer
11213
           sta BowserFeetCounter        
11214
           lda BowserBodyControls     ;and invert bit used
11215
           eorn ++%00000001             ;to control bowser's feet
11216
           sta BowserBodyControls
11217
ResetMDr:  lda FrameCounter           ;check frame counter
11218
           andn ++%00001111             ;if not on every sixteenth frame, skip
11219
           bne B_FaceP                ;ahead to continue code
11220
           ldan ++$02                   ;otherwise reset moving/facing direction every
11221
           stax Enemy_MovingDir,x      ;sixteen frames
11222
B_FaceP:   ldax EnemyFrameTimer,x      ;if timer set here expired,
11223
         checka
11224
           beq GetPRCmp               ;branch to next section
11225
           jsr PlayerEnemyDiff        ;get horizontal difference between player and bowser,
11226
           bpl GetPRCmp               ;and branch if bowser to the right of the player
11227
           ldan ++$01
11228
           stax Enemy_MovingDir,x      ;set bowser to move and face to the right
11229
           ldan ++$02
11230
           sta BowserMovementSpeed    ;set movement speed
11231
           ldan ++$20
11232
           stax EnemyFrameTimer,x      ;set timer here
11233
           sta BowserFireBreathTimer  ;set timer used for bowser's flame
11234
           ldax Enemy_X_Position,x        
11235
           cmpn ++$c8                   ;if bowser to the right past a certain point,
11236
              cmpcy
11237
           bcs HammerChk              ;skip ahead to some other section
11238
GetPRCmp:  lda FrameCounter           ;get frame counter
11239
           andn ++%00000011
11240
           bne HammerChk              ;execute this code every fourth frame, otherwise branch
11241
           ldax Enemy_X_Position,x
11242
           cmpi BowserOrigXPos         ;if bowser not at original horizontal position,
11243
           bne GetDToO                ;branch to skip this part
11244
           ldax PseudoRandomBitReg,x
11245
           andn ++%00000011             ;get pseudorandom offset
11246
           tay
11247
           lday PRandomRange,y         ;load value using pseudorandom offset
11248
           sta MaxRangeFromOrigin     ;and store here
11249
GetDToO:   ldax Enemy_X_Position,x
11250
           clc                        ;add movement speed to bowser's horizontal
11251
           adci BowserMovementSpeed    ;coordinate and save as new horizontal position
11252
           stax Enemy_X_Position,x
11253
           ldyx Enemy_MovingDir,x
11254
           cpyn ++$01                   ;if bowser moving and facing to the right, skip ahead
11255
           beq HammerChk
11256
           ldyn ++$ff                   ;set default movement speed here (move left)
11257
           secsub                        ;get difference of current vs. original
11258
           sbci BowserOrigXPos         ;horizontal position
11259
           bpl CompDToO               ;if current position to the right of original, skip ahead
11260
           eorn ++$ff
11261
           clc                        ;get two's compliment
11262
           adcn ++$01
11263
           ldyn ++$01                   ;set alternate movement speed here (move right)
11264
CompDToO:  cmpi MaxRangeFromOrigin     ;compare difference with pseudorandom value
11265
              cmpcy
11266
           bcc HammerChk              ;if difference LOW  pseudorandom value, leave speed alone
11267
           sty BowserMovementSpeed    ;otherwise change bowser's movement speed
11268
HammerChk: ldax EnemyFrameTimer,x      ;if timer set here not expired yet, skip ahead to
11269
         checka
11270
           bne MakeBJump              ;some other section of code
11271
           jsr MoveEnemySlowVert      ;otherwise start by moving bowser downwards
11272
           lda WorldNumber            ;check world number
11273
           cmpn ++World6
11274
              cmpcy
11275
           bcc SetHmrTmr              ;if world 1-5, skip this part (not time to throw hammers yet)
11276
           lda FrameCounter
11277
           andn ++%00000011             ;check to see if it's time to execute sub
11278
           bne SetHmrTmr              ;if not, skip sub, otherwise
11279
           jsr SpawnHammerObj         ;execute sub on every fourth frame to spawn misc object (hammer)
11280
SetHmrTmr: ldax Enemy_Y_Position,x     ;get current vertical position
11281
           cmpn ++$80                   ;if still above a certain point
11282
              cmpcy
11283
           bcc ChkFireB               ;then skip to world number check for flames
11284
           ldax PseudoRandomBitReg,x
11285
           andn ++%00000011             ;get pseudorandom offset
11286
           tay
11287
           lday PRandomRange,y         ;get value using pseudorandom offset
11288
           stax EnemyFrameTimer,x      ;set for timer here
11289
SkipToFB:  jmp ChkFireB               ;jump to execute flames code
11290
MakeBJump: cmpn ++$01                   ;if timer not yet about to expire,
11291
           bne ChkFireB               ;skip ahead to next part
11292
           decx Enemy_Y_Position,x     ;otherwise decrement vertical coordinate
11293
           jsr InitVStf               ;initialize movement amount
11294
           ldan ++$fe
11295
           stax Enemy_Y_Speed,x        ;set vertical speed to move bowser upwards
11296
ChkFireB:  lda WorldNumber            ;check world number here
11297
           cmpn ++World8                ;world 8?
11298
           beq SpawnFBr               ;if so, execute this part here
11299
           cmpn ++World6                ;world 6-7?
11300
              cmpcy
11301
           bcs BowserGfxHandler       ;if so, skip this part here
11302
SpawnFBr:  lda BowserFireBreathTimer  ;check timer here
11303
         checka
11304
           bne BowserGfxHandler       ;if not expired yet, skip all of this
11305
           ldan ++$20
11306
           sta BowserFireBreathTimer  ;set timer here
11307
           lda BowserBodyControls
11308
           eorn ++%10000000             ;invert bowser's mouth bit to open
11309
           sta BowserBodyControls     ;and close bowser's mouth
11310
           bmi ChkFireB               ;if bowser's mouth open, loop back
11311
           jsr SetFlameTimer          ;get timing for bowser's flame
11312
           ldy SecondaryHardMode
11313
         checky
11314
           beq SetFBTmr               ;if secondary hard mode flag not set, skip this
11315
           secsub
11316
           sbcn ++$10                   ;otherwise subtract from value in A
11317
SetFBTmr:  sta BowserFireBreathTimer  ;set value as timer here
11318
           ldan ++BowserFlame           ;put bowser's flame identifier
11319
           sta EnemyFrenzyBuffer      ;in enemy frenzy buffer
11320
 
11321
;--------------------------------
11322
 
11323
BowserGfxHandler:
11324
          jsr ProcessBowserHalf    ;do a sub here to process bowser's front
11325
          ldyn ++$10                 ;load default value here to position bowser's rear
11326
          ldax Enemy_MovingDir,x    ;check moving direction
11327
          lsr
11328
          bcc CopyFToR             ;if moving left, use default
11329
          ldyn ++$f0                 ;otherwise load alternate positioning value here
11330
CopyFToR: tya                      ;move bowser's rear object position value to A
11331
          clc
11332
          adcx Enemy_X_Position,x   ;add to bowser's front object horizontal coordinate
11333
          ldy DuplicateObj_Offset  ;get bowser's rear object offset
11334
          stay Enemy_X_Position,y   ;store A as bowser's rear horizontal coordinate
11335
          ldax Enemy_Y_Position,x
11336
          clc                      ;add eight pixels to bowser's front object
11337
          adcn ++$08                 ;vertical coordinate and store as vertical coordinate
11338
          stay Enemy_Y_Position,y   ;for bowser's rear
11339
          ldax Enemy_State,x
11340
          stay Enemy_State,y        ;copy enemy state directly from front to rear
11341
          ldax Enemy_MovingDir,x
11342
          stay Enemy_MovingDir,y    ;copy moving direction also
11343
          lda ObjectOffset         ;save enemy object offset of front to stack
11344
          pha
11345
          ldx DuplicateObj_Offset  ;put enemy object offset of rear as current
11346
          stx ObjectOffset
11347
          ldan ++Bowser              ;set bowser's enemy identifier
11348
          stax Enemy_ID,x           ;store in bowser's rear object
11349
          jsr ProcessBowserHalf    ;do a sub here to process bowser's rear
11350
          pla
11351
          sta ObjectOffset         ;get original enemy object offset
11352
          tax
11353
          ldan ++$00                 ;nullify bowser's front/rear graphics flag
11354
          sta BowserGfxFlag
11355
ExBGfxH:  rts                      ;leave!
11356
 
11357
ProcessBowserHalf:
11358
      inci BowserGfxFlag         ;increment bowser's graphics flag, then run subroutines
11359
      jsr RunRetainerObj        ;to get offscreen bits, relative position and draw bowser (finally!)
11360
      ldax Enemy_State,x
11361
         checka
11362
      bne ExBGfxH               ;if either enemy object not in normal state, branch to leave
11363
      ldan ++$0a
11364
      stax Enemy_BoundBoxCtrl,x  ;set bounding box size control
11365
      jsr GetEnemyBoundBox      ;get bounding box coordinates
11366
      jmp PlayerEnemyCollision  ;do player-to-enemy collision detection
11367
 
11368
;-------------------------------------------------------------------------------------
11369
;$00 - used to hold movement force and tile number
11370
;$01 - used to hold sprite attribute data
11371
 
11372
FlameTimerData:
11373
      .db $bf, $40, $bf, $bf, $bf, $40, $40, $bf
11374
 
11375
SetFlameTimer:
11376
      ldy BowserFlameTimerCtrl  ;load counter as offset
11377
      inci BowserFlameTimerCtrl  ;increment
11378
      lda BowserFlameTimerCtrl  ;mask out all but 3 LSB
11379
      andn ++%00000111            ;to keep in range of 0-7
11380
      sta BowserFlameTimerCtrl
11381
      lday FlameTimerData,y      ;load value to be used then leave
11382
ExFl: rts
11383
 
11384
ProcBowserFlame:
11385
         lda TimerControl            ;if master timer control flag set,
11386
         checka
11387
         bne SetGfxF                 ;skip all of this
11388
         ldan ++$40                    ;load default movement force
11389
         ldy SecondaryHardMode
11390
         checky
11391
         beq SFlmX                   ;if secondary hard mode flag not set, use default
11392
         ldan ++$60                    ;otherwise load alternate movement force to go faster
11393
SFlmX:   sta SCRATCHPAD+$00                     ;store value here
11394
         ldax Enemy_X_MoveForce,x
11395
         secsub                         ;subtract value from movement force (  X-)
11396
         sbci SCRATCHPAD+$00
11397
          push af
11398
         stax Enemy_X_MoveForce,x     ;save new value (  X-)
11399
         ldax Enemy_X_Position,x
11400
          ld h,a
11401
          pop af
11402
          ld a,h
11403
         sbcn ++$01                    ;subtract one from horizontal position to move
11404
          push af
11405
         stax Enemy_X_Position,x      ;to the left
11406
         ldax Enemy_PageLoc,x
11407
          ld h,a
11408
          pop af
11409
          ld a,h
11410
         sbcn ++$00                    ;subtract borrow from page location
11411
         stax Enemy_PageLoc,x
11412
         ldyx BowserFlamePRandomOfs,x ;get some value here and use as offset
11413
         ldax Enemy_Y_Position,x      ;load vertical coordinate
11414
         cmpy FlameYPosData,y         ;compare against coordinate data using $0417,x (???) as offset
11415
         beq SetGfxF                 ;if equal, branch and do not modify coordinate
11416
         clc
11417
         adcx Enemy_Y_MoveForce,x     ;otherwise add value here to coordinate and store
11418
         stax Enemy_Y_Position,x      ;as new vertical coordinate
11419
SetGfxF: jsr RelativeEnemyPosition   ;get new relative coordinates
11420
         ldax Enemy_State,x           ;if bowser's flame not in normal state,
11421
         checka
11422
         bne ExFl                    ;branch to leave
11423
         ldan ++$51                    ;otherwise, continue
11424
         sta SCRATCHPAD+$00                     ;write first tile number
11425
         ldyn ++$02                    ;load attributes without vertical flip by default
11426
         lda FrameCounter
11427
         andn ++%00000010              ;invert vertical flip bit every 2 frames
11428
         beq FlmeAt                  ;if d1 not set, write default value
11429
         ldyn ++$82                    ;otherwise write value with vertical flip bit set
11430
FlmeAt:  sty SCRATCHPAD+$01                     ;set bowser's flame sprite attributes here
11431
         ldyx Enemy_SprDataOffset,x   ;get OAM data offset
11432
         ldxn ++$00
11433
 
11434
DrawFlameLoop:
11435
         lda Enemy_Rel_YPos         ;get Y relative coordinate of current enemy object
11436
         stay Sprite_Y_Position,y    ;write into Y coordinate of OAM data
11437
         lda SCRATCHPAD+$00
11438
         stay Sprite_Tilenumber,y    ;write current tile number into OAM data
11439
         inci SCRATCHPAD+$00                    ;increment tile number to draw more bowser's flame
11440
         lda SCRATCHPAD+$01
11441
         stay Sprite_Attributes,y    ;write saved attributes into OAM data
11442
         lda Enemy_Rel_XPos
11443
         stay Sprite_X_Position,y    ;write X relative coordinate of current enemy object
11444
         clc
11445
         adcn ++$08
11446
         sta Enemy_Rel_XPos         ;then add eight to it and store
11447
         iny
11448
         iny
11449
         iny
11450
         iny                        ;increment Y four times to move onto the next OAM
11451
         inx                        ;move onto the next OAM, and branch if three
11452
         cpxn ++$03                   ;have not yet been done
11453
              cmpcy
11454
         bcc DrawFlameLoop
11455
         ldx ObjectOffset           ;reload original enemy offset
11456
         jsr GetEnemyOffscreenBits  ;get offscreen information
11457
         ldyx Enemy_SprDataOffset,x  ;get OAM data offset
11458
         lda Enemy_OffscreenBits    ;get enemy object offscreen bits
11459
         lsr                        ;move d0 to carry and result to stack
11460
         pha
11461
         bcc M3FOfs                 ;branch if carry not set
11462
         ldan ++$f8                   ;otherwise move sprite offscreen, this part likely
11463
         stay Sprite_Y_Position+12,y ;residual since flame is only made of three sprites
11464
M3FOfs:  pla                        ;get bits from stack
11465
         lsr                        ;move d1 to carry and move bits back to stack
11466
         pha
11467
         bcc M2FOfs                 ;branch if carry not set again
11468
         ldan ++$f8                   ;otherwise move third sprite offscreen
11469
         stay Sprite_Y_Position+8,y
11470
M2FOfs:  pla                        ;get bits from stack again
11471
         lsr                        ;move d2 to carry and move bits back to stack again
11472
         pha
11473
         bcc M1FOfs                 ;branch if carry not set yet again
11474
         ldan ++$f8                   ;otherwise move second sprite offscreen
11475
         stay Sprite_Y_Position+4,y
11476
M1FOfs:  pla                        ;get bits from stack one last time
11477
         lsr                        ;move d3 to carry
11478
         bcc ExFlmeD                ;branch if carry not set one last time
11479
         ldan ++$f8
11480
         stay Sprite_Y_Position,y    ;otherwise move first sprite offscreen
11481
ExFlmeD: rts                        ;leave
11482
 
11483
;--------------------------------
11484
 
11485
RunFireworks:
11486
           decx ExplosionTimerCounter,x ;decrement explosion timing counter here
11487
           bne SetupExpl               ;if not expired, skip this part
11488
           ldan ++$08
11489
           stax ExplosionTimerCounter,x ;reset counter
11490
           incx ExplosionGfxCounter,x   ;increment explosion graphics counter
11491
           ldax ExplosionGfxCounter,x
11492
           cmpn ++$03                    ;check explosion graphics counter
11493
              cmpcy
11494
           bcs FireworksSoundScore     ;if at a certain point, branch to kill this object
11495
SetupExpl: jsr RelativeEnemyPosition   ;get relative coordinates of explosion
11496
           lda Enemy_Rel_YPos          ;copy relative coordinates
11497
           sta Fireball_Rel_YPos       ;from the enemy object to the fireball object
11498
           lda Enemy_Rel_XPos          ;first vertical, then horizontal
11499
           sta Fireball_Rel_XPos
11500
           ldyx Enemy_SprDataOffset,x   ;get OAM data offset
11501
           ldax ExplosionGfxCounter,x   ;get explosion graphics counter
11502
           jsr DrawExplosion_Fireworks ;do a sub to draw the explosion then leave
11503
           rts
11504
 
11505
FireworksSoundScore:
11506
      ldan ++$00               ;disable enemy buffer flag
11507
      stax Enemy_Flag,x
11508
      ldan ++Sfx_Blast         ;play fireworks/gunfire sound
11509
      sta Square2SoundQueue
11510
      ldan ++$05               ;set part of score modifier for 500 points
11511
      sta DigitModifier+4
11512
      jmp EndAreaPoints     ;jump to award points accordingly then leave
11513
 
11514
;--------------------------------
11515
 
11516
StarFlagYPosAdder:
11517
      .db $00, $00, $08, $08
11518
 
11519
StarFlagXPosAdder:
11520
      .db $00, $08, $00, $08
11521
 
11522
StarFlagTileData:
11523
      .db $54, $55, $56, $57
11524
 
11525
RunStarFlagObj:
11526
      ldan ++$00                 ;initialize enemy frenzy buffer
11527
      sta EnemyFrenzyBuffer
11528
      lda StarFlagTaskControl  ;check star flag object task number here
11529
      cmpn ++$05                 ;if greater than 5, branch to exit
11530
              cmpcy
11531
      bcs StarFlagExit
11532
      jsr JumpEngine           ;otherwise jump to appropriate sub
11533
 
11534
      .dw StarFlagExit
11535
      .dw GameTimerFireworks
11536
      .dw AwardGameTimerPoints
11537
      .dw RaiseFlagSetoffFWorks
11538
      .dw DelayToAreaEnd
11539
 
11540
GameTimerFireworks:
11541
        ldyn ++$05               ;set default state for star flag object
11542
        lda GameTimerDisplay+2 ;get game timer's last digit
11543
        cmpn ++$01
11544
        beq SetFWC             ;if last digit of game timer set to 1, skip ahead
11545
        ldyn ++$03               ;otherwise load new value for state
11546
        cmpn ++$03
11547
        beq SetFWC             ;if last digit of game timer set to 3, skip ahead
11548
        ldyn ++$00               ;otherwise load one more potential value for state
11549
        cmpn ++$06
11550
        beq SetFWC             ;if last digit of game timer set to 6, skip ahead
11551
        ldan ++$ff               ;otherwise set value for no fireworks
11552
SetFWC: sta FireworksCounter   ;set fireworks counter here
11553
        styx Enemy_State,x      ;set whatever state we have in star flag object
11554
 
11555
IncrementSFTask1:
11556
      inci StarFlagTaskControl  ;increment star flag object task number
11557
 
11558
StarFlagExit:
11559
      rts                      ;leave
11560
 
11561
AwardGameTimerPoints:
11562
         lda GameTimerDisplay   ;check all game timer digits for any intervals left
11563
         orai GameTimerDisplay+1
11564
         orai GameTimerDisplay+2
11565
         beq IncrementSFTask1   ;if no time left on game timer at all, branch to next task
11566
         lda FrameCounter
11567
         andn ++%00000100         ;check frame counter for d2 set (skip ahead
11568
         beq NoTTick            ;for four frames every four frames) branch if not set
11569
         ldan ++Sfx_TimerTick
11570
         sta Square2SoundQueue  ;load timer tick sound
11571
NoTTick: ldyn ++GameTimerDisplay-DisplayDigits+2;++$23               ;set offset here to subtract from game timer's last digit
11572
         ldan ++$ff               ;set adder here to $ff, or -1, to subtract one
11573
         sta DigitModifier+5    ;from the last digit of the game timer
11574
         jsr DigitsMathRoutine  ;subtract digit
11575
         ldan ++$05               ;set now to add 50 points
11576
         sta DigitModifier+5    ;per game timer interval subtracted
11577
 
11578
EndAreaPoints:
11579
         ldyn ++$0b               ;load offset for mario's score by default
11580
         lda CurrentPlayer      ;check player on the screen
11581
         checka
11582
         beq ELPGive            ;if mario, do not change
11583
         ldyn ++$11               ;otherwise load offset for luigi's score
11584
ELPGive: jsr DigitsMathRoutine  ;award 50 points per game timer interval
11585
         lda CurrentPlayer      ;get player on the screen (or 500 points per
11586
         asl                    ;fireworks explosion if branched here from there)
11587
         asl                    ;shift to high nybble
11588
         asl
11589
         asl
11590
         oran ++%00000100         ;add four to set nybble for game timer
11591
         jmp UpdateNumber       ;jump to print the new score and game timer
11592
 
11593
RaiseFlagSetoffFWorks:
11594
         ldax Enemy_Y_Position,x  ;check star flag's vertical position
11595
         cmpn ++$72                ;against preset value
11596
              cmpcy
11597
         bcc SetoffF             ;if star flag higher vertically, branch to other code
11598
         decx Enemy_Y_Position,x  ;otherwise, raise star flag by one pixel
11599
         jmp DrawStarFlag        ;and skip this part here
11600
SetoffF: lda FireworksCounter    ;check fireworks counter
11601
         checka
11602
         beq DrawFlagSetTimer    ;if no fireworks left to go off, skip this part
11603
         bmi DrawFlagSetTimer    ;if no fireworks set to go off, skip this part
11604
         ldan ++Fireworks
11605
         sta EnemyFrenzyBuffer   ;otherwise set fireworks object in frenzy queue
11606
 
11607
DrawStarFlag:
11608
         jsr RelativeEnemyPosition  ;get relative coordinates of star flag
11609
         ldyx Enemy_SprDataOffset,x  ;get OAM data offset
11610
         ldxn ++$03                   ;do four sprites
11611
DSFLoop: lda Enemy_Rel_YPos         ;get relative vertical coordinate
11612
         clc
11613
         adcx StarFlagYPosAdder,x    ;add Y coordinate adder data
11614
         stay Sprite_Y_Position,y    ;store as Y coordinate
11615
         ldax StarFlagTileData,x     ;get tile number
11616
         stay Sprite_Tilenumber,y    ;store as tile number
11617
         ldan ++$22                   ;set palette and background priority bits
11618
         stay Sprite_Attributes,y    ;store as attributes
11619
         lda Enemy_Rel_XPos         ;get relative horizontal coordinate
11620
         clc
11621
         adcx StarFlagXPosAdder,x    ;add X coordinate adder data
11622
         stay Sprite_X_Position,y    ;store as X coordinate
11623
         iny
11624
         iny                        ;increment OAM data offset four bytes
11625
         iny                        ;for next sprite
11626
         iny
11627
         dex                        ;move onto next sprite
11628
         bpl DSFLoop                ;do this until all sprites are done
11629
         ldx ObjectOffset           ;get enemy object offset and leave
11630
         rts
11631
 
11632
DrawFlagSetTimer:
11633
      jsr DrawStarFlag          ;do sub to draw star flag
11634
      ldan ++$06
11635
      stax EnemyIntervalTimer,x  ;set interval timer here
11636
 
11637
IncrementSFTask2:
11638
      inci StarFlagTaskControl   ;move onto next task
11639
      rts
11640
 
11641
DelayToAreaEnd:
11642
      jsr DrawStarFlag          ;do sub to draw star flag
11643
      ldax EnemyIntervalTimer,x  ;if interval timer set in previous task
11644
         checka
11645
      bne StarFlagExit2         ;not yet expired, branch to leave
231 alone 11646
 
11647
;:      MUSICONINT=1
11648
        if MUSICONINT
171 demige 11649
      lda EventMusicBuffer      ;if event music buffer empty,
11650
         checka
231 alone 11651
     ret nz
11652
    ;ld hl,(EventMusicQueue_noint)      ;if event music buffer empty,
11653
    ;jr $ ;hl=fdcb/fdd0/fe2b/ (fdc9/fdce/fe29/fde0)
11654
               ;ld a,(WorldNumber)           ;check world number
11655
               ;cp ++World4;8
11656
               ;jr nc,IncrementSFTask2 ;     8-2...  !
11657
     ld hl,SoundEngine_noint
11658
     ld (soundenginepatch),hl ; MUSICONINT=1
11659
     ld a,0xcd
11660
     ld (soundenginecall),a ; MUSICONINT=1
11661
     jr IncrementSFTask2      ;branch to increment task
11662
        else
11663
      lda EventMusicBuffer      ;if event music buffer empty,
11664
         checka
171 demige 11665
      beq IncrementSFTask2      ;branch to increment task
231 alone 11666
        endif
171 demige 11667
 
11668
StarFlagExit2:
11669
      rts                       ;otherwise leave
11670
 
11671
;--------------------------------
11672
;$00 - used to store horizontal difference between player and piranha plant
11673
 
11674
MovePiranhaPlant:
11675
      ldax Enemy_State,x           ;check enemy state
11676
         checka
11677
      bne PutinPipe               ;if set at all, branch to leave
11678
      ldax EnemyFrameTimer,x       ;check enemy's timer here
11679
         checka
11680
      bne PutinPipe               ;branch to end if not yet expired
11681
      ldax PiranhaPlant_MoveFlag,x ;check movement flag
11682
         checka
11683
      bne SetupToMovePPlant       ;if moving, skip to part ahead
11684
      ldax PiranhaPlant_Y_Speed,x  ;if currently rising, branch 
11685
         checka
11686
      bmi ReversePlantSpeed       ;to move enemy upwards out of pipe
11687
      jsr PlayerEnemyDiff         ;get horizontal difference between player and
11688
      bpl ChkPlayerNearPipe       ;piranha plant, and branch if enemy to right of player
11689
      lda SCRATCHPAD+$00                     ;otherwise get saved horizontal difference
11690
      eorn ++$ff
11691
      clc                         ;and change to two's compliment
11692
      adcn ++$01
11693
      sta SCRATCHPAD+$00                     ;save as new horizontal difference
11694
 
11695
ChkPlayerNearPipe:
11696
      lda SCRATCHPAD+$00                     ;get saved horizontal difference
11697
      cmpn ++$21
11698
              cmpcy
11699
      bcc PutinPipe               ;if player within a certain distance, branch to leave
11700
 
11701
ReversePlantSpeed:
11702
      ldax PiranhaPlant_Y_Speed,x  ;get vertical speed
11703
      eorn ++$ff
11704
      clc                         ;change to two's compliment
11705
      adcn ++$01
11706
      stax PiranhaPlant_Y_Speed,x  ;save as new vertical speed
11707
      incx PiranhaPlant_MoveFlag,x ;increment to set movement flag
11708
 
11709
SetupToMovePPlant:
11710
      ldax PiranhaPlantDownYPos,x  ;get original vertical coordinate (lowest point)
11711
      ldyx PiranhaPlant_Y_Speed,x  ;get vertical speed
11712
         checky
11713
      bpl RiseFallPiranhaPlant    ;branch if moving downwards
11714
      ldax PiranhaPlantUpYPos,x    ;otherwise get other vertical coordinate (highest point)
11715
 
11716
RiseFallPiranhaPlant:
11717
      sta SCRATCHPAD+$00                     ;save vertical coordinate here
11718
      lda FrameCounter            ;get frame counter
11719
      lsr
11720
      bcc PutinPipe               ;branch to leave if d0 set (execute code every other frame)
11721
      lda TimerControl            ;get master timer control
11722
         checka
11723
      bne PutinPipe               ;branch to leave if set (likely not necessary)
11724
      ldax Enemy_Y_Position,x      ;get current vertical coordinate
11725
      clc
11726
      adcx PiranhaPlant_Y_Speed,x  ;add vertical speed to move up or down
11727
      stax Enemy_Y_Position,x      ;save as new vertical coordinate
11728
      cmpi SCRATCHPAD+$00                     ;compare against low or high coordinate
11729
      bne PutinPipe               ;branch to leave if not yet reached
11730
      ldan ++$00
11731
      stax PiranhaPlant_MoveFlag,x ;otherwise clear movement flag
11732
      ldan ++$40
11733
      stax EnemyFrameTimer,x       ;set timer to delay piranha plant movement
11734
 
11735
PutinPipe:
11736
      ldan ++%00100000              ;set background priority bit in sprite
11737
      stax Enemy_SprAttrib,x       ;attributes to give illusion of being inside pipe
11738
      rts                         ;then leave
11739
 
11740
;-------------------------------------------------------------------------------------
11741
;$07 - spinning speed
11742
 
11743
FirebarSpin:
11744
      sta SCRATCHPAD+$07                     ;save spinning speed here
11745
      ldax FirebarSpinDirection,x  ;check spinning direction
11746
         checka
11747
      bne SpinCounterClockwise    ;if moving counter-clockwise, branch to other part
11748
      ldyn ++$18                    ;possibly residual ldy
11749
      ldax FirebarSpinState_Low,x
11750
      clc                         ;add spinning speed to what would normally be
11751
      adci SCRATCHPAD+$07                     ;the horizontal speed
11752
          push af
11753
      stax FirebarSpinState_Low,x
11754
      ldax FirebarSpinState_High,x ;add carry to what would normally be the vertical speed
11755
          ld h,a
11756
          pop af
11757
          ld a,h
11758
      adcn ++$00
11759
      rts
11760
 
11761
SpinCounterClockwise:
11762
      ldyn ++$08                    ;possibly residual ldy
11763
      ldax FirebarSpinState_Low,x
11764
      secsub                         ;subtract spinning speed to what would normally be
11765
      sbci SCRATCHPAD+$07                     ;the horizontal speed
11766
          push af
11767
      stax FirebarSpinState_Low,x
11768
      ldax FirebarSpinState_High,x ;add carry to what would normally be the vertical speed
11769
          ld h,a
11770
          pop af
11771
          ld a,h
11772
      sbcn ++$00
11773
      rts
11774
 
11775
;-------------------------------------------------------------------------------------
11776
;$00 - used to hold collision flag, Y movement force + 5 or low byte of name table for rope
11777
;$01 - used to hold high byte of name table for rope
11778
;$02 - used to hold page location of rope
11779
 
11780
BalancePlatform:
11781
       ldax Enemy_Y_HighPos,x       ;check high byte of vertical position
11782
       cmpn ++$03
11783
       bne DoBPl
11784
       jmp EraseEnemyObject        ;if far below screen, kill the object
11785
DoBPl: ldax Enemy_State,x           ;get object's state (set to $ff or other platform offset)
11786
         checka
11787
       bpl CheckBalPlatform        ;if doing other balance platform, branch to leave
11788
       rts
11789
 
11790
CheckBalPlatform:
11791
       tay                         ;save offset from state as Y
11792
       ldax PlatformCollisionFlag,x ;get collision flag of platform
11793
       sta SCRATCHPAD+$00                     ;store here
11794
       ldax Enemy_MovingDir,x       ;get moving direction
11795
         checka
11796
       beq ChkForFall
11797
       jmp PlatformFall            ;if set, jump here
11798
 
11799
ChkForFall:
11800
       ldan ++$2d                    ;check if platform is above a certain point
11801
       cmpx Enemy_Y_Position,x
11802
              cmpcy
11803
       bcc ChkOtherForFall         ;if not, branch elsewhere
11804
       cpyi SCRATCHPAD+$00                     ;if collision flag is set to same value as
11805
       beq MakePlatformFall        ;enemy state, branch to make platforms fall
11806
       clc
11807
       adcn ++$02                    ;otherwise add 2 pixels to vertical position
11808
       stax Enemy_Y_Position,x      ;of current platform and branch elsewhere
11809
       jmp StopPlatforms           ;to make platforms stop
11810
 
11811
MakePlatformFall:
11812
       jmp InitPlatformFall        ;make platforms fall
11813
 
11814
ChkOtherForFall:
11815
       cmpy Enemy_Y_Position,y      ;check if other platform is above a certain point
11816
              cmpcy
11817
       bcc ChkToMoveBalPlat        ;if not, branch elsewhere
11818
       cpxi SCRATCHPAD+$00                     ;if collision flag is set to same value as
11819
       beq MakePlatformFall        ;enemy state, branch to make platforms fall
11820
       clc
11821
       adcn ++$02                    ;otherwise add 2 pixels to vertical position
11822
       stay Enemy_Y_Position,y      ;of other platform and branch elsewhere
11823
       jmp StopPlatforms           ;jump to stop movement and do not return
11824
 
11825
ChkToMoveBalPlat:
11826
        ldax Enemy_Y_Position,x      ;save vertical position to stack
11827
        pha
11828
        ldax PlatformCollisionFlag,x ;get collision flag
11829
         checka
11830
        bpl ColFlg                  ;branch if collision
11831
        ldax Enemy_Y_MoveForce,x
11832
        clc                         ;add $05 to contents of moveforce, whatever they be
11833
        adcn ++$05
11834
        sta SCRATCHPAD+$00                     ;store here
11835
        ldaxkeepcy Enemy_Y_Speed,x
11836
        adcn ++$00                    ;add carry to vertical speed
11837
        bmi PlatDn                  ;branch if moving downwards
11838
        bne PlatUp                  ;branch elsewhere if moving upwards
11839
        lda SCRATCHPAD+$00
11840
        cmpn ++$0b                    ;check if there's still a little force left
11841
              cmpcy
11842
        bcc PlatSt                  ;if not enough, branch to stop movement
11843
        bcs PlatUp                  ;otherwise keep branch to move upwards
11844
ColFlg: cmpi ObjectOffset            ;if collision flag matches
11845
        beq PlatDn                  ;current enemy object offset, branch
11846
PlatUp: jsr MovePlatformUp          ;do a sub to move upwards
11847
        jmp DoOtherPlatform         ;jump ahead to remaining code
11848
PlatSt: jsr StopPlatforms           ;do a sub to stop movement
11849
        jmp DoOtherPlatform         ;jump ahead to remaining code
11850
PlatDn: jsr MovePlatformDown        ;do a sub to move downwards
11851
 
11852
DoOtherPlatform:
11853
       ldyx Enemy_State,x           ;get offset of other platform
11854
       pla                         ;get old vertical coordinate from stack
11855
       secsub
11856
       sbcx Enemy_Y_Position,x      ;get difference of old vs. new coordinate
11857
       clc
11858
       adcy Enemy_Y_Position,y      ;add difference to vertical coordinate of other
11859
       stay Enemy_Y_Position,y      ;platform to move it in the opposite direction
11860
       ldax PlatformCollisionFlag,x ;if no collision, skip this part here
11861
         checka
11862
       bmi DrawEraseRope
11863
       tax                         ;put offset which collision occurred here
11864
       jsr PositionPlayerOnVPlat   ;and use it to position player accordingly
11865
 
11866
DrawEraseRope:
11867
         ldy ObjectOffset            ;get enemy object offset
11868
         lday Enemy_Y_Speed,y         ;check to see if current platform is
11869
         oray Enemy_Y_MoveForce,y     ;moving at all
11870
         beq ExitRp                  ;if not, skip all of this and branch to leave
11871
         ldx VRAM_Buffer1_Offset     ;get vram buffer offset
11872
         cpxn ++$20                    ;if offset beyond a certain point, go ahead
11873
              cmpcy
11874
         bcs ExitRp                  ;and skip this, branch to leave
11875
         lday Enemy_Y_Speed,y
11876
         pha                         ;save two copies of vertical speed to stack
11877
         pha
11878
         jsr SetupPlatformRope       ;do a sub to figure out where to put new bg tiles
11879
         lda SCRATCHPAD+$01                     ;write name table address to vram buffer
11880
         stax VRAM_Buffer1,x          ;first the high byte, then the low
11881
         lda SCRATCHPAD+$00
11882
         stax VRAM_Buffer1+1,x
11883
         ldan ++$02                    ;set length for 2 bytes
11884
         stax VRAM_Buffer1+2,x
11885
         lday Enemy_Y_Speed,y         ;if platform moving upwards, branch 
11886
         checka
11887
         bmi EraseR1                 ;to do something else
11888
         ldan ++xa2
11889
         stax VRAM_Buffer1+3,x        ;otherwise put tile numbers for left
11890
         ldan ++xa3                    ;and right sides of rope in vram buffer
11891
         stax VRAM_Buffer1+4,x
11892
         jmp OtherRope               ;jump to skip this part
11893
EraseR1: ldan ++$24                    ;put blank tiles in vram buffer
11894
         stax VRAM_Buffer1+3,x        ;to erase rope
11895
         stax VRAM_Buffer1+4,x
11896
 
11897
OtherRope:
11898
         lday Enemy_State,y           ;get offset of other platform from state
11899
         tay                         ;use as Y here
11900
         pla                         ;pull second copy of vertical speed from stack
11901
         eorn ++$ff                    ;invert bits to reverse speed
11902
         jsr SetupPlatformRope       ;do sub again to figure out where to put bg tiles  
11903
         lda SCRATCHPAD+$01                     ;write name table address to vram buffer
11904
         stax VRAM_Buffer1+5,x        ;this time we're doing putting tiles for
11905
         lda SCRATCHPAD+$00                     ;the other platform
11906
         stax VRAM_Buffer1+6,x
11907
         ldan ++$02
11908
         stax VRAM_Buffer1+7,x        ;set length again for 2 bytes
11909
         pla                         ;pull first copy of vertical speed from stack
11910
         checka
11911
         bpl EraseR2                 ;if moving upwards (note inversion earlier), skip this
11912
         ldan ++xa2
11913
         stax VRAM_Buffer1+8,x        ;otherwise put tile numbers for left
11914
         ldan ++xa3                    ;and right sides of rope in vram
11915
         stax VRAM_Buffer1+9,x        ;transfer buffer
11916
         jmp EndRp                   ;jump to skip this part
11917
EraseR2: ldan ++$24                    ;put blank tiles in vram buffer
11918
         stax VRAM_Buffer1+8,x        ;to erase rope
11919
         stax VRAM_Buffer1+9,x
11920
EndRp:   ldan ++$00                    ;put null terminator at the end
11921
         stax VRAM_Buffer1+10,x
11922
         lda VRAM_Buffer1_Offset     ;add ten bytes to the vram buffer offset
11923
         clc                         ;and store
11924
         adcn ++10
11925
         sta VRAM_Buffer1_Offset
11926
ExitRp:  ldx ObjectOffset            ;get enemy object buffer offset and leave
11927
         rts
11928
 
11929
SetupPlatformRope:
11930
        pha                     ;save second/third copy to stack
11931
        lday Enemy_X_Position,y  ;get horizontal coordinate
11932
        clc
11933
        adcn ++$08                ;add eight pixels
11934
        ldx SecondaryHardMode   ;if secondary hard mode flag set,
11935
         checkx
11936
        bne GetLRp              ;use coordinate as-is
11937
        clc
11938
        adcn ++$10                ;otherwise add sixteen more pixels
11939
GetLRp: pha                     ;save modified horizontal coordinate to stack
11940
        ldaykeepcy Enemy_PageLoc,y
11941
        adcn ++$00                ;add carry to page location
11942
        sta SCRATCHPAD+$02                 ;and save here
11943
        pla                     ;pull modified horizontal coordinate
11944
        andn ++%11110000          ;from the stack, mask out low nybble
11945
        lsr                     ;and shift three bits to the right
11946
        lsr
11947
        lsr
11948
        sta SCRATCHPAD+$00                 ;store result here as part of name table low byte
11949
        ldxy Enemy_Y_Position,y  ;get vertical coordinate
11950
        pla                     ;get second/third copy of vertical speed from stack
11951
         checka
11952
        bpl GetHRp              ;skip this part if moving downwards or not at all
11953
        txa
11954
        clc
11955
        adcn ++$08                ;add eight to vertical coordinate and
11956
        tax                     ;save as X
11957
GetHRp: txa                     ;move vertical coordinate to A
11958
        ldx VRAM_Buffer1_Offset ;get vram buffer offset
11959
        asl
11960
        rol                     ;rotate d7 to d0 and d6 into carry
11961
        pha                     ;save modified vertical coordinate to stack
11962
        rol                     ;rotate carry to d0, thus d7 and d6 are at 2 LSB
11963
        andn ++%00000011          ;mask out all bits but d7 and d6, then set
11964
        oran ++%00100000          ;d5 to get appropriate high byte of name table
11965
        sta SCRATCHPAD+$01                 ;address, then store
11966
        lda SCRATCHPAD+$02                 ;get saved page location from earlier
11967
        andn ++$01                ;mask out all but LSB
11968
        asl
11969
        asl                     ;shift twice to the left and save with the
11970
        orai SCRATCHPAD+$01                 ;rest of the bits of the high byte, to get
11971
        sta SCRATCHPAD+$01                 ;the proper name table and the right place on it
11972
        pla                     ;get modified vertical coordinate from stack
11973
        andn ++%11100000          ;mask out low nybble and LSB of high nybble
11974
        clc
11975
        adci SCRATCHPAD+$00                 ;add to horizontal part saved here
11976
        sta SCRATCHPAD+$00                 ;save as name table low byte
11977
        lday Enemy_Y_Position,y
11978
        cmpn ++$e8                ;if vertical position not below the
11979
              cmpcy
11980
        bcc ExPRp               ;bottom of the screen, we're done, branch to leave
11981
        lda SCRATCHPAD+$00
11982
        andn ++%10111111          ;mask out d6 of low byte of name table address
11983
        sta SCRATCHPAD+$00
11984
ExPRp:  rts                     ;leave!
11985
 
11986
InitPlatformFall:
11987
      tya                        ;move offset of other platform from Y to X
11988
      tax
11989
      jsr GetEnemyOffscreenBits  ;get offscreen bits
11990
      ldan ++$06
11991
      jsr SetupFloateyNumber     ;award 1000 points to player
11992
      lda Player_Rel_XPos
11993
      stax FloateyNum_X_Pos,x     ;put floatey number coordinates where player is
11994
      lda Player_Y_Position
11995
      stax FloateyNum_Y_Pos,x
11996
      ldan ++$01                   ;set moving direction as flag for
11997
      stax Enemy_MovingDir,x      ;falling platforms
11998
 
11999
StopPlatforms:
12000
      jsr InitVStf             ;initialize vertical speed and low byte
12001
      stay Enemy_Y_Speed,y      ;for both platforms and leave
12002
      stay Enemy_Y_MoveForce,y
12003
      rts
12004
 
12005
PlatformFall:
12006
      tya                         ;save offset for other platform to stack
12007
      pha
12008
      jsr MoveFallingPlatform     ;make current platform fall
12009
      pla
12010
      tax                         ;pull offset from stack and save to X
12011
      jsr MoveFallingPlatform     ;make other platform fall
12012
      ldx ObjectOffset
12013
      ldax PlatformCollisionFlag,x ;if player not standing on either platform,
12014
         checka
12015
      bmi ExPF                    ;skip this part
12016
      tax                         ;transfer collision flag offset as offset to X
12017
      jsr PositionPlayerOnVPlat   ;and position player appropriately
12018
ExPF: ldx ObjectOffset            ;get enemy object buffer offset and leave
12019
      rts
12020
 
12021
;--------------------------------
12022
 
12023
YMovingPlatform:
12024
        ldax Enemy_Y_Speed,x          ;if platform moving up or down, skip ahead to
12025
        orax Enemy_Y_MoveForce,x      ;check on other position
12026
        bne ChkYCenterPos
12027
        stax Enemy_YMF_Dummy,x        ;initialize dummy variable
12028
        ldax Enemy_Y_Position,x
12029
        cmpx YPlatformTopYPos,x       ;if current vertical position =HIGH  top position, branch
12030
              cmpcy
12031
        bcs ChkYCenterPos            ;ahead of all this
12032
        lda FrameCounter
12033
        andn ++%00000111               ;check for every eighth frame
12034
        bne SkipIY
12035
        incx Enemy_Y_Position,x       ;increase vertical position every eighth frame
12036
SkipIY: jmp ChkYPCollision           ;skip ahead to last part
12037
 
12038
ChkYCenterPos:
12039
        ldax Enemy_Y_Position,x       ;if current vertical position LOW  central position, branch
12040
        cmpx YPlatformCenterYPos,x    ;to slow ascent/move downwards
12041
              cmpcy
12042
        bcc YMDown
12043
        jsr MovePlatformUp           ;otherwise start slowing descent/moving upwards
12044
        jmp ChkYPCollision
12045
YMDown: jsr MovePlatformDown         ;start slowing ascent/moving downwards
12046
 
12047
ChkYPCollision:
12048
       ldax PlatformCollisionFlag,x  ;if collision flag not set here, branch
12049
         checka
12050
       bmi ExYPl                    ;to leave
12051
       jsr PositionPlayerOnVPlat    ;otherwise position player appropriately
12052
ExYPl: rts                          ;leave
12053
 
12054
;--------------------------------
12055
;$00 - used as adder to position player hotizontally
12056
 
12057
XMovingPlatform:
12058
      ldan ++$0e                     ;load preset maximum value for secondary counter
12059
      jsr XMoveCntr_Platform       ;do a sub to increment counters for movement
12060
      jsr MoveWithXMCntrs          ;do a sub to move platform accordingly, and return value
12061
      ldax PlatformCollisionFlag,x  ;if no collision with player,
12062
         checka
12063
      bmi ExXMP                    ;branch ahead to leave
12064
 
12065
PositionPlayerOnHPlat:
12066
         lda Player_X_Position
12067
         clc                       ;add saved value from second subroutine to
12068
         adci SCRATCHPAD+$00                   ;current player's position to position (    X   )
12069
         sta Player_X_Position     ;player accordingly in horizontal position
12070
         lda Player_PageLoc        ;get player's page location
12071
         ldy SCRATCHPAD+$00                   ;check to see if saved value here is positive or negative
12072
         checky
12073
         bmi PPHSubt               ;if negative, branch to subtract
12074
         adcn ++$00                  ;otherwise add carry to page location
12075
         jmp SetPVar               ;jump to skip subtraction
12076
PPHSubt:
12077
        cmpcy
12078
         sbcn ++$00                  ;subtract borrow from page location
12079
SetPVar: sta Player_PageLoc        ;save result to player's page location
12080
         sty Platform_X_Scroll     ;put saved value from second sub here to be used later
12081
         jsr PositionPlayerOnVPlat ;position player vertically and appropriately
12082
ExXMP:   rts                       ;and we are done here
12083
 
12084
;--------------------------------
12085
 
12086
DropPlatform:
12087
       ldax PlatformCollisionFlag,x  ;if no collision between platform and player
12088
         checka
12089
       bmi ExDPl                    ;occurred, just leave without moving anything
12090
       jsr MoveDropPlatform         ;otherwise do a sub to move platform down very quickly
12091
       jsr PositionPlayerOnVPlat    ;do a sub to position player appropriately
12092
ExDPl: rts                          ;leave
12093
 
12094
;--------------------------------
12095
;$00 - residual value from sub
12096
 
12097
RightPlatform:
12098
       jsr MoveEnemyHorizontally     ;move platform with current horizontal speed, if any
12099
       sta SCRATCHPAD+$00                       ;store saved value here (residual code)
12100
       ldax PlatformCollisionFlag,x   ;check collision flag, if no collision between player
12101
         checka
12102
       bmi ExRPl                     ;and platform, branch ahead, leave speed unaltered
12103
       ldan ++$10
12104
       stax Enemy_X_Speed,x           ;otherwise set new speed (gets moving if motionless)
12105
       jsr PositionPlayerOnHPlat     ;use saved value from earlier sub to position player
12106
ExRPl: rts                           ;then leave
12107
 
12108
;--------------------------------
12109
 
12110
MoveLargeLiftPlat:
12111
      jsr MoveLiftPlatforms  ;execute common to all large and small lift platforms
12112
      jmp ChkYPCollision     ;branch to position player correctly
12113
 
12114
MoveSmallPlatform:
12115
      jsr MoveLiftPlatforms      ;execute common to all large and small lift platforms
12116
      jmp ChkSmallPlatCollision  ;branch to position player correctly
12117
 
12118
MoveLiftPlatforms:
12119
      lda TimerControl         ;if master timer control set, skip all of this
12120
         checka
12121
      bne ExLiftP              ;and branch to leave
12122
      ldax Enemy_YMF_Dummy,x
12123
      clc                      ;add contents of movement amount to whatever's here
12124
      adcx Enemy_Y_MoveForce,x
12125
          push af
12126
      stax Enemy_YMF_Dummy,x
12127
      ldax Enemy_Y_Position,x   ;add whatever vertical speed is set to current
12128
          ld h,a
12129
          pop af
12130
          ld a,h
12131
      adcx Enemy_Y_Speed,x      ;vertical position plus carry to move up or down
12132
      stax Enemy_Y_Position,x   ;and then leave
12133
      rts
12134
 
12135
ChkSmallPlatCollision:
12136
         ldax PlatformCollisionFlag,x ;get bounding box counter saved in collision flag
12137
         checka
12138
         beq ExLiftP                 ;if none found, leave player position alone
12139
         jsr PositionPlayerOnS_Plat  ;use to position player correctly
12140
ExLiftP: rts                         ;then leave
12141
 
12142
;-------------------------------------------------------------------------------------
12143
;$00 - page location of extended left boundary
12144
;$01 - extended left boundary position
12145
;$02 - page location of extended right boundary
12146
;$03 - extended right boundary position
12147
 
12148
OffscreenBoundsCheck:
12149
          ldax Enemy_ID,x          ;check for cheep-cheep object
12150
          cmpn ++FlyingCheepCheep   ;branch to leave if found
12151
          beq ExScrnBd
12152
          lda ScreenLeft_X_Pos    ;get horizontal coordinate for left side of screen
12153
          ldyx Enemy_ID,x
12154
          cpyn ++HammerBro          ;check for hammer bro object
12155
          beq LimitB
12156
          cpyn ++PiranhaPlant       ;check for piranha plant object
12157
          bne ExtendLB            ;these two will be erased sooner than others if too far left
12158
LimitB:  
12159
        cmpcy
12160
          adcn ++$38                ;add 56 pixels to coordinate if hammer bro or piranha plant
12161
        cmpcy
12162
ExtendLB:
12163
          sbcn ++$48                ;subtract 72 pixels regardless of enemy object
12164
          sta SCRATCHPAD+$01                 ;store result here
12165
          lda ScreenLeft_PageLoc
12166
          sbcn ++$00                ;subtract borrow from page location of left side
12167
        cmpcy
12168
          sta SCRATCHPAD+$00                 ;store result here
12169
          lda ScreenRight_X_Pos   ;add 72 pixels to the right side horizontal coordinate
12170
          adcn ++$48
12171
          sta SCRATCHPAD+$03                 ;store result here
12172
          lda ScreenRight_PageLoc    
12173
          adcn ++$00                ;then add the carry to the page location
12174
          sta SCRATCHPAD+$02                 ;and store result here
12175
          ldax Enemy_X_Position,x  ;compare horizontal coordinate of the enemy object
12176
          cmpi SCRATCHPAD+$01                 ;to modified horizontal left edge coordinate to get carry
12177
          ldaxkeepcy Enemy_PageLoc,x
12178
          sbci SCRATCHPAD+$00                 ;then subtract it from the page coordinate of the enemy object
12179
          bmi TooFar              ;if enemy object is too far left, branch to erase it
12180
          ldax Enemy_X_Position,x  ;compare horizontal coordinate of the enemy object
12181
          cmpi SCRATCHPAD+$03                 ;to modified horizontal right edge coordinate to get carry
12182
          ldaxkeepcy Enemy_PageLoc,x
12183
          sbci SCRATCHPAD+$02                 ;then subtract it from the page coordinate of the enemy object
12184
          bmi ExScrnBd            ;if enemy object is on the screen, leave, do not erase enemy
12185
          ldax Enemy_State,x       ;if at this point, enemy is offscreen to the right, so check
12186
          cmpn ++HammerBro          ;if in state used by spiny's egg, do not erase
12187
          beq ExScrnBd
12188
          cpyn ++PiranhaPlant       ;if piranha plant, do not erase
12189
          beq ExScrnBd
12190
          cpyn ++FlagpoleFlagObject ;if flagpole flag, do not erase
12191
          beq ExScrnBd
12192
          cpyn ++StarFlagObject     ;if star flag, do not erase
12193
          beq ExScrnBd
12194
          cpyn ++JumpspringObject   ;if jumpspring, do not erase
12195
          beq ExScrnBd            ;erase all others too far to the right
12196
TooFar:   jsr EraseEnemyObject    ;erase object if necessary
12197
ExScrnBd: rts                     ;leave
12198
 
12199
;-------------------------------------------------------------------------------------
12200
 
12201
;some unused space
12202
      .db $ff, $ff, $ff
12203
 
12204
;-------------------------------------------------------------------------------------
12205
;$01 - enemy buffer offset
12206
 
12207
FireballEnemyCollision:
12208
      ldax Fireball_State,x  ;check to see if fireball state is set at all
12209
         checka
12210
      beq ExitFBallEnemy    ;branch to leave if not
12211
      asl
12212
      bcs ExitFBallEnemy    ;branch to leave also if d7 in state is set
12213
      lda FrameCounter
12214
      lsr                   ;get LSB of frame counter
12215
      bcs ExitFBallEnemy    ;branch to leave if set (do routine every other frame)
12216
      txa
12217
      asl                   ;multiply fireball offset by four
12218
      asl
12219
      clc
12220
      adcn ++$1c              ;then add $1c or 28 bytes to it
12221
      tay                   ;to use fireball's bounding box coordinates 
12222
      ldxn ++$04
12223
 
12224
FireballEnemyCDLoop:
12225
           stx SCRATCHPAD+$01                     ;store enemy object offset here
12226
           tya
12227
           pha                         ;push fireball offset to the stack
12228
           ldax Enemy_State,x
12229
           andn ++%00100000              ;check to see if d5 is set in enemy state
12230
           bne NoFToECol               ;if so, skip to next enemy slot
12231
           ldax Enemy_Flag,x            ;check to see if buffer flag is set
12232
         checka
12233
           beq NoFToECol               ;if not, skip to next enemy slot
12234
           ldax Enemy_ID,x              ;check enemy identifier
12235
           cmpn ++$24
12236
              cmpcy
12237
           bcc GoombaDie               ;if LOW  $24, branch to check further
12238
           cmpn ++$2b
12239
              cmpcy
12240
           bcc NoFToECol               ;if in range $24-$2a, skip to next enemy slot
12241
GoombaDie: cmpn ++Goomba                 ;check for goomba identifier
12242
           bne NotGoomba               ;if not found, continue with code
12243
           ldax Enemy_State,x           ;otherwise check for defeated state
12244
           cmpn ++$02                    ;if stomped or otherwise defeated,
12245
              cmpcy
12246
           bcs NoFToECol               ;skip to next enemy slot
12247
NotGoomba: ldax EnemyOffscrBitsMasked,x ;if any masked offscreen bits set,
12248
         checka
12249
           bne NoFToECol               ;skip to next enemy slot
12250
           txa
12251
           asl                         ;otherwise multiply enemy offset by four
12252
           asl
12253
           clc
12254
           adcn ++$04                    ;add 4 bytes to it
12255
           tax                         ;to use enemy's bounding box coordinates
12256
           jsr SprObjectCollisionCore  ;do fireball-to-enemy collision detection
12257
           ldx ObjectOffset            ;return fireball's original offset
12258
           bcc NoFToECol               ;if carry clear, no collision, thus do next enemy slot
12259
           ldan ++%10000000
12260
           stax Fireball_State,x        ;set d7 in enemy state
12261
           ldx SCRATCHPAD+$01                     ;get enemy offset
12262
           jsr HandleEnemyFBallCol     ;jump to handle fireball to enemy collision
12263
NoFToECol: pla                         ;pull fireball offset from stack
12264
           tay                         ;put it in Y
12265
           ldx SCRATCHPAD+$01                     ;get enemy object offset
12266
           dex                         ;decrement it
12267
           bpl FireballEnemyCDLoop     ;loop back until collision detection done on all enemies
12268
 
12269
ExitFBallEnemy:
12270
      ldx ObjectOffset                 ;get original fireball offset and leave
12271
      rts
12272
 
12273
BowserIdentities:
12274
      .db Goomba, GreenKoopa, BuzzyBeetle, Spiny, Lakitu, Bloober, HammerBro, Bowser
12275
 
12276
HandleEnemyFBallCol:
12277
      jsr RelativeEnemyPosition  ;get relative coordinate of enemy
12278
      ldx SCRATCHPAD+$01                    ;get current enemy object offset
12279
      ldax Enemy_Flag,x           ;check buffer flag for d7 set
12280
         checka
12281
      bpl ChkBuzzyBeetle         ;branch if not set to continue
12282
      andn ++%00001111             ;otherwise mask out high nybble and
12283
      tax                        ;use low nybble as enemy offset
12284
      ldax Enemy_ID,x
12285
      cmpn ++Bowser                ;check enemy identifier for bowser
12286
      beq HurtBowser             ;branch if found
12287
      ldx SCRATCHPAD+$01                    ;otherwise retrieve current enemy offset
12288
 
12289
ChkBuzzyBeetle:
12290
      ldax Enemy_ID,x
12291
      cmpn ++BuzzyBeetle           ;check for buzzy beetle
12292
      beq ExHCF                  ;branch if found to leave (buzzy beetles fireproof)
12293
      cmpn ++Bowser                ;check for bowser one more time (necessary if d7 of flag was clear)
12294
      bne ChkOtherEnemies        ;if not found, branch to check other enemies
12295
 
12296
HurtBowser:
12297
          deci BowserHitPoints        ;decrement bowser's hit points
12298
          bne ExHCF                  ;if bowser still has hit points, branch to leave
12299
          jsr InitVStf               ;otherwise do sub to init vertical speed and movement force
12300
          stax Enemy_X_Speed,x        ;initialize horizontal speed
12301
          sta EnemyFrenzyBuffer      ;init enemy frenzy buffer
12302
          ldan ++$fe
12303
          stax Enemy_Y_Speed,x        ;set vertical speed to make defeated bowser jump a little
12304
          ldy WorldNumber            ;use world number as offset
12305
          lday BowserIdentities,y     ;get enemy identifier to replace bowser with
12306
          stax Enemy_ID,x             ;set as new enemy identifier
12307
          ldan ++$20                   ;set A to use starting value for state
12308
          cpyn ++$03                   ;check to see if using offset of 3 or more
12309
              cmpcy
12310
          bcs SetDBSte               ;branch if so
12311
          oran ++$03                   ;otherwise add 3 to enemy state
12312
SetDBSte: stax Enemy_State,x          ;set defeated enemy state
12313
          ldan ++Sfx_BowserFall
12314
          sta Square2SoundQueue      ;load bowser defeat sound
12315
          ldx SCRATCHPAD+$01                    ;get enemy offset
12316
          ldan ++$09                   ;award 5000 points to player for defeating bowser
12317
         checka
12318
          bne EnemySmackScore        ;unconditional branch to award points
12319
 
12320
ChkOtherEnemies:
12321
      cmpn ++BulletBill_FrenzyVar
12322
      beq ExHCF                 ;branch to leave if bullet bill (frenzy variant) 
12323
      cmpn ++Podoboo      
12324
      beq ExHCF                 ;branch to leave if podoboo
12325
      cmpn ++$15      
12326
              cmpcy
12327
      bcs ExHCF                 ;branch to leave if identifier =HIGH  $15
12328
 
12329
ShellOrBlockDefeat:
12330
      ldax Enemy_ID,x            ;check for piranha plant
12331
      cmpn ++PiranhaPlant
12332
       cmpcy
12333
      bne StnE                  ;branch if not found
12334
      ldaxkeepcy Enemy_Y_Position,x
12335
      adcn ++$18                  ;add 24 pixels to enemy object's vertical position
12336
      stax Enemy_Y_Position,x
12337
StnE: jsr ChkToStunEnemies      ;do yet another sub
12338
      ldax Enemy_State,x
12339
      andn ++%00011111            ;mask out 2 MSB of enemy object's state
12340
      oran ++%00100000            ;set d5 to defeat enemy and save as new state
12341
      stax Enemy_State,x
12342
      ldan ++$02                  ;award 200 points by default
12343
      ldyx Enemy_ID,x            ;check for hammer bro
12344
      cpyn ++HammerBro
12345
      bne GoombaPoints          ;branch if not found
12346
      ldan ++$06                  ;award 1000 points for hammer bro
12347
 
12348
GoombaPoints:
12349
      cpyn ++Goomba               ;check for goomba
12350
      bne EnemySmackScore       ;branch if not found
12351
      ldan ++$01                  ;award 100 points for goomba
12352
 
12353
EnemySmackScore:
12354
       jsr SetupFloateyNumber   ;update necessary score variables
12355
       ldan ++Sfx_EnemySmack      ;play smack enemy sound
12356
       sta Square1SoundQueue
12357
ExHCF: rts                      ;and now let's leave
12358
 
12359
;-------------------------------------------------------------------------------------
12360
 
12361
PlayerHammerCollision:
12362
        lda FrameCounter          ;get frame counter
12363
        lsr                       ;shift d0 into carry
12364
        bcc ExPHC                 ;branch to leave if d0 not set to execute every other frame
12365
        lda TimerControl          ;if either master timer control
12366
        orai Misc_OffscreenBits    ;or any offscreen bits for hammer are set,
12367
        bne ExPHC                 ;branch to leave
12368
        txa
12369
        asl                       ;multiply misc object offset by four
12370
        asl
12371
        clc
12372
        adcn ++$24                  ;add 36 or $24 bytes to get proper offset
12373
        tay                       ;for misc object bounding box coordinates
12374
        jsr PlayerCollisionCore   ;do player-to-hammer collision detection
12375
        ldx ObjectOffset          ;get misc object offset
12376
        bcc ClHCol                ;if no collision, then branch
12377
        ldax Misc_Collision_Flag,x ;otherwise read collision flag
12378
         checka
12379
        bne ExPHC                 ;if collision flag already set, branch to leave
12380
        ldan ++$01
12381
        stax Misc_Collision_Flag,x ;otherwise set collision flag now
12382
        ldax Misc_X_Speed,x
12383
        eorn ++$ff                  ;get two's compliment of
12384
        clc                       ;hammer's horizontal speed
12385
        adcn ++$01
12386
        stax Misc_X_Speed,x        ;set to send hammer flying the opposite direction
12387
        lda StarInvincibleTimer   ;if star mario invincibility timer set,
12388
         checka
12389
        bne ExPHC                 ;branch to leave
12390
        jmp InjurePlayer          ;otherwise jump to hurt player, do not return
12391
ClHCol: ldan ++$00                  ;clear collision flag
12392
        stax Misc_Collision_Flag,x
12393
ExPHC:  rts
12394
 
12395
;-------------------------------------------------------------------------------------
12396
 
12397
HandlePowerUpCollision:
12398
      jsr EraseEnemyObject    ;erase the power-up object
12399
      ldan ++$06
12400
      jsr SetupFloateyNumber  ;award 1000 points to player by default
12401
      ldan ++Sfx_PowerUpGrab
12402
      sta Square2SoundQueue   ;play the power-up sound
12403
      lda PowerUpType         ;check power-up type
12404
      cmpn ++$02
12405
              cmpcy
12406
      bcc Shroom_Flower_PUp   ;if mushroom or fire flower, branch
12407
      cmpn ++$03
12408
      beq SetFor1Up           ;if 1-up mushroom, branch
12409
      ldan ++$23                ;otherwise set star mario invincibility
12410
      sta StarInvincibleTimer ;timer, and load the star mario music
12411
      ldan ++StarPowerMusic     ;into the area music queue, then leave
12412
      sta AreaMusicQueue
12413
      rts
12414
 
12415
Shroom_Flower_PUp:
12416
      lda PlayerStatus    ;if player status = small, branch
12417
         checka
12418
      beq UpToSuper
12419
      cmpn ++$01            ;if player status not super, leave
12420
      bne NoPUp
12421
      ldx ObjectOffset    ;get enemy offset, not necessary
12422
      ldan ++$02            ;set player status to fiery
12423
      sta PlayerStatus
12424
      jsr GetPlayerColors ;run sub to change colors of player
12425
      ldx ObjectOffset    ;get enemy offset again, and again not necessary
12426
      ldan ++$0c            ;set value to be used by subroutine tree (fiery)
12427
      jmp UpToFiery       ;jump to set values accordingly
12428
 
12429
SetFor1Up:
12430
      ldan ++$0b                 ;change 1000 points into 1-up instead
12431
      stax FloateyNum_Control,x ;and then leave
12432
      rts
12433
 
12434
UpToSuper:
12435
       ldan ++$01         ;set player status to super
12436
       sta PlayerStatus
12437
       ldan ++$09         ;set value to be used by subroutine tree (super)
12438
 
12439
UpToFiery:
12440
       ldyn ++$00         ;set value to be used as new player state
12441
       jsr SetPRout     ;set values to stop certain things in motion
12442
NoPUp: rts
12443
 
12444
;--------------------------------
12445
 
12446
ResidualXSpdData:
12447
      .db $18, $e8
12448
 
12449
KickedShellXSpdData:
12450
      .db $30, $d0
12451
 
12452
DemotedKoopaXSpdData:
12453
      .db $08, $f8
12454
 
12455
PlayerEnemyCollision:
12456
         lda FrameCounter            ;check counter for d0 set
12457
         lsr
12458
        ;ccf ;   1-2 (  CY   )
12459
        ;scf ;   
12460
         bcs NoPUp                   ;if set, branch to leave
12461
         jsr CheckPlayerVertical     ;if player object is completely offscreen or
12462
         bcs NoPECol                 ;if down past 224th pixel row, branch to leave
12463
         ldax EnemyOffscrBitsMasked,x ;if current enemy is offscreen by any amount,
12464
         checka
12465
         bne NoPECol                 ;go ahead and branch to leave
12466
         lda GameEngineSubroutine
12467
         cmpn ++$08                    ;if not set to run player control routine
12468
         bne NoPECol                 ;on next frame, branch to leave
12469
         ldax Enemy_State,x
12470
         andn ++%00100000              ;if enemy state has d5 set, branch to leave
12471
         bne NoPECol
12472
         jsr GetEnemyBoundBoxOfs     ;get bounding box offset for current enemy object
12473
         jsr PlayerCollisionCore     ;do collision detection on player vs. enemy
12474
         ldx ObjectOffset            ;get enemy object buffer offset
12475
         bcs CheckForPUpCollision    ;if collision, branch past this part here
12476
         ldax Enemy_CollisionBits,x
12477
         andn ++%11111110              ;otherwise, clear d0 of current enemy object's
12478
         stax Enemy_CollisionBits,x   ;collision bit
12479
NoPECol: rts
12480
 
12481
CheckForPUpCollision:
12482
       ldyx Enemy_ID,x
12483
       cpyn ++PowerUpObject            ;check for power-up object
12484
       bne EColl                     ;if not found, branch to next part
12485
       jmp HandlePowerUpCollision    ;otherwise, unconditional jump backwards
12486
EColl: lda StarInvincibleTimer       ;if star mario invincibility timer expired,
12487
         checka
12488
       beq HandlePECollisions        ;perform task here, otherwise kill enemy like
12489
       jmp ShellOrBlockDefeat        ;hit with a shell, or from beneath
12490
 
12491
KickedShellPtsData:
12492
      .db $0a, $06, $04
12493
 
12494
HandlePECollisions:
12495
       ldax Enemy_CollisionBits,x    ;check enemy collision bits for d0 set
12496
       andn ++%00000001               ;or for being offscreen at all
12497
       orax EnemyOffscrBitsMasked,x
12498
       bne ExPEC                    ;branch to leave if either is true
12499
       ldan ++$01
12500
       orax Enemy_CollisionBits,x    ;otherwise set d0 now
12501
       stax Enemy_CollisionBits,x
12502
       cpyn ++Spiny                   ;branch if spiny
12503
       beq ChkForPlayerInjury
12504
       cpyn ++PiranhaPlant            ;branch if piranha plant
12505
       beq InjurePlayer_PiranhaPlant
12506
       cpyn ++Podoboo                 ;branch if podoboo
12507
       beq InjurePlayer_PiranhaPlant
12508
       cpyn ++BulletBill_CannonVar    ;branch if bullet bill
12509
       beq ChkForPlayerInjury
12510
       cpyn ++$15                     ;branch if object =>  $15
12511
              cmpcy
12512
       bcs InjurePlayer
12513
       lda AreaType                 ;branch if water type level
12514
         checka
12515
       beq InjurePlayer
12516
       ldax Enemy_State,x            ;branch if d7 of enemy state was set
12517
       asl
12518
       bcs ChkForPlayerInjury
12519
       ldax Enemy_State,x            ;mask out all but 3 LSB of enemy state
12520
       andn ++%00000111
12521
       cmpn ++$02                     ;branch if enemy is in normal or falling state
12522
              cmpcy
12523
       bcc ChkForPlayerInjury
12524
       ldax Enemy_ID,x               ;branch to leave if goomba in defeated state
12525
       cmpn ++Goomba
12526
       beq ExPEC
12527
       ldan ++Sfx_EnemySmack          ;play smack enemy sound
12528
       sta Square1SoundQueue
12529
       ldax Enemy_State,x            ;set d7 in enemy state, thus become moving shell
12530
       oran ++%10000000
12531
       stax Enemy_State,x
12532
       jsr EnemyFacePlayer          ;set moving direction and get offset
12533
       lday KickedShellXSpdData,y    ;load and set horizontal speed data with offset
12534
       stax Enemy_X_Speed,x
12535
       ldan ++$03                     ;add three to whatever the stomp counter contains
12536
       clc                          ;to give points for kicking the shell
12537
       adci StompChainCounter
12538
       ldyx EnemyIntervalTimer,x     ;check shell enemy's timer
12539
       cpyn ++$03                     ;if above a certain point, branch using the points
12540
              cmpcy
12541
       bcs KSPts                    ;data obtained from the stomp counter + 3
12542
       lday KickedShellPtsData,y     ;otherwise, set points based on proximity to timer expiration
12543
KSPts: jsr SetupFloateyNumber       ;set values for floatey number now
12544
ExPEC: rts                          ;leave!!!
12545
 
12546
ChkForPlayerInjury:
12547
          lda Player_Y_Speed     ;check player's vertical speed
12548
         checka
12549
          bmi ChkInj             ;perform procedure below if player moving upwards
12550
           ;jr $ ;       1-2 (yspeed=0!!!)     EnemyStomped (       ),     
12551
          bne EnemyStomped       ;or not at all, and branch elsewhere if moving downwards
12552
ChkInj:   ldax Enemy_ID,x         ;branch if enemy object <  $07
231 alone 12553
      if GOODBULLET
12554
       cp BulletBill_CannonVar
12555
       ret z
12556
      endif
171 demige 12557
          cmpn ++Bloober
12558
              cmpcy
12559
          bcc ChkETmrs
12560
          lda Player_Y_Position  ;add 12 pixels to player's vertical position
12561
          clc
12562
          adcn ++$0c
12563
          cmpx Enemy_Y_Position,x ;compare modified player's position to enemy's position
12564
              cmpcy
12565
          bcc EnemyStomped       ;branch if this player's position above (less than) enemy's
12566
ChkETmrs: lda StompTimer         ;check stomp timer
12567
         checka
12568
          bne EnemyStomped       ;branch if set
12569
          lda InjuryTimer        ;check to see if injured invincibility timer still
12570
         checka
12571
          bne ExInjColRoutines   ;counting down, and branch elsewhere to leave if so
12572
          lda Player_Rel_XPos
12573
          cmpi Enemy_Rel_XPos     ;if player's relative position to the left of enemy's
12574
              cmpcy
12575
          bcc TInjE              ;relative position, branch here
12576
          jmp ChkEnemyFaceRight  ;otherwise do a jump here
12577
TInjE:    ldax Enemy_MovingDir,x  ;if enemy moving towards the left,
12578
          cmpn ++$01               ;branch, otherwise do a jump here
12579
          bne InjurePlayer       ;to turn the enemy around
12580
          jmp LInj
12581
 
12582
InjurePlayer_PiranhaPlant:
12583
      if GOODPIRANHAPLANT
12584
       ret
12585
      endif
12586
InjurePlayer:
12587
      lda InjuryTimer          ;check again to see if injured invincibility timer is
12588
         checka
12589
      bne ExInjColRoutines     ;at zero, and branch to leave if so
12590
 
12591
ForceInjury:
12592
          ldx PlayerStatus          ;check player's status
12593
         checkx
12594
          beq KillPlayer            ;branch if small
12595
          sta PlayerStatus          ;otherwise set player's status to small
12596
          ldan ++$08
12597
          sta InjuryTimer           ;set injured invincibility timer
12598
          asl
12599
          sta Square1SoundQueue     ;play pipedown/injury sound
12600
          jsr GetPlayerColors       ;change player's palette if necessary
12601
          ldan ++$0a                  ;set subroutine to run on next frame
12602
SetKRout: ldyn ++$01                  ;set new player state
12603
SetPRout: sta GameEngineSubroutine  ;load new value to run subroutine on next frame
12604
          sty Player_State          ;store new player state
12605
          ldyn ++$ff
12606
          sty TimerControl          ;set master timer control flag to halt timers
12607
          iny
12608
          sty ScrollAmount          ;initialize scroll speed
12609
 
12610
ExInjColRoutines:
12611
      ldx ObjectOffset              ;get enemy offset and leave
12612
      rts
12613
 
12614
KillPlayer:
12615
      stx Player_X_Speed   ;halt player's horizontal movement by initializing speed
12616
      inx
12617
      stx EventMusicQueue  ;set event music queue to death music
12618
      ldan ++$fc
12619
      sta Player_Y_Speed   ;set new vertical speed
12620
      ldan ++$0b             ;set subroutine to run on next frame
12621
         checka
12622
      bne SetKRout         ;branch to set player's state and other things
12623
 
12624
StompedEnemyPtsData:
12625
      .db $02, $06, $05, $06
12626
 
12627
EnemyStomped:
12628
      ldax Enemy_ID,x             ;check for spiny, branch to hurt player
12629
      cmpn ++Spiny                 ;if found
12630
      beq InjurePlayer
12631
      ldan ++Sfx_EnemyStomp        ;otherwise play stomp/swim sound
12632
      sta Square1SoundQueue
12633
      ldax Enemy_ID,x
12634
      ldyn ++$00                   ;initialize points data offset for stomped enemies
12635
      cmpn ++FlyingCheepCheep      ;branch for cheep-cheep
12636
      beq EnemyStompedPts
12637
      cmpn ++BulletBill_FrenzyVar  ;branch for either bullet bill object
12638
      beq EnemyStompedPts
12639
      cmpn ++BulletBill_CannonVar
12640
      beq EnemyStompedPts
12641
      cmpn ++Podoboo               ;branch for podoboo (this branch is logically impossible
12642
      beq EnemyStompedPts        ;for cpu to take due to earlier checking of podoboo)
12643
      iny                        ;increment points data offset
12644
      cmpn ++HammerBro             ;branch for hammer bro
12645
      beq EnemyStompedPts
12646
      iny                        ;increment points data offset
12647
      cmpn ++Lakitu                ;branch for lakitu
12648
      beq EnemyStompedPts
12649
      iny                        ;increment points data offset
12650
      cmpn ++Bloober               ;branch if NOT bloober
12651
      bne ChkForDemoteKoopa
12652
 
12653
EnemyStompedPts:
12654
      lday StompedEnemyPtsData,y  ;load points data using offset in Y
12655
      jsr SetupFloateyNumber     ;run sub to set floatey number controls
12656
      ldax Enemy_MovingDir,x
12657
      pha                        ;save enemy movement direction to stack
12658
      jsr SetStun                ;run sub to kill enemy
12659
      pla
12660
      stax Enemy_MovingDir,x      ;return enemy movement direction from stack
12661
      ldan ++%00100000
12662
      stax Enemy_State,x          ;set d5 in enemy state
12663
      jsr InitVStf               ;nullify vertical speed, physics-related thing,
12664
      stax Enemy_X_Speed,x        ;and horizontal speed
12665
      ldan ++$fd                   ;set player's vertical speed, to give bounce
12666
      sta Player_Y_Speed
12667
      rts
12668
 
12669
ChkForDemoteKoopa:
12670
      cmpn ++$09                   ;branch elsewhere if enemy object < $09 ;   #9  misc objects ( ???)
12671
              cmpcy
12672
      bcc HandleStompedShellE
12673
      andn ++%00000001             ;demote koopa paratroopas to ordinary troopas
12674
      stax Enemy_ID,x
12675
      ldyn ++$00                   ;return enemy to normal state
12676
      styx Enemy_State,x
12677
      ldan ++$03                   ;award 400 points to the player
12678
      jsr SetupFloateyNumber
12679
      jsr InitVStf               ;nullify physics-related thing and vertical speed
12680
      jsr EnemyFacePlayer        ;turn enemy around if necessary
12681
      lday DemotedKoopaXSpdData,y
12682
      stax Enemy_X_Speed,x        ;set appropriate moving speed based on direction
12683
      jmp SBnce                  ;then move onto something else
12684
 
12685
RevivalRateData:
12686
      .db $10, $0b
12687
 
12688
HandleStompedShellE:
12689
       ldan ++$04                   ;set defeated state for enemy
12690
       stax Enemy_State,x
12691
       inci StompChainCounter      ;increment the stomp counter
12692
       lda StompChainCounter      ;add whatever is in the stomp counter
12693
       clc                        ;to whatever is in the stomp timer
12694
       adci StompTimer
12695
       jsr SetupFloateyNumber     ;award points accordingly
12696
       inci StompTimer             ;increment stomp timer of some sort
12697
       ldy PrimaryHardMode        ;check primary hard mode flag
12698
       lday RevivalRateData,y      ;load timer setting according to flag
12699
       stax EnemyIntervalTimer,x   ;set as enemy timer to revive stomped enemy
12700
SBnce: ldan ++$fc                   ;set player's vertical speed for bounce
12701
       sta Player_Y_Speed         ;and then leave!!!
12702
       rts
12703
 
12704
ChkEnemyFaceRight:
12705
       ldax Enemy_MovingDir,x ;check to see if enemy is moving to the right
12706
       cmpn ++$01
12707
       bne LInj              ;if not, branch
12708
       jmp InjurePlayer      ;otherwise go back to hurt player
12709
LInj:  jsr EnemyTurnAround   ;turn the enemy around, if necessary
12710
       jmp InjurePlayer      ;go back to hurt player
12711
 
12712
 
12713
EnemyFacePlayer:
12714
       ldyn ++$01               ;set to move right by default
12715
       jsr PlayerEnemyDiff    ;get horizontal difference between player and enemy
12716
       bpl SFcRt              ;if enemy is to the right of player, do not increment
12717
       iny                    ;otherwise, increment to set to move to the left
12718
SFcRt: styx Enemy_MovingDir,x  ;set moving direction here
12719
       dey                    ;then decrement to use as a proper offset
12720
       rts
12721
 
12722
SetupFloateyNumber:
12723
       stax FloateyNum_Control,x ;set number of points control for floatey numbers
12724
       ldan ++$30
12725
       stax FloateyNum_Timer,x   ;set timer for floatey numbers
12726
       ldax Enemy_Y_Position,x
12727
       stax FloateyNum_Y_Pos,x   ;set vertical coordinate
12728
       lda Enemy_Rel_XPos
12729
       stax FloateyNum_X_Pos,x   ;set horizontal coordinate and leave
12730
ExSFN: rts
12731
 
12732
;-------------------------------------------------------------------------------------
12733
;$01 - used to hold enemy offset for second enemy
12734
 
12735
SetBitsMask:
12736
      .db %10000000, %01000000, %00100000, %00010000, %00001000, %00000100, %00000010
12737
 
12738
ClearBitsMask:
12739
      .db %01111111, %10111111, %11011111, %11101111, %11110111, %11111011, %11111101
12740
 
12741
EnemiesCollision:
12742
;TODO   ix  c
12743
       if Z80OPT2
12744
        ld a,(FrameCounter)            ;check counter for d0 set
12745
        rra
12746
        ret nc;bcc ExSFN                   ;if d0 not set, leave
12747
        ld a,(AreaType)
12748
        or a
12749
        ret z;beq ExSFN                   ;if water area type, leave
12750
        ld hl,Enemy_ID
12751
        add hl,bc
12752
        ld a,(hl)
12753
        cp ++$15                    ;if enemy object =>  $15, branch to leave
12754
        jp nc,ExitECRoutine
12755
        cp ++Lakitu                 ;if lakitu, branch to leave
12756
        jp z,ExitECRoutine
12757
        cp ++PiranhaPlant           ;if piranha plant, branch to leave
12758
        jp z,ExitECRoutine
12759
        ldax EnemyOffscrBitsMasked,x ;if masked offscreen bits nonzero, branch to leave
12760
        or a
12761
        jp nz,ExitECRoutine
12762
        call GetEnemyBoundBoxOfs     ;otherwise, do sub, get appropriate bounding box offset for
12763
        dec c                         ;first enemy we're going to compare, then decrement for second
12764
        jp m,ExitECRoutine           ;branch to leave if there are no other enemies
12765
ECLoop: ;ld ly,c;stx SCRATCHPAD+$01                     ;save enemy object buffer offset for second enemy here
12766
       ;ld hy,e;tya                         ;save first enemy's bounding box offset to stack
12767
       ;pha
12768
        ldax Enemy_Flag,x            ;check enemy object enable flag
12769
        or a
12770
        jr z,ReadyNextEnemy_fast          ;branch if flag not set
12771
        ldax Enemy_ID,x
12772
        cp ++$15                    ;check for enemy object =>  $15
12773
        jr nc,ReadyNextEnemy_fast          ;branch if true
12774
        cp ++Lakitu
12775
        jr z,ReadyNextEnemy_fast          ;branch if enemy object is lakitu
12776
        cp ++PiranhaPlant
12777
        jr z,ReadyNextEnemy_fast          ;branch if enemy object is piranha plant
12778
        ldax EnemyOffscrBitsMasked,x
12779
        or a
12780
        jr nz,ReadyNextEnemy_fast          ;branch if masked offscreen bits set
12781
      ld ly,c
12782
      ;ld hy,e ; 
12783
        ld a,c                         ;get second enemy object's bounding box offset
12784
        inc a
12785
        add a,a                         ;multiply by four, then add four
12786
        add a,a
12787
        ld c,a                         ;use as new contents of X
12788
       push ix
12789
       push iy
12790
       call SprObjectCollisionCore  ;do collision detection using the two enemies here ;  y
12791
       pop iy
12792
       pop ix
12793
        ld hy,e
12794
      ld hl,ObjectOffset
12795
      ld e,(hl);ld c,(hl)      ;use first enemy offset for X
12796
      ld c,ly;ld e,ly;ldy SCRATCHPAD+$01                     ;use second enemy offset for Y
12797
        jr nc,NoEnemyCollision        ;if carry clear, no collision, branch ahead of this
12798
        ld hl,Enemy_State
12799
        add hl,de;bc
12800
        ld a,(hl) ;ldax Enemy_State,x
12801
        ld hl,Enemy_State
12802
        add hl,bc;de
12803
        or (hl) ;oray Enemy_State,y           ;check both enemy states for d7 set
12804
        jp m,YesEC                   ;branch if at least one of them is set
12805
        ld ix,Enemy_CollisionBits
12806
        add ix,bc;de
12807
        ld a,(ix);lday Enemy_CollisionBits,y   ;load first enemy's collision-related bits
12808
        ld hl,SetBitsMask
12809
        add hl,de;bc
12810
        and (hl);andx SetBitsMask,x           ;check to see if bit connected to second enemy is
12811
        jr nz,ReadyNextEnemy          ;already set, and move onto next enemy slot if set
12812
        ld a,(ix);lday Enemy_CollisionBits,y
12813
        or (hl);orax SetBitsMask,x           ;if the bit is not set, set it now
12814
        ld (ix),a;stay Enemy_CollisionBits,y
12815
YesEC:  ;push iy ; 
12816
        ;ly  SCRATCHPAD+$01!!!
12817
       if Z80OPT2bug==0
12818
        ld a,c
12819
        ld c,e
12820
        ld e,a ;-  !       
12821
       endif
12822
        call ProcEnemyCollisions     ;react according to the nature of collision ; x,y
12823
        ;pop iy
12824
        jp ReadyNextEnemy          ;move onto next enemy slot
12825
 
12826
NoEnemyCollision:
12827
        ld hl,ClearBitsMask
12828
        add hl,de;bc
12829
        ld a,(hl)
12830
        ld hl,Enemy_CollisionBits
12831
        add hl,bc;de
12832
      ;lday Enemy_CollisionBits,y     ;load first enemy's collision-related bits
12833
      and (hl) ;andx ClearBitsMask,x           ;clear bit connected to second enemy
12834
      ld (hl),a ;stay Enemy_CollisionBits,y     ;then move onto next enemy slot
12835
 
12836
ReadyNextEnemy:
12837
     ;pla              ;get first enemy's bounding box offset from the stack
12838
     ld e,hy ;tay              ;use as Y again
12839
      ld c,ly;ldx SCRATCHPAD+$01          ;get and decrement second enemy's object buffer offset
12840
ReadyNextEnemy_fast:
12841
      dec c
12842
      jp p,ECLoop       ;loop until all enemy slots have been checked
12843
 
12844
ExitECRoutine:
12845
      ld hl,ObjectOffset
12846
      ld c,(hl) ;get enemy object buffer offset
12847
      ret              ;leave
12848
 
12849
       else ;~Z80
12850
 
12851
        lda FrameCounter            ;check counter for d0 set
12852
        lsr
12853
        bcc ExSFN                   ;if d0 not set, leave
12854
        lda AreaType
12855
         checka
12856
        beq ExSFN                   ;if water area type, leave
12857
        ldax Enemy_ID,x
12858
        cmpn ++$15                    ;if enemy object =>  $15, branch to leave
12859
              cmpcy
12860
        bcs ExitECRoutine
12861
        cmpn ++Lakitu                 ;if lakitu, branch to leave
12862
        beq ExitECRoutine
12863
        cmpn ++PiranhaPlant           ;if piranha plant, branch to leave
12864
        beq ExitECRoutine
12865
        ldax EnemyOffscrBitsMasked,x ;if masked offscreen bits nonzero, branch to leave
12866
         checka
12867
        bne ExitECRoutine
12868
        jsr GetEnemyBoundBoxOfs     ;otherwise, do sub, get appropriate bounding box offset for
12869
        dex                         ;first enemy we're going to compare, then decrement for second
12870
        bmi ExitECRoutine           ;branch to leave if there are no other enemies
12871
ECLoop: stx SCRATCHPAD+$01                     ;save enemy object buffer offset for second enemy here
12872
        tya                         ;save first enemy's bounding box offset to stack
12873
        pha
12874
        ldax Enemy_Flag,x            ;check enemy object enable flag
12875
         checka
12876
        beq ReadyNextEnemy          ;branch if flag not set
12877
        ldax Enemy_ID,x
12878
        cmpn ++$15                    ;check for enemy object =>  $15
12879
              cmpcy
12880
        bcs ReadyNextEnemy          ;branch if true
12881
        cmpn ++Lakitu
12882
        beq ReadyNextEnemy          ;branch if enemy object is lakitu
12883
        cmpn ++PiranhaPlant
12884
        beq ReadyNextEnemy          ;branch if enemy object is piranha plant
12885
        ldax EnemyOffscrBitsMasked,x
12886
         checka
12887
        bne ReadyNextEnemy          ;branch if masked offscreen bits set
12888
        txa                         ;get second enemy object's bounding box offset
12889
        asl                         ;multiply by four, then add four
12890
        asl
12891
        clc
12892
        adcn ++$04
12893
        tax                         ;use as new contents of X
12894
        jsr SprObjectCollisionCore  ;do collision detection using the two enemies here
12895
        ldx ObjectOffset            ;use first enemy offset for X
12896
        ldy SCRATCHPAD+$01                     ;use second enemy offset for Y
12897
        bcc NoEnemyCollision        ;if carry clear, no collision, branch ahead of this
12898
        ldax Enemy_State,x
12899
        oray Enemy_State,y           ;check both enemy states for d7 set
12900
        andn ++%10000000
12901
        bne YesEC                   ;branch if at least one of them is set
12902
        lday Enemy_CollisionBits,y   ;load first enemy's collision-related bits
12903
        andx SetBitsMask,x           ;check to see if bit connected to second enemy is
12904
        bne ReadyNextEnemy          ;already set, and move onto next enemy slot if set
12905
        lday Enemy_CollisionBits,y
12906
        orax SetBitsMask,x           ;if the bit is not set, set it now
12907
        stay Enemy_CollisionBits,y
12908
YesEC:  jsr ProcEnemyCollisions     ;react according to the nature of collision
12909
        jmp ReadyNextEnemy          ;move onto next enemy slot
12910
 
12911
NoEnemyCollision:
12912
      lday Enemy_CollisionBits,y     ;load first enemy's collision-related bits
12913
      andx ClearBitsMask,x           ;clear bit connected to second enemy
12914
      stay Enemy_CollisionBits,y     ;then move onto next enemy slot
12915
 
12916
ReadyNextEnemy:
12917
      pla              ;get first enemy's bounding box offset from the stack
12918
      tay              ;use as Y again
12919
      ldx SCRATCHPAD+$01          ;get and decrement second enemy's object buffer offset
12920
      dex
12921
      bpl ECLoop       ;loop until all enemy slots have been checked
12922
 
12923
ExitECRoutine:
12924
      ldx ObjectOffset ;get enemy object buffer offset
12925
      rts              ;leave
12926
        endif
12927
 
12928
ProcEnemyCollisions:
12929
;ly  SCRATCHPAD+$01!!!
12930
      lday Enemy_State,y        ;check both enemy states for d5 set
12931
      orax Enemy_State,x
12932
      andn ++%00100000           ;if d5 is set in either state, or both, branch
12933
      bne ExitProcessEColl     ;to leave and do nothing else at this point
12934
      ldax Enemy_State,x
12935
      cmpn ++$06                 ;if second enemy state <  $06, branch elsewhere
12936
              cmpcy
12937
      bcc ProcSecondEnemyColl
12938
      ldax Enemy_ID,x           ;check second enemy identifier for hammer bro
12939
      cmpn ++HammerBro           ;if hammer bro found in alt state, branch to leave
12940
      beq ExitProcessEColl
12941
      lday Enemy_State,y        ;check first enemy state for d7 set
12942
      asl
12943
      bcc ShellCollisions      ;branch if d7 is clear
12944
      ldan ++$06
12945
      jsr SetupFloateyNumber   ;award 1000 points for killing enemy
12946
      jsr ShellOrBlockDefeat   ;then kill enemy, then load
12947
     if Z80OPT2
12948
      ld e,ly;ldy SCRATCHPAD+$01                  ;original offset of second enemy
12949
     else
12950
      ldy SCRATCHPAD+$01                  ;original offset of second enemy
12951
     endif
12952
 
12953
ShellCollisions:
12954
      tya                      ;move Y to X
12955
      tax
12956
      jsr ShellOrBlockDefeat   ;kill second enemy
12957
      ldx ObjectOffset
12958
      ldax ShellChainCounter,x  ;get chain counter for shell
12959
      clc
12960
      adcn ++$04                 ;add four to get appropriate point offset
12961
     if Z80OPT2
12962
      ld c,ly;ldx SCRATCHPAD+$01
12963
     else
12964
      ldx SCRATCHPAD+$01
12965
     endif
12966
      jsr SetupFloateyNumber   ;award appropriate number of points for second enemy
12967
      ldx ObjectOffset         ;load original offset of first enemy
12968
      incx ShellChainCounter,x  ;increment chain counter for additional enemies
12969
 
12970
ExitProcessEColl:
12971
      rts                      ;leave!!!
12972
 
12973
ProcSecondEnemyColl:
12974
      lday Enemy_State,y        ;if first enemy state <  $06, branch elsewhere
12975
      cmpn ++$06
12976
              cmpcy
12977
      bcc MoveEOfs
12978
      lday Enemy_ID,y           ;check first enemy identifier for hammer bro
12979
      cmpn ++HammerBro           ;if hammer bro found in alt state, branch to leave
12980
      beq ExitProcessEColl
12981
      jsr ShellOrBlockDefeat   ;otherwise, kill first enemy
12982
     if Z80OPT2
12983
      ld e,ly;ldy SCRATCHPAD+$01
12984
     else
12985
      ldy SCRATCHPAD+$01
12986
     endif
12987
      lday ShellChainCounter,y  ;get chain counter for shell
12988
      clc
12989
      adcn ++$04                 ;add four to get appropriate point offset
12990
      ldx ObjectOffset
12991
      jsr SetupFloateyNumber   ;award appropriate number of points for first enemy
12992
     if Z80OPT2
12993
      ld c,ly;ldx SCRATCHPAD+$01                  ;load original offset of second enemy
12994
     else
12995
      ldx SCRATCHPAD+$01                  ;load original offset of second enemy
12996
     endif
12997
      incx ShellChainCounter,x  ;increment chain counter for additional enemies
12998
      rts                      ;leave!!!
12999
 
13000
MoveEOfs:
13001
      tya                      ;move Y ($01) to X
13002
      tax
13003
      jsr EnemyTurnAround      ;do the sub here using value from $01
13004
      ldx ObjectOffset         ;then do it again using value from $08
13005
 
13006
EnemyTurnAround:
13007
       ldax Enemy_ID,x           ;check for specific enemies
13008
       cmpn ++PiranhaPlant
13009
       beq ExTA                 ;if piranha plant, leave
13010
       cmpn ++Lakitu
13011
       beq ExTA                 ;if lakitu, leave
13012
       cmpn ++HammerBro
13013
       beq ExTA                 ;if hammer bro, leave
13014
       cmpn ++Spiny
13015
       beq RXSpd                ;if spiny, turn it around
13016
       cmpn ++GreenParatroopaJump
13017
       beq RXSpd                ;if green paratroopa, turn it around
13018
       cmpn ++$07
13019
              cmpcy
13020
       bcs ExTA                 ;if any OTHER enemy object =>  $07, leave
13021
RXSpd: ldax Enemy_X_Speed,x      ;load horizontal speed
13022
       eorn ++$ff                 ;get two's compliment for horizontal speed
13023
       tay
13024
       iny
13025
       styx Enemy_X_Speed,x      ;store as new horizontal speed
13026
       ldax Enemy_MovingDir,x
13027
       eorn ++%00000011           ;invert moving direction and store, then leave
13028
       stax Enemy_MovingDir,x    ;thus effectively turning the enemy around
13029
ExTA:  rts                      ;leave!!!
13030
 
13031
;-------------------------------------------------------------------------------------
13032
;$00 - vertical position of platform
13033
 
13034
LargePlatformCollision:
13035
       ldan ++$ff                     ;save value here
13036
       stax PlatformCollisionFlag,x
13037
       lda TimerControl             ;check master timer control
13038
         checka
13039
       bne ExLPC                    ;if set, branch to leave
13040
       ldax Enemy_State,x            ;if d7 set in object state,
13041
         checka
13042
       bmi ExLPC                    ;branch to leave
13043
       ldax Enemy_ID,x
13044
       cmpn ++$24                     ;check enemy object identifier for
13045
       bne ChkForPlayerC_LargeP     ;balance platform, branch if not found
13046
       ldax Enemy_State,x
13047
       tax                          ;set state as enemy offset here
13048
       jsr ChkForPlayerC_LargeP     ;perform code with state offset, then original offset, in X
13049
 
13050
ChkForPlayerC_LargeP:
13051
       jsr CheckPlayerVertical      ;figure out if player is below a certain point
13052
       bcs ExLPC                    ;or offscreen, branch to leave if true
13053
       txa
13054
       jsr GetEnemyBoundBoxOfsArg   ;get bounding box offset in Y
13055
       ldax Enemy_Y_Position,x       ;store vertical coordinate in
13056
       sta SCRATCHPAD+$00                      ;temp variable for now
13057
       txa                          ;send offset we're on to the stack
13058
       pha
13059
       jsr PlayerCollisionCore      ;do player-to-platform collision detection
13060
       plakeepcy                          ;retrieve offset from the stack
13061
       tax
13062
       bcc ExLPC                    ;if no collision, branch to leave
13063
       jsr ProcLPlatCollisions      ;otherwise collision, perform sub
13064
ExLPC: ldx ObjectOffset             ;get enemy object buffer offset and leave
13065
       rts
13066
 
13067
;--------------------------------
13068
;$00 - counter for bounding boxes
13069
 
13070
SmallPlatformCollision:
13071
      lda TimerControl             ;if master timer control set,
13072
         checka
13073
      bne ExSPC                    ;branch to leave
13074
      stax PlatformCollisionFlag,x  ;otherwise initialize collision flag
13075
      jsr CheckPlayerVertical      ;do a sub to see if player is below a certain point
13076
      bcs ExSPC                    ;or entirely offscreen, and branch to leave if true
13077
      ldan ++$02
13078
      sta SCRATCHPAD+$00                      ;load counter here for 2 bounding boxes
13079
 
13080
ChkSmallPlatLoop:
13081
      ldx ObjectOffset           ;get enemy object offset
13082
      jsr GetEnemyBoundBoxOfs    ;get bounding box offset in Y
13083
      andn ++%00000010             ;if d1 of offscreen lower nybble bits was set
13084
      bne ExSPC                  ;then branch to leave
13085
      lday BoundingBox_UL_YPos,y  ;check top of platform's bounding box for being
13086
      cmpn ++$20                   ;above a specific point
13087
              cmpcy
13088
      bcc MoveBoundBox           ;if so, branch, don't do collision detection
13089
      jsr PlayerCollisionCore    ;otherwise, perform player-to-platform collision detection
13090
      bcs ProcSPlatCollisions    ;skip ahead if collision
13091
 
13092
MoveBoundBox:
13093
       lday BoundingBox_UL_YPos,y  ;move bounding box vertical coordinates
13094
       clc                        ;128 pixels downwards
13095
       adcn ++$80
13096
       stay BoundingBox_UL_YPos,y
13097
       lday BoundingBox_DR_YPos,y
13098
       clc
13099
       adcn ++$80
13100
       stay BoundingBox_DR_YPos,y
13101
       deci SCRATCHPAD+$00                    ;decrement counter we set earlier
13102
       bne ChkSmallPlatLoop       ;loop back until both bounding boxes are checked
13103
ExSPC: ldx ObjectOffset           ;get enemy object buffer offset, then leave
13104
       rts
13105
 
13106
;--------------------------------
13107
 
13108
ProcSPlatCollisions:
13109
      ldx ObjectOffset             ;return enemy object buffer offset to X, then continue
13110
 
13111
ProcLPlatCollisions:
13112
      lday BoundingBox_DR_YPos,y    ;get difference by subtracting the top
13113
      secsub                          ;of the player's bounding box from the bottom
13114
      sbci BoundingBox_UL_YPos      ;of the platform's bounding box
13115
      cmpn ++$04                     ;if difference too large or negative,
13116
              cmpcy
13117
      bcs ChkForTopCollision       ;branch, do not alter vertical speed of player
13118
      lda Player_Y_Speed           ;check to see if player's vertical speed is moving down
13119
         checka
13120
      bpl ChkForTopCollision       ;if so, don't mess with it
13121
      ldan ++$01                     ;otherwise, set vertical
13122
      sta Player_Y_Speed           ;speed of player to kill jump
13123
 
13124
ChkForTopCollision:
13125
      lda BoundingBox_DR_YPos      ;get difference by subtracting the top
13126
      secsub                          ;of the platform's bounding box from the bottom
13127
      sbcy BoundingBox_UL_YPos,y    ;of the player's bounding box
13128
      cmpn ++$06
13129
              cmpcy
13130
      bcs PlatformSideCollisions   ;if difference not close enough, skip all of this
13131
      lda Player_Y_Speed
13132
         checka
13133
      bmi PlatformSideCollisions   ;if player's vertical speed moving upwards, skip this
13134
      lda SCRATCHPAD+$00                      ;get saved bounding box counter from earlier
13135
      ldyx Enemy_ID,x
13136
      cpyn ++$2b                     ;if either of the two small platform objects are found,
13137
      beq SetCollisionFlag         ;regardless of which one, branch to use bounding box counter
13138
      cpyn ++$2c                     ;as contents of collision flag
13139
      beq SetCollisionFlag
13140
      txa                          ;otherwise use enemy object buffer offset
13141
 
13142
SetCollisionFlag: ;   ???
13143
      ldx ObjectOffset             ;get enemy object buffer offset
13144
      stax PlatformCollisionFlag,x  ;save either bounding box counter or enemy offset here
13145
      ldan ++$00
13146
      sta Player_State             ;set player state to normal then leave
13147
      rts
13148
 
13149
PlatformSideCollisions:
13150
         ldan ++$01                   ;set value here to indicate possible horizontal
13151
         sta SCRATCHPAD+$00                    ;collision on left side of platform
13152
         lda BoundingBox_DR_XPos    ;get difference by subtracting platform's left edge
13153
         secsub                        ;from player's right edge
13154
         sbcy BoundingBox_UL_XPos,y
13155
         cmpn ++$08                   ;if difference close enough, skip all of this
13156
              cmpcy
13157
         bcc SideC
13158
         inci SCRATCHPAD+$00                    ;otherwise increment value set here for right side collision
13159
         lday BoundingBox_DR_XPos,y  ;get difference by subtracting player's left edge
13160
         clc                        ;from platform's right edge
13161
         sbci BoundingBox_UL_XPos
13162
         cmpn ++$09                   ;if difference not close enough, skip subroutine
13163
              cmpcy
13164
         bcs NoSideC                ;and instead branch to leave (no collision)
13165
SideC:   jsr ImpedePlayerMove       ;deal with horizontal collision
13166
NoSideC: ldx ObjectOffset           ;return with enemy object buffer offset
13167
         rts
13168
 
13169
;-------------------------------------------------------------------------------------
13170
 
13171
PlayerPosSPlatData:
13172
      .db $80, $00
13173
 
13174
PositionPlayerOnS_Plat:
13175
      tay                        ;use bounding box counter saved in collision flag
13176
      ldax Enemy_Y_Position,x     ;for offset
13177
      clc                        ;add positioning data using offset to the vertical
13178
      adcy PlayerPosSPlatData-1,y ;coordinate
13179
      jr PositionPlayerOnVPlat_go;.db $2c                    ;BIT instruction opcode
13180
 
13181
PositionPlayerOnVPlat:
13182
         ldax Enemy_Y_Position,x    ;get vertical coordinate
13183
PositionPlayerOnVPlat_go
13184
         ldy GameEngineSubroutine
13185
         cpyn ++$0b                  ;if certain routine being executed on this frame,
13186
         beq ExPlPos               ;skip all of this
13187
         ldyx Enemy_Y_HighPos,x
13188
         cpyn ++$01                  ;if vertical high byte offscreen, skip this
13189
         bne ExPlPos
13190
         secsub                       ;subtract 32 pixels from vertical coordinate
13191
         sbcn ++$20                  ;for the player object's height
13192
         sta Player_Y_Position     ;save as player's new vertical coordinate
13193
         tya
13194
         sbcn ++$00                  ;subtract borrow and store as player's
13195
         sta Player_Y_HighPos      ;new vertical high byte
13196
         ldan ++$00
13197
         sta Player_Y_Speed        ;initialize vertical speed and low byte of force
13198
         sta Player_Y_MoveForce    ;and then leave
13199
ExPlPos: rts
13200
 
13201
;-------------------------------------------------------------------------------------
13202
 
13203
CheckPlayerVertical:
13204
       lda Player_OffscreenBits  ;if player object is completely offscreen
13205
       cmpn ++$f0                  ;vertically, leave this routine
13206
              cmpcy
13207
       bcs ExCPV
13208
       ldy Player_Y_HighPos      ;if player high vertical byte is not
13209
       dey                       ;within the screen, leave this routine
13210
       bne ExCPV
13211
       lda Player_Y_Position     ;if on the screen, check to see how far down
13212
       cmpn ++$d0                  ;the player is vertically
13213
              cmpcy
13214
ExCPV: rts
13215
 
13216
;-------------------------------------------------------------------------------------
13217
 
13218
GetEnemyBoundBoxOfs:
13219
      lda ObjectOffset         ;get enemy object buffer offset
13220
 
13221
GetEnemyBoundBoxOfsArg:
13222
      asl                      ;multiply A by four, then add four
13223
      asl                      ;to skip player's bounding box
13224
      clc
13225
      adcn ++$04
13226
      tay                      ;send to Y
13227
      lda Enemy_OffscreenBits  ;get offscreen bits for enemy object
13228
      andn ++%00001111           ;save low nybble
13229
      cmpn ++%00001111           ;check for all bits set
13230
              cmpcy
13231
      rts
13232
 
13233
;-------------------------------------------------------------------------------------
13234
;$00-$01 - used to hold many values, essentially temp variables
13235
;$04 - holds lower nybble of vertical coordinate from block buffer routine
13236
;$eb - used to hold block buffer adder
13237
 
13238
PlayerBGUpperExtent:
13239
      .db $20, $10
13240
 
13241
PlayerBGCollision:
13242
          lda DisableCollisionDet   ;if collision detection disabled flag set,
13243
         checka
13244
          bne ExPBGCol              ;branch to leave
13245
          lda GameEngineSubroutine
13246
          cmpn ++$0b                  ;if running routine ++11 or $0b
13247
          beq ExPBGCol              ;branch to leave
13248
          cmpn ++$04
13249
              cmpcy
13250
          bcc ExPBGCol              ;if running routines $00-$03 branch to leave
13251
          ldan ++$01                  ;load default player state for swimming
13252
          ldy SwimmingFlag          ;if swimming flag set,
13253
         checky
13254
          bne SetPSte               ;branch ahead to set default state
13255
          lda Player_State          ;if player in normal state,
13256
         checka
13257
          beq SetFallS              ;branch to set default state for falling
13258
          cmpn ++$03
13259
          bne ChkOnScr              ;if in any other state besides climbing, skip to next part
13260
SetFallS: ldan ++$02                  ;load default player state for falling
13261
SetPSte:  sta Player_State          ;set whatever player state is appropriate
13262
ChkOnScr: lda Player_Y_HighPos
13263
          cmpn ++$01                  ;check player's vertical high byte for still on the screen
13264
          bne ExPBGCol              ;branch to leave if not
13265
          ldan ++$ff
13266
          sta Player_CollisionBits  ;initialize player's collision flag
13267
          lda Player_Y_Position
13268
          cmpn ++$cf                  ;check player's vertical coordinate
13269
              cmpcy
13270
          bcc ChkCollSize           ;if not too close to the bottom of screen, continue
13271
ExPBGCol: rts                       ;otherwise leave
13272
 
13273
ChkCollSize:
13274
         ldyn ++$02                    ;load default offset
13275
         lda CrouchingFlag
13276
         checka
13277
         bne GBBAdr                  ;if player crouching, skip ahead
13278
         lda PlayerSize
13279
         checka
13280
         bne GBBAdr                  ;if player small, skip ahead
13281
         dey                         ;otherwise decrement offset for big player not crouching
13282
         lda SwimmingFlag
13283
         checka
13284
         bne GBBAdr                  ;if swimming flag set, skip ahead
13285
         dey                         ;otherwise decrement offset
13286
GBBAdr:  lday BlockBufferAdderData,y  ;get value using offset ;0,7,14
13287
         sta SCRATCHPAD+$eb                     ;store value here
13288
         tay                         ;put value into Y, as offset for block buffer routine
13289
         ldx PlayerSize              ;get player's size as offset
13290
         lda CrouchingFlag
13291
         checka
13292
         beq HeadChk                 ;if player not crouching, branch ahead
13293
         inx                         ;otherwise increment size as offset
13294
HeadChk: lda Player_Y_Position       ;get player's vertical coordinate ;   $b0???
13295
         cmpx PlayerBGUpperExtent,x   ;compare with upper extent value based on offset ;$20  $10
13296
              cmpcy
13297
         bcc DoFootCheck             ;if player is too high, skip this part
13298
         jsr BlockBufferColli_Head   ;do player-to-bg collision detection on top of
13299
         beq DoFootCheck             ;player, and branch if nothing above player's head
13300
         jsr CheckForCoinMTiles      ;check to see if player touched coin with their head
13301
         bcs AwardTouchedCoin        ;if so, branch to some other part of code
13302
         ldy Player_Y_Speed          ;check player's vertical speed
13303
         checky
13304
         bpl DoFootCheck             ;if player not moving upwards, branch elsewhere
13305
         ldy SCRATCHPAD+$04                     ;check lower nybble of vertical coordinate returned
13306
         cpyn ++$04                    ;from collision detection routine
13307
              cmpcy
13308
         bcc DoFootCheck             ;if low nybble <  4, branch
13309
         jsr CheckForSolidMTiles     ;check to see what player's head bumped on
13310
         bcs SolidOrClimb            ;if player collided with solid metatile, branch
13311
         ldy AreaType                ;otherwise check area type
13312
         checky
13313
         beq NYSpd                   ;if water level, branch ahead
13314
         ldy BlockBounceTimer        ;if block bounce timer not expired,
13315
         checky
13316
         bne NYSpd                   ;branch ahead, do not process collision
13317
         jsr PlayerHeadCollision     ;otherwise do a sub to process collision
13318
         jmp DoFootCheck             ;jump ahead to skip these other parts here
13319
 
13320
SolidOrClimb:
13321
       cmpn ++$26               ;if climbing metatile,
13322
       beq NYSpd              ;branch ahead and do not play sound
13323
       ldan ++Sfx_Bump
13324
       sta Square1SoundQueue  ;otherwise load bump sound
13325
NYSpd: ldan ++$01               ;set player's vertical speed to nullify
13326
       sta Player_Y_Speed     ;jump or swim
13327
 
13328
DoFootCheck:
13329
      ldy SCRATCHPAD+$eb                    ;get block buffer adder offset ;0,7,14?
13330
      lda Player_Y_Position
13331
      cmpn ++$cf                   ;check to see how low player is
13332
              cmpcy
13333
      bcs DoPlayerSideCheck      ;if player is too far down on screen, skip all of this
13334
      jsr BlockBufferColli_Feet  ;do player-to-bg collision detection on bottom left of player
13335
      jsr CheckForCoinMTiles     ;check to see if player touched coin with their left foot
13336
      bcs AwardTouchedCoin       ;if so, branch to some other part of code
13337
      pha                        ;save bottom left metatile to stack
13338
      jsr BlockBufferColli_Feet  ;do player-to-bg collision detection on bottom right of player
13339
      sta SCRATCHPAD+$00                    ;save bottom right metatile here
13340
      pla
13341
      sta SCRATCHPAD+$01                    ;pull bottom left metatile and save here
13342
         checka
13343
      bne ChkFootMTile           ;if anything here, skip this part
13344
      lda SCRATCHPAD+$00                    ;otherwise check for anything in bottom right metatile
13345
         checka
13346
      beq DoPlayerSideCheck      ;and skip ahead if not
13347
      jsr CheckForCoinMTiles     ;check to see if player touched coin with their right foot
13348
      bcc ChkFootMTile           ;if not, skip unconditional jump and continue code
13349
 
13350
AwardTouchedCoin:
13351
      jmp HandleCoinMetatile     ;follow the code to erase coin and award to player 1 coin
13352
 
13353
ChkFootMTile:
13354
          jsr CheckForClimbMTiles    ;check to see if player landed on climbable metatiles
13355
          bcs DoPlayerSideCheck      ;if so, branch
13356
          ldy Player_Y_Speed         ;check player's vertical speed
13357
         checky
13358
          bmi DoPlayerSideCheck      ;if player moving upwards, branch
13359
          cmpn ++$c5
13360
          bne ContChk                ;if player did not touch axe, skip ahead
13361
          jmp HandleAxeMetatile      ;otherwise jump to set modes of operation
13362
ContChk:  jsr ChkInvisibleMTiles     ;do sub to check for hidden coin or 1-up blocks
13363
          beq DoPlayerSideCheck      ;if either found, branch
13364
          ldy JumpspringAnimCtrl     ;if jumpspring animating right now,
13365
         checky
13366
          bne InitSteP               ;branch ahead
13367
          ldy SCRATCHPAD+$04                    ;check lower nybble of vertical coordinate returned
13368
          cpyn ++$05                   ;from collision detection routine
13369
              cmpcy
13370
          bcc LandPlyr               ;if lower nybble <  5, branch
13371
          lda Player_MovingDir
13372
          sta SCRATCHPAD+$00                    ;use player's moving direction as temp variable
13373
          jmp ImpedePlayerMove       ;jump to impede player's movement in that direction
13374
LandPlyr: jsr ChkForLandJumpSpring   ;do sub to check for jumpspring metatiles and deal with it
13375
          ldan ++$f0
13376
          andi Player_Y_Position      ;mask out lower nybble of player's vertical position
13377
          sta Player_Y_Position      ;and store as new vertical position to land player properly
13378
          jsr HandlePipeEntry        ;do sub to process potential pipe entry
13379
          ldan ++$00
13380
          sta Player_Y_Speed         ;initialize vertical speed and fractional
13381
          sta Player_Y_MoveForce     ;movement force to stop player's vertical movement
13382
          sta StompChainCounter      ;initialize enemy stomp counter
13383
InitSteP: ldan ++$00
13384
          sta Player_State           ;set player's state to normal
13385
 
13386
DoPlayerSideCheck:
13387
      ldy SCRATCHPAD+$eb       ;get block buffer adder offset ;  ???0,7,14?
13388
      iny
13389
      iny           ;increment offset 2 bytes to use adders for side collisions ;  ??? (       ???)
13390
      ldan ++$02      ;set value here to be used as counter
13391
      sta SCRATCHPAD+$00
13392
 
13393
SideCheckLoop:
13394
       iny                       ;move onto the next one ;   3   ,  4,5,6???
13395
       sty SCRATCHPAD+$eb                   ;store it
13396
       lda Player_Y_Position
13397
       cmpn ++$20                  ;check player's vertical position
13398
              cmpcy
13399
       bcc BHalf                 ;if player is in status bar area, branch ahead to skip this part
13400
       cmpn ++$e4
13401
              cmpcy
13402
       bcs ExSCH                 ;branch to leave if player is too far down
13403
       jsr BlockBufferColli_Side ;do player-to-bg collision detection on one half of player
13404
       beq BHalf                 ;branch ahead if nothing found
13405
       cmpn ++$1c                  ;otherwise check for pipe metatiles
13406
       beq BHalf                 ;if collided with sideways pipe (top), branch ahead
13407
       cmpn ++$6b
13408
       beq BHalf                 ;if collided with water pipe (top), branch ahead
13409
       jsr CheckForClimbMTiles   ;do sub to see if player bumped into anything climbable
13410
       bcc CheckSideMTiles       ;if not, branch to alternate section of code
13411
BHalf: ldy SCRATCHPAD+$eb                   ;load block adder offset
13412
       iny                       ;increment it ;???
13413
       lda Player_Y_Position     ;get player's vertical position
13414
       cmpn ++$08
13415
              cmpcy
13416
       bcc ExSCH                 ;if too high, branch to leave
13417
       cmpn ++$d0
13418
              cmpcy
13419
       bcs ExSCH                 ;if too low, branch to leave
13420
       jsr BlockBufferColli_Side ;do player-to-bg collision detection on other half of player
13421
       bne CheckSideMTiles       ;if something found, branch
13422
       deci SCRATCHPAD+$00                   ;otherwise decrement counter ;  ImpedePlayerMove ( =1???  ???)
13423
       bne SideCheckLoop         ;run code until both sides of player are checked ; ,       ,      
13424
ExSCH: rts                       ;leave
13425
 
13426
CheckSideMTiles:
13427
          jsr ChkInvisibleMTiles     ;check for hidden or coin 1-up blocks
13428
          beq ExCSM                  ;branch to leave if either found
13429
          jsr CheckForClimbMTiles    ;check for climbable metatiles
13430
          bcc ContSChk               ;if not found, skip and continue with code
13431
          jmp HandleClimbing         ;otherwise jump to handle climbing
13432
ContSChk: jsr CheckForCoinMTiles     ;check to see if player touched coin
13433
          bcs HandleCoinMetatile     ;if so, execute code to erase coin and award to player 1 coin
13434
          jsr ChkJumpspringMetatiles ;check for jumpspring metatiles
13435
          bcc ChkPBtm                ;if not found, branch ahead to continue cude
13436
          lda JumpspringAnimCtrl     ;otherwise check jumpspring animation control
13437
         checka
13438
          bne ExCSM                  ;branch to leave if set
13439
          jmp StopPlayerMove         ;otherwise jump to impede player's movement
13440
ChkPBtm:  ldy Player_State           ;get player's state
13441
        ;jr $ ;    ,   ($1c)
13442
          cpyn ++$00                   ;check for player's state set to normal
13443
          bne StopPlayerMove         ;if not, branch to impede player's movement ;      ;  (SCRATCHPAD+$00)? ( =1???)
13444
          ldy PlayerFacingDir        ;get player's facing direction
13445
          dey
13446
          bne StopPlayerMove         ;if facing left, branch to impede movement
13447
          cmpn ++$6c                   ;otherwise check for pipe metatiles
13448
          beq PipeDwnS               ;if collided with sideways pipe (bottom), branch
13449
          cmpn ++$1f                   ;if collided with water pipe (bottom), continue
13450
          bne StopPlayerMove         ;otherwise branch to impede player's movement
13451
PipeDwnS: lda Player_SprAttrib       ;check player's attributes
13452
        ;jr $ ;   ,      ,      -   
13453
         checka
13454
          bne PlyrPipe               ;if already set, branch, do not play sound again
13455
          ldyn ++Sfx_PipeDown_Injury
13456
          sty Square1SoundQueue      ;otherwise load pipedown/injury sound
13457
PlyrPipe: oran ++%00100000
13458
          sta Player_SprAttrib       ;set background priority bit in player attributes
13459
          lda Player_X_Position
13460
          andn ++%00001111             ;get lower nybble of player's horizontal coordinate
13461
          beq ChkGERtn               ;if at zero, branch ahead to skip this part
13462
          ldyn ++$00                   ;set default offset for timer setting data
13463
          lda ScreenLeft_PageLoc     ;load page location for left side of screen
13464
         checka
13465
          beq SetCATmr               ;if at page zero, use default offset
13466
          iny                        ;otherwise increment offset
13467
SetCATmr: lday AreaChangeTimerData,y  ;set timer for change of area as appropriate
13468
          sta ChangeAreaTimer
13469
ChkGERtn: lda GameEngineSubroutine   ;get number of game engine routine running
13470
          cmpn ++$07
13471
          beq ExCSM                  ;if running player entrance routine or
13472
          cmpn ++$08                   ;player control routine, go ahead and branch to leave
13473
          bne ExCSM
13474
          ldan ++$02
13475
          sta GameEngineSubroutine   ;otherwise set sideways pipe entry routine to run
13476
          rts                        ;and leave
13477
 
13478
;--------------------------------
13479
;$02 - high nybble of vertical coordinate from block buffer
13480
;$04 - low nybble of horizontal coordinate from block buffer
13481
;$06-$07 - block buffer address
13482
 
13483
StopPlayerMove:
13484
;   ,  (SCRATCHPAD+$00) != 1!!!  ?
13485
       jsr ImpedePlayerMove      ;stop player's movement
13486
ExCSM: rts                       ;leave
13487
 
13488
AreaChangeTimerData:
13489
      .db $a0, $34
13490
 
13491
HandleCoinMetatile:
13492
        ;jr $
13493
      jsr ErACM             ;do sub to erase coin metatile from block buffer
13494
      inci CoinTallyFor1Ups  ;increment coin tally used for 1-up blocks
13495
      jmp GiveOneCoin       ;update coin amount and tally on the screen
13496
 
13497
HandleAxeMetatile:
13498
       ldan ++$00
13499
       sta OperMode_Task   ;reset secondary mode
13500
       ldan ++$02
13501
       sta OperMode        ;set primary mode to autoctrl mode
13502
       ldan ++$18
13503
       sta Player_X_Speed  ;set horizontal speed and continue to erase axe metatile
13504
ErACM: ldy SCRATCHPAD+$02             ;load vertical high nybble offset for block buffer
13505
       ldan ++$00            ;load blank metatile
13506
       stayindirect (SCRATCHPAD+$06),y         ;store to remove old contents from block buffer
13507
       jmp RemoveCoin_Axe  ;update the screen accordingly
13508
 
13509
;--------------------------------
13510
;$02 - high nybble of vertical coordinate from block buffer
13511
;$04 - low nybble of horizontal coordinate from block buffer
13512
;$06-$07 - block buffer address
13513
 
13514
ClimbXPosAdder:
13515
      .db $f9, $07
13516
 
13517
ClimbPLocAdder:
13518
      .db $ff, $00
13519
 
13520
FlagpoleYPosData:
13521
      .db $18, $22, $50, $68, $90
13522
 
13523
HandleClimbing:
13524
      ldy SCRATCHPAD+$04            ;check low nybble of horizontal coordinate returned from
13525
      cpyn ++$06           ;collision detection routine against certain values, this
13526
              cmpcy
13527
      bcc ExHC           ;makes actual physical part of vine or flagpole thinner
13528
      cpyn ++$0a           ;than 16 pixels
13529
              cmpcy
13530
      bcc ChkForFlagpole
13531
ExHC: rts                ;leave if too far left or too far right
13532
 
13533
ChkForFlagpole:
13534
      cmpn ++$24               ;check climbing metatiles
13535
      beq FlagpoleCollision  ;branch if flagpole ball found
13536
      cmpn ++$25
13537
      bne VineCollision      ;branch to alternate code if flagpole shaft not found
13538
 
13539
FlagpoleCollision:
13540
      lda GameEngineSubroutine
13541
      cmpn ++$05                  ;check for end-of-level routine running
13542
      beq PutPlayerOnVine       ;if running, branch to end of climbing code
13543
      ldan ++$01
13544
      sta PlayerFacingDir       ;set player's facing direction to right
13545
      inci ScrollLock            ;set scroll lock flag
13546
      lda GameEngineSubroutine
13547
      cmpn ++$04                  ;check for flagpole slide routine running
13548
      beq RunFR                 ;if running, branch to end of flagpole code here
13549
      ldan ++BulletBill_CannonVar ;load identifier for bullet bills (cannon variant)
13550
      jsr KillEnemies           ;get rid of them
13551
      ldan ++Silence
13552
      sta EventMusicQueue       ;silence music
13553
      lsr
13554
      sta FlagpoleSoundQueue    ;load flagpole sound into flagpole sound queue
13555
      ldxn ++$04                  ;start at end of vertical coordinate data
13556
      lda Player_Y_Position
13557
      sta FlagpoleCollisionYPos ;store player's vertical coordinate here to be used later
13558
 
13559
ChkFlagpoleYPosLoop:
13560
       cmpx FlagpoleYPosData,x    ;compare with current vertical coordinate data
13561
              cmpcy
13562
       bcs MtchF                 ;if player's =>  current, branch to use current offset
13563
       dex                       ;otherwise decrement offset to use 
13564
       bne ChkFlagpoleYPosLoop   ;do this until all data is checked (use last one if all checked)
13565
MtchF: stx FlagpoleScore         ;store offset here to be used later
13566
RunFR: ldan ++$04
13567
       sta GameEngineSubroutine  ;set value to run flagpole slide routine
13568
       jmp PutPlayerOnVine       ;jump to end of climbing code
13569
 
13570
VineCollision:
13571
      cmpn ++$26                  ;check for climbing metatile used on vines
13572
      bne PutPlayerOnVine
13573
      lda Player_Y_Position     ;check player's vertical coordinate
13574
      cmpn ++$20                  ;for being in status bar area
13575
              cmpcy
13576
      bcs PutPlayerOnVine       ;branch if not that far up
13577
      ldan ++$01
13578
      sta GameEngineSubroutine  ;otherwise set to run autoclimb routine next frame
13579
 
13580
PutPlayerOnVine:
13581
         ldan ++$03                ;set player state to climbing
13582
         sta Player_State
13583
         ldan ++$00                ;nullify player's horizontal speed
13584
         sta Player_X_Speed      ;and fractional horizontal movement force
13585
         sta Player_X_MoveForce ; (  X-)
13586
         lda Player_X_Position   ;get player's horizontal coordinate
13587
         secsub
13588
         sbci ScreenLeft_X_Pos    ;subtract from left side horizontal coordinate
13589
         cmpn ++$10
13590
              cmpcy
13591
         bcs SetVXPl             ;if 16 or more pixels difference, do not alter facing direction
13592
         ldan ++$02
13593
         sta PlayerFacingDir     ;otherwise force player to face left
13594
SetVXPl: ldy PlayerFacingDir     ;get current facing direction, use as offset
13595
         lda SCRATCHPAD+$06                 ;get low byte of block buffer address
13596
         asl
13597
         asl                     ;move low nybble to high
13598
         asl
13599
         asl
13600
         clc
13601
         adcy ClimbXPosAdder-1,y  ;add pixels depending on facing direction
13602
         sta Player_X_Position   ;store as player's horizontal coordinate
13603
         lda SCRATCHPAD+$06                 ;get low byte of block buffer address again
13604
         checka
13605
         bne ExPVne              ;if not zero, branch
13606
         lda ScreenRight_PageLoc ;load page location of right side of screen
13607
         clc
13608
         adcy ClimbPLocAdder-1,y  ;add depending on facing location
13609
         sta Player_PageLoc      ;store as player's page location
13610
ExPVne:  rts                     ;finally, we're done!
13611
 
13612
;--------------------------------
13613
 
13614
ChkInvisibleMTiles:
13615
         cmpn ++$5f       ;check for hidden coin block
13616
         beq ExCInvT    ;branch to leave if found
13617
         cmpn ++$60       ;check for hidden 1-up block
13618
ExCInvT:
13619
              cmpcy ;???
13620
         rts            ;leave with zero flag set if either found
13621
 
13622
;--------------------------------
13623
;$00-$01 - used to hold bottom right and bottom left metatiles (in that order)
13624
;$00 - used as flag by ImpedePlayerMove to restrict specific movement
13625
 
13626
ChkForLandJumpSpring:
13627
        jsr ChkJumpspringMetatiles  ;do sub to check if player landed on jumpspring
13628
        bcc ExCJSp                  ;if carry not set, jumpspring not found, therefore leave
13629
        ldan ++$70
13630
        sta VerticalForce           ;otherwise set vertical movement force for player
13631
        ldan ++$f9
13632
        sta JumpspringForce         ;set default jumpspring force
13633
        ldan ++$03
13634
        sta JumpspringTimer         ;set jumpspring timer to be used later
13635
        lsr
13636
        sta JumpspringAnimCtrl      ;set jumpspring animation control to start animating
13637
ExCJSp: rts                         ;and leave
13638
 
13639
ChkJumpspringMetatiles:
13640
         cmpn ++$67      ;check for top jumpspring metatile
13641
         beq JSFnd     ;branch to set carry if found
13642
         cmpn ++$68      ;check for bottom jumpspring metatile
13643
         clc           ;clear carry flag
13644
         bne NoJSFnd   ;branch to use cleared carry if not found
13645
JSFnd:   sec           ;set carry if found
13646
NoJSFnd: rts           ;leave
13647
 
13648
HandlePipeEntry:
13649
         lda Up_Down_Buttons       ;check saved controller bits from earlier
13650
         andn ++%00000100            ;for pressing down
13651
         beq ExPipeE               ;if not pressing down, branch to leave
13652
         lda SCRATCHPAD+$00
13653
         cmpn ++$11                  ;check right foot metatile for warp pipe right metatile
13654
         bne ExPipeE               ;branch to leave if not found
13655
         lda SCRATCHPAD+$01
13656
         cmpn ++$10                  ;check left foot metatile for warp pipe left metatile
13657
         bne ExPipeE               ;branch to leave if not found
13658
         ldan ++$30
13659
         sta ChangeAreaTimer       ;set timer for change of area
13660
         ldan ++$03
13661
         sta GameEngineSubroutine  ;set to run vertical pipe entry routine on next frame
13662
         ldan ++Sfx_PipeDown_Injury
13663
         sta Square1SoundQueue     ;load pipedown/injury sound
13664
         ldan ++%00100000
13665
         sta Player_SprAttrib      ;set background priority bit in player's attributes
13666
         lda WarpZoneControl       ;check warp zone control
13667
         checka
13668
         beq ExPipeE               ;branch to leave if none found
13669
         andn ++%00000011            ;mask out all but 2 LSB
13670
         asl
13671
         asl                       ;multiply by four
13672
         tax                       ;save as offset to warp zone numbers (starts at left pipe)
13673
         lda Player_X_Position     ;get player's horizontal position
13674
         cmpn ++$60      
13675
              cmpcy
13676
         bcc GetWNum               ;if player at left, not near middle, use offset and skip ahead
13677
         inx                       ;otherwise increment for middle pipe
13678
         cmpn ++$a0      
13679
              cmpcy
13680
         bcc GetWNum               ;if player at middle, but not too far right, use offset and skip
13681
         inx                       ;otherwise increment for last pipe
13682
GetWNum: ldyx WarpZoneNumbers,x     ;get warp zone numbers
13683
         dey                       ;decrement for use as world number
13684
         sty WorldNumber           ;store as world number and offset
13685
         ldxy WorldAddrOffsets,y    ;get offset to where this world's area offsets are
13686
         ldax AreaAddrOffsets,x     ;get area offset based on world offset
13687
         sta AreaPointer           ;store area offset here to be used to change areas
13688
         ldan ++Silence
13689
         sta EventMusicQueue       ;silence music
13690
         ldan ++$00
13691
         sta EntrancePage          ;initialize starting page number
13692
         sta AreaNumber            ;initialize area number used for area address offset
13693
         sta LevelNumber           ;initialize level number used for world display
13694
         sta AltEntranceControl    ;initialize mode of entry
13695
         inci Hidden1UpFlag         ;set flag for hidden 1-up blocks
13696
         inci FetchNewGameTimerFlag ;set flag to load new game timer
13697
ExPipeE: rts                       ;leave!!!
13698
 
13699
ImpedePlayerMove:
13700
;   ,  (SCRATCHPAD+$00) != 1!!!  ???  (SCRATCHPAD+$00)
13701
; Player_CollisionBits, SideCollisionTimer,  X  XSpeed
13702
       ldan ++$00                  ;initialize value here
13703
       ldy Player_X_Speed        ;get player's horizontal speed
13704
       ldx SCRATCHPAD+$00                   ;check value set earlier for
13705
       dex                       ;left side collision
13706
      ;jr RImpd
13707
      bne RImpd                 ;if right side collision, skip this part ; jr RImpd,   53672     ,          !!!???
13708
; ???
13709
       inx                       ;return value to X
13710
       cpyn ++$00                  ;if player moving to the left,
13711
       bmi ExIPM                 ;branch to invert bit and leave ;  ,    -   
13712
       ldan ++$ff                  ;otherwise load A with value to be used later (     1 )
13713
       jmp NXSpd                 ;and jump to affect movement
13714
RImpd: ldxn ++$02                  ;return $02 to X
13715
       cpyn ++$01                  ;if player moving to the right,
13716
       bpl ExIPM                 ;branch to invert bit and leave
13717
       ldan ++$01                  ;otherwise load A with value to be used here
13718
NXSpd: ldyn ++$10
13719
       sty SideCollisionTimer    ;set timer of some sort
13720
       ldyn ++$00
13721
       sty Player_X_Speed        ;nullify player's horizontal speed
13722
       cmpn ++$00                  ;if value set in A not set to $ff,
13723
       bpl PlatF                 ;branch ahead, do not decrement Y
13724
       dey                       ;otherwise decrement Y now
13725
PlatF: sty SCRATCHPAD+$00                   ;store Y as high bits of horizontal adder
13726
       clc
13727
       adci Player_X_Position     ;add contents of A to player's horizontal
13728
       sta Player_X_Position     ;position to move player left or right
13729
       lda Player_PageLoc
13730
       adci SCRATCHPAD+$00                   ;add high bits and carry to
13731
       sta Player_PageLoc        ;page location if necessary
13732
ExIPM: txa                       ;invert contents of X
13733
       eorn ++$ff ;1->fe, 2->fd
13734
       andi Player_CollisionBits  ;mask out bit that was set here
13735
       sta Player_CollisionBits  ;store to clear bit
13736
       rts
13737
 
13738
;--------------------------------
13739
 
13740
SolidMTileUpperExt:
13741
      .db $10, $61, $88, $c4
13742
 
13743
CheckForSolidMTiles:
13744
;a=metatile
13745
;out: CY=???
13746
      jsr GetMTileAttrib        ;find appropriate offset based on metatile's 2 MSB
13747
      cmpx SolidMTileUpperExt,x  ;compare current metatile with solid metatiles
13748
       cmpcy
13749
      rts
13750
 
13751
ClimbMTileUpperExt:
13752
      .db $24, $6d, $8a, $c6
13753
 
13754
CheckForClimbMTiles:
13755
;a=metatile
13756
;out: CY=???
13757
      jsr GetMTileAttrib        ;find appropriate offset based on metatile's 2 MSB
13758
      cmpx ClimbMTileUpperExt,x  ;compare current metatile with climbable metatiles
13759
       cmpcy
13760
      rts
13761
 
13762
CheckForCoinMTiles:
13763
;out: CY=1:touched coin
13764
         cmpn ++$c2              ;check for regular coin
13765
         beq CoinSd            ;branch if found
13766
         cmpn ++$c3              ;check for underwater coin
13767
         beq CoinSd            ;branch if found
13768
         clc                   ;otherwise clear carry and leave
13769
         rts
13770
CoinSd:  ldan ++Sfx_CoinGrab
13771
         sta Square2SoundQueue ;load coin grab sound and leave
13772
        scf
13773
         rts
13774
 
13775
GetMTileAttrib:
13776
       tay            ;save metatile value into Y
13777
       andn ++%11000000 ;mask out all but 2 MSB
13778
       asl
13779
       rol            ;shift and rotate d7-d6 to d1-d0
13780
       rol
13781
       tax            ;use as offset for metatile data
13782
       tya            ;get original metatile value back
13783
ExEBG: rts            ;leave
13784
 
13785
;-------------------------------------------------------------------------------------
13786
;$06-$07 - address from block buffer routine
13787
 
13788
EnemyBGCStateData:
13789
      .db $01, $01, $02, $02, $02, $05
13790
 
13791
EnemyBGCXSpdData:
13792
      .db $10, $f0
13793
 
13794
EnemyToBGCollisionDet:
13795
      ldax Enemy_State,x        ;check enemy state for d6 set
13796
      andn ++%00100000
13797
      bne ExEBG                ;if set, branch to leave
13798
      jsr SubtEnemyYPos        ;otherwise, do a subroutine here
13799
      bcc ExEBG                ;if enemy vertical coord + 62 <  68, branch to leave
13800
      ldyx Enemy_ID,x
13801
      cpyn ++Spiny               ;if enemy object is not spiny, branch elsewhere
13802
      bne DoIDCheckBGColl
13803
      ldax Enemy_Y_Position,x
13804
      cmpn ++$25                 ;if enemy vertical coordinate <  36 branch to leave
13805
              cmpcy
13806
      bcc ExEBG
13807
 
13808
DoIDCheckBGColl:
13809
       cpyn ++GreenParatroopaJump ;check for some other enemy object
13810
       bne HBChk                ;branch if not found
13811
       jmp EnemyJump            ;otherwise jump elsewhere
13812
HBChk: cpyn ++HammerBro           ;check for hammer bro
13813
       bne CInvu                ;branch if not found
13814
       jmp HammerBroBGColl      ;otherwise jump elsewhere
13815
CInvu: cpyn ++Spiny               ;if enemy object is spiny, branch
13816
       beq YesIn
13817
       cpyn ++PowerUpObject       ;if special power-up object, branch
13818
       beq YesIn
13819
       cpyn ++$07                 ;if enemy object => $07, branch to leave
13820
              cmpcy
13821
       bcs ExEBGChk
13822
YesIn: jsr ChkUnderEnemy        ;if enemy object <  $07, or = $12 or $2e, do this sub
13823
       bne HandleEToBGCollision ;if block underneath enemy, branch
13824
 
13825
NoEToBGCollision:
13826
       jmp ChkForRedKoopa       ;otherwise skip and do something else
13827
 
13828
;--------------------------------
13829
;$02 - vertical coordinate from block buffer routine
13830
 
13831
HandleEToBGCollision:
13832
      jsr ChkForNonSolids       ;if something is underneath enemy, find out what
13833
      beq NoEToBGCollision      ;if blank $26, coins, or hidden blocks, jump, enemy falls through
13834
      cmpn ++$23
13835
      bne LandEnemyProperly     ;check for blank metatile $23 and branch if not found
13836
      ldy SCRATCHPAD+$02                   ;get vertical coordinate used to find block
13837
      ldan ++$00                  ;store default blank metatile in that spot so we won't
13838
      stayindirect (SCRATCHPAD+$06),y               ;trigger this routine accidentally again
13839
      ldax Enemy_ID,x
13840
      cmpn ++$15                  ;if enemy object =HIGH  $15, branch ahead
13841
              cmpcy
13842
      bcs ChkToStunEnemies
13843
      cmpn ++Goomba               ;if enemy object not goomba, branch ahead of this routine
13844
      bne GiveOEPoints
13845
      jsr KillEnemyAboveBlock   ;if enemy object IS goomba, do this sub
13846
 
13847
GiveOEPoints:
13848
      ldan ++$01                  ;award 100 points for hitting block beneath enemy
13849
      jsr SetupFloateyNumber
13850
 
13851
ChkToStunEnemies:
13852
          cmpn ++$09                   ;perform many comparisons on enemy object identifier
13853
              cmpcy
13854
          bcc SetStun      
13855
          cmpn ++$11                   ;if the enemy object identifier is equal to the values
13856
              cmpcy
13857
          bcs SetStun                ;$09, $0e, $0f or $10, it will be modified, and not
13858
          cmpn ++$0a                   ;modified if not any of those values, note that piranha plant will
13859
              cmpcy
13860
          bcc Demote                 ;always fail this test because A will still have vertical
13861
          cmpn ++PiranhaPlant          ;coordinate from previous addition, also these comparisons
13862
              cmpcy
13863
          bcc SetStun                ;are only necessary if branching from $d7a1
13864
Demote:   andn ++%00000001             ;erase all but LSB, essentially turning enemy object
13865
          stax Enemy_ID,x             ;into green or red koopa troopa to demote them
13866
SetStun:  ldax Enemy_State,x          ;load enemy state
13867
          andn ++%11110000             ;save high nybble
13868
          oran ++%00000010
13869
          stax Enemy_State,x          ;set d1 of enemy state
13870
          decx Enemy_Y_Position,x
13871
          decx Enemy_Y_Position,x     ;subtract two pixels from enemy's vertical position
13872
          ldax Enemy_ID,x
13873
          cmpn ++Bloober               ;check for bloober object
13874
          beq SetWYSpd
13875
          ldan ++$fd                   ;set default vertical speed
13876
          ldy AreaType
13877
         checky
13878
          bne SetNotW                ;if area type not water, set as speed, otherwise
13879
SetWYSpd: ldan ++$ff                   ;change the vertical speed
13880
SetNotW:  stax Enemy_Y_Speed,x        ;set vertical speed now
13881
          ldyn ++$01
13882
          jsr PlayerEnemyDiff        ;get horizontal difference between player and enemy object
13883
          bpl ChkBBill               ;branch if enemy is to the right of player
13884
          iny                        ;increment Y if not
13885
ChkBBill: ldax Enemy_ID,x      
13886
          cmpn ++BulletBill_CannonVar  ;check for bullet bill (cannon variant)
13887
          beq NoCDirF
13888
          cmpn ++BulletBill_FrenzyVar  ;check for bullet bill (frenzy variant)
13889
          beq NoCDirF                ;branch if either found, direction does not change
13890
          styx Enemy_MovingDir,x      ;store as moving direction
13891
NoCDirF:  dey                        ;decrement and use as offset
13892
          lday EnemyBGCXSpdData,y     ;get proper horizontal speed
13893
          stax Enemy_X_Speed,x        ;and store, then leave
13894
ExEBGChk: rts
13895
 
13896
;--------------------------------
13897
;$04 - low nybble of vertical coordinate from block buffer routine
13898
 
13899
LandEnemyProperly:
13900
       lda SCRATCHPAD+$04                 ;check lower nybble of vertical coordinate saved earlier
13901
       secsub
13902
       sbcn ++$08                ;subtract eight pixels
13903
       cmpn ++$05                ;used to determine whether enemy landed from falling
13904
              cmpcy
13905
       bcs ChkForRedKoopa      ;branch if lower nybble in range of $0d-$0f before subtract
13906
       ldax Enemy_State,x      
13907
       andn ++%01000000          ;branch if d6 in enemy state is set
13908
       bne LandEnemyInitState
13909
       ldax Enemy_State,x
13910
       asl                     ;branch if d7 in enemy state is not set
13911
       bcc ChkLandedEnemyState
13912
SChkA: jmp DoEnemySideCheck    ;if lower nybble LOW  $0d, d7 set but d6 not set, jump here
13913
 
13914
ChkLandedEnemyState:
13915
           ldax Enemy_State,x         ;if enemy in normal state, branch back to jump here
13916
         checka
13917
           beq SChkA
13918
           cmpn ++$05                  ;if in state used by spiny's egg
13919
           beq ProcEnemyDirection    ;then branch elsewhere
13920
           cmpn ++$03                  ;if already in state used by koopas and buzzy beetles
13921
              cmpcy
13922
           bcs ExSteChk              ;or in higher numbered state, branch to leave
13923
           ldax Enemy_State,x         ;load enemy state again (why?)
13924
           cmpn ++$02                  ;if not in $02 state (used by koopas and buzzy beetles)
13925
           bne ProcEnemyDirection    ;then branch elsewhere
13926
           ldan ++$10                  ;load default timer here
13927
           ldyx Enemy_ID,x            ;check enemy identifier for spiny
13928
           cpyn ++Spiny
13929
           bne SetForStn             ;branch if not found
13930
           ldan ++$00                  ;set timer for $00 if spiny
13931
SetForStn: stax EnemyIntervalTimer,x  ;set timer here
13932
           ldan ++$03                  ;set state here, apparently used to render
13933
           stax Enemy_State,x         ;upside-down koopas and buzzy beetles
13934
           jsr EnemyLanding          ;then land it properly
13935
ExSteChk:  rts                       ;then leave
13936
 
13937
ProcEnemyDirection:
13938
         ldax Enemy_ID,x            ;check enemy identifier for goomba
13939
         cmpn ++Goomba               ;branch if found
13940
         beq LandEnemyInitState
13941
         cmpn ++Spiny                ;check for spiny
13942
         bne InvtD                 ;branch if not found
13943
         ldan ++$01
13944
         stax Enemy_MovingDir,x     ;send enemy moving to the right by default
13945
         ldan ++$08
13946
         stax Enemy_X_Speed,x       ;set horizontal speed accordingly
13947
         lda FrameCounter
13948
         andn ++%00000111            ;if timed appropriately, spiny will skip over
13949
         beq LandEnemyInitState    ;trying to face the player
13950
InvtD:   ldyn ++$01                  ;load 1 for enemy to face the left (inverted here)
13951
         jsr PlayerEnemyDiff       ;get horizontal difference between player and enemy
13952
         bpl CNwCDir               ;if enemy to the right of player, branch
13953
         iny                       ;if to the left, increment by one for enemy to face right (inverted)
13954
CNwCDir: tya
13955
         cmpx Enemy_MovingDir,x     ;compare direction in A with current direction in memory
13956
         bne LandEnemyInitState
13957
         jsr ChkForBump_HammerBroJ ;if equal, not facing in correct dir, do sub to turn around
13958
 
13959
LandEnemyInitState:
13960
      jsr EnemyLanding       ;land enemy properly
13961
      ldax Enemy_State,x
13962
      andn ++%10000000         ;if d7 of enemy state is set, branch
13963
      bne NMovShellFallBit
13964
      ldan ++$00               ;otherwise initialize enemy state and leave
13965
      stax Enemy_State,x      ;note this will also turn spiny's egg into spiny
13966
      rts
13967
 
13968
NMovShellFallBit:
13969
      ldax Enemy_State,x   ;nullify d6 of enemy state, save other bits
13970
      andn ++%10111111      ;and store, then leave
13971
      stax Enemy_State,x
13972
      rts
13973
 
13974
;--------------------------------
13975
 
13976
ChkForRedKoopa:
13977
             ldax Enemy_ID,x            ;check for red koopa troopa $03
13978
             cmpn ++RedKoopa
13979
             bne Chk2MSBSt             ;branch if not found
13980
             ldax Enemy_State,x
13981
         checka
13982
             beq ChkForBump_HammerBroJ ;if enemy found and in normal state, branch
13983
Chk2MSBSt:   ldax Enemy_State,x         ;save enemy state into Y
13984
             tay
13985
             asl                       ;check for d7 set
13986
             bcc GetSteFromD           ;branch if not set
13987
             ldax Enemy_State,x
13988
             oran ++%01000000            ;set d6
13989
             jmp SetD6Ste              ;jump ahead of this part
13990
GetSteFromD: lday EnemyBGCStateData,y   ;load new enemy state with old as offset
13991
SetD6Ste:    stax Enemy_State,x         ;set as new state
13992
 
13993
;--------------------------------
13994
;$00 - used to store bitmask (not used but initialized here)
13995
;$eb - used in DoEnemySideCheck as counter and to compare moving directions
13996
 
13997
DoEnemySideCheck:
13998
          ldax Enemy_Y_Position,x     ;if enemy within status bar, branch to leave
13999
          cmpn ++$20                   ;because there's nothing there that impedes movement
14000
              cmpcy
14001
          bcc ExESdeC
14002
          ldyn ++$16                   ;start by finding block to the left of enemy ($00,$14)
14003
          ldan ++$02                   ;set value here in what is also used as
14004
          sta SCRATCHPAD+$eb                    ;OAM data offset
14005
SdeCLoop: lda SCRATCHPAD+$eb                    ;check value
14006
          cmpx Enemy_MovingDir,x      ;compare value against moving direction
14007
          bne NextSdeC               ;branch if different and do not seek block there
14008
          ldan ++$01                   ;set flag in A for save horizontal coordinate 
14009
          jsr BlockBufferChk_Enemy   ;find block to left or right of enemy object
14010
          beq NextSdeC               ;if nothing found, branch
14011
          jsr ChkForNonSolids        ;check for non-solid blocks
14012
          bne ChkForBump_HammerBroJ  ;branch if not found
14013
NextSdeC: deci SCRATCHPAD+$eb                    ;move to the next direction
14014
          iny
14015
          cpyn ++$18                   ;increment Y, loop only if Y <  $18, thus we check
14016
              cmpcy
14017
          bcc SdeCLoop               ;enemy ($00, $14) and ($10, $14) pixel coordinates
14018
ExESdeC:  rts
14019
 
14020
ChkForBump_HammerBroJ:
14021
        cpxn ++$05               ;check if we're on the special use slot
14022
        beq NoBump             ;and if so, branch ahead and do not play sound
14023
        ldax Enemy_State,x      ;if enemy state d7 not set, branch
14024
        asl                    ;ahead and do not play sound
14025
        bcc NoBump
14026
        ldan ++Sfx_Bump          ;otherwise, play bump sound
14027
        sta Square1SoundQueue  ;sound will never be played if branching from ChkForRedKoopa
14028
NoBump: ldax Enemy_ID,x         ;check for hammer bro
14029
        cmpn ++$05
14030
        bne InvEnemyDir        ;branch if not found
14031
        ldan ++$00
14032
        sta SCRATCHPAD+$00                ;initialize value here for bitmask  
14033
        ldyn ++$fa               ;load default vertical speed for jumping
14034
        jmp SetHJ              ;jump to code that makes hammer bro jump
14035
 
14036
InvEnemyDir:
14037
      jmp RXSpd     ;jump to turn the enemy around
14038
 
14039
;--------------------------------
14040
;$00 - used to hold horizontal difference between player and enemy
14041
 
14042
PlayerEnemyDiff:
14043
      ldax Enemy_X_Position,x  ;get distance between enemy object's
14044
      secsub                     ;horizontal coordinate and the player's
14045
      sbci Player_X_Position   ;horizontal coordinate
14046
      sta SCRATCHPAD+$00                 ;and store here
14047
      ldaxkeepcy Enemy_PageLoc,x
14048
      sbci Player_PageLoc      ;subtract borrow, then leave
14049
       cmpcy ;  
14050
      rts
14051
 
14052
;--------------------------------
14053
 
14054
EnemyLanding:
14055
      jsr InitVStf            ;do something here to vertical speed and something else
14056
      ldax Enemy_Y_Position,x
14057
      andn ++%11110000          ;save high nybble of vertical coordinate, and
14058
      oran ++%00001000          ;set d3, then store, probably used to set enemy object
14059
      stax Enemy_Y_Position,x  ;neatly on whatever it's landing on
14060
      rts
14061
 
14062
SubtEnemyYPos:
14063
      ldax Enemy_Y_Position,x  ;add 62 pixels to enemy object's
14064
      clc                     ;vertical coordinate
14065
      adcn ++$3e
14066
      cmpn ++$44                ;compare against a certain range
14067
              cmpcy
14068
      rts                     ;and leave with flags set for conditional branch
14069
 
14070
EnemyJump:
14071
        jsr SubtEnemyYPos     ;do a sub here
14072
        bcc DoSide            ;if enemy vertical coord + 62 LOW  68, branch to leave
14073
        ldax Enemy_Y_Speed,x
14074
        clc                   ;add two to vertical speed
14075
        adcn ++$02
14076
        cmpn ++$03              ;if green paratroopa not falling, branch ahead
14077
              cmpcy
14078
        bcc DoSide
14079
        jsr ChkUnderEnemy     ;otherwise, check to see if green paratroopa is 
14080
        beq DoSide            ;standing on anything, then branch to same place if not
14081
        jsr ChkForNonSolids   ;check for non-solid blocks
14082
        beq DoSide            ;branch if found
14083
        jsr EnemyLanding      ;change vertical coordinate and speed
14084
        ldan ++$fd
14085
        stax Enemy_Y_Speed,x   ;make the paratroopa jump again
14086
DoSide: jmp DoEnemySideCheck  ;check for horizontal blockage, then leave
14087
 
14088
;--------------------------------
14089
 
14090
HammerBroBGColl:
14091
      jsr ChkUnderEnemy    ;check to see if hammer bro is standing on anything
14092
      beq NoUnderHammerBro      
14093
      cmpn ++$23             ;check for blank metatile $23 and branch if not found
14094
      bne UnderHammerBro
14095
 
14096
KillEnemyAboveBlock:
14097
      jsr ShellOrBlockDefeat  ;do this sub to kill enemy
14098
      ldan ++$fc                ;alter vertical speed of enemy and leave
14099
      stax Enemy_Y_Speed,x
14100
      rts
14101
 
14102
UnderHammerBro:
14103
      ldax EnemyFrameTimer,x ;check timer used by hammer bro
14104
         checka
14105
      bne NoUnderHammerBro  ;branch if not expired
14106
      ldax Enemy_State,x
14107
      andn ++%10001000        ;save d7 and d3 from enemy state, nullify other bits
14108
      stax Enemy_State,x     ;and store
14109
      jsr EnemyLanding      ;modify vertical coordinate, speed and something else
14110
      jmp DoEnemySideCheck  ;then check for horizontal blockage and leave
14111
 
14112
NoUnderHammerBro:
14113
      ldax Enemy_State,x  ;if hammer bro is not standing on anything, set d0
14114
      oran ++$01           ;in the enemy state to indicate jumping or falling, then leave
14115
      stax Enemy_State,x
14116
      rts
14117
 
14118
ChkUnderEnemy:
14119
      ldan ++$00                  ;set flag in A for save vertical coordinate
14120
      ldyn ++$15                  ;set Y to check the bottom middle (8,18) of enemy object
14121
      jmp BlockBufferChk_Enemy  ;hop to it!
14122
 
14123
ChkForNonSolids:
14124
       cmpn ++$26       ;blank metatile used for vines?
14125
       beq NSFnd
14126
       cmpn ++$c2       ;regular coin?
14127
       beq NSFnd
14128
       cmpn ++$c3       ;underwater coin?
14129
       beq NSFnd
14130
       cmpn ++$5f       ;hidden coin block?
14131
       beq NSFnd
14132
       cmpn ++$60       ;hidden 1-up block?
14133
NSFnd:
14134
              cmpcy ;???
14135
        rts
14136
 
14137
;-------------------------------------------------------------------------------------
14138
 
14139
FireballBGCollision:
14140
      ldax Fireball_Y_Position,x   ;check fireball's vertical coordinate
14141
      cmpn ++$18
14142
              cmpcy
14143
      bcc ClearBounceFlag         ;if within the status bar area of the screen, branch ahead
14144
      jsr BlockBufferChk_FBall    ;do fireball to background collision detection on bottom of it
14145
      beq ClearBounceFlag         ;if nothing underneath fireball, branch
14146
      jsr ChkForNonSolids         ;check for non-solid metatiles
14147
      beq ClearBounceFlag         ;branch if any found
14148
      ldax Fireball_Y_Speed,x      ;if fireball's vertical speed set to move upwards,
14149
         checka
14150
      bmi InitFireballExplode     ;branch to set exploding bit in fireball's state
14151
      ldax FireballBouncingFlag,x  ;if bouncing flag already set,
14152
         checka
14153
      bne InitFireballExplode     ;branch to set exploding bit in fireball's state
14154
      ldan ++$fd
14155
      stax Fireball_Y_Speed,x      ;otherwise set vertical speed to move upwards (give it bounce)
14156
      ldan ++$01
14157
      stax FireballBouncingFlag,x  ;set bouncing flag
14158
      ldax Fireball_Y_Position,x
14159
      andn ++$f8                    ;modify vertical coordinate to land it properly
14160
      stax Fireball_Y_Position,x   ;store as new vertical coordinate
14161
      rts                         ;leave
14162
 
14163
ClearBounceFlag:
14164
      ldan ++$00
14165
      stax FireballBouncingFlag,x  ;clear bouncing flag by default
14166
      rts                         ;leave
14167
 
14168
InitFireballExplode:
14169
      ldan ++$80
14170
      stax Fireball_State,x        ;set exploding flag in fireball's state
14171
      ldan ++Sfx_Bump
14172
      sta Square1SoundQueue       ;load bump sound
14173
      rts                         ;leave
14174
 
14175
;-------------------------------------------------------------------------------------
14176
;$00 - used to hold one of bitmasks, or offset
14177
;$01 - used for relative X coordinate, also used to store middle screen page location
14178
;$02 - used for relative Y coordinate, also used to store middle screen coordinate
14179
 
14180
;this data added to relative coordinates of sprite objects
14181
;stored in order: left edge, top edge, right edge, bottom edge
14182
BoundBoxCtrlData:
14183
      .db $02, $08, $0e, $20
14184
      .db $03, $14, $0d, $20
14185
      .db $02, $14, $0e, $20
14186
      .db $02, $09, $0e, $15
14187
      .db $00, $00, $18, $06
14188
      .db $00, $00, $20, $0d
14189
      .db $00, $00, $30, $0d
14190
      .db $00, $00, $08, $08
14191
      .db $06, $04, $0a, $08
14192
      .db $03, $0e, $0d, $14
14193
      .db $00, $02, $10, $15
14194
      .db $04, $04, $0c, $1c
14195
 
14196
GetFireballBoundBox:
14197
      txa         ;add seven bytes to offset
14198
      clc         ;to use in routines as offset for fireball
14199
      adcn ++$07
14200
      tax
14201
      ldyn ++$02    ;set offset for relative coordinates
14202
         checky
14203
      bne FBallB  ;unconditional branch
14204
 
14205
GetMiscBoundBox:
14206
        txa                       ;add nine bytes to offset
14207
        clc                       ;to use in routines as offset for misc object
14208
        adcn ++$09 ;   #9  misc objects ( ???)
14209
        tax
14210
        ldyn ++$06                  ;set offset for relative coordinates
14211
FBallB: jsr BoundingBoxCore       ;get bounding box coordinates
14212
        jmp CheckRightScreenBBox  ;jump to handle any offscreen coordinates
14213
 
14214
GetEnemyBoundBox:
14215
      ldyn ++$48                 ;store bitmask here for now
14216
      sty SCRATCHPAD+$00
14217
      ldyn ++$44                 ;store another bitmask here for now and jump
14218
      jmp GetMaskedOffScrBits
14219
 
14220
SmallPlatformBoundBox:
14221
      ldyn ++$08                 ;store bitmask here for now
14222
      sty SCRATCHPAD+$00
14223
      ldyn ++$04                 ;store another bitmask here for now
14224
 
14225
GetMaskedOffScrBits:
14226
        ldax Enemy_X_Position,x      ;get enemy object position relative
14227
        secsub                         ;to the left side of the screen
14228
        sbci ScreenLeft_X_Pos
14229
        sta SCRATCHPAD+$01                     ;store here
14230
        ldaxkeepcy Enemy_PageLoc,x         ;subtract borrow from current page location
14231
        sbci ScreenLeft_PageLoc      ;of left side
14232
        bmi CMBits                  ;if enemy object is beyond left edge, branch
14233
        orai SCRATCHPAD+$01 ; Z???
14234
        beq CMBits                  ;if precisely at the left edge, branch
14235
        ldy SCRATCHPAD+$00                     ;if to the right of left edge, use value in $00 for A
14236
CMBits: tya                         ;otherwise use contents of Y
14237
        andi Enemy_OffscreenBits     ;preserve bitwise whatever's in here
14238
        stax EnemyOffscrBitsMasked,x ;save masked offscreen bits here
14239
         checka
14240
        bne MoveBoundBoxOffscreen   ;if anything set here, branch
14241
        jmp SetupEOffsetFBBox       ;otherwise, do something else
14242
 
14243
LargePlatformBoundBox:
14244
        if Z80OPT
14245
        push bc
14246
      inc c                        ;increment X to get the proper offset
14247
      call GetXOffscreenBits      ;then jump directly to the sub for horizontal offscreen bits
14248
        pop bc                   ;decrement to return to original offset
14249
        else
14250
      inx                        ;increment X to get the proper offset
14251
      jsr GetXOffscreenBits      ;then jump directly to the sub for horizontal offscreen bits
14252
      dex                        ;decrement to return to original offset
14253
        endif
14254
      cmpn ++$fe                   ;if completely offscreen, branch to put entire bounding ;TODO >>4  GetXOffscreenBits
14255
              cmpcy
14256
      bcs MoveBoundBoxOffscreen  ;box offscreen, otherwise start getting coordinates
14257
 
14258
SetupEOffsetFBBox:
14259
      txa                        ;add 1 to offset to properly address
14260
      clc                        ;the enemy object memory locations
14261
      adcn ++$01
14262
      tax
14263
      ldyn ++$01                   ;load 1 as offset here, same reason
14264
      jsr BoundingBoxCore        ;do a sub to get the coordinates of the bounding box
14265
      jmp CheckRightScreenBBox   ;jump to handle offscreen coordinates of bounding box
14266
 
14267
MoveBoundBoxOffscreen:
14268
      txa                            ;multiply offset by 4
14269
      asl
14270
      asl
14271
      tay                            ;use as offset here
14272
      ldan ++$ff
14273
      stay EnemyBoundingBoxCoord,y    ;load value into four locations here and leave
14274
      stay EnemyBoundingBoxCoord+1,y
14275
      stay EnemyBoundingBoxCoord+2,y
14276
      stay EnemyBoundingBoxCoord+3,y
14277
      rts
14278
 
14279
BoundingBoxCore:
14280
;x=obj?
14281
;y=obj2?
14282
;keep x
14283
;out: y=x*4 (  CheckRightScreenBBox,     )
14284
        if Z80OPT ;???   1-2
14285
        ld iy,SprObject_Rel_YPos
14286
        add iy,de
14287
        ld hl,SprObj_BoundBoxCtrl
14288
        add hl,bc
14289
      ld a,(hl)
14290
      add a,a
14291
      add a,a ;*4
14292
     ld hl,BoundBoxCtrlData ;left edge, top edge, right edge, bottom edge (12  )
14293
     add a,l
14294
     ld l,a
14295
     adc a,h
14296
     sub l
14297
     ld h,a
14298
      ld a,c ;txa                         ;multiply offset by four and save to stack
14299
      add a,a
14300
      add a,a ;*4
14301
     ld e,a                        ;use as offset
14302
     ;push de
14303
        ld ix,BoundingBox_UL_Corner
14304
        add ix,de
14305
      ld a,(iy+SprObject_Rel_XPos-SprObject_Rel_YPos) ;object X coordinate relative to screen
14306
      add a,(hl) ;adcx BoundBoxCtrlData,x     ;add the first number in the bounding box data to the
14307
      ld (ix+BoundingBox_UL_Corner-BoundingBox_UL_Corner),a ;stay BoundingBox_UL_Corner,y ;store here
14308
     sub (hl)
14309
     inc hl
14310
     inc hl
14311
      add a,(hl) ;adcx BoundBoxCtrlData+2,x    ;add the third number in the bounding box data to the
14312
      ld (ix+BoundingBox_LR_Corner-BoundingBox_UL_Corner),a ;stay BoundingBox_LR_Corner,y ;relative horizontal coordinate and store
14313
     dec hl
14314
      ld a,(iy+SprObject_Rel_YPos-SprObject_Rel_YPos) ;object Y coordinate relative to screen
14315
      add a,(hl);adcx BoundBoxCtrlData,x      ;add the second number to the relative vertical coordinate
14316
      ld (ix+BoundingBox_UL_Corner-BoundingBox_UL_Corner+1),a ;stay BoundingBox_UL_Corner,y
14317
     sub (hl)
14318
     inc hl
14319
     inc hl
14320
      add a,(hl) ;adcx BoundBoxCtrlData+2,x    ;add the fourth number to the relative vertical coordinate
14321
      ld (ix+BoundingBox_LR_Corner-BoundingBox_UL_Corner+1),a ;stay BoundingBox_LR_Corner,y ;and store
14322
     ;pop de
14323
      ret
14324
 
14325
CheckRightScreenBBox:
14326
;y = x*4
14327
;ix = BoundingBox_UL_Corner + (x*4)
14328
        ld iy,SprObject_X_Position
14329
        add iy,bc
14330
       lda ScreenLeft_X_Pos       ;add 128 pixels to left side of screen
14331
       add a,0x80
14332
       ld h,a;sta SCRATCHPAD+$02 ;and store as horizontal coordinate of middle
14333
       lda ScreenLeft_PageLoc     ;add carry to page location of left side of screen
14334
       adcn ++$00                   ;and store as page location of middle
14335
       ld l,a;sta SCRATCHPAD+$01
14336
       ld a,(iy+SprObject_X_Position-SprObject_X_Position) ;ldax SprObject_X_Position,x ;get horizontal coordinate
14337
       sub h;cmpi SCRATCHPAD+$02                    ;compare against middle horizontal coordinate
14338
       ld a,(iy+SprObject_PageLoc-SprObject_X_Position) ;ldaxkeepcy SprObject_PageLoc,x    ;get page location
14339
       sbc a,l;sbci SCRATCHPAD+$01                    ;subtract from middle page location
14340
       jr c,CheckLeftScreenBBox    ;if object is on the left side of the screen, branch
14341
       ld a,(ix+BoundingBox_DR_XPos-BoundingBox_UL_Corner) ;lday BoundingBox_DR_XPos,y  ;check right-side edge of bounding box for offscreen
14342
        or a
14343
       bmi NoOfs                  ;coordinates, branch if still on the screen
14344
       ld a,(ix+BoundingBox_UL_XPos-BoundingBox_UL_Corner) ;ldxy BoundingBox_UL_XPos,y  ;check left-side edge of bounding box for offscreen
14345
        or a
14346
       ldan ++$ff                   ;load offscreen value here to use on one or both horizontal sides
14347
       bmi SORte                  ;coordinates, and branch if still on the screen
14348
       ld (ix+BoundingBox_UL_XPos-BoundingBox_UL_Corner),a ;stay BoundingBox_UL_XPos,y  ;store offscreen value for left side
14349
SORte: ld (ix+BoundingBox_DR_XPos-BoundingBox_UL_Corner),a ;stay BoundingBox_DR_XPos,y  ;store offscreen value for right side
14350
NoOfs: ldx ObjectOffset           ;get object offset and leave
14351
       ret
14352
 
14353
CheckLeftScreenBBox:
14354
        ld a,(ix+BoundingBox_UL_XPos-BoundingBox_UL_Corner) ;lday BoundingBox_UL_XPos,y  ;check left-side edge of bounding box for offscreen
14355
         or a
14356
        bpl NoOfs2                 ;coordinates, and branch if still on the screen
14357
        cmpn ++$a0                   ;check to see if left-side edge is in the middle of the
14358
        jr c,NoOfs2                 ;screen or really offscreen, and branch if still on
14359
        ld a,(ix+BoundingBox_DR_XPos-BoundingBox_UL_Corner) ;ldxy BoundingBox_DR_XPos,y  ;check right-side edge of bounding box for offscreen
14360
         or a
14361
        ldan ++$00
14362
        bpl SOLft                  ;coordinates, branch if still onscreen
14363
        ld (ix+BoundingBox_DR_XPos-BoundingBox_UL_Corner),a ;stay BoundingBox_DR_XPos,y  ;store offscreen value for right side
14364
SOLft:  ld (ix+BoundingBox_UL_XPos-BoundingBox_UL_Corner),a ;stay BoundingBox_UL_XPos,y  ;store offscreen value for left side
14365
NoOfs2: ldx ObjectOffset           ;get object offset and leave
14366
        rts
14367
 
14368
        else ;~Z80
14369
;     
14370
;    SCRATCHPAD (   )
14371
;   CY   (  plakeepcy)
14372
;    ix  Z80- CheckRightScreenBBox
14373
      stx zSCRATCHPAD+$00                     ;save offset here
14374
      lday SprObject_Rel_YPos,y    ;store object coordinates relative to screen
14375
      sta zSCRATCHPAD+$02                     ;vertically and horizontally, respectively
14376
      lday SprObject_Rel_XPos,y
14377
      sta zSCRATCHPAD+$01
14378
      txa                         ;multiply offset by four and save to stack
14379
      asl
14380
      asl
14381
      pha
14382
      tay                         ;use as offset for Y, X is left alone
14383
      ldax SprObj_BoundBoxCtrl,x   ;load value here to be used as offset for X
14384
      asl                         ;multiply that by four and use as X
14385
      asl
14386
      tax
14387
      lda zSCRATCHPAD+$01                     ;add the first number in the bounding box data to the
14388
      clc                         ;relative horizontal coordinate using enemy object offset
14389
      adcx BoundBoxCtrlData,x      ;and store somewhere using same offset * 4
14390
      stay BoundingBox_UL_Corner,y ;store here
14391
      lda zSCRATCHPAD+$01
14392
      clc
14393
      adcx BoundBoxCtrlData+2,x    ;add the third number in the bounding box data to the
14394
      stay BoundingBox_LR_Corner,y ;relative horizontal coordinate and store
14395
      inx                         ;increment both offsets
14396
      iny
14397
      lda zSCRATCHPAD+$02                     ;add the second number to the relative vertical coordinate
14398
      clc                         ;using incremented offset and store using the other
14399
      adcx BoundBoxCtrlData,x      ;incremented offset
14400
      stay BoundingBox_UL_Corner,y
14401
      lda zSCRATCHPAD+$02
14402
      clc
14403
      adcx BoundBoxCtrlData+2,x    ;add the fourth number to the relative vertical coordinate
14404
      stay BoundingBox_LR_Corner,y ;and store
14405
      plakeepcy;pla                         ;get original offset loaded into $00 * y from stack
14406
      tay                         ;use as Y
14407
      ldx zSCRATCHPAD+$00                     ;get original offset and use as X again
14408
      rts
14409
zSCRATCHPAD=SCRATCHPAD
14410
        ;ds 3
14411
 
14412
CheckRightScreenBBox:
14413
;y = x*4
14414
       lda ScreenLeft_X_Pos       ;add 128 pixels to left side of screen
14415
       clc                        ;and store as horizontal coordinate of middle
14416
       adcn ++$80
14417
       sta SCRATCHPAD+$02
14418
       lda ScreenLeft_PageLoc     ;add carry to page location of left side of screen
14419
       adcn ++$00                   ;and store as page location of middle
14420
       sta SCRATCHPAD+$01
14421
       ldax SprObject_X_Position,x ;get horizontal coordinate
14422
       cmpi SCRATCHPAD+$02                    ;compare against middle horizontal coordinate
14423
       ldaxkeepcy SprObject_PageLoc,x    ;get page location
14424
       sbci SCRATCHPAD+$01                    ;subtract from middle page location
14425
              cmpcy
14426
       bcc CheckLeftScreenBBox    ;if object is on the left side of the screen, branch
14427
       lday BoundingBox_DR_XPos,y  ;check right-side edge of bounding box for offscreen
14428
         checka
14429
       bmi NoOfs                  ;coordinates, branch if still on the screen
14430
       ldan ++$ff                   ;load offscreen value here to use on one or both horizontal sides
14431
       ldxy BoundingBox_UL_XPos,y  ;check left-side edge of bounding box for offscreen
14432
         checkx
14433
       bmi SORte                  ;coordinates, and branch if still on the screen
14434
       stay BoundingBox_UL_XPos,y  ;store offscreen value for left side
14435
SORte: stay BoundingBox_DR_XPos,y  ;store offscreen value for right side
14436
NoOfs: ldx ObjectOffset           ;get object offset and leave
14437
       rts
14438
 
14439
CheckLeftScreenBBox:
14440
        lday BoundingBox_UL_XPos,y  ;check left-side edge of bounding box for offscreen
14441
         checka
14442
        bpl NoOfs2                 ;coordinates, and branch if still on the screen
14443
        cmpn ++$a0                   ;check to see if left-side edge is in the middle of the
14444
              cmpcy
14445
        bcc NoOfs2                 ;screen or really offscreen, and branch if still on
14446
        ldan ++$00
14447
        ldxy BoundingBox_DR_XPos,y  ;check right-side edge of bounding box for offscreen
14448
         checkx
14449
        bpl SOLft                  ;coordinates, branch if still onscreen
14450
        stay BoundingBox_DR_XPos,y  ;store offscreen value for right side
14451
SOLft:  stay BoundingBox_UL_XPos,y  ;store offscreen value for left side
14452
NoOfs2: ldx ObjectOffset           ;get object offset and leave
14453
        rts
14454
        endif
14455
 
14456
;-------------------------------------------------------------------------------------
14457
;$06 - second object's offset
14458
;$07 - counter
14459
;y=second object's offset
14460
;  y
14461
 
14462
;TODO  
14463
 
14464
PlayerCollisionCore:
14465
      ldxn ++$00     ;initialize X to use player's bounding box for comparison
14466
 
14467
SprObjectCollisionCore:
14468
 
14469
        if Z80OPT2a
14470
 
14471
      push de;sty SCRATCHPAD+$06      ;save contents of Y here
14472
      ld iy,BoundingBox_UL_Corner
14473
      add iy,de
14474
      ld ix,BoundingBox_UL_Corner
14475
      add ix,bc
14476
      ;ldan ++$01
14477
      ld d,1 ;sta SCRATCHPAD+$07      ;save value 1 here as counter, compare horizontal coordinates first
14478
 
14479
CollisionCoreLoop:
14480
      ld e,(ix)
14481
      ld c,(ix+BoundingBox_LR_Corner-BoundingBox_UL_Corner)
14482
      ld a,(iy);lday BoundingBox_UL_Corner,y  ;compare left/top coordinates
14483
      cp e;(ix);icmpx BoundingBox_UL_Corner,x  ;of first and second objects' bounding boxes
14484
      jr nc,FirstBoxGreater          ;if first left/top =>  second, branch
14485
      cp c;(ix+BoundingBox_LR_Corner-BoundingBox_UL_Corner);cmpx BoundingBox_LR_Corner,x  ;otherwise compare to right/bottom of second
14486
      jr c,SecondBoxVerticalChk     ;if first left/top <  second right/bottom, branch elsewhere
14487
      jr z,CollisionFound           ;if somehow equal, collision, thus branch
14488
       ld c,a
14489
      ld a,(iy+BoundingBox_LR_Corner-BoundingBox_UL_Corner);lday BoundingBox_LR_Corner,y  ;if somehow greater, check to see if bottom of
14490
      cp c;(iy);cmpy BoundingBox_UL_Corner,y  ;first object's bounding box is greater than its top
14491
      jr c,CollisionFound           ;if somehow less, vertical wrap collision, thus branch
14492
      cp e;(ix);cmpx BoundingBox_UL_Corner,x  ;otherwise compare bottom of first bounding box to the top
14493
      jr nc,CollisionFound           ;of second box, and if equal or greater, collision, thus branch
14494
      or a
14495
      pop de;ldy SCRATCHPAD+$06                      ;otherwise return with carry clear and Y = $0006
14496
      ret                       ;note horizontal wrapping never occurs
14497
 
14498
SecondBoxVerticalChk:
14499
      ld a,(ix+BoundingBox_LR_Corner-BoundingBox_UL_Corner);ldax BoundingBox_LR_Corner,x  ;check to see if the vertical bottom of the box
14500
      cp e;(ix);cmpx BoundingBox_UL_Corner,x  ;is greater than the vertical top
14501
      jr c,CollisionFound           ;if somehow less, vertical wrap collision, thus branch
14502
      ld a,(iy+BoundingBox_LR_Corner-BoundingBox_UL_Corner);lday BoundingBox_LR_Corner,y  ;otherwise compare horizontal right or vertical bottom
14503
      cp e;(ix);cmpx BoundingBox_UL_Corner,x  ;of first box with horizontal left or vertical top of second box
14504
      jr nc,CollisionFound           ;if equal or greater, collision, thus branch
14505
      or a
14506
      pop de;ldy SCRATCHPAD+$06                      ;otherwise return with carry clear and Y = $0006
14507
      ret
14508
 
14509
FirstBoxGreater:
14510
      cp e;(ix);cmpx BoundingBox_UL_Corner,x  ;compare first and second box horizontal left/vertical top again
14511
      jr z,CollisionFound           ;if first coordinate = second, collision, thus branch
14512
      cp c;(ix+BoundingBox_LR_Corner-BoundingBox_UL_Corner);cmpx BoundingBox_LR_Corner,x  ;if not, compare with second object right or bottom edge
14513
      jr c,CollisionFound           ;if left/top of first less than or equal to right/bottom of second
14514
      jr z,CollisionFound           ;then collision, thus branch
14515
      cp (iy+BoundingBox_LR_Corner-BoundingBox_UL_Corner);cmpy BoundingBox_LR_Corner,y  ;otherwise check to see if top of first box is greater than bottom
14516
      jr c,NoCollisionFound         ;if less than or equal, no collision, branch to end
14517
      jr z,NoCollisionFound
14518
      ld a,(iy+BoundingBox_LR_Corner-BoundingBox_UL_Corner);lday BoundingBox_LR_Corner,y  ;otherwise compare bottom of first to top of second
14519
      cp c;(ix+BoundingBox_LR_Corner-BoundingBox_UL_Corner);cmpx BoundingBox_UL_Corner,x  ;if bottom of first is greater than top of second, vertical wrap
14520
      jr nc,CollisionFound           ;collision, and branch, otherwise, proceed onwards here
14521
NoCollisionFound:
14522
      or a          ;clear carry, then load value set earlier, then leave
14523
      pop de;ldy SCRATCHPAD+$06      ;like previous ones, if horizontal coordinates do not collide, we do
14524
      ret          ;not bother checking vertical ones, because what's the point?
14525
 
14526
CollisionFound:
14527
      inc ix ;inx                    ;increment offsets on both objects to check
14528
      inc iy ;iny                    ;the vertical coordinates
14529
      dec d ;deci SCRATCHPAD+$07                ;decrement counter to reflect this
14530
      jp p,CollisionCoreLoop  ;if counter not expired, branch to loop
14531
      scf                    ;otherwise we already did both sets, therefore collision, so set carry
14532
      pop de;ldy SCRATCHPAD+$06                ;load original value set here earlier, then leave
14533
      ret
14534
 
14535
        else ;~Z80
14536
 
14537
      sty SCRATCHPAD+$06      ;save contents of Y here
14538
      ldan ++$01
14539
      sta SCRATCHPAD+$07      ;save value 1 here as counter, compare horizontal coordinates first
14540
 
14541
CollisionCoreLoop:
14542
      lday BoundingBox_UL_Corner,y  ;compare left/top coordinates
14543
      cmpx BoundingBox_UL_Corner,x  ;of first and second objects' bounding boxes
14544
              cmpcy
14545
      bcs FirstBoxGreater          ;if first left/top =>  second, branch
14546
      cmpx BoundingBox_LR_Corner,x  ;otherwise compare to right/bottom of second
14547
              cmpcy
14548
      bcc SecondBoxVerticalChk     ;if first left/top <  second right/bottom, branch elsewhere
14549
      beq CollisionFound           ;if somehow equal, collision, thus branch
14550
      lday BoundingBox_LR_Corner,y  ;if somehow greater, check to see if bottom of
14551
      cmpy BoundingBox_UL_Corner,y  ;first object's bounding box is greater than its top
14552
              cmpcy
14553
      bcc CollisionFound           ;if somehow less, vertical wrap collision, thus branch
14554
      cmpx BoundingBox_UL_Corner,x  ;otherwise compare bottom of first bounding box to the top
14555
              cmpcy
14556
      bcs CollisionFound           ;of second box, and if equal or greater, collision, thus branch
14557
      ldy SCRATCHPAD+$06                      ;otherwise return with carry clear and Y = $0006
14558
      rts                          ;note horizontal wrapping never occurs
14559
 
14560
SecondBoxVerticalChk:
14561
      ldax BoundingBox_LR_Corner,x  ;check to see if the vertical bottom of the box
14562
      cmpx BoundingBox_UL_Corner,x  ;is greater than the vertical top
14563
              cmpcy
14564
      bcc CollisionFound           ;if somehow less, vertical wrap collision, thus branch
14565
      lday BoundingBox_LR_Corner,y  ;otherwise compare horizontal right or vertical bottom
14566
      cmpx BoundingBox_UL_Corner,x  ;of first box with horizontal left or vertical top of second box
14567
              cmpcy
14568
      bcs CollisionFound           ;if equal or greater, collision, thus branch
14569
      ldy SCRATCHPAD+$06                      ;otherwise return with carry clear and Y = $0006
14570
      rts
14571
 
14572
FirstBoxGreater:
14573
      cmpx BoundingBox_UL_Corner,x  ;compare first and second box horizontal left/vertical top again
14574
      beq CollisionFound           ;if first coordinate = second, collision, thus branch
14575
      cmpx BoundingBox_LR_Corner,x  ;if not, compare with second object right or bottom edge
14576
              cmpcy
14577
      bcc CollisionFound           ;if left/top of first less than or equal to right/bottom of second
14578
      beq CollisionFound           ;then collision, thus branch
14579
      cmpy BoundingBox_LR_Corner,y  ;otherwise check to see if top of first box is greater than bottom
14580
              cmpcy
14581
      bcc NoCollisionFound         ;if less than or equal, no collision, branch to end
14582
      beq NoCollisionFound
14583
      lday BoundingBox_LR_Corner,y  ;otherwise compare bottom of first to top of second
14584
      cmpx BoundingBox_UL_Corner,x  ;if bottom of first is greater than top of second, vertical wrap
14585
              cmpcy
14586
      bcs CollisionFound           ;collision, and branch, otherwise, proceed onwards here
14587
 
14588
NoCollisionFound:
14589
      clc          ;clear carry, then load value set earlier, then leave
14590
      ldy SCRATCHPAD+$06      ;like previous ones, if horizontal coordinates do not collide, we do
14591
      rts          ;not bother checking vertical ones, because what's the point?
14592
 
14593
CollisionFound:
14594
      inx                    ;increment offsets on both objects to check
14595
      iny                    ;the vertical coordinates
14596
      deci SCRATCHPAD+$07                ;decrement counter to reflect this
14597
      bpl CollisionCoreLoop  ;if counter not expired, branch to loop
14598
      sec                    ;otherwise we already did both sets, therefore collision, so set carry
14599
      ldy SCRATCHPAD+$06                ;load original value set here earlier, then leave
14600
      rts
14601
 
14602
        endif
14603
 
14604
;-------------------------------------------------------------------------------------
14605
;$02 - modified y coordinate
14606
;$03 - stores metatile involved in block buffer collisions
14607
;$04 - comes in with offset to block buffer adder data, goes out with low nybble x/y coordinate
14608
;$05 - modified x coordinate
14609
;$06-$07 - block buffer address
14610
 
14611
BlockBufferChk_Enemy:
14612
      pha        ;save contents of A to stack
14613
      txa
14614
      clc        ;add 1 to X to run sub with enemy offset in mind
14615
      adcn ++$01
14616
      tax
14617
      pla        ;pull A from stack and jump elsewhere
14618
      jmp BBChk_E
14619
 
14620
ResidualMiscObjectCode:
14621
      txa
14622
      clc           ;supposedly used once to set offset for
14623
      adcn ++$0d      ;miscellaneous objects
14624
      tax
14625
      ldyn ++$1b      ;supposedly used once to set offset for block buffer data
14626
      jmp ResJmpM   ;probably used in early stages to do misc to bg collision detection
14627
 
14628
BlockBufferChk_FBall:
14629
         ldyn ++$1a                  ;set offset for block buffer adder data
14630
         txa
14631
         clc
14632
         adcn ++$07                  ;add seven bytes to use
14633
         tax
14634
ResJmpM: ldan ++$00                  ;set A to return vertical coordinate
14635
BBChk_E: jsr BlockBufferCollision  ;do collision detection subroutine for sprite object
14636
         ldx ObjectOffset          ;get object offset
14637
         cmpn ++$00                  ;check to see if object bumped into anything
14638
              cmpcy ;???
14639
         rts
14640
 
14641
BlockBufferAdderData:
14642
      .db $00, $07, $0e
14643
 
14644
;      ???
14645
BlockBuffer_X_Adder:
14646
; 7 (    3     ,  4  )
14647
      .db $08, $03, $0c, $02, $02, $0d, $0d
14648
      .db $08, $03, $0c, $02, $02, $0d, $0d
14649
      .db $08, $03, $0c, $02, $02, $0d, $0d
14650
      .db $08, $00, $10, $04, $14, $04, $04 ;  ???
14651
 
14652
BlockBuffer_Y_Adder:
14653
; 7 (    3     ,  4  )
14654
      .db $04, $20, $20, $08, $18, $08, $18
14655
      .db $02, $20, $20, $08, $18, $08, $18
14656
      .db $12, $20, $20, $18, $18, $18, $18
14657
      .db $18, $14, $14, $06, $06, $08, $10 ;  ???
14658
 
14659
BlockBufferColli_Feet:
14660
       iny            ;if branched here, increment to next set of adders
14661
 
14662
BlockBufferColli_Head:
14663
;out: NZ=collision
14664
       ldan ++$00       ;set flag to return vertical coordinate
14665
       jr BlockBufferColli_Side_go;.db $2c        ;BIT instruction opcode
14666
 
14667
BlockBufferColli_Side:
14668
       ldan ++$01       ;set flag to return horizontal coordinate
14669
BlockBufferColli_Side_go
14670
       ldxn ++$00       ;set offset for player object
14671
 
14672
BlockBufferCollision:
14673
;x=obj
14674
;y=??? ( !)    BlockBuffer_X_Adder, BlockBuffer_Y_Adder
14675
;a=1: return X to ($04)
14676
;a=0: return Y to ($04)
14677
;  ($02) = (y+yadder)&0xf0 - 32
14678
;  ($06..07) = blockbuffer+x
14679
        if Z80OPT
14680
       ld hl,BlockBuffer_X_Adder
14681
       add hl,de
14682
       ld ix,SprObject_X_Position
14683
       add ix,bc
14684
         or a
14685
       jr nz,RetXC                   ;if A = 1, branch
14686
       ld a,(ix+SprObject_Y_Position-SprObject_X_Position) ;ldax SprObject_Y_Position,x  ;if A = 0, load vertical coordinate
14687
       jp RetYC                   ;and jump
14688
RetXC: ld a,(ix+SprObject_X_Position-SprObject_X_Position) ;ldax SprObject_X_Position,x  ;otherwise load horizontal coordinate
14689
RetYC: and ++%00001111              ;and mask out high nybble
14690
       ld (SCRATCHPAD+$04),a                     ;store masked out result here
14691
 
14692
       ld a,(hl) ;lday BlockBuffer_X_Adder,y   ;add horizontal coordinate
14693
       add a,(ix+SprObject_X_Position-SprObject_X_Position) ;adcx SprObject_X_Position,x ;of object to value obtained using Y as offset
14694
       ld l,a ;sta SCRATCHPAD+$05                     ;store here ;   3???
14695
       adc a,(ix+SprObject_PageLoc-SprObject_X_Position) ;adcn ++$00                    ;add carry to page location
14696
       sub l
14697
       rra                         ;move to carry ;xHSB
14698
       ld a,l ;orai SCRATCHPAD+$05                     ;get stored value ;xLSB
14699
        ld hl,Block_Buffer_1
14700
        jr nc,$+5
14701
         ld hl,Block_Buffer_2
14702
       rra
14703
       rra
14704
       rra
14705
       rra
14706
        and 0x0f
14707
        add a,l
14708
        ld l,a
14709
        ;adc a,h
14710
        ;sub l
14711
        ;ld h,a
14712
        ld (SCRATCHPAD+$06),hl ;???
14713
       ld hl,BlockBuffer_Y_Adder
14714
       add hl,de
14715
       ld a,(ix+SprObject_Y_Position-SprObject_X_Position) ;ldax SprObject_Y_Position,x  ;get vertical coordinate of object
14716
       add a,(hl);adcy BlockBuffer_Y_Adder,y   ;add it to value obtained using Y as offset       
14717
       and ++%11110000              ;mask out low nybble
14718
       sub 32               ;subtract 32 pixels for the status bar
14719
       ld (SCRATCHPAD+$02),a                     ;store result here ;???
14720
       ;use as offset for block buffer
14721
        ld hl,(SCRATCHPAD+$06)
14722
        add a,l
14723
        ld l,a
14724
        adc a,h
14725
        sub l
14726
        ld h,a
14727
       ;ld a,(hl) ;ldayindirect (SCRATCHPAD+$06),y                 ;check current content of block buffer
14728
       ;sta SCRATCHPAD+$03                     ;and store here
14729
       ld a,(hl) ;lda SCRATCHPAD+$03                     ;get saved content of block buffer
14730
       ;lda SCRATCHPAD+$03                     ;get saved content of block buffer
14731
        or a
14732
       ret                         ;and leave
14733
 
14734
        else ;~Z80
14735
 
14736
       pha                         ;save contents of A to stack
14737
       sty SCRATCHPAD+$04                     ;save contents of Y here
14738
       lday BlockBuffer_X_Adder,y   ;add horizontal coordinate
14739
       clc                         ;of object to value obtained using Y as offset
14740
       adcx SprObject_X_Position,x
14741
       sta SCRATCHPAD+$05                     ;store here ;   3???
14742
       ldaxkeepcy SprObject_PageLoc,x
14743
       adcn ++$00                    ;add carry to page location
14744
       andn ++$01                    ;get LSB, mask out all other bits
14745
       lsr                         ;move to carry
14746
      push af
14747
       orai SCRATCHPAD+$05                     ;get stored value
14748
      ld h,a
14749
      pop af
14750
      ld a,h
14751
       ror                         ;rotate carry to MSB of A
14752
       lsr                         ;and effectively move high nybble to
14753
       lsr                         ;lower, LSB which became MSB will be
14754
       lsr                         ;d4 at this point
14755
       jsr GetBlockBufferAddr      ;get address of block buffer into $06, $07
14756
       ldy SCRATCHPAD+$04                     ;get old contents of Y
14757
       ldax SprObject_Y_Position,x  ;get vertical coordinate of object
14758
       clc
14759
       adcy BlockBuffer_Y_Adder,y   ;add it to value obtained using Y as offset
14760
       andn ++%11110000              ;mask out low nybble
14761
       secsub
14762
       sbcn ++$20                    ;subtract 32 pixels for the status bar
14763
       sta SCRATCHPAD+$02                     ;store result here
14764
       tay                         ;use as offset for block buffer
14765
       ldayindirect (SCRATCHPAD+$06),y                 ;check current content of block buffer
14766
       sta SCRATCHPAD+$03                     ;and store here
14767
       ldy SCRATCHPAD+$04                     ;get old contents of Y again
14768
       pla                         ;pull A from stack
14769
         checka
14770
       bne RetXC                   ;if A = 1, branch
14771
       ldax SprObject_Y_Position,x  ;if A = 0, load vertical coordinate
14772
       jmp RetYC                   ;and jump
14773
RetXC: ldax SprObject_X_Position,x  ;otherwise load horizontal coordinate
14774
RetYC: andn ++%00001111              ;and mask out high nybble
14775
       sta SCRATCHPAD+$04                     ;store masked out result here
14776
       lda SCRATCHPAD+$03                     ;get saved content of block buffer
14777
        checka
14778
       rts                         ;and leave
14779
        endif
14780
 
14781
;-------------------------------------------------------------------------------------
14782
 
14783
        if Z80==0
14784
;unused byte
14785
      .db $ff
14786
        endif
14787
 
14788
;-------------------------------------------------------------------------------------
14789
;$00 - offset to vine Y coordinate adder
14790
;$02 - offset to sprite data
14791
 
14792
VineYPosAdder:
14793
      .db $00, $30
14794
 
14795
DrawVine:
14796
         sty SCRATCHPAD+$00                    ;save offset here
14797
         lda Enemy_Rel_YPos         ;get relative vertical coordinate
14798
         clc
14799
         adcy VineYPosAdder,y        ;add value using offset in Y to get value
14800
         ldxy VineObjOffset,y        ;get offset to vine
14801
         ldyx Enemy_SprDataOffset,x  ;get sprite data offset
14802
         sty SCRATCHPAD+$02                    ;store sprite data offset here
14803
         jsr SixSpriteStacker       ;stack six sprites on top of each other vertically
14804
         lda Enemy_Rel_XPos         ;get relative horizontal coordinate
14805
         stay Sprite_X_Position,y    ;store in first, third and fifth sprites
14806
         stay Sprite_X_Position+8,y
14807
         stay Sprite_X_Position+16,y
14808
         clc
14809
         adcn ++$06                   ;add six pixels to second, fourth and sixth sprites
14810
         stay Sprite_X_Position+4,y  ;to give characteristic staggered vine shape to
14811
         stay Sprite_X_Position+12,y ;our vertical stack of sprites
14812
         stay Sprite_X_Position+20,y
14813
         ldan ++%00100001             ;set bg priority and palette attribute bits
14814
         stay Sprite_Attributes,y    ;set in first, third and fifth sprites
14815
         stay Sprite_Attributes+8,y
14816
         stay Sprite_Attributes+16,y
14817
         oran ++%01000000             ;additionally, set horizontal flip bit
14818
         stay Sprite_Attributes+4,y  ;for second, fourth and sixth sprites
14819
         stay Sprite_Attributes+12,y
14820
         stay Sprite_Attributes+20,y
14821
         ldxn ++$05                   ;set tiles for six sprites
14822
VineTL:  ldan ++$e1                   ;set tile number for sprite
14823
         stay Sprite_Tilenumber,y
14824
         iny                        ;move offset to next sprite data
14825
         iny
14826
         iny
14827
         iny
14828
         dex                        ;move onto next sprite
14829
         bpl VineTL                 ;loop until all sprites are done
14830
         ldy SCRATCHPAD+$02                    ;get original offset
14831
         lda SCRATCHPAD+$00                    ;get offset to vine adding data
14832
         checka
14833
         bne SkpVTop                ;if offset not zero, skip this part
14834
         ldan ++$e0
14835
         stay Sprite_Tilenumber,y    ;set other tile number for top of vine
14836
SkpVTop: ldxn ++$00                   ;start with the first sprite again
14837
ChkFTop: lda VineStart_Y_Position   ;get original starting vertical coordinate
14838
         secsub
14839
         sbcy Sprite_Y_Position,y    ;subtract top-most sprite's Y coordinate
14840
         cmpn ++$64                   ;if two coordinates are less than 100/$64 pixels
14841
              cmpcy
14842
         bcc NextVSp                ;apart, skip this to leave sprite alone
14843
         ldan ++$f8
14844
         stay Sprite_Y_Position,y    ;otherwise move sprite offscreen
14845
NextVSp: iny                        ;move offset to next OAM data
14846
         iny
14847
         iny
14848
         iny
14849
         inx                        ;move onto next sprite
14850
         cpxn ++$06                   ;do this until all sprites are checked
14851
         bne ChkFTop
14852
         ldy SCRATCHPAD+$00                    ;return offset set earlier
14853
         rts
14854
 
14855
SixSpriteStacker:
14856
       ldxn ++$06           ;do six sprites
14857
StkLp: stay Sprite_Data,y  ;store X or Y coordinate into OAM data
14858
       clc
14859
       adcn ++$08           ;add eight pixels
14860
       iny
14861
       iny                ;move offset four bytes forward
14862
       iny
14863
       iny
14864
       dex                ;do another sprite
14865
       bne StkLp          ;do this until all sprites are done
14866
       ldy SCRATCHPAD+$02            ;get saved OAM data offset and leave
14867
       rts
14868
 
14869
;-------------------------------------------------------------------------------------
14870
 
14871
FirstSprXPos:
14872
      .db $04, $00, $04, $00
14873
 
14874
FirstSprYPos:
14875
      .db $00, $04, $00, $04
14876
 
14877
SecondSprXPos:
14878
      .db $00, $08, $00, $08
14879
 
14880
SecondSprYPos:
14881
      .db $08, $00, $08, $00
14882
 
14883
FirstSprTilenum:
14884
      .db $80, $82, $81, $83
14885
 
14886
SecondSprTilenum:
14887
      .db $81, $83, $80, $82
14888
 
14889
HammerSprAttrib:
14890
      .db $03, $03, $c3, $c3
14891
 
14892
DrawHammer:
14893
            ldyx Misc_SprDataOffset,x    ;get misc object OAM data offset
14894
            lda TimerControl
14895
         checka
14896
            bne ForceHPose              ;if master timer control set, skip this part
14897
            ldax Misc_State,x            ;otherwise get hammer's state
14898
            andn ++%01111111              ;mask out d7
14899
            cmpn ++$01                    ;check to see if set to 1 yet
14900
            beq GetHPose                ;if so, branch
14901
ForceHPose: ldxn ++$00                    ;reset offset here
14902
         checkx
14903
            beq RenderH                 ;do unconditional branch to rendering part
14904
GetHPose:   lda FrameCounter            ;get frame counter
14905
            lsr                         ;move d3-d2 to d1-d0
14906
            lsr
14907
            andn ++%00000011              ;mask out all but d1-d0 (changes every four frames)
14908
            tax                         ;use as timing offset
14909
RenderH:    lda Misc_Rel_YPos           ;get relative vertical coordinate
14910
            clc
14911
            adcx FirstSprYPos,x          ;add first sprite vertical adder based on offset
14912
            stay Sprite_Y_Position,y     ;store as sprite Y coordinate for first sprite
14913
            clc
14914
            adcx SecondSprYPos,x         ;add second sprite vertical adder based on offset
14915
            stay Sprite_Y_Position+4,y   ;store as sprite Y coordinate for second sprite
14916
            lda Misc_Rel_XPos           ;get relative horizontal coordinate
14917
            clc
14918
            adcx FirstSprXPos,x          ;add first sprite horizontal adder based on offset
14919
            stay Sprite_X_Position,y     ;store as sprite X coordinate for first sprite
14920
            clc
14921
            adcx SecondSprXPos,x         ;add second sprite horizontal adder based on offset
14922
            stay Sprite_X_Position+4,y   ;store as sprite X coordinate for second sprite
14923
            ldax FirstSprTilenum,x
14924
            stay Sprite_Tilenumber,y     ;get and store tile number of first sprite
14925
            ldax SecondSprTilenum,x
14926
            stay Sprite_Tilenumber+4,y   ;get and store tile number of second sprite
14927
            ldax HammerSprAttrib,x
14928
            stay Sprite_Attributes,y     ;get and store attribute bytes for both
14929
            stay Sprite_Attributes+4,y   ;note in this case they use the same data
14930
            ldx ObjectOffset            ;get misc object offset
14931
            lda Misc_OffscreenBits
14932
            andn ++%11111100              ;check offscreen bits
14933
            beq NoHOffscr               ;if all bits clear, leave object alone
14934
            ldan ++$00
14935
            stax Misc_State,x            ;otherwise nullify misc object state
14936
            ldan ++$f8
14937
            jsr DumpTwoSpr              ;do sub to move hammer sprites offscreen
14938
NoHOffscr:  rts                         ;leave
14939
 
14940
;-------------------------------------------------------------------------------------
14941
;$00-$01 - used to hold tile numbers ($01 addressed in draw floatey number part)
14942
;$02 - used to hold Y coordinate for floatey number
14943
;$03 - residual byte used for flip (but value set here affects nothing)
14944
;$04 - attribute byte for floatey number
14945
;$05 - used as X coordinate for floatey number
14946
 
14947
FlagpoleScoreNumTiles:
14948
      .db $f9, $50
14949
      .db $f7, $50
14950
      .db $fa, $fb
14951
      .db $f8, $fb
14952
      .db $f6, $fb
14953
 
14954
FlagpoleGfxHandler:
14955
      ldyx Enemy_SprDataOffset,x      ;get sprite data offset for flagpole flag
14956
      lda Enemy_Rel_XPos             ;get relative horizontal coordinate
14957
      stay Sprite_X_Position,y        ;store as X coordinate for first sprite
14958
      clc
14959
      adcn ++$08                       ;add eight pixels and store
14960
      stay Sprite_X_Position+4,y      ;as X coordinate for second and third sprites
14961
      stay Sprite_X_Position+8,y
14962
      clc
14963
      adcn ++$0c                       ;add twelve more pixels and
14964
          push af
14965
      sta SCRATCHPAD+$05                        ;store here to be used later by floatey number
14966
      ldax Enemy_Y_Position,x         ;get vertical coordinate
14967
      jsr DumpTwoSpr                 ;and do sub to dump into first and second sprites
14968
          ld h,a
14969
          pop af
14970
          ld a,h
14971
      adcn ++$08                       ;add eight pixels
14972
      stay Sprite_Y_Position+8,y      ;and store into third sprite
14973
      lda FlagpoleFNum_Y_Pos         ;get vertical coordinate for floatey number
14974
      sta SCRATCHPAD+$02                        ;store it here
14975
      ldan ++$01
14976
      sta SCRATCHPAD+$03                        ;set value for flip which will not be used, and
14977
      sta SCRATCHPAD+$04                        ;attribute byte for floatey number
14978
      stay Sprite_Attributes,y        ;set attribute bytes for all three sprites
14979
      stay Sprite_Attributes+4,y
14980
      stay Sprite_Attributes+8,y
14981
      ldan ++$7e
14982
      stay Sprite_Tilenumber,y        ;put triangle shaped tile
14983
      stay Sprite_Tilenumber+8,y      ;into first and third sprites
14984
      ldan ++$7f
14985
      stay Sprite_Tilenumber+4,y      ;put skull tile into second sprite
14986
      lda FlagpoleCollisionYPos      ;get vertical coordinate at time of collision
14987
         checka
14988
      beq ChkFlagOffscreen           ;if zero, branch ahead
14989
      tya
14990
      clc                            ;add 12 bytes to sprite data offset
14991
      adcn ++$0c
14992
      tay                            ;put back in Y
14993
      lda FlagpoleScore              ;get offset used to award points for touching flagpole
14994
      asl                            ;multiply by 2 to get proper offset here
14995
      tax
14996
        if Z80OPT
14997
      ld hl,FlagpoleScoreNumTiles
14998
      add hl,bc
14999
      call DrawSpriteObject
15000
        else
15001
      ldax FlagpoleScoreNumTiles,x    ;get appropriate tile data
15002
      sta SCRATCHPAD+$00
15003
      ldax FlagpoleScoreNumTiles+1,x
15004
      jsr DrawOneSpriteRow           ;use it to render floatey number
15005
        endif
15006
 
15007
ChkFlagOffscreen:
15008
      ldx ObjectOffset               ;get object offset for flag
15009
      ldyx Enemy_SprDataOffset,x      ;get OAM data offset
15010
      lda Enemy_OffscreenBits        ;get offscreen bits
15011
      andn ++%00001110                 ;mask out all but d3-d1
15012
      beq ExitDumpSpr                ;if none of these bits set, branch to leave
15013
 
15014
;-------------------------------------------------------------------------------------
15015
 
15016
MoveSixSpritesOffscreen:
15017
      ldan ++$f8                  ;set offscreen coordinate if jumping here
15018
 
15019
DumpSixSpr:
15020
      stay Sprite_Data+20,y      ;dump A contents
15021
      stay Sprite_Data+16,y      ;into third row sprites
15022
 
15023
DumpFourSpr:
15024
      stay Sprite_Data+12,y      ;into second row sprites
15025
 
15026
DumpThreeSpr:
15027
      stay Sprite_Data+8,y
15028
 
15029
DumpTwoSpr:
15030
      stay Sprite_Data+4,y       ;and into first row sprites
15031
      stay Sprite_Data,y
15032
 
15033
ExitDumpSpr:
15034
      rts
15035
 
15036
;-------------------------------------------------------------------------------------
15037
 
15038
DrawLargePlatform:
15039
      ldyx Enemy_SprDataOffset,x   ;get OAM data offset
15040
      sty SCRATCHPAD+$02                     ;store here
15041
      iny                         ;add 3 to it for offset
15042
      iny                         ;to X coordinate
15043
      iny
15044
      lda Enemy_Rel_XPos          ;get horizontal relative coordinate
15045
      jsr SixSpriteStacker        ;store X coordinates using A as base, stack horizontally
15046
      ldx ObjectOffset
15047
      ldax Enemy_Y_Position,x      ;get vertical coordinate
15048
      jsr DumpFourSpr             ;dump into first four sprites as Y coordinate
15049
      ldy AreaType
15050
      cpyn ++$03                    ;check for castle-type level
15051
      beq ShrinkPlatform
15052
      ldy SecondaryHardMode       ;check for secondary hard mode flag set
15053
         checky
15054
      beq SetLast2Platform        ;branch if not set elsewhere
15055
 
15056
ShrinkPlatform:
15057
      ldan ++$f8                    ;load offscreen coordinate if flag set or castle-type level
15058
 
15059
SetLast2Platform:
15060
      ldyx Enemy_SprDataOffset,x   ;get OAM data offset
15061
      stay Sprite_Y_Position+16,y  ;store vertical coordinate or offscreen
15062
      stay Sprite_Y_Position+20,y  ;coordinate into last two sprites as Y coordinate
15063
      ldan ++$5b                    ;load default tile for platform (girder)
15064
      ldx CloudTypeOverride
15065
         checkx
15066
      beq SetPlatformTilenum      ;if cloud level override flag not set, use
15067
      ldan ++$75                    ;otherwise load other tile for platform (puff)
15068
 
15069
SetPlatformTilenum:
15070
;TODO  rla:jr nc,$+5;ld (ix),L
15071
        ldx ObjectOffset            ;get enemy object buffer offset
15072
        iny                         ;increment Y for tile offset
15073
        jsr DumpSixSpr              ;dump tile number into all six sprites
15074
        ldan ++$02                    ;set palette controls
15075
        iny                         ;increment Y for sprite attributes
15076
        jsr DumpSixSpr              ;dump attributes into all six sprites
15077
        if Z80OPT
15078
        push bc
15079
      inc c                        ;increment X to get the proper offset
15080
      call GetXOffscreenBits      ;then jump directly to the sub for horizontal offscreen bits
15081
        pop bc                   ;decrement to return to original offset
15082
        else
15083
        inx                         ;increment X for enemy objects
15084
        jsr GetXOffscreenBits       ;get offscreen bits again
15085
        dex
15086
        endif
15087
        ldyx Enemy_SprDataOffset,x   ;get OAM data offset
15088
        asl                         ;rotate d7 into carry, save remaining ;TODO >>4  GetXOffscreenBits
15089
        pha                         ;bits to the stack
15090
        bcc SChk2
15091
        ldan ++$f8                    ;if d7 was set, move first sprite offscreen
15092
        stay Sprite_Y_Position,y
15093
SChk2:  pla                         ;get bits from stack
15094
        asl                         ;rotate d6 into carry ;TODO >>4  GetXOffscreenBits
15095
        pha                         ;save to stack
15096
        bcc SChk3
15097
        ldan ++$f8                    ;if d6 was set, move second sprite offscreen
15098
        stay Sprite_Y_Position+4,y
15099
SChk3:  pla                         ;get bits from stack
15100
        asl                         ;rotate d5 into carry ;TODO >>4  GetXOffscreenBits
15101
        pha                         ;save to stack
15102
        bcc SChk4
15103
        ldan ++$f8                    ;if d5 was set, move third sprite offscreen
15104
        stay Sprite_Y_Position+8,y
15105
SChk4:  pla                         ;get bits from stack
15106
        asl                         ;rotate d4 into carry ;TODO >>4  GetXOffscreenBits
15107
        pha                         ;save to stack
15108
        bcc SChk5
15109
        ldan ++$f8                    ;if d4 was set, move fourth sprite offscreen
15110
        stay Sprite_Y_Position+12,y
15111
SChk5:  pla                         ;get bits from stack
15112
        asl                         ;rotate d3 into carry ;???
15113
        pha                         ;save to stack
15114
        bcc SChk6
15115
        ldan ++$f8                    ;if d3 was set, move fifth sprite offscreen
15116
        stay Sprite_Y_Position+16,y
15117
SChk6:  pla                         ;get bits from stack
15118
        asl                         ;rotate d2 into carry ;???
15119
        bcc SLChk                   ;save to stack
15120
        ldan ++$f8
15121
        stay Sprite_Y_Position+20,y  ;if d2 was set, move sixth sprite offscreen
15122
SLChk:  lda Enemy_OffscreenBits     ;check d7 of offscreen bits
15123
        asl                         ;and if d7 is not set, skip sub
15124
        bcc ExDLPl
15125
        jsr MoveSixSpritesOffscreen ;otherwise branch to move all sprites offscreen
15126
ExDLPl: rts
15127
 
15128
;-------------------------------------------------------------------------------------
15129
 
15130
DrawFloateyNumber_Coin:
15131
          lda FrameCounter          ;get frame counter
15132
          lsr                       ;divide by 2
15133
          bcs NotRsNum              ;branch if d0 not set to raise number every other frame
15134
          decx Misc_Y_Position,x     ;otherwise, decrement vertical coordinate
15135
NotRsNum: ldax Misc_Y_Position,x     ;get vertical coordinate
15136
          jsr DumpTwoSpr            ;dump into both sprites
15137
          lda Misc_Rel_XPos         ;get relative horizontal coordinate
15138
          stay Sprite_X_Position,y   ;store as X coordinate for first sprite
15139
          clc
15140
          adcn ++$08                  ;add eight pixels
15141
          stay Sprite_X_Position+4,y ;store as X coordinate for second sprite
15142
          ldan ++$02
15143
          stay Sprite_Attributes,y   ;store attribute byte in both sprites
15144
          stay Sprite_Attributes+4,y
15145
          ldan ++$f7
15146
          stay Sprite_Tilenumber,y   ;put tile numbers into both sprites
15147
          ldan ++$fb                  ;that resemble "200"
15148
          stay Sprite_Tilenumber+4,y
15149
          jmp ExJCGfx               ;then jump to leave (why not an rts here instead?)
15150
 
15151
JumpingCoinTiles:
15152
      .db $60, $61, $62, $63
15153
 
15154
JCoinGfxHandler:
15155
         ldyx Misc_SprDataOffset,x    ;get coin/floatey number's OAM data offset
15156
         ldax Misc_State,x            ;get state of misc object
15157
         cmpn ++$02                    ;if 2 or greater, 
15158
              cmpcy
15159
         bcs DrawFloateyNumber_Coin  ;branch to draw floatey number
15160
         ldax Misc_Y_Position,x       ;store vertical coordinate as
15161
         stay Sprite_Y_Position,y     ;Y coordinate for first sprite
15162
         clc
15163
         adcn ++$08                    ;add eight pixels
15164
         stay Sprite_Y_Position+4,y   ;store as Y coordinate for second sprite
15165
         lda Misc_Rel_XPos           ;get relative horizontal coordinate
15166
         stay Sprite_X_Position,y
15167
         stay Sprite_X_Position+4,y   ;store as X coordinate for first and second sprites
15168
         lda FrameCounter            ;get frame counter
15169
         lsr                         ;divide by 2 to alter every other frame
15170
         andn ++%00000011              ;mask out d2-d1
15171
         tax                         ;use as graphical offset
15172
         ldax JumpingCoinTiles,x      ;load tile number
15173
         iny                         ;increment OAM data offset to write tile numbers
15174
         jsr DumpTwoSpr              ;do sub to dump tile number into both sprites
15175
         dey                         ;decrement to get old offset
15176
         ldan ++$02
15177
         stay Sprite_Attributes,y     ;set attribute byte in first sprite
15178
         ldan ++$82
15179
         stay Sprite_Attributes+4,y   ;set attribute byte with vertical flip in second sprite
15180
         ldx ObjectOffset            ;get misc object offset
15181
ExJCGfx: rts                         ;leave
15182
 
15183
;-------------------------------------------------------------------------------------
15184
;$00-$01 - used to hold tiles for drawing the power-up, $00 also used to hold power-up type
15185
;$02 - used to hold bottom row Y position
15186
;$03 - used to hold flip control (not used here)
15187
;$04 - used to hold sprite attributes
15188
;$05 - used to hold X position
15189
;$07 - counter
15190
 
15191
;tiles arranged in top left, right, bottom left, right order
15192
PowerUpGfxTable:
15193
      .db $76, $77, $78, $79 ;regular mushroom
15194
      .db $d6, $d6, $d9, $d9 ;fire flower
15195
      .db $8d, $8d, $e4, $e4 ;star
15196
      .db $76, $77, $78, $79 ;1-up mushroom
15197
 
15198
PowerUpAttributes:
15199
      .db $02, $01, $02, $01
15200
 
15201
DrawPowerUp:
15202
      ldy Enemy_SprDataOffset+5  ;get power-up's sprite data offset
15203
      lda Enemy_Rel_YPos         ;get relative vertical coordinate
15204
      clc
15205
      adcn ++$08                   ;add eight pixels
15206
      sta SCRATCHPAD+$02                    ;store result here
15207
      lda Enemy_Rel_XPos         ;get relative horizontal coordinate
15208
      sta SCRATCHPAD+$05                    ;store here
15209
      ldx PowerUpType            ;get power-up type
15210
      ldax PowerUpAttributes,x    ;get attribute data for power-up type
15211
      orai Enemy_SprAttrib+5      ;add background priority bit if set
15212
      sta SCRATCHPAD+$04                    ;store attributes here
15213
      txa
15214
      pha                        ;save power-up type to the stack
15215
      asl
15216
      asl                        ;multiply by four to get proper offset
15217
      tax                        ;use as X
15218
      ldan ++$01
15219
        if Z80OPT
15220
      ;ld (SCRATCHPAD+$07),a                    ;set counter here to draw two rows of sprite object
15221
      ld (SCRATCHPAD+$03),a                    ;init d1 of flip control
15222
      ld hl,PowerUpGfxTable
15223
      add hl,bc
15224
      call DrawSpriteObject
15225
      call DrawSpriteObject
15226
        else
15227
      sta SCRATCHPAD+$07                    ;set counter here to draw two rows of sprite object
15228
      sta SCRATCHPAD+$03                    ;init d1 of flip control
15229
PUpDrawLoop0
15230
        ldax PowerUpGfxTable,x      ;load left tile of power-up object
15231
        sta SCRATCHPAD+$00
15232
        ldax PowerUpGfxTable+1,x    ;load right tile
15233
        jsr DrawOneSpriteRow       ;branch to draw one row of our power-up object
15234
        deci SCRATCHPAD+$07                    ;decrement counter
15235
        bpl PUpDrawLoop0            ;branch until two rows are drawn
15236
        endif
15237
        ldy Enemy_SprDataOffset+5  ;get sprite data offset again
15238
        pla                        ;pull saved power-up type from the stack
15239
         checka
15240
        beq PUpOfs                 ;if regular mushroom, branch, do not change colors or flip
15241
        cmpn ++$03
15242
        beq PUpOfs                 ;if 1-up mushroom, branch, do not change colors or flip
15243
        sta SCRATCHPAD+$00                    ;store power-up type here now
15244
        lda FrameCounter           ;get frame counter
15245
        lsr                        ;divide by 2 to change colors every two frames
15246
        andn ++%00000011             ;mask out all but d1 and d0 (previously d2 and d1)
15247
        orai Enemy_SprAttrib+5      ;add background priority bit if any set
15248
        stay Sprite_Attributes,y    ;set as new palette bits for top left and
15249
        stay Sprite_Attributes+4,y  ;top right sprites for fire flower and star
15250
        ldx SCRATCHPAD+$00
15251
        dex                        ;check power-up type for fire flower
15252
        beq FlipPUpRightSide       ;if found, skip this part
15253
        stay Sprite_Attributes+8,y  ;otherwise set new palette bits  for bottom left
15254
        stay Sprite_Attributes+12,y ;and bottom right sprites as well for star only
15255
 
15256
FlipPUpRightSide:
15257
        lday Sprite_Attributes+4,y
15258
        oran ++%01000000             ;set horizontal flip bit for top right sprite
15259
        stay Sprite_Attributes+4,y
15260
        lday Sprite_Attributes+12,y
15261
        oran ++%01000000             ;set horizontal flip bit for bottom right sprite
15262
        stay Sprite_Attributes+12,y ;note these are only done for fire flower and star power-ups
15263
PUpOfs: jmp SprObjectOffscrChk     ;jump to check to see if power-up is offscreen at all, then leave
15264
 
15265
;-------------------------------------------------------------------------------------
15266
;$00-$01 - used in DrawEnemyObjRow to hold sprite tile numbers
15267
;$02 - used to store Y position
15268
;$03 - used to store moving direction, used to flip enemies horizontally
15269
;$04 - used to store enemy's sprite attributes
15270
;$05 - used to store X position
15271
;$eb - used to hold sprite data offset
15272
;$ec - used to hold either altered enemy state or special value used in gfx handler as condition
15273
;$ed - used to hold enemy state from buffer 
15274
;$ef - used to hold enemy code used in gfx handler (may or may not resemble Enemy_ID values)
15275
 
15276
;tiles arranged in top left, right, middle left, right, bottom left, right order
15277
EnemyGraphicsTable:
15278
      .db $fc, $fc, $aa, $ab, $ac, $ad  ;buzzy beetle frame 1
15279
      .db $fc, $fc, $ae, $af, $b0, $b1  ;             frame 2
15280
      .db $fc, $a5, $a6, $a7, $a8, $a9  ;koopa troopa frame 1
15281
      .db $fc, $a0, $a1, $a2, $a3, $a4  ;             frame 2
15282
      .db $69, $a5, $6a, $a7, $a8, $a9  ;koopa paratroopa frame 1
15283
      .db $6b, $a0, $6c, $a2, $a3, $a4  ;                 frame 2
15284
      .db $fc, $fc, $96, $97, $98, $99  ;spiny frame 1
15285
      .db $fc, $fc, $9a, $9b, $9c, $9d  ;      frame 2
15286
      .db $fc, $fc, $8f, $8e, $8e, $8f  ;spiny's egg frame 1
15287
      .db $fc, $fc, $95, $94, $94, $95  ;            frame 2
15288
      .db $fc, $fc, $dc, $dc, $df, $df  ;bloober frame 1
15289
      .db $dc, $dc, $dd, $dd, $de, $de  ;        frame 2
15290
      .db $fc, $fc, $b2, $b3, $b4, $b5  ;cheep-cheep frame 1
15291
      .db $fc, $fc, $b6, $b3, $b7, $b5  ;            frame 2
15292
      .db $fc, $fc, $70, $71, $72, $73  ;goomba
15293
      .db $fc, $fc, $6e, $6e, $6f, $6f  ;koopa shell frame 1 (upside-down)
15294
      .db $fc, $fc, $6d, $6d, $6f, $6f  ;            frame 2
15295
      .db $fc, $fc, $6f, $6f, $6e, $6e  ;koopa shell frame 1 (rightsideup)
15296
      .db $fc, $fc, $6f, $6f, $6d, $6d  ;            frame 2
15297
      .db $fc, $fc, $f4, $f4, $f5, $f5  ;buzzy beetle shell frame 1 (rightsideup)
15298
      .db $fc, $fc, $f4, $f4, $f5, $f5  ;                   frame 2
15299
      .db $fc, $fc, $f5, $f5, $f4, $f4  ;buzzy beetle shell frame 1 (upside-down)
15300
      .db $fc, $fc, $f5, $f5, $f4, $f4  ;                   frame 2
15301
      .db $fc, $fc, $fc, $fc, $ef, $ef  ;defeated goomba
15302
      .db $b9, $b8, $bb, $ba, $bc, $bc  ;lakitu frame 1
15303
      .db $fc, $fc, $bd, $bd, $bc, $bc  ;       frame 2
15304
      .db $7a, $7b, $da, $db, $d8, $d8  ;princess
15305
      .db $cd, $cd, $ce, $ce, $cf, $cf  ;mushroom retainer
15306
      .db $7d, $7c, $d1, $8c, $d3, $d2  ;hammer bro frame 1
15307
      .db $7d, $7c, $89, $88, $8b, $8a  ;           frame 2
15308
      .db $d5, $d4, $e3, $e2, $d3, $d2  ;           frame 3
15309
      .db $d5, $d4, $e3, $e2, $8b, $8a  ;           frame 4
15310
      .db $e5, $e5, $e6, $e6, $eb, $eb  ;piranha plant frame 1
15311
      .db $ec, $ec, $ed, $ed, $ee, $ee  ;              frame 2
15312
      .db $fc, $fc, $d0, $d0, $d7, $d7  ;podoboo
15313
      .db $bf, $be, $c1, $c0, $c2, $fc  ;bowser front frame 1
15314
      .db $c4, $c3, $c6, $c5, $c8, $c7  ;bowser rear frame 1
15315
      .db $bf, $be, $ca, $c9, $c2, $fc  ;       front frame 2
15316
      .db $c4, $c3, $c6, $c5, $cc, $cb  ;       rear frame 2
15317
      .db $fc, $fc, $e8, $e7, $ea, $e9  ;bullet bill
15318
      .db $f2, $f2, $f3, $f3, $f2, $f2  ;jumpspring frame 1
15319
      .db $f1, $f1, $f1, $f1, $fc, $fc  ;           frame 2
15320
      .db $f0, $f0, $fc, $fc, $fc, $fc  ;           frame 3
15321
 
15322
EnemyGfxTableOffsets:
15323
      .db $0c, $0c, $00, $0c, $0c, $a8, $54, $3c
15324
      .db $ea, $18, $48, $48, $cc, $c0, $18, $18
15325
      .db $18, $90, $24, $ff, $48, $9c, $d2, $d8
15326
      .db $f0, $f6, $fc
15327
 
15328
EnemyAttributeData:
15329
      .db $01, $02, $03, $02, $01, $01, $03, $03
15330
      .db $03, $01, $01, $02, $02, $21, $01, $02
15331
      .db $01, $01, $02, $ff, $02, $02, $01, $01
15332
      .db $02, $02, $02
15333
 
15334
EnemyAnimTimingBMask:
15335
      .db $08, $18
15336
 
15337
JumpspringFrameOffsets:
15338
      .db $18, $19, $1a, $19, $18
15339
 
15340
EnemyGfxHandler:
15341
;TODO           ,  
15342
      ldax Enemy_Y_Position,x      ;get enemy object vertical position
15343
      sta SCRATCHPAD+$02
15344
      lda Enemy_Rel_XPos          ;get enemy object horizontal position
15345
      sta SCRATCHPAD+$05                     ;relative to screen
15346
      ldyx Enemy_SprDataOffset,x
15347
      sty SCRATCHPAD+$eb                     ;get sprite data offset
15348
      ldan ++$00
15349
      sta VerticalFlipFlag        ;initialize vertical flip flag by default
15350
      ldax Enemy_MovingDir,x
15351
      sta SCRATCHPAD+$03                     ;get enemy object moving direction
15352
      ldax Enemy_SprAttrib,x
15353
      sta SCRATCHPAD+$04                     ;get enemy object sprite attributes
15354
      ldax Enemy_ID,x
15355
 
15356
      cmpn ++PiranhaPlant           ;is enemy object piranha plant?
15357
     bne CheckForRetainerObj     ;if not, branch
15358
      ldyx PiranhaPlant_Y_Speed,x
15359
         checky
15360
     bmi CheckForRetainerObj     ;if piranha plant moving upwards, branch
15361
      ldyx EnemyFrameTimer,x
15362
         checky
15363
     beq CheckForRetainerObj     ;if timer for movement expired, branch
15364
      rts                         ;if all conditions fail, leave
15365
 
15366
CheckForRetainerObj:
15367
      ldax Enemy_State,x           ;store enemy state
15368
      sta SCRATCHPAD+$ed
15369
      andn ++%00011111              ;nullify all but 5 LSB and use as Y
15370
      tay
15371
      ldax Enemy_ID,x              ;check for mushroom retainer/princess object
15372
      cmpn ++RetainerObject
15373
     bne CheckForBulletBillCV    ;if not found, branch
15374
      ldyn ++$00                    ;if found, nullify saved state in Y
15375
      ldan ++$01                    ;set value that will not be used
15376
      sta SCRATCHPAD+$03
15377
      ldan ++$15                    ;set value $15 as code for mushroom retainer/princess object
15378
 
15379
CheckForBulletBillCV:
15380
       cmpn ++BulletBill_CannonVar   ;otherwise check for bullet bill object
15381
      bne CheckForJumpspring      ;if not found, branch again
15382
       deci SCRATCHPAD+$02                     ;decrement saved vertical position
15383
       ldan ++$03
15384
       ldyx EnemyFrameTimer,x       ;get timer for enemy object
15385
         checky
15386
       beq SBBAt                   ;if expired, do not set priority bit
15387
       oran ++%00100000              ;otherwise do so
15388
SBBAt: sta SCRATCHPAD+$04                     ;set new sprite attributes
15389
       ldyn ++$00                    ;nullify saved enemy state both in Y and in
15390
       sty SCRATCHPAD+$ed                     ;memory location here
15391
       ldan ++$08                    ;set specific value to unconditionally branch once
15392
 
15393
CheckForJumpspring:
15394
      cmpn ++JumpspringObject        ;check for jumpspring object
15395
     bne CheckForPodoboo
15396
      ldyn ++$03                     ;set enemy state -2 MSB here for jumpspring object
15397
      ldx JumpspringAnimCtrl       ;get current frame number for jumpspring object
15398
      ldax JumpspringFrameOffsets,x ;load data using frame number as offset
15399
 
15400
CheckForPodoboo:
15401
      sta SCRATCHPAD+$ef                 ;store saved enemy object value here
15402
      sty SCRATCHPAD+$ec                 ;and Y here (enemy state -2 MSB if not changed)
15403
      ldx ObjectOffset        ;get enemy object offset
15404
      cmpn ++$0c                ;check for podoboo object
15405
     bne CheckBowserGfxFlag  ;branch if not found
15406
      ldax Enemy_Y_Speed,x     ;if moving upwards, branch
15407
         checka
15408
     bmi CheckBowserGfxFlag
15409
      inci VerticalFlipFlag    ;otherwise, set flag for vertical flip
15410
 
15411
CheckBowserGfxFlag:
15412
             lda BowserGfxFlag   ;if not drawing bowser at all, skip to something else
15413
         checka
15414
      beq CheckForGoomba
15415
             ldyn ++$16            ;if set to 1, draw bowser's front
15416
             cmpn ++$01
15417
             beq SBwsrGfxOfs
15418
             iny                 ;otherwise draw bowser's rear
15419
SBwsrGfxOfs: sty SCRATCHPAD+$ef
15420
 
15421
CheckForGoomba:
15422
; 485t
15423
          ldy SCRATCHPAD+$ef               ;check value for goomba object
15424
          cpyn ++Goomba
15425
       bne CheckBowserFront  ;branch if not found
15426
          ldax Enemy_State,x
15427
          cmpn ++$02              ;check for defeated state
15428
              cmpcy
15429
          bcc GmbaAnim          ;if not defeated, go ahead and animate
15430
          ldxn ++$04              ;if defeated, write new value here
15431
          stx SCRATCHPAD+$ec
15432
GmbaAnim: andn ++%00100000        ;check for d5 set in enemy object state 
15433
          orai TimerControl      ;or timer disable flag set
15434
        bne CheckBowserFront  ;if either condition true, do not animate goomba
15435
          lda FrameCounter
15436
          andn ++%00001000        ;check for every eighth frame
15437
        bne CheckBowserFront
15438
          lda SCRATCHPAD+$03
15439
          eorn ++%00000011        ;invert bits to flip horizontally every eight frames
15440
          sta SCRATCHPAD+$03               ;leave alone otherwise
15441
 
15442
CheckBowserFront:
15443
             lday EnemyAttributeData,y    ;load sprite attribute using enemy object
15444
             orai SCRATCHPAD+$04                     ;as offset, and add to bits already loaded
15445
             sta SCRATCHPAD+$04
15446
             lday EnemyGfxTableOffsets,y  ;load value based on enemy object as offset
15447
             tax                         ;save as X
15448
             ldy SCRATCHPAD+$ec                     ;get previously saved value
15449
             lda BowserGfxFlag
15450
         checka
15451
       beq CheckForSpiny           ;if not drawing bowser object at all, skip all of this
15452
             cmpn ++$01
15453
             bne CheckBowserRear         ;if not drawing front part, branch to draw the rear part
15454
             lda BowserBodyControls      ;check bowser's body control bits
15455
         checka
15456
             bpl ChkFrontSte             ;branch if d7 not set (control's bowser's mouth)      
15457
             ldxn ++$de                    ;otherwise load offset for second frame
15458
ChkFrontSte: lda SCRATCHPAD+$ed                     ;check saved enemy state
15459
             andn ++%00100000              ;if bowser not defeated, do not set flag
15460
             beq DrawBowser
15461
 
15462
FlipBowserOver:
15463
      stx VerticalFlipFlag  ;set vertical flip flag to nonzero
15464
 
15465
DrawBowser:
15466
      jmp DrawEnemyObject   ;draw bowser's graphics now
15467
 
15468
CheckBowserRear:
15469
            lda BowserBodyControls  ;check bowser's body control bits
15470
            andn ++$01
15471
            beq ChkRearSte          ;branch if d0 not set (control's bowser's feet)
15472
            ldxn ++$e4                ;otherwise load offset for second frame
15473
ChkRearSte: lda SCRATCHPAD+$ed                 ;check saved enemy state
15474
            andn ++%00100000          ;if bowser not defeated, do not set flag
15475
            beq DrawBowser
15476
            lda SCRATCHPAD+$02                 ;subtract 16 pixels from
15477
            secsub                     ;saved vertical coordinate
15478
            sbcn ++$10
15479
            sta SCRATCHPAD+$02
15480
            jmp FlipBowserOver      ;jump to set vertical flip flag
15481
 
15482
CheckForSpiny:
15483
        cpxn ++$24               ;check if value loaded is for spiny
15484
       bne CheckForLakitu     ;if not found, branch
15485
        cpyn ++$05               ;if enemy state set to $05, do this,
15486
        bne NotEgg             ;otherwise branch
15487
        ldxn ++$30               ;set to spiny egg offset
15488
        ldan ++$02
15489
        sta SCRATCHPAD+$03                ;set enemy direction to reverse sprites horizontally
15490
        ldan ++$05
15491
        sta SCRATCHPAD+$ec                ;set enemy state
15492
NotEgg: jmp CheckForHammerBro  ;skip a big chunk of this if we found spiny but not in egg
15493
 
15494
CheckForLakitu:
15495
        cpxn ++$90                  ;check value for lakitu's offset loaded
15496
       bne CheckUpsideDownShell  ;branch if not loaded
15497
        lda SCRATCHPAD+$ed
15498
        andn ++%00100000            ;check for d5 set in enemy state
15499
        bne NoLAFr                ;branch if set
15500
        lda FrenzyEnemyTimer
15501
        cmpn ++$10                  ;check timer to see if we've reached a certain range
15502
              cmpcy
15503
        bcs NoLAFr                ;branch if not
15504
        ldxn ++$96                  ;if d6 not set and timer in range, load alt frame for lakitu
15505
NoLAFr: jmp CheckDefeatedState    ;skip this next part if we found lakitu but alt frame not needed
15506
 
15507
CheckUpsideDownShell:
15508
      lda SCRATCHPAD+$ef                    ;check for enemy object => $04
15509
      cmpn ++$04
15510
              cmpcy
15511
     bcs CheckRightSideUpShell  ;branch if true
15512
      cpyn ++$02
15513
              cmpcy
15514
     bcc CheckRightSideUpShell  ;branch if enemy state < $02
15515
      ldxn ++$5a                   ;set for upside-down koopa shell by default
15516
      ldy SCRATCHPAD+$ef
15517
      cpyn ++BuzzyBeetle           ;check for buzzy beetle object
15518
     bne CheckRightSideUpShell
15519
      ldxn ++$7e                   ;set for upside-down buzzy beetle shell if found
15520
      inci SCRATCHPAD+$02                    ;increment vertical position by one pixel
15521
 
15522
CheckRightSideUpShell:
15523
      lda SCRATCHPAD+$ec                ;check for value set here
15524
      cmpn ++$04               ;if enemy state < $02, do not change to shell, if
15525
     bne CheckForHammerBro  ;enemy state => $02 but not = $04, leave shell upside-down
15526
      ldxn ++$72               ;set right-side up buzzy beetle shell by default
15527
      inci SCRATCHPAD+$02                ;increment saved vertical position by one pixel
15528
      ldy SCRATCHPAD+$ef
15529
      cpyn ++BuzzyBeetle       ;check for buzzy beetle object
15530
     beq CheckForDefdGoomba ;branch if found
15531
      ldxn ++$66               ;change to right-side up koopa shell if not found
15532
      inci SCRATCHPAD+$02                ;and increment saved vertical position again
15533
 
15534
CheckForDefdGoomba:
15535
      cpyn ++Goomba            ;check for goomba object (necessary if previously
15536
     bne CheckForHammerBro  ;failed buzzy beetle object test)
15537
      ldxn ++$54               ;load for regular goomba
174 demige 15538
      lda SCRATCHPAD+$ed                ;note that this only gets performed if enemy state => $02
171 demige 15539
      andn ++%00100000         ;check saved enemy state for d5 set
15540
     bne CheckForHammerBro  ;branch if set
15541
      ldxn ++$8a               ;load offset for defeated goomba
15542
      deci SCRATCHPAD+$02                ;set different value and decrement saved vertical position
15543
 
15544
CheckForHammerBro:
15545
      ldy ObjectOffset
15546
      lda SCRATCHPAD+$ef                  ;check for hammer bro object
15547
      cmpn ++HammerBro
15548
     bne CheckForBloober      ;branch if not found
15549
      lda SCRATCHPAD+$ed
15550
         checka
15551
     beq CheckToAnimateEnemy  ;branch if not in normal enemy state
15552
      andn ++%00001000
15553
     beq CheckDefeatedState   ;if d3 not set, branch further away
15554
      ldxn ++$b4                 ;otherwise load offset for different frame
15555
         checkx
15556
     bne CheckToAnimateEnemy  ;unconditional branch
15557
 
15558
CheckForBloober:
15559
      cpxn ++$48                 ;check for cheep-cheep offset loaded
15560
     beq CheckToAnimateEnemy  ;branch if found
15561
      lday EnemyIntervalTimer,y
15562
      cmpn ++$05
15563
              cmpcy
15564
     bcs CheckDefeatedState   ;branch if some timer is above a certain point
15565
      cpxn ++$3c                 ;check for bloober offset loaded
15566
     bne CheckToAnimateEnemy  ;branch if not found this time
15567
      cmpn ++$01
15568
     beq CheckDefeatedState   ;branch if timer is set to certain point
15569
      inci SCRATCHPAD+$02                  ;increment saved vertical coordinate three pixels
15570
      inci SCRATCHPAD+$02
15571
      inci SCRATCHPAD+$02
15572
      jmp CheckAnimationStop   ;and do something else
15573
 
15574
CheckToAnimateEnemy:
15575
      lda SCRATCHPAD+$ef                  ;check for specific enemy objects
15576
      cmpn ++Goomba
15577
     beq CheckDefeatedState   ;branch if goomba
15578
      cmpn ++$08
15579
     beq CheckDefeatedState   ;branch if bullet bill (note both variants use $08 here)
15580
      cmpn ++Podoboo
15581
     beq CheckDefeatedState   ;branch if podoboo
15582
      cmpn ++$18                 ;branch if => $18
15583
              cmpcy
15584
      bcs CheckDefeatedState
15585
      ldyn ++$00    
15586
      cmpn ++$15                 ;check for mushroom retainer/princess object
15587
       ;jr $
15588
      bne CheckForSecondFrame  ;which uses different code here, branch if not found
15589
      iny                      ;residual instruction
15590
      lda WorldNumber          ;are we on world 8?
15591
      cmpn ++World8
15592
              cmpcy
180 demige 15593
        if ALWAYSPRINCESS
15594
        scf
15595
        endif
171 demige 15596
      bcs CheckDefeatedState   ;if so, leave the offset alone (use princess)
15597
      ldxn ++$a2                 ;otherwise, set for mushroom retainer object instead
15598
      ldan ++$03                 ;set alternate state here
15599
      sta SCRATCHPAD+$ec
15600
         checka
15601
      bne CheckDefeatedState   ;unconditional branch
15602
 
15603
CheckForSecondFrame:
15604
      lda FrameCounter            ;load frame counter
15605
      andy EnemyAnimTimingBMask,y  ;mask it (partly residual, one byte not ever used)
15606
      bne CheckDefeatedState      ;branch if timing is off
15607
 
15608
CheckAnimationStop:
15609
      lda SCRATCHPAD+$ed                 ;check saved enemy state
15610
      andn ++%10100000          ;for d7 or d5, or check for timers stopped
15611
      orai TimerControl
15612
      bne CheckDefeatedState  ;if either condition true, branch
15613
      txa
15614
      clc
15615
      adcn ++$06                ;add $06 to current enemy offset
15616
      tax                     ;to animate various enemy objects
15617
 
15618
CheckDefeatedState:
15619
      lda SCRATCHPAD+$ed               ;check saved enemy state
15620
      andn ++%00100000        ;for d5 set
15621
     beq DrawEnemyObject   ;branch if not set
15622
      lda SCRATCHPAD+$ef
15623
      cmpn ++$04              ;check for saved enemy object => $04
15624
              cmpcy
15625
     bcc DrawEnemyObject   ;branch if less
15626
      ldyn ++$01
15627
      sty VerticalFlipFlag  ;set vertical flip flag
15628
      dey
15629
      sty SCRATCHPAD+$ec               ;init saved value here
15630
 
15631
DrawEnemyObject:
15632
; 1118t (  )
15633
      ldy SCRATCHPAD+$eb                    ;load sprite data offset
15634
        if Z80OPT
15635
        ld hl,EnemyGraphicsTable
15636
        add hl,bc
15637
        call DrawSpriteObject ;360t
15638
        call DrawSpriteObject ;360t
15639
        call DrawSpriteObject ;360t
15640
        else
15641
      jsr DrawEnemyObjRow        ;draw six tiles of data
15642
      jsr DrawEnemyObjRow        ;into sprite data
15643
      jsr DrawEnemyObjRow
15644
        endif
15645
;   1030t ( Goomba)/604t ()
15646
      ldx ObjectOffset           ;get enemy object offset
15647
      ldyx Enemy_SprDataOffset,x  ;get sprite data offset
15648
      lda SCRATCHPAD+$ef
15649
      cmpn ++$08                   ;get saved enemy object and check
15650
      bne CheckForVerticalFlip   ;for bullet bill, branch if not found
15651
 
15652
SkipToOffScrChk:
15653
      jmp SprObjectOffscrChk     ;jump if found
15654
 
15655
CheckForVerticalFlip:
15656
      lda VerticalFlipFlag       ;check if vertical flip flag is set here
15657
         checka
15658
      beq CheckForESymmetry      ;branch if not
15659
      lday Sprite_Attributes,y    ;get attributes of first sprite we dealt with
15660
      oran ++%10000000             ;set bit for vertical flip
15661
      iny
15662
      iny                        ;increment two bytes so that we store the vertical flip
15663
      jsr DumpSixSpr             ;in attribute bytes of enemy obj sprite data
15664
      dey
15665
      dey                        ;now go back to the Y coordinate offset
15666
      tya
15667
      tax                        ;give offset to X
15668
      lda SCRATCHPAD+$ef
15669
      cmpn ++HammerBro             ;check saved enemy object for hammer bro
15670
      beq FlipEnemyVertically
15671
      cmpn ++Lakitu                ;check saved enemy object for lakitu
15672
      beq FlipEnemyVertically    ;branch for hammer bro or lakitu
15673
      cmpn ++$15
15674
              cmpcy
15675
      bcs FlipEnemyVertically    ;also branch if enemy object => $15
15676
      txa
15677
      clc
15678
      adcn ++$08                   ;if not selected objects or => $15, set
15679
      tax                        ;offset in X for next row
15680
 
15681
FlipEnemyVertically:
15682
      ldax Sprite_Tilenumber,x     ;load first or second row tiles
15683
      pha                         ;and save tiles to the stack
15684
      ldax Sprite_Tilenumber+4,x
15685
      pha
15686
      lday Sprite_Tilenumber+16,y  ;exchange third row tiles
15687
      stax Sprite_Tilenumber,x     ;with first or second row tiles
15688
      lday Sprite_Tilenumber+20,y
15689
      stax Sprite_Tilenumber+4,x
15690
      pla                         ;pull first or second row tiles from stack
15691
      stay Sprite_Tilenumber+20,y  ;and save in third row
15692
      pla
15693
      stay Sprite_Tilenumber+16,y
15694
 
15695
CheckForESymmetry:
15696
        lda BowserGfxFlag           ;are we drawing bowser at all?
15697
         checka
15698
        bne SkipToOffScrChk         ;branch if so
15699
        lda SCRATCHPAD+$ef      
15700
        ldx SCRATCHPAD+$ec                     ;get alternate enemy state
15701
        cmpn ++$05                    ;check for hammer bro object
15702
        bne ContES
15703
        jmp SprObjectOffscrChk      ;jump if found
15704
ContES: cmpn ++Bloober                ;check for bloober object
15705
        beq MirrorEnemyGfx
15706
        cmpn ++PiranhaPlant           ;check for piranha plant object
15707
        beq MirrorEnemyGfx
15708
        cmpn ++Podoboo                ;check for podoboo object
15709
        beq MirrorEnemyGfx          ;branch if either of three are found
15710
        cmpn ++Spiny                  ;check for spiny object
15711
        bne ESRtnr                  ;branch closer if not found
15712
        cpxn ++$05                    ;check spiny's state
15713
        bne CheckToMirrorLakitu     ;branch if not an egg, otherwise
15714
ESRtnr: cmpn ++$15                    ;check for princess/mushroom retainer object
15715
        bne SpnySC
15716
        ldan ++$42                    ;set horizontal flip on bottom right sprite
15717
        stay Sprite_Attributes+20,y  ;note that palette bits were already set earlier
15718
SpnySC: cpxn ++$02                    ;if alternate enemy state set to 1 or 0, branch
15719
              cmpcy
15720
        bcc CheckToMirrorLakitu
15721
 
15722
MirrorEnemyGfx:
15723
        lda BowserGfxFlag           ;if enemy object is bowser, skip all of this
15724
         checka
15725
        bne CheckToMirrorLakitu
15726
        lday Sprite_Attributes,y     ;load attribute bits of first sprite
15727
        andn ++%10100011
15728
        stay Sprite_Attributes,y     ;save vertical flip, priority, and palette bits
15729
        stay Sprite_Attributes+8,y   ;in left sprite column of enemy object OAM data
15730
        stay Sprite_Attributes+16,y
15731
        oran ++%01000000              ;set horizontal flip
15732
        cpxn ++$05                    ;check for state used by spiny's egg
15733
        bne EggExc                  ;if alternate state not set to $05, branch
15734
        oran ++%10000000              ;otherwise set vertical flip
15735
EggExc: stay Sprite_Attributes+4,y   ;set bits of right sprite column
15736
        stay Sprite_Attributes+12,y  ;of enemy object sprite data
15737
        stay Sprite_Attributes+20,y
15738
        cpxn ++$04                    ;check alternate enemy state
15739
        bne CheckToMirrorLakitu     ;branch if not $04
15740
        lday Sprite_Attributes+8,y   ;get second row left sprite attributes
15741
        oran ++%10000000
15742
        stay Sprite_Attributes+8,y   ;store bits with vertical flip in
15743
        stay Sprite_Attributes+16,y  ;second and third row left sprites
15744
        oran ++%01000000
15745
        stay Sprite_Attributes+12,y  ;store with horizontal and vertical flip in
15746
        stay Sprite_Attributes+20,y  ;second and third row right sprites
15747
 
15748
CheckToMirrorLakitu:
15749
        lda SCRATCHPAD+$ef                     ;check for lakitu enemy object
15750
        cmpn ++Lakitu
15751
        bne CheckToMirrorJSpring    ;branch if not found
15752
        lda VerticalFlipFlag
15753
         checka
15754
        bne NVFLak                  ;branch if vertical flip flag not set
15755
        lday Sprite_Attributes+16,y  ;save vertical flip and palette bits
15756
        andn ++%10000001              ;in third row left sprite
15757
        stay Sprite_Attributes+16,y
15758
        lday Sprite_Attributes+20,y  ;set horizontal flip and palette bits
15759
        oran ++%01000001              ;in third row right sprite
15760
        stay Sprite_Attributes+20,y
15761
        ldx FrenzyEnemyTimer        ;check timer
15762
        cpxn ++$10
15763
              cmpcy
15764
        bcs SprObjectOffscrChk      ;branch if timer has not reached a certain range
15765
        stay Sprite_Attributes+12,y  ;otherwise set same for second row right sprite
15766
        andn ++%10000001
15767
        stay Sprite_Attributes+8,y   ;preserve vertical flip and palette bits for left sprite
15768
       if Z80
15769
       or a
15770
       endif
15771
        bcc SprObjectOffscrChk      ;unconditional branch
15772
NVFLak: lday Sprite_Attributes,y     ;get first row left sprite attributes
15773
        andn ++%10000001
15774
        stay Sprite_Attributes,y     ;save vertical flip and palette bits
15775
        lday Sprite_Attributes+4,y   ;get first row right sprite attributes
15776
        oran ++%01000001              ;set horizontal flip and palette bits
15777
        stay Sprite_Attributes+4,y   ;note that vertical flip is left as-is
15778
 
15779
CheckToMirrorJSpring:
15780
      lda SCRATCHPAD+$ef                     ;check for jumpspring object (any frame)
15781
      cmpn ++$18
15782
              cmpcy
15783
      bcc SprObjectOffscrChk      ;branch if not jumpspring object at all
15784
      ldan ++$82
15785
      stay Sprite_Attributes+8,y   ;set vertical flip and palette bits of 
15786
      stay Sprite_Attributes+16,y  ;second and third row left sprites
15787
      oran ++%01000000
15788
      stay Sprite_Attributes+12,y  ;set, in addition to those, horizontal flip
15789
      stay Sprite_Attributes+20,y  ;for second and third row right sprites
15790
 
15791
SprObjectOffscrChk:
15792
;    238t ( Goomba)
15793
         ldx ObjectOffset          ;get enemy buffer offset
15794
         lda Enemy_OffscreenBits   ;check offscreen information
15795
         lsr
15796
         lsr                       ;shift three times to the right
15797
         lsr                       ;which puts d2 into carry
15798
         pha                       ;save to stack
15799
         bcc LcChk                 ;branch if not set
15800
         ldan ++$04                  ;set for right column sprites
15801
         jsr MoveESprColOffscreen  ;and move them offscreen
15802
LcChk:   pla                       ;get from stack
15803
         lsr                       ;move d3 to carry
15804
         pha                       ;save to stack
15805
         bcc Row3C                 ;branch if not set
15806
         ldan ++$00                  ;set for left column sprites,
15807
         jsr MoveESprColOffscreen  ;move them offscreen
15808
Row3C:   pla                       ;get from stack again
15809
         lsr                       ;move d5 to carry this time
15810
         lsr
15811
         pha                       ;save to stack again
15812
         bcc Row23C                ;branch if carry not set
15813
         ldan ++$10                  ;set for third row of sprites
15814
         jsr MoveESprRowOffscreen  ;and move them offscreen
15815
Row23C:  pla                       ;get from stack
15816
         lsr                       ;move d6 into carry
15817
         pha                       ;save to stack
15818
         bcc AllRowC
15819
         ldan ++$08                  ;set for second and third rows
15820
         jsr MoveESprRowOffscreen  ;move them offscreen
15821
AllRowC: pla                       ;get from stack once more
15822
         lsr                       ;move d7 into carry
15823
         bcc ExEGHandler
15824
         jsr MoveESprRowOffscreen  ;move all sprites offscreen (A should be 0 by now)
15825
         ldax Enemy_ID,x
15826
         cmpn ++Podoboo              ;check enemy identifier for podoboo
15827
         beq ExEGHandler           ;skip this part if found, we do not want to erase podoboo!
15828
         ldax Enemy_Y_HighPos,x     ;check high byte of vertical position
15829
         cmpn ++$02                  ;if not yet past the bottom of the screen, branch
15830
         bne ExEGHandler
15831
         jsr EraseEnemyObject      ;what it says
15832
 
15833
ExEGHandler:
15834
      rts
15835
 
15836
        if Z80OPT
15837
        else
15838
DrawEnemyObjRow:
15839
      ldax EnemyGraphicsTable,x    ;load two tiles of enemy graphics
15840
      sta SCRATCHPAD+$00
15841
      ldax EnemyGraphicsTable+1,x
15842
DrawOneSpriteRow:
15843
      sta SCRATCHPAD+$01
15844
      jmp DrawSpriteObject        ;draw them
15845
        endif
15846
 
15847
MoveESprRowOffscreen:
15848
      clc                         ;add A to enemy object OAM data offset
15849
      adcx Enemy_SprDataOffset,x
15850
      tay                         ;use as offset
15851
      ldan ++$f8
15852
      jmp DumpTwoSpr              ;move first row of sprites offscreen
15853
 
15854
MoveESprColOffscreen:
15855
      clc                         ;add A to enemy object OAM data offset
15856
      adcx Enemy_SprDataOffset,x
15857
      tay                         ;use as offset
15858
      jsr MoveColOffscreen        ;move first and second row sprites in column offscreen
15859
      stay Sprite_Data+16,y        ;move third row sprite in column offscreen
15860
      rts
15861
 
15862
;-------------------------------------------------------------------------------------
15863
;$00-$01 - tile numbers
15864
;$02 - relative Y position
15865
;$03 - horizontal flip flag (not used here)
15866
;$04 - attributes
15867
;$05 - relative X position
15868
 
15869
DefaultBlockObjTiles:
15870
      .db $85, $85, $86, $86             ;brick w/ line (these are sprite tiles, not BG!)
15871
 
15872
DrawBlock:
15873
           lda Block_Rel_YPos            ;get relative vertical coordinate of block object
15874
           sta SCRATCHPAD+$02                       ;store here
15875
           lda Block_Rel_XPos            ;get relative horizontal coordinate of block object
15876
           sta SCRATCHPAD+$05                       ;store here
15877
           ldan ++$03
15878
           sta SCRATCHPAD+$04                       ;set attribute byte here
15879
           lsr
15880
           sta SCRATCHPAD+$03                       ;set horizontal flip bit here (will not be used) ???
15881
           ldyx Block_SprDataOffset,x     ;get sprite data offset
15882
        if Z80OPT
15883
      ld hl,DefaultBlockObjTiles
15884
      ;add hl,bc
15885
      call DrawSpriteObject
15886
      call DrawSpriteObject
15887
        else
15888
           ldxn ++$00                      ;reset X for use as offset to tile data
15889
DBlkLoop:  
15890
           ldax DefaultBlockObjTiles,x    ;get left tile number
15891
           sta SCRATCHPAD+$00                       ;set here
15892
           ldax DefaultBlockObjTiles+1,x  ;get right tile number
15893
           jsr DrawOneSpriteRow          ;do sub to write tile numbers to first row of sprites
15894
           cpxn ++$04                      ;check incremented offset
15895
           bne DBlkLoop                  ;and loop back until all four sprites are done
15896
        endif
15897
           ldx ObjectOffset              ;get block object offset
15898
           ldyx Block_SprDataOffset,x     ;get sprite data offset
15899
           lda AreaType
15900
           cmpn ++$01                      ;check for ground level type area
15901
           beq ChkRep                    ;if found, branch to next part
15902
           ldan ++$86
15903
           stay Sprite_Tilenumber,y       ;otherwise remove brick tiles with lines
15904
           stay Sprite_Tilenumber+4,y     ;and replace then with lineless brick tiles
15905
ChkRep:    ldax Block_Metatile,x          ;check replacement metatile
15906
           cmpn ++$c4                      ;if not used block metatile, then
15907
           bne BlkOffscr                 ;branch ahead to use current graphics
15908
           ldan ++$87                      ;set A for used block tile
15909
           iny                           ;increment Y to write to tile bytes
15910
           jsr DumpFourSpr               ;do sub to dump into all four sprites
15911
           dey                           ;return Y to original offset
15912
           ldan ++$03                      ;set palette bits
15913
           ldx AreaType
15914
           dex                           ;check for ground level type area again
15915
           beq SetBFlip                  ;if found, use current palette bits
15916
           lsr                           ;otherwise set to $01
15917
SetBFlip:  ldx ObjectOffset              ;put block object offset back in X
15918
           stay Sprite_Attributes,y       ;store attribute byte as-is in first sprite
15919
           oran ++%01000000
15920
           stay Sprite_Attributes+4,y     ;set horizontal flip bit for second sprite
15921
           oran ++%10000000
15922
           stay Sprite_Attributes+12,y    ;set both flip bits for fourth sprite
15923
           andn ++%10000011
15924
           stay Sprite_Attributes+8,y     ;set vertical flip bit for third sprite
15925
BlkOffscr: lda Block_OffscreenBits       ;get offscreen bits for block object
15926
           pha                           ;save to stack
15927
           andn ++%00000100                ;check to see if d2 in offscreen bits are set
15928
           beq PullOfsB                  ;if not set, branch, otherwise move sprites offscreen
15929
           ldan ++$f8                      ;move offscreen two OAMs
15930
           stay Sprite_Y_Position+4,y     ;on the right side
15931
           stay Sprite_Y_Position+12,y
15932
PullOfsB:  pla                           ;pull offscreen bits from stack
15933
ChkLeftCo: andn ++%00001000                ;check to see if d3 in offscreen bits are set
15934
           beq ExDBlk                    ;if not set, branch, otherwise move sprites offscreen
15935
 
15936
MoveColOffscreen:
15937
        ldan ++$f8                   ;move offscreen two OAMs
15938
        stay Sprite_Y_Position,y    ;on the left side (or two rows of enemy on either side
15939
        stay Sprite_Y_Position+8,y  ;if branched here from enemy graphics handler)
15940
ExDBlk: rts
15941
 
15942
;-------------------------------------------------------------------------------------
15943
;$00 - used to hold palette bits for attribute byte or relative X position
15944
 
15945
DrawBrickChunks:
15946
         ldan ++$02                   ;set palette bits here
15947
         sta SCRATCHPAD+$00
15948
         ldan ++$75                   ;set tile number for ball (something residual, likely)
15949
         ldy GameEngineSubroutine
15950
         cpyn ++$05                   ;if end-of-level routine running,
15951
         beq DChunks                ;use palette and tile number assigned
15952
         ldan ++$03                   ;otherwise set different palette bits
15953
         sta SCRATCHPAD+$00
15954
         ldan ++$84                   ;and set tile number for brick chunks
15955
DChunks: ldyx Block_SprDataOffset,x  ;get OAM data offset
15956
         iny                        ;increment to start with tile bytes in OAM
15957
         jsr DumpFourSpr            ;do sub to dump tile number into all four sprites
15958
         lda FrameCounter           ;get frame counter
15959
         asl
15960
         asl
15961
         asl                        ;move low nybble to high
15962
         asl
15963
         andn ++$c0                   ;get what was originally d3-d2 of low nybble
15964
         orai SCRATCHPAD+$00                    ;add palette bits
15965
         iny                        ;increment offset for attribute bytes
15966
         jsr DumpFourSpr            ;do sub to dump attribute data into all four sprites
15967
         dey
15968
         dey                        ;decrement offset to Y coordinate
15969
         lda Block_Rel_YPos         ;get first block object's relative vertical coordinate
15970
         jsr DumpTwoSpr             ;do sub to dump current Y coordinate into two sprites
15971
         lda Block_Rel_XPos         ;get first block object's relative horizontal coordinate
15972
         stay Sprite_X_Position,y    ;save into X coordinate of first sprite
15973
         ldax Block_Orig_XPos,x      ;get original horizontal coordinate
15974
         secsub
15975
         sbci ScreenLeft_X_Pos       ;subtract coordinate of left side from original coordinate
15976
         sta SCRATCHPAD+$00                    ;store result as relative horizontal coordinate of original
15977
         secsub
15978
         sbci Block_Rel_XPos         ;get difference of relative positions of original - current
15979
        cmpcy
15980
         adci SCRATCHPAD+$00                    ;add original relative position to result
15981
         adcn ++$06                   ;plus 6 pixels to position second brick chunk correctly
15982
         stay Sprite_X_Position+4,y  ;save into X coordinate of second sprite
15983
         lda Block_Rel_YPos+1       ;get second block object's relative vertical coordinate
15984
         stay Sprite_Y_Position+8,y
15985
         stay Sprite_Y_Position+12,y ;dump into Y coordinates of third and fourth sprites
15986
         lda Block_Rel_XPos+1       ;get second block object's relative horizontal coordinate
15987
         stay Sprite_X_Position+8,y  ;save into X coordinate of third sprite
15988
         lda SCRATCHPAD+$00                    ;use original relative horizontal position
15989
         secsub
15990
         sbci Block_Rel_XPos+1       ;get difference of relative positions of original - current
15991
        cmpcy
15992
         adci SCRATCHPAD+$00                    ;add original relative position to result
15993
         adcn ++$06                   ;plus 6 pixels to position fourth brick chunk correctly
15994
         stay Sprite_X_Position+12,y ;save into X coordinate of fourth sprite
15995
         lda Block_OffscreenBits    ;get offscreen bits for block object
15996
         jsr ChkLeftCo              ;do sub to move left half of sprites offscreen if necessary
15997
         lda Block_OffscreenBits    ;get offscreen bits again
15998
         asl                        ;shift d7 into carry
15999
         bcc ChnkOfs                ;if d7 not set, branch to last part
16000
         ldan ++$f8
16001
         jsr DumpTwoSpr             ;otherwise move top sprites offscreen
16002
ChnkOfs: lda SCRATCHPAD+$00                    ;if relative position on left side of screen,
16003
         checka
16004
         bpl ExBCDr                 ;go ahead and leave
16005
         lday Sprite_X_Position,y    ;otherwise compare left-side X coordinate
16006
         cmpy Sprite_X_Position+4,y  ;to right-side X coordinate
16007
              cmpcy
16008
         bcc ExBCDr                 ;branch to leave if less
16009
         ldan ++$f8                   ;otherwise move right half of sprites offscreen
16010
         stay Sprite_Y_Position+4,y
16011
         stay Sprite_Y_Position+12,y
16012
ExBCDr:  rts                        ;leave
16013
 
16014
;-------------------------------------------------------------------------------------
16015
 
16016
DrawFireball:
16017
      ldyx FBall_SprDataOffset,x  ;get fireball's sprite data offset
16018
      lda Fireball_Rel_YPos      ;get relative vertical coordinate
16019
      stay Sprite_Y_Position,y    ;store as sprite Y coordinate
16020
      lda Fireball_Rel_XPos      ;get relative horizontal coordinate
16021
      stay Sprite_X_Position,y    ;store as sprite X coordinate, then do shared code
16022
 
16023
DrawFirebar:
16024
       lda FrameCounter         ;get frame counter
16025
       lsr                      ;divide by four
16026
       lsr
16027
       pha                      ;save result to stack
16028
       andn ++$01                 ;mask out all but last bit
16029
       eorn ++$64                 ;set either tile $64 or $65 as fireball tile
16030
       stay Sprite_Tilenumber,y  ;thus tile changes every four frames
16031
       pla                      ;get from stack
16032
       lsr                      ;divide by four again
16033
       lsr
16034
       ldan ++$02                 ;load value $02 to set palette in attrib byte
16035
       bcc FireA                ;if last bit shifted out was not set, skip this
16036
       oran ++%11000000           ;otherwise flip both ways every eight frames
16037
FireA: stay Sprite_Attributes,y  ;store attribute byte and leave
16038
       rts
16039
 
16040
;-------------------------------------------------------------------------------------
16041
 
16042
ExplosionTiles:
16043
      .db $68, $67, $66
16044
 
16045
DrawExplosion_Fireball:
16046
      ldyx Alt_SprDataOffset,x  ;get OAM data offset of alternate sort for fireball's explosion
16047
      ldax Fireball_State,x     ;load fireball state
16048
      incx Fireball_State,x     ;increment state for next frame
16049
      lsr                      ;divide by 2
16050
      andn ++%00000111           ;mask out all but d3-d1
16051
      cmpn ++$03                 ;check to see if time to kill fireball
16052
              cmpcy
16053
      bcs KillFireBall         ;branch if so, otherwise continue to draw explosion
16054
 
16055
DrawExplosion_Fireworks:
16056
      tax                         ;use whatever's in A for offset
16057
      ldax ExplosionTiles,x        ;get tile number using offset
16058
      iny                         ;increment Y (contains sprite data offset)
16059
      jsr DumpFourSpr             ;and dump into tile number part of sprite data
16060
      dey                         ;decrement Y so we have the proper offset again
16061
      ldx ObjectOffset            ;return enemy object buffer offset to X
16062
      lda Fireball_Rel_YPos       ;get relative vertical coordinate
16063
      secsub                         ;subtract four pixels vertically
16064
      sbcn ++$04                    ;for first and third sprites
16065
      stay Sprite_Y_Position,y
16066
      stay Sprite_Y_Position+8,y
16067
      clc                         ;add eight pixels vertically
16068
      adcn ++$08                    ;for second and fourth sprites
16069
      stay Sprite_Y_Position+4,y
16070
      stay Sprite_Y_Position+12,y
16071
      lda Fireball_Rel_XPos       ;get relative horizontal coordinate
16072
      secsub                         ;subtract four pixels horizontally
16073
      sbcn ++$04                    ;for first and second sprites
16074
      stay Sprite_X_Position,y
16075
      stay Sprite_X_Position+4,y
16076
      clc                         ;add eight pixels horizontally
16077
      adcn ++$08                    ;for third and fourth sprites
16078
      stay Sprite_X_Position+8,y
16079
      stay Sprite_X_Position+12,y
16080
      ldan ++$02                    ;set palette attributes for all sprites, but
16081
      stay Sprite_Attributes,y     ;set no flip at all for first sprite
16082
      ldan ++$82
16083
      stay Sprite_Attributes+4,y   ;set vertical flip for second sprite
16084
      ldan ++$42
16085
      stay Sprite_Attributes+8,y   ;set horizontal flip for third sprite
16086
      ldan ++$c2
16087
      stay Sprite_Attributes+12,y  ;set both flips for fourth sprite
16088
      rts                         ;we are done
16089
 
16090
KillFireBall:
16091
      ldan ++$00                    ;clear fireball state to kill it
16092
      stax Fireball_State,x
16093
      rts
16094
 
16095
;-------------------------------------------------------------------------------------
16096
 
16097
DrawSmallPlatform:
16098
       ldyx Enemy_SprDataOffset,x   ;get OAM data offset
16099
       ldan ++$5b                    ;load tile number for small platforms
16100
       iny                         ;increment offset for tile numbers
16101
       jsr DumpSixSpr              ;dump tile number into all six sprites
16102
       iny                         ;increment offset for attributes
16103
       ldan ++$02                    ;load palette controls
16104
       jsr DumpSixSpr              ;dump attributes into all six sprites
16105
       dey                         ;decrement for original offset
16106
       dey
16107
       lda Enemy_Rel_XPos          ;get relative horizontal coordinate
16108
       stay Sprite_X_Position,y
16109
       stay Sprite_X_Position+12,y  ;dump as X coordinate into first and fourth sprites
16110
       clc
16111
       adcn ++$08                    ;add eight pixels
16112
       stay Sprite_X_Position+4,y   ;dump into second and fifth sprites
16113
       stay Sprite_X_Position+16,y
16114
       clc
16115
       adcn ++$08                    ;add eight more pixels
16116
       stay Sprite_X_Position+8,y   ;dump into third and sixth sprites
16117
       stay Sprite_X_Position+20,y
16118
       ldax Enemy_Y_Position,x      ;get vertical coordinate
16119
       tax
16120
       pha                         ;save to stack
16121
       cpxn ++$20                    ;if vertical coordinate below status bar,
16122
              cmpcy
16123
       bcs TopSP                   ;do not mess with it
16124
       ldan ++$f8                    ;otherwise move first three sprites offscreen
16125
TopSP: jsr DumpThreeSpr            ;dump vertical coordinate into Y coordinates
16126
       pla                         ;pull from stack
16127
       clc
16128
       adcn ++$80                    ;add 128 pixels
16129
       tax
16130
       cpxn ++$20                    ;if below status bar (taking wrap into account)
16131
              cmpcy
16132
       bcs BotSP                   ;then do not change altered coordinate
16133
       ldan ++$f8                    ;otherwise move last three sprites offscreen
16134
BotSP: stay Sprite_Y_Position+12,y  ;dump vertical coordinate + 128 pixels
16135
       stay Sprite_Y_Position+16,y  ;into Y coordinates
16136
       stay Sprite_Y_Position+20,y
16137
       lda Enemy_OffscreenBits     ;get offscreen bits
16138
       pha                         ;save to stack
16139
       andn ++%00001000              ;check d3
16140
       beq SOfs
16141
       ldan ++$f8                    ;if d3 was set, move first and
16142
       stay Sprite_Y_Position,y     ;fourth sprites offscreen
16143
       stay Sprite_Y_Position+12,y
16144
SOfs:  pla                         ;move out and back into stack
16145
       pha
16146
       andn ++%00000100              ;check d2
16147
       beq SOfs2
16148
       ldan ++$f8                    ;if d2 was set, move second and
16149
       stay Sprite_Y_Position+4,y   ;fifth sprites offscreen
16150
       stay Sprite_Y_Position+16,y
16151
SOfs2: pla                         ;get from stack
16152
       andn ++%00000010              ;check d1
16153
       beq ExSPl
16154
       ldan ++$f8                    ;if d1 was set, move third and
16155
       stay Sprite_Y_Position+8,y   ;sixth sprites offscreen
16156
       stay Sprite_Y_Position+20,y
16157
ExSPl: ldx ObjectOffset            ;get enemy object offset and leave
16158
       rts
16159
 
16160
;-------------------------------------------------------------------------------------
16161
 
16162
DrawBubble:
16163
        ldy Player_Y_HighPos        ;if player's vertical high position
16164
        dey                         ;not within screen, skip all of this
16165
        bne ExDBub
16166
        lda Bubble_OffscreenBits    ;check air bubble's offscreen bits
16167
        andn ++%00001000
16168
        bne ExDBub                  ;if bit set, branch to leave
16169
        ldyx Bubble_SprDataOffset,x  ;get air bubble's OAM data offset
16170
        lda Bubble_Rel_XPos         ;get relative horizontal coordinate
16171
        stay Sprite_X_Position,y     ;store as X coordinate here
16172
        lda Bubble_Rel_YPos         ;get relative vertical coordinate
16173
        stay Sprite_Y_Position,y     ;store as Y coordinate here
16174
        ldan ++$74
16175
        stay Sprite_Tilenumber,y     ;put air bubble tile into OAM data
16176
        ldan ++$02
16177
        stay Sprite_Attributes,y     ;set attribute byte
16178
ExDBub: rts                         ;leave
16179
 
16180
;-------------------------------------------------------------------------------------
16181
;$00 - used to store player's vertical offscreen bits
16182
 
16183
PlayerGfxTblOffsets:
16184
      .db $20, $28, $c8, $18, $00, $40, $50, $58
16185
      .db $80, $88, $b8, $78, $60, $a0, $b0, $b8
16186
 
16187
;tiles arranged in order, 2 tiles per row, top to bottom
16188
 
16189
PlayerGraphicsTable:
16190
;big player table
16191
      .db $00, $01, $02, $03, $04, $05, $06, $07 ;walking frame 1
16192
      .db $08, $09, $0a, $0b, $0c, $0d, $0e, $0f ;        frame 2
16193
      .db $10, $11, $12, $13, $14, $15, $16, $17 ;        frame 3
16194
      .db $18, $19, $1a, $1b, $1c, $1d, $1e, $1f ;skidding
16195
      .db $20, $21, $22, $23, $24, $25, $26, $27 ;jumping
16196
      .db $08, $09, $28, $29, $2a, $2b, $2c, $2d ;swimming frame 1
16197
      .db $08, $09, $0a, $0b, $0c, $30, $2c, $2d ;         frame 2
16198
      .db $08, $09, $0a, $0b, $2e, $2f, $2c, $2d ;         frame 3
16199
      .db $08, $09, $28, $29, $2a, $2b, $5c, $5d ;climbing frame 1
16200
      .db $08, $09, $0a, $0b, $0c, $0d, $5e, $5f ;         frame 2
16201
      .db $fc, $fc, $08, $09, $58, $59, $5a, $5a ;crouching
16202
      .db $08, $09, $28, $29, $2a, $2b, $0e, $0f ;fireball throwing
16203
 
16204
;small player table
16205
      .db $fc, $fc, $fc, $fc, $32, $33, $34, $35 ;walking frame 1
16206
      .db $fc, $fc, $fc, $fc, $36, $37, $38, $39 ;        frame 2
16207
      .db $fc, $fc, $fc, $fc, $3a, $37, $3b, $3c ;        frame 3
16208
      .db $fc, $fc, $fc, $fc, $3d, $3e, $3f, $40 ;skidding
16209
      .db $fc, $fc, $fc, $fc, $32, $41, $42, $43 ;jumping
16210
      .db $fc, $fc, $fc, $fc, $32, $33, $44, $45 ;swimming frame 1
16211
      .db $fc, $fc, $fc, $fc, $32, $33, $44, $47 ;         frame 2
16212
      .db $fc, $fc, $fc, $fc, $32, $33, $48, $49 ;         frame 3
16213
      .db $fc, $fc, $fc, $fc, $32, $33, $90, $91 ;climbing frame 1
16214
      .db $fc, $fc, $fc, $fc, $3a, $37, $92, $93 ;         frame 2
16215
      .db $fc, $fc, $fc, $fc, $9e, $9e, $9f, $9f ;killed
16216
 
16217
;used by both player sizes
16218
      .db $fc, $fc, $fc, $fc, $3a, $37, $4f, $4f ;small player standing
16219
      .db $fc, $fc, $00, $01, $4c, $4d, $4e, $4e ;intermediate grow frame
16220
      .db $00, $01, $4c, $4d, $4a, $4a, $4b, $4b ;big player standing
16221
 
16222
SwimKickTileNum:
16223
      .db $31, $46
16224
 
16225
PlayerGfxHandler:
16226
        lda InjuryTimer             ;if player's injured invincibility timer
16227
         checka
16228
        beq CntPl                   ;not set, skip checkpoint and continue code
16229
        lda FrameCounter
16230
        lsr                         ;otherwise check frame counter and branch
16231
        bcs ExPGH                   ;to leave on every other frame (when d0 is set)
16232
CntPl:  lda GameEngineSubroutine    ;if executing specific game engine routine,
16233
        cmpn ++$0b                    ;branch ahead to some other part
16234
        beq PlayerKilled
16235
        lda PlayerChangeSizeFlag    ;if grow/shrink flag set
16236
         checka
16237
        bne DoChangeSize            ;then branch to some other code
16238
        ldy SwimmingFlag            ;if swimming flag set, branch to
16239
         checky
16240
        beq FindPlayerAction        ;different part, do not return
16241
        lda Player_State
16242
        cmpn ++$00                    ;if player status normal,
16243
        beq FindPlayerAction        ;branch and do not return
16244
        jsr FindPlayerAction        ;otherwise jump and return
16245
        lda FrameCounter
16246
        andn ++%00000100              ;check frame counter for d2 set (8 frames every
16247
        bne ExPGH                   ;eighth frame), and branch if set to leave
16248
        tax                         ;initialize X to zero
16249
        ldy Player_SprDataOffset    ;get player sprite data offset
16250
        lda PlayerFacingDir         ;get player's facing direction
16251
        lsr
16252
        bcs SwimKT                  ;if player facing to the right, use current offset
16253
        iny
16254
        iny                         ;otherwise move to next OAM data
16255
        iny
16256
        iny
16257
SwimKT: lda PlayerSize              ;check player's size
16258
         checka
16259
        beq BigKTS                  ;if big, use first tile
16260
        lday Sprite_Tilenumber+24,y  ;check tile number of seventh/eighth sprite
16261
        cmpi SwimTileRepOffset       ;against tile number in player graphics table
16262
        beq ExPGH                   ;if spr7/spr8 tile number = value, branch to leave
16263
        inx                         ;otherwise increment X for second tile
16264
BigKTS: ldax SwimKickTileNum,x       ;overwrite tile number in sprite 7/8
16265
        stay Sprite_Tilenumber+24,y  ;to animate player's feet when swimming
16266
ExPGH:  rts                         ;then leave
16267
 
16268
FindPlayerAction:
16269
      jsr ProcessPlayerAction       ;find proper offset to graphics table by player's actions
16270
      jmp PlayerGfxProcessing       ;draw player, then process for fireball throwing
16271
 
16272
DoChangeSize:
16273
      jsr HandleChangeSize          ;find proper offset to graphics table for grow/shrink
16274
      jmp PlayerGfxProcessing       ;draw player, then process for fireball throwing
16275
 
16276
PlayerKilled:
16277
      ldyn ++$0e                      ;load offset for player killed
16278
      lday PlayerGfxTblOffsets,y     ;get offset to graphics table
16279
 
16280
PlayerGfxProcessing:
16281
       sta PlayerGfxOffset           ;store offset to graphics table here
16282
       ldan ++$04
16283
       jsr RenderPlayerSub           ;draw player based on offset loaded
16284
       jsr ChkForPlayerAttrib        ;set horizontal flip bits as necessary
16285
       lda FireballThrowingTimer
16286
         checka
16287
       beq PlayerOffscreenChk        ;if fireball throw timer not set, skip to the end
16288
       ldyn ++$00                      ;set value to initialize by default
16289
       lda PlayerAnimTimer           ;get animation frame timer
16290
       cmpi FireballThrowingTimer     ;compare to fireball throw timer
16291
       sty FireballThrowingTimer     ;initialize fireball throw timer
16292
              cmpcy
180 demige 16293
       bcs PlayerOffscreenChk        ;if animation frame timer =>  fireball throw timer skip to end
171 demige 16294
       sta FireballThrowingTimer     ;otherwise store animation timer into fireball throw timer
16295
       ldyn ++$07                      ;load offset for throwing
16296
       lday PlayerGfxTblOffsets,y     ;get offset to graphics table
16297
       sta PlayerGfxOffset           ;store it for use later
16298
       ldyn ++$04                      ;set to update four sprite rows by default
16299
       lda Player_X_Speed
16300
       orai Left_Right_Buttons        ;check for horizontal speed or left/right button press
16301
       beq SUpdR                     ;if no speed or button press, branch using set value in Y
16302
       dey                           ;otherwise set to update only three sprite rows
16303
SUpdR: tya                           ;save in A for use
16304
       jsr RenderPlayerSub           ;in sub, draw player object again
16305
 
16306
PlayerOffscreenChk:
16307
           lda Player_OffscreenBits      ;get player's offscreen bits
16308
           lsr
16309
           lsr                           ;move vertical bits to low nybble
16310
           lsr
16311
           lsr
16312
           sta SCRATCHPAD+$00                       ;store here
16313
           ldxn ++$03                      ;check all four rows of player sprites
16314
           lda Player_SprDataOffset      ;get player's sprite data offset
16315
           clc
16316
           adcn ++$18                      ;add 24 bytes to start at bottom row
16317
           tay                           ;set as offset here
16318
PROfsLoop: ldan ++$f8                      ;load offscreen Y coordinate just in case
16319
           lsri SCRATCHPAD+$00                       ;shift bit into carry
16320
           bcc NPROffscr                 ;if bit not set, skip, do not move sprites
16321
           jsr DumpTwoSpr                ;otherwise dump offscreen Y coordinate into sprite data
16322
NPROffscr: tya
16323
           secsub                           ;subtract eight bytes to do
16324
           sbcn ++$08                      ;next row up
16325
           tay
16326
           dex                           ;decrement row counter
16327
           bpl PROfsLoop                 ;do this until all sprite rows are checked
16328
           rts                           ;then we are done!
16329
 
16330
;-------------------------------------------------------------------------------------
16331
 
16332
IntermediatePlayerData:
16333
        .db $58, $01, $00, $60, $ff, $04
16334
 
16335
DrawPlayer_Intermediate:
16336
        if Z80OPT
16337
        ld hl,IntermediatePlayerData
16338
        ld de,SCRATCHPAD+$02
16339
        ld c,6
16340
        ldir
16341
        ld d,b;0
16342
          ld e,++$04                       ;load sprite data offset
16343
      ld hl,PlayerGraphicsTable+$b8                       ;load offset for small standing
16344
      ;add hl,bc
16345
          call DrawPlayerLoop             ;draw player accordingly
16346
        else
16347
          ldxn ++$05                       ;store data into zero page memory
16348
PIntLoop: ldax IntermediatePlayerData,x   ;load data to display player as he always
16349
          stax SCRATCHPAD+$02,x                      ;appears on world/lives display
16350
          dex
16351
          bpl PIntLoop                   ;do this until all data is loaded
16352
          ldxn ++$b8                       ;load offset for small standing
16353
          ldyn ++$04                       ;load sprite data offset
16354
          jsr DrawPlayerLoop             ;draw player accordingly
16355
        endif
16356
          lda Sprite_Attributes+36       ;get empty sprite attributes
16357
          oran ++%01000000                 ;set horizontal flip bit for bottom-right sprite
16358
          sta Sprite_Attributes+32       ;store and leave
16359
          rts
16360
 
16361
;-------------------------------------------------------------------------------------
16362
;$00-$01 - used to hold tile numbers, $00 also used to hold upper extent of animation frames
16363
;$02 - vertical position
16364
;$03 - facing direction, used as horizontal flip control
16365
;$04 - attributes
16366
;$05 - horizontal position
16367
;$07 - number of rows to draw
16368
;these also used in IntermediatePlayerData
16369
 
16370
RenderPlayerSub:
16371
        sta SCRATCHPAD+$07                      ;store number of rows of sprites to draw
16372
        lda Player_Rel_XPos
16373
        sta Player_Pos_ForScroll     ;store player's relative horizontal position
16374
        sta SCRATCHPAD+$05                      ;store it here also
16375
        lda Player_Rel_YPos
16376
        sta SCRATCHPAD+$02                      ;store player's vertical position
16377
        lda PlayerFacingDir
16378
        sta SCRATCHPAD+$03                      ;store player's facing direction
16379
        lda Player_SprAttrib
16380
        sta SCRATCHPAD+$04                      ;store player's sprite attributes
16381
        ldx PlayerGfxOffset          ;load graphics table offset
16382
        ldy Player_SprDataOffset     ;get player's sprite data offset
16383
 
16384
        if Z80OPT
16385
      ld hl,PlayerGraphicsTable
16386
      add hl,bc
16387
DrawPlayerLoop:
16388
      ld a,(SCRATCHPAD+$07)
16389
      ld b,a
16390
DrawPlayerLoop0
16391
      call DrawSpriteObject
16392
      djnz DrawPlayerLoop0           ;do this until all rows are drawn
16393
        else
16394
DrawPlayerLoop:
16395
DrawPlayerLoop0
16396
        ldax PlayerGraphicsTable,x    ;load player's left side
16397
        sta SCRATCHPAD+$00
16398
        ldax PlayerGraphicsTable+1,x  ;now load right side
16399
        jsr DrawOneSpriteRow
16400
        deci SCRATCHPAD+$07                      ;decrement rows of sprites to draw
16401
        bne DrawPlayerLoop0           ;do this until all rows are drawn
16402
        endif
16403
        rts
16404
 
16405
ProcessPlayerAction:
16406
        lda Player_State      ;get player's state
16407
        cmpn ++$03
16408
        beq ActionClimbing    ;if climbing, branch here
16409
        cmpn ++$02
16410
        beq ActionFalling     ;if falling, branch here
16411
        cmpn ++$01
16412
        bne ProcOnGroundActs  ;if not jumping, branch here
16413
        lda SwimmingFlag
16414
         checka
16415
        bne ActionSwimming    ;if swimming flag set, branch elsewhere
16416
        ldyn ++$06              ;load offset for crouching
16417
        lda CrouchingFlag     ;get crouching flag
16418
         checka
16419
        bne NonAnimatedActs   ;if set, branch to get offset for graphics table
16420
        ldyn ++$00              ;otherwise load offset for jumping
16421
        jmp NonAnimatedActs   ;go to get offset to graphics table
16422
 
16423
ProcOnGroundActs:
16424
        ldyn ++$06                   ;load offset for crouching
16425
        lda CrouchingFlag          ;get crouching flag
16426
         checka
16427
        bne NonAnimatedActs        ;if set, branch to get offset for graphics table
16428
        ldyn ++$02                   ;load offset for standing
16429
        lda Player_X_Speed         ;check player's horizontal speed
16430
        orai Left_Right_Buttons     ;and left/right controller bits
16431
        beq NonAnimatedActs        ;if no speed or buttons pressed, use standing offset
16432
        lda Player_XSpeedAbsolute  ;load walking/running speed
16433
        cmpn ++$09
16434
              cmpcy
16435
        bcc ActionWalkRun          ;if less than a certain amount, branch, too slow to skid
16436
        lda Player_MovingDir       ;otherwise check to see if moving direction
16437
        andi PlayerFacingDir        ;and facing direction are the same
16438
        bne ActionWalkRun          ;if moving direction = facing direction, branch, don't skid
16439
        iny                        ;otherwise increment to skid offset ($03)
16440
 
16441
NonAnimatedActs:
16442
        jsr GetGfxOffsetAdder      ;do a sub here to get offset adder for graphics table
16443
        ldan ++$00
16444
        sta PlayerAnimCtrl         ;initialize animation frame control
16445
        lday PlayerGfxTblOffsets,y  ;load offset to graphics table using size as offset
16446
        rts
16447
 
16448
ActionFalling:
16449
        ldyn ++$04                  ;load offset for walking/running
16450
        jsr GetGfxOffsetAdder     ;get offset to graphics table
16451
        jmp GetCurrentAnimOffset  ;execute instructions for falling state
16452
 
16453
ActionWalkRun:
16454
        ldyn ++$04               ;load offset for walking/running
16455
        jsr GetGfxOffsetAdder  ;get offset to graphics table
16456
        jmp FourFrameExtent    ;execute instructions for normal state
16457
 
16458
ActionClimbing:
16459
        ldyn ++$05               ;load offset for climbing
16460
        lda Player_Y_Speed     ;check player's vertical speed
16461
         checka
16462
        beq NonAnimatedActs    ;if no speed, branch, use offset as-is
16463
        jsr GetGfxOffsetAdder  ;otherwise get offset for graphics table
16464
        jmp ThreeFrameExtent   ;then skip ahead to more code
16465
 
16466
ActionSwimming:
16467
        ldyn ++$01               ;load offset for swimming
16468
        jsr GetGfxOffsetAdder
16469
        lda JumpSwimTimer      ;check jump/swim timer
16470
        orai PlayerAnimCtrl     ;and animation frame control
16471
        bne FourFrameExtent    ;if any one of these set, branch ahead
16472
        lda A_B_Buttons
16473
        asl                    ;check for A button pressed
16474
        bcs FourFrameExtent    ;branch to same place if A button pressed
16475
 
16476
GetCurrentAnimOffset:
16477
        lda PlayerAnimCtrl         ;get animation frame control
16478
        jmp GetOffsetFromAnimCtrl  ;jump to get proper offset to graphics table
16479
 
16480
FourFrameExtent:
16481
        ldan ++$03              ;load upper extent for frame control
16482
        jmp AnimationControl  ;jump to get offset and animate player object
16483
 
16484
ThreeFrameExtent:
16485
        ldan ++$02              ;load upper extent for frame control for climbing
16486
 
16487
AnimationControl:
16488
          sta SCRATCHPAD+$00                   ;store upper extent here
16489
          jsr GetCurrentAnimOffset  ;get proper offset to graphics table
16490
          pha                       ;save offset to stack
16491
          lda PlayerAnimTimer       ;load animation frame timer
16492
         checka
16493
          bne ExAnimC               ;branch if not expired
16494
          lda PlayerAnimTimerSet    ;get animation frame timer amount
16495
          sta PlayerAnimTimer       ;and set timer accordingly
16496
          lda PlayerAnimCtrl
16497
          clc                       ;add one to animation frame control
16498
          adcn ++$01
16499
          cmpi SCRATCHPAD+$00                   ;compare to upper extent
16500
              cmpcy
180 demige 16501
          bcc SetAnimC              ;if frame control + 1 < upper extent, use as next
171 demige 16502
          ldan ++$00                  ;otherwise initialize frame control
16503
SetAnimC: sta PlayerAnimCtrl        ;store as new animation frame control
16504
ExAnimC:  pla                       ;get offset to graphics table from stack and leave
16505
          rts
16506
 
16507
GetGfxOffsetAdder:
16508
        lda PlayerSize  ;get player's size
16509
         checka
16510
        beq SzOfs       ;if player big, use current offset as-is
16511
        tya             ;for big player
16512
        clc             ;otherwise add eight bytes to offset
16513
        adcn ++$08        ;for small player
16514
        tay
16515
SzOfs:  rts             ;go back
16516
 
16517
ChangeSizeOffsetAdder:
16518
        .db $00, $01, $00, $01, $00, $01, $02, $00, $01, $02
16519
        .db $02, $00, $02, $00, $02, $00, $02, $00, $02, $00
16520
 
16521
HandleChangeSize:
16522
         ldy PlayerAnimCtrl           ;get animation frame control
16523
         lda FrameCounter
16524
         andn ++%00000011               ;get frame counter and execute this code every
16525
         bne GorSLog                  ;fourth frame, otherwise branch ahead
16526
         iny                          ;increment frame control
16527
         cpyn ++$0a                     ;check for preset upper extent
16528
              cmpcy
16529
         bcc CSzNext                  ;if not there yet, skip ahead to use
16530
         ldyn ++$00                     ;otherwise initialize both grow/shrink flag
16531
         sty PlayerChangeSizeFlag     ;and animation frame control
16532
CSzNext: sty PlayerAnimCtrl           ;store proper frame control
16533
GorSLog: lda PlayerSize               ;get player's size
16534
         checka
16535
         bne ShrinkPlayer             ;if player small, skip ahead to next part
16536
         lday ChangeSizeOffsetAdder,y  ;get offset adder based on frame control as offset
16537
         ldyn ++$0f                     ;load offset for player growing
16538
 
16539
GetOffsetFromAnimCtrl:
16540
        asl                        ;multiply animation frame control
16541
        asl                        ;by eight to get proper amount
16542
        asl                        ;to add to our offset
16543
        adcy PlayerGfxTblOffsets,y  ;add to offset to graphics table
16544
        rts                        ;and return with result in A
16545
 
16546
ShrinkPlayer:
16547
        tya                          ;add ten bytes to frame control as offset
16548
        clc
16549
        adcn ++$0a                     ;this thing apparently uses two of the swimming frames
16550
        tax                          ;to draw the player shrinking
16551
        ldyn ++$09                     ;load offset for small player swimming
16552
        ldax ChangeSizeOffsetAdder,x  ;get what would normally be offset adder
16553
         checka
16554
        bne ShrPlF                   ;and branch to use offset if nonzero
16555
        ldyn ++$01                     ;otherwise load offset for big player swimming
16556
ShrPlF: lday PlayerGfxTblOffsets,y    ;get offset to graphics table based on offset loaded
16557
        rts                          ;and leave
16558
 
16559
ChkForPlayerAttrib:
16560
           ldy Player_SprDataOffset    ;get sprite data offset
16561
           lda GameEngineSubroutine
16562
           cmpn ++$0b                    ;if executing specific game engine routine,
16563
           beq KilledAtt               ;branch to change third and fourth row OAM attributes
16564
           lda PlayerGfxOffset         ;get graphics table offset
16565
           cmpn ++$50
16566
           beq C_S_IGAtt               ;if crouch offset, either standing offset,
16567
           cmpn ++$b8                    ;or intermediate growing offset,
16568
           beq C_S_IGAtt               ;go ahead and execute code to change 
16569
           cmpn ++$c0                    ;fourth row OAM attributes only
16570
           beq C_S_IGAtt
16571
           cmpn ++$c8
16572
           bne ExPlyrAt                ;if none of these, branch to leave
16573
KilledAtt: lday Sprite_Attributes+16,y
16574
           andn ++%00111111              ;mask out horizontal and vertical flip bits
16575
           stay Sprite_Attributes+16,y  ;for third row sprites and save
16576
           lday Sprite_Attributes+20,y
16577
           andn ++%00111111  
16578
           oran ++%01000000              ;set horizontal flip bit for second
16579
           stay Sprite_Attributes+20,y  ;sprite in the third row
16580
C_S_IGAtt: lday Sprite_Attributes+24,y
16581
           andn ++%00111111              ;mask out horizontal and vertical flip bits
16582
           stay Sprite_Attributes+24,y  ;for fourth row sprites and save
16583
           lday Sprite_Attributes+28,y
16584
           andn ++%00111111
16585
           oran ++%01000000              ;set horizontal flip bit for second
16586
           stay Sprite_Attributes+28,y  ;sprite in the fourth row
16587
ExPlyrAt:  rts                         ;leave
16588
 
16589
;-------------------------------------------------------------------------------------
16590
;$00 - used in adding to get proper offset
16591
 
16592
RelativePlayerPosition:
16593
        ldxn ++$00      ;set offsets for relative cooordinates
16594
        ldyn ++$00      ;routine to correspond to player object
16595
        jmp RelWOfs   ;get the coordinates
16596
 
16597
RelativeBubblePosition:
16598
        ldyn ++$01                ;set for air bubble offsets
16599
        jsr GetProperObjOffset  ;modify X to get proper air bubble offset
16600
        ldyn ++$03
16601
        jmp RelWOfs             ;get the coordinates
16602
 
16603
RelativeFireballPosition:
16604
         ldyn ++$00                    ;set for fireball offsets
16605
         jsr GetProperObjOffset      ;modify X to get proper fireball offset
16606
         ldyn ++$02
16607
RelWOfs: jsr GetObjRelativePosition  ;get the coordinates
16608
         ldx ObjectOffset            ;return original offset
16609
         rts                         ;leave
16610
 
16611
RelativeMiscPosition:
16612
        ldyn ++$02                ;set for misc object offsets
16613
        jsr GetProperObjOffset  ;modify X to get proper misc object offset
16614
        ldyn ++$06
16615
        jmp RelWOfs             ;get the coordinates
16616
 
16617
RelativeEnemyPosition:
16618
        ldan ++$01                     ;get coordinates of enemy object 
16619
        ldyn ++$01                     ;relative to the screen
16620
        jmp VariableObjOfsRelPos
16621
 
16622
RelativeBlockPosition:
16623
        ldan ++$09                     ;get coordinates of one block object
16624
        ldyn ++$04                     ;relative to the screen
16625
        jsr VariableObjOfsRelPos
16626
        inx                          ;adjust offset for other block object if any
16627
        inx
16628
        ldan ++$09
16629
        iny                          ;adjust other and get coordinates for other one
16630
 
16631
VariableObjOfsRelPos:
16632
        stx SCRATCHPAD+$00                     ;store value to add to A here
16633
        clc
16634
        adci SCRATCHPAD+$00                     ;add A to value stored
16635
        tax                         ;use as enemy offset
16636
        jsr GetObjRelativePosition
16637
        ldx ObjectOffset            ;reload old object offset and leave
16638
        rts
16639
 
16640
GetObjRelativePosition:
16641
        ldax SprObject_Y_Position,x  ;load vertical coordinate low
16642
        stay SprObject_Rel_YPos,y    ;store here
16643
        ldax SprObject_X_Position,x  ;load horizontal coordinate
16644
        secsub                         ;subtract left edge coordinate
16645
        sbci ScreenLeft_X_Pos
16646
        stay SprObject_Rel_XPos,y    ;store result here
16647
        rts
16648
 
16649
;-------------------------------------------------------------------------------------
16650
;$00 - used as temp variable to hold offscreen bits
16651
 
16652
GetPlayerOffscreenBits:
16653
        ldxn ++$00                 ;set offsets for player-specific variables
16654
        ldyn ++$00                 ;and get offscreen information about player
16655
        jmp GetOffScreenBitsSet
16656
 
16657
GetFireballOffscreenBits:
16658
        ldyn ++$00                 ;set for fireball offsets
16659
        jsr GetProperObjOffset   ;modify X to get proper fireball offset
16660
        ldyn ++$02                 ;set other offset for fireball's offscreen bits
16661
        jmp GetOffScreenBitsSet  ;and get offscreen information about fireball
16662
 
16663
GetBubbleOffscreenBits:
16664
        ldyn ++$01                 ;set for air bubble offsets
16665
        jsr GetProperObjOffset   ;modify X to get proper air bubble offset
16666
        ldyn ++$03                 ;set other offset for airbubble's offscreen bits
16667
        jmp GetOffScreenBitsSet  ;and get offscreen information about air bubble
16668
 
16669
GetMiscOffscreenBits:
16670
        ldyn ++$02                 ;set for misc object offsets
16671
        jsr GetProperObjOffset   ;modify X to get proper misc object offset
16672
        ldyn ++$06                 ;set other offset for misc object's offscreen bits
16673
        jmp GetOffScreenBitsSet  ;and get offscreen information about misc object
16674
 
16675
ObjOffsetData:
16676
        .db $07, $16, $0d
16677
 
16678
GetProperObjOffset:
16679
        txa                  ;move offset to A
16680
        clc
16681
        adcy ObjOffsetData,y  ;add amount of bytes to offset depending on setting in Y
16682
        tax                  ;put back in X and leave
16683
        rts
16684
 
16685
GetEnemyOffscreenBits:
16686
        if Z80OPT ;???   1-2
16687
        inc c
16688
        call RunOffscrBitsSubs ;a=$00, $08, $0c, $0e, $0f, $07, $03, $01, $00
16689
        add a,a                         ;move low nybble to high nybble
16690
        add a,a
16691
        add a,a
16692
        add a,a
16693
        ld hl,SCRATCHPAD+$00
16694
        or (hl)                    ;mask together with previously saved low nybble
16695
        ld (SprObject_OffscrBits+1),a
16696
        ld hl,ObjectOffset
16697
        ld c,(hl)
16698
        ret
16699
        else
16700
        ldan ++$01                 ;set A to add 1 byte in order to get enemy offset
16701
        ldyn ++$01                 ;set Y to put offscreen bits in Enemy_OffscreenBits
16702
        jmp SetOffscrBitsOffset
16703
        endif
16704
 
16705
GetBlockOffscreenBits:
16706
        ldan ++$09       ;set A to add 9 bytes in order to get block obj offset
16707
        ldyn ++$04       ;set Y to put offscreen bits in Block_OffscreenBits
16708
 
16709
SetOffscrBitsOffset:
16710
        stx SCRATCHPAD+$00
16711
        clc           ;add contents of X to A to get
16712
        adci SCRATCHPAD+$00       ;appropriate offset, then give back to X
16713
        tax
16714
 
16715
GetOffScreenBitsSet:
16716
        tya                         ;save offscreen bits offset to stack for now
16717
        pha
16718
        jsr RunOffscrBitsSubs ;a=$00, $08, $0c, $0e, $0f, $07, $03, $01, $00
16719
        asl                         ;move low nybble to high nybble
16720
        asl
16721
        asl
16722
        asl
16723
        orai SCRATCHPAD+$00                     ;mask together with previously saved low nybble
16724
        sta SCRATCHPAD+$00                     ;store both here
16725
        pla                         ;get offscreen bits offset from stack
16726
        tay
16727
        lda SCRATCHPAD+$00                     ;get value here and store elsewhere
16728
        stay SprObject_OffscrBits,y
16729
        ldx ObjectOffset
16730
        rts
16731
 
16732
RunOffscrBitsSubs:
16733
;2 calls
16734
;x    ,  SCRATCHPAD+$00 [ +$07(???)]
16735
        if Z80OPT ;???
16736
 
16737
        call GetXOffscreenBits  ;do subroutine here
16738
        rra                    ;move high nybble to low
16739
        rra
16740
        rra
16741
        rra        ;TODO   GetXOffscreenBits
16742
        and 0x0f
16743
        ld (SCRATCHPAD+$00),a                ;store here
16744
;test top of screen
16745
        ;ld c,0
16746
        xor a ;load coordinate for edge of vertical unit ;.db $ff, $00
16747
        sub (ix+SprObject_Y_Position-SprObject_X_Position)  ;subtract from vertical coordinate of object
16748
          ld l,a;sta SCRATCHPAD+$07                      ;store here
16749
          ld a,++$01                     ;subtract one from vertical high byte of object
16750
        sbc a,(ix+SprObject_Y_HighPos-SprObject_X_Position)
16751
        ;  jp m,YLdBData                 ;if under top of the screen or beyond bottom, branch
16752
        jp m,YLdBbottom ;if under top of the screen or beyond bottom
16753
        ld c,4  ;if not, load alternate offset value here (y+DefaultYOnscreenOfs+1) ;.db $04, $00, $04
16754
          jp nz,YLdBData                 ;if one vertical unit or more above the screen, branch ;  
16755
; dyhigh==0
16756
          ld a,l;lda SCRATCHPAD+$07       ;get pixel difference
16757
          cp 32 ;cmpi SCRATCHPAD+$06       ;compare to preset value
16758
          jr nc,YLdBData  ;if pixel difference HIGH = preset value, branch ; c=x=4 ;  
16759
          rra           ;divide by eight
16760
          rra
16761
          rra ;  : 0..3
16762
          and 3 ;andn ++$07      ;mask out all but 3 LSB ;  2 ,        X  Y
16763
          ld c,a;tax           ;use as offset
16764
YLdBData:
16765
        ld hl,YOffscreenBitsData ;.db $00, $08, $0c, $0e, $0f, $07, $03, $01, $00 ;  0?
16766
        add hl,bc
16767
        ld a,(hl) ;get offscreen data bits using offset
16768
          or a
16769
          ret nz                     ;if bits not zero, branch to leave
16770
;test bottom of screen
16771
YLdBbottom:
16772
        ;ld c,4
16773
        ld a,-1 ;load coordinate for edge of vertical unit ;.db $ff, $00
16774
        sub (ix+SprObject_Y_Position-SprObject_X_Position)  ;subtract from vertical coordinate of object
16775
          ld l,a;sta SCRATCHPAD+$07                      ;store here
16776
          ld a,++$01                     ;subtract one from vertical high byte of object
16777
        sbc a,(ix+SprObject_Y_HighPos-SprObject_X_Position)
16778
        ;  jp m,YLdBDatabottom                 ;if under top of the screen or beyond bottom, branch
16779
        ld a,15
16780
        ret m ;if under top of the screen or beyond bottom
16781
        ;ld c,0  ;if not, load alternate offset value here (y+DefaultYOnscreenOfs+1) ;.db $04, $00, $04
16782
        ld c,8-4 ;    
16783
          jp nz,YLdBDatabottom                 ;if one vertical unit or more above the screen, branch
16784
; dyHSB==0
16785
          ld a,l;lda SCRATCHPAD+$07       ;get pixel difference
16786
          cp 32 ;cmpi SCRATCHPAD+$06       ;compare to preset value
16787
          jr nc,YLdBDatabottom  ;if pixel difference HIGH = preset value, branch ; c=x=0
16788
          rra           ;divide by eight
16789
          rra
16790
          rra ;  : 0..3
16791
          and 3 ;andn ++$07      ;mask out all but 3 LSB ;  2 ,        X  Y
16792
          ;add a,4
16793
          ld c,a;tax           ;use as offset
16794
YLdBDatabottom:
16795
        ld hl,YOffscreenBitsData +4 ;.db $00, $08, $0c, $0e, $0f, $07, $03, $01, $00 ;  0?    
16796
        add hl,bc
16797
        ld a,(hl) ;get offscreen data bits using offset
16798
          ret
16799
 
16800
        else ;~Z80
16801
 
16802
        jsr GetXOffscreenBits  ;do subroutine here
16803
        lsr                    ;move high nybble to low
16804
        lsr
16805
        lsr
16806
        lsr
16807
        sta SCRATCHPAD+$00                ;store here
16808
        jmp GetYOffscreenBits
16809
 
16810
        endif
16811
 
16812
;--------------------------------
16813
;(these apply to these three subsections)
16814
;$04 - used to store proper offset
16815
;$05 - used as adder in DividePDiff
16816
;$06 - used to store preset value used to compare to pixel difference in $07
16817
;$07 - used to store difference between coordinates of object and screen edges
16818
 
16819
;TODO   8 ,   
16820
XOffscreenBitsData:
16821
        .db $7f, $3f, $1f, $0f, $07, $03, $01, $00
16822
        .db $80, $c0, $e0, $f0, $f8, $fc, $fe, $ff
16823
 
16824
DefaultXOnscreenOfs:
16825
        .db $07, $0f, $07
16826
 
16827
GetXOffscreenBits:
16828
;TODO >>4?
16829
        if Z80OPT
16830
          ld ix,SprObject_X_Position
16831
          add ix,bc
16832
;right side of screen
16833
          ld a,(ScreenEdge_X_Pos+1) ;get pixel coordinate of edge ; !!!
16834
        ;ld c,15
16835
        sub (ix) ;get difference between pixel coordinate of edge and pixel coordinate of object position
16836
         ld l,a ;sta SCRATCHPAD+$07                     ;store here
16837
          ld a,(ScreenEdge_PageLoc+1)    ;get page location of edge ; !!!
16838
        sbc a,(ix+SprObject_PageLoc-SprObject_X_Position) ;subtract from page location of object position
16839
          ;jp m,XLdBData                ;if beyond right edge or in front of left edge, branch ;  
16840
         ;ld a,0xff
16841
         ; ret m                ;if beyond right edge or in front of left edge, branch
16842
         jp m,XLdBDataleftq ;if beyond right edge or in front of left edge, branch
16843
         ;ld c,7 ;ldxy DefaultXOnscreenOfs+1,y ;if not, load alternate offset value here ;.db $07, $0f, $07
16844
          jp nz,XLdBleft;XLdBData                ;if one page or more to the left of either edge, branch
16845
; dxHSB==0
16846
         ld a,l ;lda SCRATCHPAD+$07       ;get pixel difference
16847
          cp 56 ;cmpi SCRATCHPAD+$06       ;compare to preset value
16848
          jr nc,XLdBleft;XLdBData  ;if pixel difference >= preset value, branch
16849
          rra           ;divide by eight
16850
          rra
16851
          rra ;  : 0..6
16852
          and ++$07      ;mask out all but 3 LSB
16853
          ld c,a;tax           ;use as offset
16854
;XLdBData:
16855
        ld hl,XOffscreenBitsData
16856
        add hl,bc
16857
        ld a,(hl) ;.db $7f, $3f, $1f, $0f, $07, $03, $01, $00, $80, $c0, $e0, $f0, $f8, $fc, $fe, $ff
16858
          or a                    ;if bits not zero, branch to leave
16859
          ret nz
16860
;left side of screen
16861
XLdBleft
16862
        ld a,(ScreenEdge_X_Pos) ;get pixel coordinate of edge ; !!!
16863
        ld c,7
16864
        sub (ix) ;get difference between pixel coordinate of edge and pixel coordinate of object position
16865
         ld l,a ;sta SCRATCHPAD+$07                     ;store here
16866
          ld a,(ScreenEdge_PageLoc)    ;get page location of edge ; !!!
16867
        sbc a,(ix+SprObject_PageLoc-SprObject_X_Position) ;subtract from page location of object position
16868
          jp m,XLdBDataleft                ;if beyond right edge or in front of left edge, branch
16869
         ;ld c,15 ;ldxy DefaultXOnscreenOfs+1,y ;if not, load alternate offset value here ;.db $07, $0f, $07
16870
          jp nz,XLdBDataleftq;XLdBDataleft                ;if one page or more to the left of either edge, branch ;  
16871
; dxHSB==0
16872
         ld a,l ;lda SCRATCHPAD+$07       ;get pixel difference
16873
          cp 56 ;cmpi SCRATCHPAD+$06       ;compare to preset value
16874
          jr nc,XLdBDataleftq;XLdBDataleft  ;if pixel difference >= preset value, branch ; x=c=15 ;  
16875
          rra           ;divide by eight
16876
          rra
16877
          rra ;  : 0..6
16878
          and ++$07      ;mask out all but 3 LSB
16879
          add a,8
16880
          ld c,a;tax           ;use as offset
16881
XLdBDataleft:
16882
        ld hl,XOffscreenBitsData
16883
        add hl,bc
16884
        ld a,(hl) ;.db $7f, $3f, $1f, $0f, $07, $03, $01, $00, $80, $c0, $e0, $f0, $f8, $fc, $fe, $ff
16885
          ret
16886
XLdBDataleftq
16887
        ld a,0xff
16888
        ret
16889
 
16890
        else ;~Z80
16891
 
16892
;keep x!
16893
          stx SCRATCHPAD+$04                     ;save position in buffer to here
16894
          ldyn ++$01                    ;start with right side of screen
16895
XOfsLoop: lday ScreenEdge_X_Pos,y      ;get pixel coordinate of edge
16896
          secsub                         ;get difference between pixel coordinate of edge
16897
          sbcx SprObject_X_Position,x  ;and pixel coordinate of object position
16898
          sta SCRATCHPAD+$07                     ;store here
16899
          ldaykeepcy ScreenEdge_PageLoc,y    ;get page location of edge
16900
          sbcx SprObject_PageLoc,x     ;subtract from page location of object position
16901
          ldxy DefaultXOnscreenOfs,y   ;load offset value here
16902
          cmpn ++$00      
16903
          bmi XLdBData                ;if beyond right edge or in front of left edge, branch
16904
          ldxy DefaultXOnscreenOfs+1,y ;if not, load alternate offset value here
16905
          cmpn ++$01      
16906
          bpl XLdBData                ;if one page or more to the left of either edge, branch
16907
          ldan ++$38                    ;if no branching, load value here and store
16908
          sta SCRATCHPAD+$06
16909
          ldan ++$08                    ;load some other value and execute subroutine
16910
          jsr DividePDiff
16911
XLdBData: ldax XOffscreenBitsData,x    ;get bits here
16912
          ldx SCRATCHPAD+$04                     ;reobtain position in buffer
16913
          cmpn ++$00                    ;if bits not zero, branch to leave
16914
          bne ExXOfsBS
16915
          dey                         ;otherwise, do left side of screen now
16916
          bpl XOfsLoop                ;branch if not already done with left side ;2 
16917
ExXOfsBS: rts
16918
        endif
16919
 
16920
;--------------------------------
16921
 
16922
;TODO   8 ,   
16923
YOffscreenBitsData:
16924
        .db $00, $08, $0c, $0e
16925
        .db $0f, $07, $03, $01
16926
        .db $00 ;   ? ( Z80  )
16927
 
16928
DefaultYOnscreenOfs:
16929
        .db $04, $00, $04
16930
 
16931
HighPosUnitData:
16932
        .db $ff, $00
16933
 
16934
        if Z80OPT
16935
        else
16936
GetYOffscreenBits:
16937
          stx SCRATCHPAD+$04                      ;save position in buffer to here
16938
          ldyn ++$01                     ;start with top of screen
16939
YOfsLoop0: lday HighPosUnitData,y        ;load coordinate for edge of vertical unit
16940
          secsub
16941
          sbcx SprObject_Y_Position,x   ;subtract from vertical coordinate of object
16942
          sta SCRATCHPAD+$07                      ;store here
16943
          ldan ++$01                     ;subtract one from vertical high byte of object
16944
          sbcx SprObject_Y_HighPos,x
16945
          ldxy DefaultYOnscreenOfs,y    ;load offset value here
16946
          cmpn ++$00
16947
          bmi YLdBData                 ;if under top of the screen or beyond bottom, branch
16948
          ldxy DefaultYOnscreenOfs+1,y  ;if not, load alternate offset value here
16949
          cmpn ++$01
16950
          bpl YLdBData                 ;if one vertical unit or more above the screen, branch
16951
          ldan ++$20                     ;if no branching, load value here and store
16952
          sta SCRATCHPAD+$06
16953
          ldan ++$04                     ;load some other value and execute subroutine
16954
          jsr DividePDiff
16955
YLdBData: ldax YOffscreenBitsData,x     ;get offscreen data bits using offset
16956
          ldx SCRATCHPAD+$04                      ;reobtain position in buffer
16957
          cmpn ++$00
16958
          bne ExYOfsBS                 ;if bits not zero, branch to leave
16959
          dey                          ;otherwise, do bottom of the screen now
16960
          bpl YOfsLoop0
16961
ExYOfsBS: rts
16962
        endif
16963
 
16964
;--------------------------------
16965
 
16966
DividePDiff:
16967
;a = 4 (Y) / 8 (X)
16968
;y =     (0 = /, 1 = /)
16969
;out: x
16970
        if Z80OPT
16971
          ld ly,a;sta SCRATCHPAD+$05       ;store current value in A here
16972
          ld hl,(SCRATCHPAD+$06)
16973
          ld a,h ;lda SCRATCHPAD+$07       ;get pixel difference
16974
          cp l ;cmpi SCRATCHPAD+$06       ;compare to preset value
16975
          ret nc  ;if pixel difference >= preset value, branch
16976
          rra           ;divide by eight
16977
          rra
16978
          rra
16979
          and ++$07      ;mask out all but 3 LSB
16980
        inc e ;right side of the screen or top?
16981
        dec e
16982
          jr nz,SetOscrO  ;if so, branch, use difference / 8 as offset
16983
          add a,ly; SCRATCHPAD+$05       ;if not, add value to difference / 8
16984
SetOscrO: ld c,a           ;use as offset
16985
        ret
16986
        else
16987
          sta SCRATCHPAD+$05       ;store current value in A here
16988
          lda SCRATCHPAD+$07       ;get pixel difference
16989
          cmpi SCRATCHPAD+$06       ;compare to preset value
16990
              cmpcy
16991
          bcs ExDivPD   ;if pixel difference >= preset value, branch
16992
          lsr           ;divide by eight
16993
          lsr
16994
          lsr
16995
          andn ++$07      ;mask out all but 3 LSB
16996
          cpyn ++$01      ;right side of the screen or top?
16997
              cmpcy
16998
          bcs SetOscrO  ;if so, branch, use difference / 8 as offset
16999
          adci SCRATCHPAD+$05       ;if not, add value to difference / 8
17000
SetOscrO: tax           ;use as offset
17001
ExDivPD:  rts           ;leave
17002
        endif
17003
 
17004
;-------------------------------------------------------------------------------------
17005
;$00-$01 - tile numbers (hl, out: hl+=2)
17006
;$02 - Y coordinate
17007
;$03 - flip control
17008
;$04 - sprite attributes
17009
;$05 - X coordinate
17010
;y = Sprite_Data offset
17011
;out: [x+=2], y+=8
17012
 
17013
DrawSpriteObject:
17014
        if Z80OPT
17015
         ld ix,Sprite_Data
17016
         add ix,de
17017
         lda SCRATCHPAD+$03                    ;get saved flip control bits
17018
         rra
17019
         rra                        ;move d1 into carry
17020
         ;ld hl,(SCRATCHPAD+$00)
17021
         ld a,(hl)
17022
         jr nc,NoHFlip                ;if d1 not set, branch
17023
         ld (ix+Sprite_Tilenumber-Sprite_Data+4),a  ;store first tile into second sprite
17024
         inc hl
17025
         ld a,(hl)
17026
         ld (ix+Sprite_Tilenumber-Sprite_Data),a ;and second into first sprite
17027
         ld a,(SCRATCHPAD+$04)
17028
         or 0x40                   ;activate horizontal flip OAM attribute
17029
         jp SetHFAt                ;and unconditionally branch
17030
NoHFlip: ld (ix+Sprite_Tilenumber-Sprite_Data),a    ;store first tile into first sprite
17031
         inc hl
17032
         ld a,(hl)
17033
         ld (ix+Sprite_Tilenumber-Sprite_Data+4),a ;and second into second sprite
17034
         ld a,(SCRATCHPAD+$04)                    ; +0x40 OAM attribute
17035
SetHFAt:
17036
         ld (ix+Sprite_Attributes-Sprite_Data),a    ;store sprite attributes
17037
         ld (ix+Sprite_Attributes-Sprite_Data+4),a
17038
         ld a,(SCRATCHPAD+$02)                    ;now the y coordinates
17039
         ld (ix+Sprite_Y_Position-Sprite_Data),a   ;note because they are
17040
         ld (ix+Sprite_Y_Position-Sprite_Data+4),a ;side by side, they are the same
17041
         add a,8    ;add eight pixels to the next y coordinate
17042
         ld (SCRATCHPAD+$02),a
17043
         ld a,(SCRATCHPAD+$05)
17044
         ld (ix+Sprite_X_Position-Sprite_Data),a    ;store x coordinate, then
17045
         add a,8                        ;add 8 pixels and store another to
17046
         ld (ix+Sprite_X_Position-Sprite_Data+4),a  ;put them side by side
17047
         ld a,e                        ;add eight to the offset in Y to
17048
         add a,8                      ;move to the next two sprites
17049
         ld e,a
17050
         inc hl
17051
        else
17052
         lda SCRATCHPAD+$03                    ;get saved flip control bits
17053
         lsr
17054
         lsr                        ;move d1 into carry
17055
         lda SCRATCHPAD+$00
17056
         bcc NoHFlip                ;if d1 not set, branch
17057
         stay Sprite_Tilenumber+4,y  ;store first tile into second sprite
17058
         lda SCRATCHPAD+$01                    ;and second into first sprite
17059
         stay Sprite_Tilenumber,y
17060
         ldan ++$40                   ;activate horizontal flip OAM attribute
17061
         checka
17062
         bne SetHFAt                ;and unconditionally branch
17063
NoHFlip: stay Sprite_Tilenumber,y    ;store first tile into first sprite
17064
         lda SCRATCHPAD+$01                    ;and second into second sprite
17065
         stay Sprite_Tilenumber+4,y
17066
         ldan ++$00                   ;clear bit for horizontal flip
17067
SetHFAt: orai SCRATCHPAD+$04                    ;add other OAM attributes if necessary
17068
         stay Sprite_Attributes,y    ;store sprite attributes
17069
         stay Sprite_Attributes+4,y
17070
         lda SCRATCHPAD+$02                    ;now the y coordinates
17071
         stay Sprite_Y_Position,y    ;note because they are
17072
         stay Sprite_Y_Position+4,y  ;side by side, they are the same
17073
         lda SCRATCHPAD+$05      
17074
         stay Sprite_X_Position,y    ;store x coordinate, then
17075
         clc                        ;add 8 pixels and store another to
17076
         adcn ++$08                   ;put them side by side
17077
         stay Sprite_X_Position+4,y
17078
         lda SCRATCHPAD+$02                    ;add eight pixels to the next y
17079
         clc                        ;coordinate
17080
         adcn ++$08
17081
         sta SCRATCHPAD+$02
17082
         tya                        ;add eight to the offset in Y to
17083
         clc                        ;move to the next two sprites
17084
         adcn ++$08
17085
         tay
17086
         inx                        ;increment offset to return it to the
17087
         inx                        ;routine that called this subroutine
17088
        endif
17089
         rts
17090
 
17091
;-------------------------------------------------------------------------------------
17092
 
17093
        if Z80==0
17094
;unused space (  Super Mario Bros..nes)
17095
;   Super Mario Bros (JU) (PRG 1).nes  78, ee, cb, f2, ff, ff - ???      !!!
17096
        .db $ff, $ff, $ff, $ff, $ff, $ff
17097
        endif
17098
 
17099
;-------------------------------------------------------------------------------------
174 demige 17100
        if MUSICONINT==0
171 demige 17101
        include "smbsound.asm"
17102
        include "smbmusic.asm"
174 demige 17103
        endif
171 demige 17104
;-------------------------------------------------------------------------------------
17105
;INTERRUPT VECTORS
17106
 
17107
       if Z80==0
17108
;   : 82 80 00 80 f0 ff
17109
      .dw NonMaskableInterrupt
17110
      .dw Start
17111
      .dw $fff0  ;unused ( Xevious    ff,   ,  Bomberman1   7  )
17112
       endif
17113
 
17114
SwimTileRepOffset     = PlayerGraphicsTable + $9e
17115
MusicHeaderOffsetData = MusicHeaderData - 1
17116
MHD                   = MusicHeaderData