;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;THE NOOB'S BOSS 1.3 ; By Maxx ; A 32x32 sprite that will walk or sit there. It's a boss, ending the level when his hitpoints reach 0. ; No Extra Byte. ; haha... who knows when I'll document this thing! ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; VVVVVVVVVVVVVVVVVVVVVVV CHANGE THAT VVVVVVVVVVVVVVVVVVVVVVVVVVVVV ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;CHANGE THIS! ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; ; DO NOT GO OVER 100 OR USE 3-DIGIT NUMBERS! ;;;; BONE_OR_HAMMER = $04 ; 06 = Boss throws bones 04 = boss throws hammers. These have different ways of moving- the bones move straight and the hammers move in a arch. You must remember hammers only work with certain (there are many) sprite GFX. Bones only work with castle sprite GFX. HITPOINTS = $03 ; How much health the boss has FINALSTAND = $01 ; How many hitpoints he is at when he activates a power (drop enemies on Mario or something here!) FINALTYPE = $00 ; What to do for the final stand. 00 = Activate the POW, 01 = Switch the ON/OFF switch, 02 = Roar and throw a bunch of hammers POWLENGTH = $28 ; How long a pow lasts. This is not in seconds- FF is a 16 second POW. (If you don't know hex, this just means it's okay to put a number under 99 here. HAMMERFREQ = $02 ; hammer frequency. 00 = none, 01 = two per 4 seconds or so, 02 = 3 per four seconds or so DIRECTION = $00 ; Initally $00 = facing left, $40 = facing right. WALKING = $00 ; 00 = won't walk, 01 = will walk. ENDOPTION = $01 ; When boss is beaten: 00 = end level, 01 = warp using the screen exit, like when you go through a door SPEEDLEFT = $80 ; ONLY USE NUMBERS 80-FF, FF IS THE SLOWEST, 80 IS THE FASTEST. SPEEDRIGHT = $7F ; ONLY USE NUMBERS 00-7F, 00 IS THE SLOWEST, 7F IS THE FASTEST. STATUSSHOW = $01 ; 00 - Won't say "BOSS:(HP)" on the status bar. 01 = Will. GRAVITY = $00 ; 00 - No gravity on sprite; 10 - Suggested Gravity by tutorial ; 1D - Normal Gravity ; You can use any number BELOW 60 (perhaps a little higher) unless you want your sprite going through walls. ;;;;;;;;;; ;GRAPHICS STUFF ;;;;;;;;;; TOPRIGHT = $80 ; THESE GRAPHICS ARE DETERMINED LIKE THIS: Go to the 8x8 editor in LM (the item box with 3 quarters of it blacked out.) Press the down until you see enemies.( you should be on page 2. Do not try to use GFX from other pages.) Now, put your mouse over the GFX you want. Make sure it is four 8x8 tiles! Now, go to the very top left tile of those graphics. The number you see at the status bar (bottom of that window you just opened) is what you need to put for these. TOPRIGHTWALK = $80 ; ALSO- Please note that these tile positions are when the sprite is facing right- that is, when the sprite is going left to right. If that made no sense to you, just specifiy the tiles and you can fix it for yourself, it's not hard. TOPLEFT = $82 TOPLEFTWALK = $82 BOTTOMRIGHT = $A7 BOTTOMLEFT = $A9 BOTTOMLEFTWALK = $E2 ; the walking frame for your boss. Do not edit if he does not walk. BOTTOMRIGHTWALK = $E2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;VVVVVVVVVVVVVVVVVVV DO NOT MESS WITH ANYTHNG DOWN HERE! VVVVVVVVVVVVVVVVVVVV;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Tables ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; TBL_B2D0 dcb $F0,$FF TBL_B2D2 dcb $FF,$00 TBL_B2D4 dcb $10,$F0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; INIT and MAIN JSL targets ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; dcb "INIT" LDA #HITPOINTS STA $7F8888 RTL dcb "MAIN" PHB PHK PLB JSR SPRITE_ROUTINE LDA $157C,x CMP #$01 BEQ SetXswitch LDA #$00 STA $7F9877 BRA afterXset SetXswitch: LDA #$10 STA $7F9877 afterXset LDA #STATUSSHOW BEQ noshow LDA #$0B STA $0F09 LDA #$18 STA $0F0A LDA #$1C STA $0F0B STA $0F0C LDA #$78 STA $0F0D LDA $7F8888 STA $0F0E noshow: LDA $157C,x ; $02 = sprite direction STA $02 PLB RTL ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; SPRITE_ROUTINE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; SPEED_TABLE dcb SPEEDRIGHT,SPEEDLEFT ; speeds (right, left) ;;;;;;;;;;;1. fix the speed when facing right (more) SPRITE_ROUTINE JSR SUB_GFX LDA $14C8,x ; return if sprite status != 8 CMP #$08 BNE RETURN LDA $9D ; return if sprites locked BNE RETURN LDA #HAMMERFREQ CMP #$02 BEQ highfreqstart LDA $13 CMP #$15 BEQ hammer LDA $13 CMP #$45 BEQ hammer BRA back highfreqstart: LDA $12 CMP #$05 BEQ freqjsl LDA $13 CMP #$15 BEQ freqjsl LDA $13 CMP #$25 BEQ freqjsl LDA $13 CMP #$35 BEQ freqjsl BRA back freqjsl: JSR freqhammer back: JSR SUB_OFF_SCREEN_X0 ; only process sprite while on screen JSR general JSL $01802A ; update position based on speed values JSL $01A7DC ; check for mario/sprite contact LDA $7F9654 CMP #$01 BEQ already already: RETURN: LDA #WALKING CMP #$01 BEQ walkingjump RTS hammer: JSR hammergen BRA back RTS walkingjump: JSR walkcode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;generate sprite routine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; general: LDA $7F8888 CMP #FINALSTAND BEQ final normie: LDA #$00 CMP $7F8888 BEQ dead BRA notdead dead: LDA #$04 STA $14C8,x LDA #ENDOPTION CMP #$01 BEQ Screenend LDA #$FF STA $1493 LDA #$0B STA $1DFB LDA #$3B STA $1DFC RTS Screenend: LDA #$06 STA $71 STZ $89 STZ $88 RTS final: LDA #FINALTYPE CMP #$01 BEQ Finalonoff LDA #FINALTYPE CMP #$02 BEQ FinalRoar LDA #POWLENGTH STA $14AD BRA notdead Finalonoff: LDA $14AF EOR #$01 STA $14AF BRA notdead FinalRoar: LDA #$25 STA $1DF9 JSR hammergen JSR hammergen notdead: SPRITE_INTERACT LDY #$0B ; LOOP LDA $14C8,y ; \ if the sprite status is.. CMP #$09 ; | ...shell-like BEQ PROCESS_SPRITE ; / CMP #$0A ; \ ...throwned shell-like BEQ PROCESS_SPRITE ; / NEXT_SPRITE DEY ; BPL LOOP ; ...otherwise, loop RTS ; return PROCESS_SPRITE PHX ; push x TYX ; transfer x to y JSL $03B6E5 ; get sprite clipping B routine PLX ; pull x JSL $03B69F ; get sprite clipping A routine JSL $03B72B ; check for contact routine BCC NEXT_SPRITE ; LDA #$03 ; \ set sprite state STA $C2,x ; / LDA #$40 ; \ set timer STA $1540,x ; / PHX ; push x TYX ; transfer x to y STZ $14C8,x ; destroy the sprite BLOCK_SETUP LDA $E4,x ; \ setup block properties STA $9A ; | LDA $14E0,x ; | STA $9B ; | LDA $D8,x ; | STA $98 ; | LDA $14D4,x ; | STA $99 ; / EXPLODING_BLOCK PHB ; \ set the exploding block routine LDA #$02 ; | PHA ; | PLB ; | LDA #$FF ; | $FF = set flashing palette JSL $028663 ; | LDA $7F8888 DEC A STA $7F8888 LDA #STATUSSHOW CMP #$00 BEQ aftershowthing STA $7E0F0E aftershowthing: PLB ; / PLX ; pull x LDA #$28 ; \ sound effect STA $1DFC ; / RTS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; GRAPHICS ROUTINE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; TILEMAPLEFTTOP dcb TOPLEFT,TOPLEFTWALK,TOPLEFT,TOPLEFTWALK,TOPLEFT,TOPLEFTWALK,TOPLEFT,TOPLEFTWALK,TOPLEFT,TOPLEFTWALK,TOPLEFT,TOPLEFTWALK,TOPLEFT,TOPLEFTWALK,TOPLEFT,TOPLEFTWALK TILEMAPLEFT dcb BOTTOMLEFT,BOTTOMLEFTWALK,BOTTOMLEFT,BOTTOMLEFTWALK,BOTTOMLEFT,BOTTOMLEFTWALK,BOTTOMLEFT,BOTTOMLEFTWALK,BOTTOMLEFT,BOTTOMLEFTWALK,BOTTOMLEFT,BOTTOMLEFTWALK,BOTTOMLEFT,BOTTOMLEFTWALK,BOTTOMLEFT,BOTTOMLEFTWALK TILEMAPRIGHTTOP dcb TOPRIGHT,TOPRIGHTWALK,TOPRIGHT,TOPRIGHTWALK,TOPRIGHT,TOPRIGHTWALK,TOPRIGHT,TOPRIGHTWALK,TOPRIGHT,TOPRIGHTWALK,TOPRIGHT,TOPRIGHTWALK,TOPRIGHT,TOPRIGHTWALK,TOPRIGHT,TOPRIGHTWALK SUB_GFX JSR GET_DRAW_INFO ; after: Y = index to sprite OAM ($300) ; $00 = sprite x position relative to screen boarder ; $01 = sprite y position relative to screen boarder LDA $157C,x ; $02 = sprite direction STA $02 ;;;;;;;;;Top-Left tile here;;;;;;;;;;;;;;;; LDA $00 ; set x position of the tile CLC ADC $7F9877 STA $0300,y LDA $01 ; set y position of the tile CLC ADC #$02 STA $0301,y LDA $13 ; \ LSR A ; | $03 = index to frame start (frame to show * 2 tile per frame) LSR A LSR A LSR A STA $03 ; / LOOP_START PHX ; push current tile number TAX ; \ X = index to horizontal displacement ORA $03 ; / get index of tile (index to first tile of frame + current tile number) FACING_LOL TAX ; \ LDA TILEMAPLEFTTOP,x STA $0302,y PLX LDA $15F6,x ; get sprite palette info ORA $64 ; add in the priority bits from the level settings PHX LDX $02 ; flip the tile if the sprite direction is 0 BNE NO_FLIP_4 ORA #$40 NO_FLIP_4 PLX STA $0303,y ; set properties INY ; get the index to the next slot of the OAM INY ; (this is needed if you wish to draw another tile) INY INY ;;;;;;;;;;;;;;;;;;;;TOP-RIGHT Tile;;;;;;;;;;;;;;;;;;; LDA $157C,x ; $02 = sprite direction STA $02 LDA $00 ; set x position of the tile CLC ADC #$10 SEC SBC $7F9877 STA $0300,y LDA $01 ; set y position of the tile CLC ADC #$02 STA $0301,y LDA $13 ; \ LSR A ; | $03 = index to frame start (frame to show * 2 tile per frame) LSR A LSR A LSR A STA $03 ; / LOOP_STARX PHX ; push current tile number TAX ; \ X = index to horizontal displacement ORA $03 ; / get index of tile (index to first tile of frame + current tile number) FACING_LOX TAX ; \ LDA TILEMAPRIGHTTOP,x STA $0302,y PLX LDA $15F6,x ; get sprite palette info ORA $64 ; add in the priority bits from the level settings PHX LDX $02 ; flip the tile if the sprite direction is 0 BNE NO_FLIP_7 ORA #$40 NO_FLIP_7 PLX STA $0303,y ; set properties INY ; get the index to the next slot of the OAM INY ; (this is needed if you wish to draw another tile) INY INY BRA aftertile ;;;;;;;;;;;;;;;;;;;;;;;;; TILEMAP dcb BOTTOMRIGHT,BOTTOMRIGHTWALK,BOTTOMRIGHT,BOTTOMRIGHTWALK,BOTTOMRIGHT,BOTTOMRIGHTWALK,BOTTOMRIGHT,BOTTOMRIGHTWALK,BOTTOMRIGHT,BOTTOMRIGHTWALK,BOTTOMRIGHT,BOTTOMRIGHTWALK,BOTTOMRIGHT,BOTTOMRIGHTWALK,BOTTOMRIGHT,BOTTOMRIGHTWALK aftertile: ;;;;;;;;;;;;;Bottom-Right Tile;;;;;;;;;;;;;; LDA $157C,x ; $02 = sprite direction STA $02 LDA $00 ; set x position of the tile CLC ADC #$10 SEC SBC $7F9877 STA $0300,y LDA $01 ; set y position of the tile CLC ADC #$10 STA $0301,y LDA #WALKING BEQ nowalkGFX LDA $13 ; \ LSR A ; | $03 = index to frame start (frame to show * 2 tile per frame) LSR A LSR A LSR A STA $03 ; / LOOP_START PHX ; push current tile number TAX ; \ X = index to horizontal displacement ORA $03 ; / get index of tile (index to first tile of frame + current tile number) FACING_LEFT TAX ; \ ;LDA #BOTTOMRIGHT LDA TILEMAP,x ; \ store tile STA $0302,y ; / PLX BRA afternowalk nowalkGFX: LDA #BOTTOMRIGHT STA $0302,y ; / afternowalk: LDA $15F6,x ; get sprite palette info ORA $64 ; add in the priority bits from the level settings PHX LDX $02 ; flip the tile if the sprite direction is 0 BNE NO_FLIP_2 ORA #$40 NO_FLIP_2 PLX STA $0303,y ; set properties INY ; get the index to the next slot of the OAM INY ; (this is needed if you wish to draw another tile) INY INY ;;;;;;;;;;;;;;;;;;;;;Bottom-Left Tile;;;;;;;;;;; LDA $157C,x ; $02 = sprite direction STA $02 LDA $00 ; set x position of the tile CLC ADC $7F9877 STA $0300,y LDA $01 ; set y position of the tile CLC ADC #$10 STA $0301,y LDA #WALKING BEQ nowalkGFXL LDA $13 ; \ LSR A ; | $03 = index to frame start (frame to show * 2 tile per frame) LSR A LSR A LSR A STA $03 ; / LOOP_START PHX ; push current tile number TAX ; \ X = index to horizontal displacement ORA $03 ; / get index of tile (index to first tile of frame + current tile number) FACING_LEFT TAX ; \ ;LDA #BOTTOMLEFT LDA TILEMAPLEFT,x ; \ store tile STA $0302,y ; / PLX BRA afternowalkL nowalkGFXL: LDA #BOTTOMLEFT STA $0302,y afternowalkL: LDA $15F6,x ; get sprite palette info ORA $64 ; add in the priority bits from the level settings PHX LDX $02 ; flip the tile if the sprite direction is 0 BNE NO_FLIP_1 ORA #$40 NO_FLIP_1 PLX STA $0303,y ; set properties INY ; get the index to the next slot of the OAM INY ; (this is needed if you wish to draw another tile) INY INY ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; LDY #$02 ; #$02 means the tiles are 16x16 LDA #$03 ; This means we drew one tile JSL $01B7B3 RTS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Extended sprite routine, adapted by Maxx and Roy, but originally by Carol ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; HAM_TABLE dcb $25,$DA hammergen: LDA #HAMMERFREQ CMP #$01 BEQ real LDA #HAMMERFREQ CMP #02 BEQ freqhammer RTS real: LDY #$07 EXTRA_LOOP LDA $170B,y BEQ EXTRA_1 DEY BPL EXTRA_LOOP RTS EXTRA_1 LDA #BONE_OR_HAMMER STA $170B,y LDA $E4,x STA $171F,y LDA $14E0,x STA $1733,y LDA $D8,x STA $1715,y LDA $14D4,x STA $1729,y LDA #$DA STA $173D,y LDA $157C,x ; $02 = sprite direction STA $7F9987 PHX LDA $7F9987 TAX LDA HAM_TABLE,x PLX STA $1747,y STA $0F0B LDA #$FF STA $176F,y LDA #$26 STA $1DF9 RTS freqhammer: LDY #$07 EXTRA_LOOP LDA $170B,y BEQ EXTRA_1 DEY BPL EXTRA_LOOP RTS EXTRA_1 LDA #BONE_OR_HAMMER STA $170B,y LDA $E4,x STA $171F,y LDA $14E0,x STA $1733,y LDA $D8,x STA $1715,y LDA $14D4,x STA $1729,y LDA #$DA STA $173D,y LDA $157C,x ; $7F9987 = sprite direction STA $7F9987 PHX LDA $7F9987 TAX LDA HAM_TABLE,x PLX STA $1747,y LDA #$FF STA $176F,y LDA #$26 STA $1DF9 LDA #$00 STA #TOPRIGHT RTS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;WALKING ROUTINE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; SPEED_TABLE dcb SPEEDRIGHT,SPEEDLEFT ; speeds (right, left) walkcode: LDA #GRAVITY ; y speed = 10 STA $AA,x ; LDY $157C,x ; LDA SPEED_TABLE,y ; x speed depends on direction STA $B6,x ; LDA $1588,x ; check if sprite is touching object side AND #$03 ; BEQ DONT_CHANGE_DIR ; LDA $157C,x ; EOR #$01 ; flip sprite direction STA $157C,x ; DONT_CHANGE_DIR RTS ; this code ripped off lesson2b.asm in the tutorials folder. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ROUTINES FROM THE LIBRARY ARE PASTED BELOW ; You should never have to modify this code ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; SUB_SMOKE LDY #$03 ; \ find a free slot to display effect FINDFREE LDA $17C0,y ; | BEQ FOUNDONE ; | DEY ; | BPL FINDFREE ; | RTS ; / return if no slots open FOUNDONE LDA #$01 ; \ set effect graphic to smoke graphic STA $17C0,y ; / LDA #$1B ; \ set time to show smoke STA $17CC,y ; / LDA $D8,x ; \ smoke y position = generator y position STA $17C4,y ; / LDA $E4,x ; \ load generator x position and store it for later STA $17C8,y ; / RTS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; $B817 - horizontal mario/sprite check - shared ; Y = 1 if mario left of sprite?? ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;org $03B817 SUB_HORZ_POS LDY #$00 ;A:25D0 X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNvMXdizCHC:1020 VC:097 00 FL:31642 LDA $94 ;A:25D0 X:0006 Y:0000 D:0000 DB:03 S:01ED P:envMXdiZCHC:1036 VC:097 00 FL:31642 SEC ;A:25F0 X:0006 Y:0000 D:0000 DB:03 S:01ED P:eNvMXdizCHC:1060 VC:097 00 FL:31642 SBC $E4,x ;A:25F0 X:0006 Y:0000 D:0000 DB:03 S:01ED P:eNvMXdizCHC:1074 VC:097 00 FL:31642 STA $0F ;A:25F4 X:0006 Y:0000 D:0000 DB:03 S:01ED P:eNvMXdizcHC:1104 VC:097 00 FL:31642 LDA $95 ;A:25F4 X:0006 Y:0000 D:0000 DB:03 S:01ED P:eNvMXdizcHC:1128 VC:097 00 FL:31642 SBC $14E0,x ;A:2500 X:0006 Y:0000 D:0000 DB:03 S:01ED P:envMXdiZcHC:1152 VC:097 00 FL:31642 BPL LABEL16 ;A:25FF X:0006 Y:0000 D:0000 DB:03 S:01ED P:eNvMXdizcHC:1184 VC:097 00 FL:31642 INY ;A:25FF X:0006 Y:0000 D:0000 DB:03 S:01ED P:eNvMXdizcHC:1200 VC:097 00 FL:31642 LABEL16 RTS ;A:25FF X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizcHC:1214 VC:097 00 FL:31642 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; GET_DRAW_INFO ; This is a helper for the graphics routine. It sets off screen flags, and sets up ; variables. It will return with the following: ; ; Y = index to sprite OAM ($300) ; $00 = sprite x position relative to screen boarder ; $01 = sprite y position relative to screen boarder ; ; It is adapted from the subroutine at $03B760 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; SPR_T1 dcb $0C,$1C SPR_T2 dcb $01,$02 GET_DRAW_INFO STZ $186C,x ; reset sprite offscreen flag, vertical STZ $15A0,x ; reset sprite offscreen flag, horizontal LDA $E4,x ; \ CMP $1A ; | set horizontal offscreen if necessary LDA $14E0,x ; | SBC $1B ; | BEQ ON_SCREEN_X ; | INC $15A0,x ; / ON_SCREEN_X LDA $14E0,x ; \ XBA ; | LDA $E4,x ; | REP #$20 ; | SEC ; | SBC $1A ; | mark sprite invalid if far enough off screen CLC ; | ADC.W #$0040 ; | CMP.W #$0180 ; | SEP #$20 ; | ROL A ; | AND #$01 ; | STA $15C4,x ; / BNE INVALID ; LDY #$00 ; \ set up loop: LDA $1662,x ; | AND #$20 ; | if not smushed (1662 & 0x20), go through loop twice BEQ ON_SCREEN_LOOP ; | else, go through loop once INY ; / ON_SCREEN_LOOP LDA $D8,x ; \ CLC ; | set vertical offscreen if necessary ADC SPR_T1,y ; | PHP ; | CMP $1C ; | (vert screen boundry) ROL $00 ; | PLP ; | LDA $14D4,x ; | ADC #$00 ; | LSR $00 ; | SBC $1D ; | BEQ ON_SCREEN_Y ; | LDA $186C,x ; | (vert offscreen) ORA SPR_T2,y ; | STA $186C,x ; | ON_SCREEN_Y DEY ; | BPL ON_SCREEN_LOOP ; / LDY $15EA,x ; get offset to sprite OAM LDA $E4,x ; \ SEC ; | SBC $1A ; | $00 = sprite x position relative to screen boarder STA $00 ; / LDA $D8,x ; \ SEC ; | SBC $1C ; | $01 = sprite y position relative to screen boarder STA $01 ; / RTS ; return INVALID PLA ; \ return from *main gfx routine* subroutine... PLA ; | ...(not just this subroutine) RTS ; / ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; SUB_OFF_SCREEN ; This subroutine deals with sprites that have moved off screen ; It is adapted from the subroutine at $01AC0D ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; SPR_T12 dcb $40,$B0 SPR_T13 dcb $01,$FF SPR_T14 dcb $30,$C0,$A0,$C0,$A0,$F0,$60,$90 ;bank 1 sizes dcb $30,$C0,$A0,$80,$A0,$40,$60,$B0 ;bank 3 sizes SPR_T15 dcb $01,$FF,$01,$FF,$01,$FF,$01,$FF ;bank 1 sizes dcb $01,$FF,$01,$FF,$01,$00,$01,$FF ;bank 3 sizes SUB_OFF_SCREEN_X1 LDA #$02 ; \ entry point of routine determines value of $03 BRA STORE_03 ; | (table entry to use on horizontal levels) SUB_OFF_SCREEN_X2 LDA #$04 ; | BRA STORE_03 ; | SUB_OFF_SCREEN_X3 LDA #$06 ; | BRA STORE_03 ; | SUB_OFF_SCREEN_X4 LDA #$08 ; | BRA STORE_03 ; | SUB_OFF_SCREEN_X5 LDA #$0A ; | BRA STORE_03 ; | SUB_OFF_SCREEN_X6 LDA #$0C ; | BRA STORE_03 ; | SUB_OFF_SCREEN_X7 LDA #$0E ; | STORE_03 STA $03 ; | BRA START_SUB ; | SUB_OFF_SCREEN_X0 STZ $03 ; / START_SUB JSR SUB_IS_OFF_SCREEN ; \ if sprite is not off screen, return BEQ RETURN_35 ; / LDA $5B ; \ goto VERTICAL_LEVEL if vertical level AND #$01 ; | BNE VERTICAL_LEVEL ; / LDA $D8,x ; \ CLC ; | ADC #$50 ; | if the sprite has gone off the bottom of the level... LDA $14D4,x ; | (if adding 0x50 to the sprite y position would make the high byte >= 2) ADC #$00 ; | CMP #$02 ; | BPL ERASE_SPRITE ; / ...erase the sprite LDA $167A,x ; \ if "process offscreen" flag is set, return AND #$04 ; | BNE RETURN_35 ; / LDA $13 ;A:8A00 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdiZcHC:0756 VC:176 00 FL:205 AND #$01 ;A:8A01 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizcHC:0780 VC:176 00 FL:205 ORA $03 ;A:8A01 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizcHC:0796 VC:176 00 FL:205 STA $01 ;A:8A01 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizcHC:0820 VC:176 00 FL:205 TAY ;A:8A01 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizcHC:0844 VC:176 00 FL:205 LDA $1A ;A:8A01 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizcHC:0858 VC:176 00 FL:205 CLC ;A:8A00 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdiZcHC:0882 VC:176 00 FL:205 ADC SPR_T14,y ;A:8A00 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdiZcHC:0896 VC:176 00 FL:205 ROL $00 ;A:8AC0 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:eNvMXdizcHC:0928 VC:176 00 FL:205 CMP $E4,x ;A:8AC0 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:eNvMXdizCHC:0966 VC:176 00 FL:205 PHP ;A:8AC0 X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizCHC:0996 VC:176 00 FL:205 LDA $1B ;A:8AC0 X:0009 Y:0001 D:0000 DB:01 S:01F0 P:envMXdizCHC:1018 VC:176 00 FL:205 LSR $00 ;A:8A00 X:0009 Y:0001 D:0000 DB:01 S:01F0 P:envMXdiZCHC:1042 VC:176 00 FL:205 ADC SPR_T15,y ;A:8A00 X:0009 Y:0001 D:0000 DB:01 S:01F0 P:envMXdizcHC:1080 VC:176 00 FL:205 PLP ;A:8AFF X:0009 Y:0001 D:0000 DB:01 S:01F0 P:eNvMXdizcHC:1112 VC:176 00 FL:205 SBC $14E0,x ;A:8AFF X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizCHC:1140 VC:176 00 FL:205 STA $00 ;A:8AFF X:0009 Y:0001 D:0000 DB:01 S:01F1 P:eNvMXdizCHC:1172 VC:176 00 FL:205 LSR $01 ;A:8AFF X:0009 Y:0001 D:0000 DB:01 S:01F1 P:eNvMXdizCHC:1196 VC:176 00 FL:205 BCC SPR_L31 ;A:8AFF X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdiZCHC:1234 VC:176 00 FL:205 EOR #$80 ;A:8AFF X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdiZCHC:1250 VC:176 00 FL:205 STA $00 ;A:8A7F X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizCHC:1266 VC:176 00 FL:205 SPR_L31 LDA $00 ;A:8A7F X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizCHC:1290 VC:176 00 FL:205 BPL RETURN_35 ;A:8A7F X:0009 Y:0001 D:0000 DB:01 S:01F1 P:envMXdizCHC:1314 VC:176 00 FL:205 ERASE_SPRITE LDA $14C8,x ; \ if sprite status < 8, permanently erase sprite CMP #$08 ; | BCC KILL_SPRITE ; / LDY $161A,x ;A:FF08 X:0007 Y:0001 D:0000 DB:01 S:01F3 P:envMXdiZCHC:1108 VC:059 00 FL:2878 CPY #$FF ;A:FF08 X:0007 Y:0000 D:0000 DB:01 S:01F3 P:envMXdiZCHC:1140 VC:059 00 FL:2878 BEQ KILL_SPRITE ;A:FF08 X:0007 Y:0000 D:0000 DB:01 S:01F3 P:envMXdizcHC:1156 VC:059 00 FL:2878 LDA #$00 ;A:FF08 X:0007 Y:0000 D:0000 DB:01 S:01F3 P:envMXdizcHC:1172 VC:059 00 FL:2878 STA $1938,y ;A:FF00 X:0007 Y:0000 D:0000 DB:01 S:01F3 P:envMXdiZcHC:1188 VC:059 00 FL:2878 KILL_SPRITE STZ $14C8,x ; erase sprite RETURN_35 RTS ; return VERTICAL_LEVEL LDA $167A,x ; \ if "process offscreen" flag is set, return AND #$04 ; | BNE RETURN_35 ; / LDA $13 ; \ LSR A ; | BCS RETURN_35 ; / LDA $E4,x ; \ CMP #$00 ; | if the sprite has gone off the side of the level... LDA $14E0,x ; | SBC #$00 ; | CMP #$02 ; | BCS ERASE_SPRITE ; / ...erase the sprite LDA $13 ;A:0000 X:0009 Y:00E4 D:0000 DB:01 S:01F3 P:eNvMXdizcHC:1218 VC:250 00 FL:5379 LSR A ;A:0016 X:0009 Y:00E4 D:0000 DB:01 S:01F3 P:envMXdizcHC:1242 VC:250 00 FL:5379 AND #$01 ;A:000B X:0009 Y:00E4 D:0000 DB:01 S:01F3 P:envMXdizcHC:1256 VC:250 00 FL:5379 STA $01 ;A:0001 X:0009 Y:00E4 D:0000 DB:01 S:01F3 P:envMXdizcHC:1272 VC:250 00 FL:5379 TAY ;A:0001 X:0009 Y:00E4 D:0000 DB:01 S:01F3 P:envMXdizcHC:1296 VC:250 00 FL:5379 LDA $1C ;A:001A X:0009 Y:0001 D:0000 DB:01 S:01F3 P:eNvMXdizcHC:0052 VC:251 00 FL:5379 CLC ;A:00BD X:0009 Y:0001 D:0000 DB:01 S:01F3 P:eNvMXdizcHC:0076 VC:251 00 FL:5379 ADC SPR_T12,y ;A:00BD X:0009 Y:0001 D:0000 DB:01 S:01F3 P:eNvMXdizcHC:0090 VC:251 00 FL:5379 ROL $00 ;A:006D X:0009 Y:0001 D:0000 DB:01 S:01F3 P:enVMXdizCHC:0122 VC:251 00 FL:5379 CMP $D8,x ;A:006D X:0009 Y:0001 D:0000 DB:01 S:01F3 P:eNVMXdizcHC:0160 VC:251 00 FL:5379 PHP ;A:006D X:0009 Y:0001 D:0000 DB:01 S:01F3 P:eNVMXdizcHC:0190 VC:251 00 FL:5379 LDA.W $001D ;A:006D X:0009 Y:0001 D:0000 DB:01 S:01F2 P:eNVMXdizcHC:0212 VC:251 00 FL:5379 LSR $00 ;A:0000 X:0009 Y:0001 D:0000 DB:01 S:01F2 P:enVMXdiZcHC:0244 VC:251 00 FL:5379 ADC SPR_T13,y ;A:0000 X:0009 Y:0001 D:0000 DB:01 S:01F2 P:enVMXdizCHC:0282 VC:251 00 FL:5379 PLP ;A:0000 X:0009 Y:0001 D:0000 DB:01 S:01F2 P:envMXdiZCHC:0314 VC:251 00 FL:5379 SBC $14D4,x ;A:0000 X:0009 Y:0001 D:0000 DB:01 S:01F3 P:eNVMXdizcHC:0342 VC:251 00 FL:5379 STA $00 ;A:00FF X:0009 Y:0001 D:0000 DB:01 S:01F3 P:eNvMXdizcHC:0374 VC:251 00 FL:5379 LDY $01 ;A:00FF X:0009 Y:0001 D:0000 DB:01 S:01F3 P:eNvMXdizcHC:0398 VC:251 00 FL:5379 BEQ SPR_L38 ;A:00FF X:0009 Y:0001 D:0000 DB:01 S:01F3 P:envMXdizcHC:0422 VC:251 00 FL:5379 EOR #$80 ;A:00FF X:0009 Y:0001 D:0000 DB:01 S:01F3 P:envMXdizcHC:0438 VC:251 00 FL:5379 STA $00 ;A:007F X:0009 Y:0001 D:0000 DB:01 S:01F3 P:envMXdizcHC:0454 VC:251 00 FL:5379 SPR_L38 LDA $00 ;A:007F X:0009 Y:0001 D:0000 DB:01 S:01F3 P:envMXdizcHC:0478 VC:251 00 FL:5379 BPL RETURN_35 ;A:007F X:0009 Y:0001 D:0000 DB:01 S:01F3 P:envMXdizcHC:0502 VC:251 00 FL:5379 BMI ERASE_SPRITE ;A:8AFF X:0002 Y:0000 D:0000 DB:01 S:01F3 P:eNvMXdizcHC:0704 VC:184 00 FL:5490 SUB_IS_OFF_SCREEN LDA $15A0,x ; \ if sprite is on screen, accumulator = 0 ORA $186C,x ; | RTS ; / return ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; SUB_HORZ_POS ; This routine determines which side of the sprite Mario is on. It sets the Y register ; to the direction such that the sprite would face Mario ; It is ripped from $03B817 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; SUB_HORZ_POS LDY #$00 ;A:25D0 X:0006 Y:0001 D:0000 DB:03 S:01ED P:eNvMXdizCHC:1020 VC:097 00 FL:31642 LDA $94 ;A:25D0 X:0006 Y:0000 D:0000 DB:03 S:01ED P:envMXdiZCHC:1036 VC:097 00 FL:31642 SEC ;A:25F0 X:0006 Y:0000 D:0000 DB:03 S:01ED P:eNvMXdizCHC:1060 VC:097 00 FL:31642 SBC $E4,x ;A:25F0 X:0006 Y:0000 D:0000 DB:03 S:01ED P:eNvMXdizCHC:1074 VC:097 00 FL:31642 STA $0F ;A:25F4 X:0006 Y:0000 D:0000 DB:03 S:01ED P:eNvMXdizcHC:1104 VC:097 00 FL:31642 LDA $95 ;A:25F4 X:0006 Y:0000 D:0000 DB:03 S:01ED P:eNvMXdizcHC:1128 VC:097 00 FL:31642 SBC $14E0,x ;A:2500 X:0006 Y:0000 D:0000 DB:03 S:01ED P:envMXdiZcHC:1152 VC:097 00 FL:31642 BPL SPR_L16 ;A:25FF X:0006 Y:0000 D:0000 DB:03 S:01ED P:eNvMXdizcHC:1184 VC:097 00 FL:31642 INY ;A:25FF X:0006 Y:0000 D:0000 DB:03 S:01ED P:eNvMXdizcHC:1200 VC:097 00 FL:31642 SPR_L16 RTS ;A:25FF X:0006 Y:0001 D:0000 DB:03 S:01ED P:envMXdizcHC:1214 VC:097 00 FL:31642