;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Slime Ball, by imamelia ;; ;; This is that small yellow thing in YI that Salvo the Slime is transformed from. ;; It also appears in one section of 3-4, dropping from the ceiling. ;; ;; Uses first extra bit: NO ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;!GetDrawInfo = $19BA50 ;!SubOffscreenX0 = $19BA10 ;!SubHorzPos = $19BA59 ;!SubVertPos = $19BA5D ;incsrc subroutinedefsx.asm StarSFX: db $00,$13,$14,$15,$16,$17,$18,$19 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; defines ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Tilemap: ; the tilemap for the sprite db $B7,$B6,$B6,$B7 ; frame 1 db $A6,$A6,$FF,$FF ; frame 2 db $A7,$A7,$FF,$FF ; frame 3 db $A4,$FF,$FF,$FF ; frame 4 db $A0,$FF,$FF,$FF ; frame 5 db $A8,$FF,$FF,$FF ; frame 6 XOffset: ; the horizontal displacement of each tile db $F8,$00,$08,$10 ; frame 1 db $00,$08,$FF,$FF ; frame 2 db $00,$08,$FF,$FF ; frame 3 db $00,$FF,$FF,$FF ; frame 4 db $00,$FF,$FF,$FF ; frame 5 db $00,$FF,$FF,$FF ; frame 6 TileSize: ; the size of each tile, 8x8 or 16x16 db $00,$00,$00,$00 ; frame 1 db $00,$00,$FF,$FF ; frame 2 db $00,$00,$FF,$FF ; frame 3 db $02,$FF,$FF,$FF ; frame 4 db $02,$FF,$FF,$FF ; frame 5 db $02,$FF,$FF,$FF ; frame 6 TilesToDraw: ; the number of tiles to draw on each frame db $03,$01,$01,$00,$00,$00 ; 4, 2, 2, 1, 1, 1 XFlip: ; the horizontal flip of each tile db $40,$40,$00,$00 ; frame 1 db $00,$40,$FF,$FF ; frame 2 db $00,$40,$FF,$FF ; frame 3 db $00,$FF,$FF,$FF ; frame 4 (changes to 40 when the sprite is facing right) db $00,$FF,$FF,$FF ; frame 5 (changes to 40 when the sprite is facing right) db $00,$FF,$FF,$FF ; frame 6 (changes to 40 when the sprite is facing right) MoveFrames: ; the 4 frames the sprite will use when moving db $04,$05,$04,$06 ; StatePointers: ; pointer table for the sprite, indexed by $C2,x dw Invisible ; 00: the sprite is still invisible dw WaitOnCeiling ; 01: the sprite is visible, but not close enough to drop dw ReadyToDrop ; 02: the sprite is about to drop from the ceiling dw Dropping ; 03: the sprite has dropped dw WaitOnGround ; 04: the sprite is momentarily stunned after dropping dw Move ; 05: the sprite is moving on the ground EorTbl1: db $FF,$00 !Range1 = $50 !Range2 = $38 ; If the player is farther away than "Range1", then the sprite will be invisible. ; If the player is within "Range1", but not closer than "Range2", the sprite will ; be visible on the ceiling, but will not drop. ; If the player is within "Range2", the sprite will drop from the ceiling. !TimeToDrop = $20 ; how long the sprite will stay on the ceiling before dropping !FrameChange = $10 !XSpeed = $06 ; the sprite's X speed when it is on the ground and moving !SFX1 = $02 ; sound effects to play !SFX2 = $54 ; when the sprite is stomped ; There are two sound effects here; the first goes into $1DF9 and the second into $1DFC. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; init routine wrapper ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; print "INIT ",pc PHB PHK PLB JSR SlimeballInit PLB RTL ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; main routine wrapper ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; print "MAIN ",pc PHB PHK PLB JSR SlimeballMain PLB RTL ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; init routine ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; SlimeballInit: JSR !SubHorzPos ; face the player initially TYA ; (this matters only if the STA $157C,x ; sprite state is 03 or greater) LDA #!Range1 ; set the outer boundary for the proximity routine LDY #!Range2 ; set the inner boundary for the proximity routine JSR Proximity2 ; check how close the sprite is to the player STA $C2,x ; and store the result to the sprite state PHA ; save the value we get from the proximity routine LDA $151C,x ; if this is nonzero, then the sprite was created BEQ NoErase ; by the generator and should be erased if it is too close LDA $C2,x ; check the sprite state/proximity value CMP #$02 ; if the sprite is so close that it will drop... BNE NoErase ; STZ $14C8,x ; then simply erase it NoErase: ; PLA ; pull back the value from the proximity routine/sprite state CMP #$02 ; if the sprite state should be set to 02... BNE SkipDropTimer1; then set the time before it drops LDA #!TimeToDrop ; STA $1558,x ; SkipDropTimer1: ; LDA $D8,x ; for some reason, SEC ; the sprite seems to be shifted SBC #$01 ; down one pixel, STA $D8,x ; so we'll offset it upward one pixel LDA $14D4,x ; to fix SBC #$00 ; this STA $14D4,x ; problem. RTS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; main routine ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; SlimeballMain: LDA $1602,x ; if the frame is zero... BEQ NoGFX ; don't draw the sprite JSR SubSlimeGFX ; NoGFX: LDA $14C8,x ; if the sprite is not in normal status... CMP #$08 ; BNE Return0 ; return LDA $9D ; if sprites are locked... BNE Return0 ; return JSL !SubOffscreenX0 ; LDA $C2,x ; load the sprite state JSR SubCallPointer ; jump to a 16-bit pointer depending on the sprite state Return0: RTS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; 16-bit pointer routine ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; SubCallPointer: PHX ASL A TAX REP #$20 LDA StatePointers,x STA $0A SEP #$20 PLX JMP ($000A) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; sprite state 00: invisible, not close enough to the player to appear ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Invisible: STZ $1602,x ; set the frame to 0 LDA #!Range1 ; set the outer boundary for the proximity routine LDY #!Range2 ; set the inner boundary for the proximity routine JSR Proximity2 ; check how close the sprite is to the player STA $C2,x ; and set the sprite state accordingly RTS ; do absolutely nothing ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; sprite state 01: visible on the ceiling, but not close enough to the player to drop ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; WaitOnCeiling: LDA #$01 ; set the frame STA $1602,x ; to 1 LDA #!Range1 ; set the outer boundary for the proximity routine LDY #!Range2 ; set the inner boundary for the proximity routine JSR Proximity2 ; check how close the sprite is to the player STA $C2,x ; and set the sprite state accordingly CMP #$02 ; if the sprite state should be set to 02... BNE SkipDropTimer2; then set the time before it drops LDA #!TimeToDrop ; STA $1558,x ; SkipDropTimer2: ; RTS ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; sprite state 02: about to drop from the ceiling ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ReadyToDrop: LDA $1558,x ; check the drop timer BEQ Drop ; if it has run out, then make the sprite drop DEC ; if not... LDY #$02 ; start the frame at 02 CMP #!FrameChange ; check to see if the frame should be changed BCS NoChangeFrame ; INY ; if so, increment Y NoChangeFrame: ; TYA ; transfer Y to A STA $1602,x ; so that we can store the new frame number ;LDA $1662,x ; ;PHA ; preserve the sprite clipping ;AND #$C0 ; ;ORA #$2D ; set sprite clipping 2D JSR PlayerInteraction ; interact with the player ;PLA ; ;STA $1662,x ; restore the original clipping size RTS ; Drop: ; LDA #$10 ; set the Y speed at which the sprite should drop STA $AA,x ; INC $C2,x ; change the sprite state to dropping RTS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; sprite state 03: dropping, falling through the air ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Dropping: LDA #$04 ; frame 4 STA $1602,x ; set the frame number JSL $01802A ; update sprite position depending on its speed LDA $1588,x ; check the sprite's blocked status AND #$04 ; if the sprite is touching the ground... BEQ InAir ; LDA #$06 ; then set STA $1602,x ; frame 6, INC $C2,x ; set the sprite state as 04 (waiting on the ground), LDA #$14 ; set the time STA $1558,x ; to remain stationary, LDA #$08 ; set a timer STA $163E,x ; to show the slightly flattened frame, LDA #$0E ; and play a sound effect STA $1DF9 ; (swimming sound effect; it's as close as SMW will allow) InAir: ; JSR PlayerInteraction ; interact with the player RTS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; sprite state 04: just hit the ground and is temporarily stationary ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; WaitOnGround: LDA $1558,x ; check the stun timer BNE Stationary ; if it has not run out, keep the sprite stationary INC $C2,x ; if the sprite is supposed to start moving, Stationary: ; change the sprite state to 05 LDA $163E,x ; check the frame timer BNE FlatFrame ; if nonzero, then the flattened frame should be shown LDA #$04 ; if the frame timer has run out, STA $1602,x ; then change the frame to the round one FlatFrame: ; JSR PlayerInteraction ; interact with the player RTS ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; sprite state 05: is on the ground and moving ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Move: LDA $1588,x ; check to see if the sprite is on the ground AND #$04 ; if not... BEQ NoSpeed ; don't set any speed values LDA #$10 ; set some STA $AA,x ; Y speed for gravity LDA #!XSpeed ; load the X speed into A LDY $157C,x ; sprite direction BEQ NoFlipSpeed ; if the sprite is facing left... EOR #$FF ; flip the X INC ; speed value NoFlipSpeed: ; STA $B6,x ; NoSpeed: ; LDA $1588,x ; check the sprite's blocked status AND #$03 ; if it is touching a wall... BEQ NoFlip ; flip its direction LDA $157C,x ; horizontal direction EOR #$01 ; flip it STA $157C,x ; NoFlip: JSL $01802A ; update the sprite's position depending on its speed JSR PlayerInteraction ; interact with the player LDA $14 ; sprite frame counter LSR ; LSR ; divided by 4 AND #$03 ; 4 possible frame values TAY ; index the frame table LDA MoveFrames,y ; set the frame STA $1602,x ; RTS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; graphics routine ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; SubSlimeGFX: JSL !GetDrawInfo LDA $15F6,x ; sprite palette and GFX page ORA $64 ; add in the priority bits STA $03 ; LDA $157C,x ; sprite direction ROR #3 ; rotate right thrice AND #$40 ; clear all bits but bit 6 EOR #$40 ; set the X-flip of the tile STA $02 ; depending on the sprite's direction LDA $1602,x ; check the sprite frame CMP #$04 ; if the current frame is less than 4... BCS NoClearFlip ; then clear the X-flip bit regardless STZ $02 ; NoClearFlip: ; DEC ; decrement the frame number TAX ; and transfer it to X ASL ; ASL ; multiply it by 4 STA $06 ; to keep track of the tilemap LDA TilesToDraw,x ; so we can determine how many tiles to draw STA $05 ; TileLoop: ; LDA $05 ; take the frame index CLC ; ADC $06 ; add the value from the frame TAX ; and transfer the result to X for our tilemap index LDA $00 ; base X position CLC ; ADC XOffset,x ; plus X offset STA $0300,y ; equals final X position LDA $01 ; base Y position STA $0301,y ; no need for an offset here LDA Tilemap,x ; load a tile depending on the frame and number of tiles drawn STA $0302,y ; set the tile number LDA $03 ; sprite palette and GFX page ORA XFlip,x ; add in any necessary X flip for the 16x16 tiles ORA $02 ; add in any necessary X flip for the 8x8 tiles STA $0303,y ; set the tile properties PHY ; preserve the OAM index TYA ; transfer the OAM index to A LSR ; divide the result by 4 LSR ; because the tile size table has 1 byte per tile TAY ; get the result back into Y LDA TileSize,x ; set the tile size depending on the frame STA $0460,y ; store to the tile size OAM table PLY ; pull back the original OAM index INY #4 ; increment Y 4 times because OAM uses 4 bytes per tile DEC $05 ; decrement the tile counter BPL TileLoop ; if still positive, we have more tiles to draw LDA TilesToDraw,x ; load the number of tiles drawn into A LDY #$FF ; load FF into Y because we already set the tile size LDX $15E9 ; load the sprite index back into X JSL $01B7B3 ; fix the tiles into OAM, prevent them from being overwritten RTS ; end the graphics routine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; player interaction routine ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; PlayerInteraction: JSL $018032 ; interact with other sprites as well JSL $01A7DC ; check to see if the player is in contact with the sprite BCC NoContact ; if the carry flag is clear, then no contact has been made LDA $1490 ; if the player has a star... BNE StarKill ; then go to the star kill routine LDA $0E ; check the player's Y position minus the sprite's Y position CMP #$E6 ; if it is greater than E6, then the sprite hurts the player BPL SpriteWins ; (I never understood why this is usually a BPL rather than BCS...) PlayerWins: ; LDA $140D ; if the player is spin-jumping ORA $187A ; or on Yoshi... BNE SpinKill ; make the sprite die by spin-jump LDA #$02 ; set the sprite state STA $14C8,x ; as killed and falling offscreen JSL $01AB99 ; display contact graphics ;LDA #!SFX1 ; play the stomp sound effect ;STA $1DF9 ; LDA #!SFX2 ; AND the yoshi-spit sound effect STA $1DFC ; NoContact: ; RTS SpinKill: LDA #$04 ; set the sprite state: STA $14C8,x ; spin-jump killed LDA #$08 ; play a spin-jump-kill STA $1DF9 ; sound effect JSL $07FC3B ; display spin-jump stars JSL $01AB99 ; as well as the contact graphic RTS ; SpriteWins: ; JSL $00F5B7 ; hurt the player RTS StarKill: ; LDA $167A,x ; set the "don't disable clipping when killed by a star" ORA #$01 ; bit (normally set in the .cfg editor) STA $167A,x ; this prevents glitched graphics from showing up LDA #$02 ; set the sprite status to STA $14C8,x ; killed and falling offscreen LDA #$D0 ; set some sprite Y speed STA $AA,x ; so the sprite goes up and falls back down INC $18D2 ; increase the number of consecutive enemies stomped/star-killed LDA $18D2 ; if this number is greater than 8... CMP #$08 ; BCC NotEightYet ; then just keep it at 8 LDA #$08 ; STA $18D2 ; NotEightYet: ; JSL $02ACE5 ; give points LDY $18D2 ; load the enemy stomp counter again CPY #$08 ; if less than 8... BCC NoStarSFX ; don't play a sound LDA StarSFX,y ; play a sound effect depending on the enemies stomped STA $1DF9 ; (although, if the enemy stomp counter can't go higher than 8, NoStarSFX: ; and it has to be at least 8 for this code to run, why bother with RTS ; a table? Besides, the table looks one byte too short anyway.) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Schwa's proximity routine ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Proximity2: STA $0B ; STY $0C ; LDA $14E0,x XBA LDA $E4,x REP #$20 SEC SBC $94 SEP #$20 ;PHA ;JSL !SubHorzPos ;PLA ;EOR EorTbl1,y BPL NoFlipRange EOR #$FF INC NoFlipRange: CMP $0B BCS PRange_Out3 CMP $0C BCC InsideRange LDA #$01 RTS PRange_Out3: LDA $E4,x CMP $94 BNE PRange_Out2 LDA #$01 RTS ; if A=01 after this call, then the player is in the middle range PRange_Out2: LDA #$00 RTS ; if A=00 after this call, then the player is in the outer range InsideRange: LDA #$02 RTS ; if A=02 after this call, then the player is in the inner range ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; generic subroutines ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Table1: db $0C,$1C Table2: db $01,$02 Table3: db $40,$B0 Table6: db $01,$FF Table4: db $30,$C0,$A0,$C0,$A0,$F0,$60,$90,$30,$C0,$A0,$80,$A0,$40,$60,$B0 Table5: db $01,$FF,$01,$FF,$01,$FF,$01,$FF,$01,$FF,$01,$FF,$01,$00,$01,$FF SubHorzPos: LDY #$00 LDA $94 SEC SBC $E4 STA $0F LDA $95 SBC $14E0,x BPL $01 INY RTS SubOffscreenX0: LDA #$00 ;BRA SubOffscreenMain ;SubOffscreenX1: ;LDA #$02 ;BRA SubOffscreenMain ;SubOffscreenX2: ;LDA #$04 ;BRA SubOffscreenMain ;SubOffscreenX3: ;LDA #$06 ;BRA SubOffscreenMain ;SubOffscreenX4: ;LDA #$08 ;BRA SubOffscreenMain ;SubOffscreenX5: ;LDA #$0A ;BRA SubOffscreenMain ;SubOffscreenX6: ;LDA #$0C ;BRA SubOffscreenMain ;SubOffscreenX7: ;LDA #$0E SubOffscreenMain: STA $03 JSR SubIsOffscreen BEQ Return2 LDA $5B LSR BCS VerticalLevel LDA $D8,x CLC ADC #$50 LDA $14D4,x ADC #$00 CMP #$02 BPL EraseSprite LDA $167A,x AND #$04 BNE Return2 LDA $13 AND #$01 ORA $03 STA $01 TAY LDA $1A CLC ADC Table4,y ROL $00 CMP $E4,x PHP LDA $1B LSR $00 ADC Table5,y PLP SBC $14E0,x STA $00 LSR $01 BCC Label20 EOR #$80 STA $00 Label20: LDA $00 BPL Return2 EraseSprite: LDA $14C8,x CMP #$08 BCC KillSprite LDY $161A,x CPY #$FF BEQ KillSprite LDA #$00 STA $1938,y KillSprite: STZ $14C8,x Return2: RTS VerticalLevel: LDA $167A,x AND #$04 BNE Return2 LDA $13 LSR BCS Return2 AND #$01 STA $01 TAY LDA $1C CLC ADC Table3,y ROL $00 CMP $D8,x PHP LDA $1D LSR $00 ADC Table6,y PLP SBC $14D4,x STA $00 LDY $02 BEQ Label22 EOR #$80 STA $00 Label22: LDA $00 BPL Return2 BMI EraseSprite SubIsOffscreen: LDA $15A0,x ORA $186C,x RTS GetDrawInfo: STZ $186C,x STZ $15A0,x LDA $E4,x CMP $1A LDA $14E0,x SBC $1B BEQ OnscreenX INC $15A0,x OnscreenX: LDA $14E0,x XBA LDA $E4,x REP #$20 SEC SBC $1A CLC ADC.w #$0040 CMP #$0180 SEP #$20 ROL A AND #$01 STA $15C4,x BNE Invalid LDY #$00 LDA $1662,x AND #$20 BEQ OnscreenLoop INY OnscreenLoop: LDA $D8,x CLC ADC Table1,y PHP CMP $1C ROL $00 PLP LDA $14D4,x ADC #$00 LSR $00 SBC $1D BEQ OnscreenY LDA $186C,x ORA Table2,y STA $186C,x OnscreenY: DEY BPL OnscreenLoop LDY $15EA,x LDA $E4,x SEC SBC $1A STA $00 LDA $D8,x SEC SBC $1C STA $01 RTS Invalid: PLA PLA RTS