get paid to paste

Nipper SMB3

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;
; SMB3 Nipper v2, by imamelia
;
; This is the Nipper from SMB3.  It is a little plant creature that stays in one place
; or hops back and forth until the player tries to jump over it, at which point it
; either jumps into the air and then starts moving around or spits a stream of
; fireballs.  It can be found in, for example, 5-1 and 6-5.
;
; Extra bytes: 1
;
; - 00: stationary; jumps in place
; - 01: starts out stationary, but starts moving once triggered
; - 02: move back and forth about 3 tiles
; - 03: spit fireballs
;
; Sprite tables:
; - !C2,x: Sprite state.
; - !1504,x: Time to wait before moving.
; - !1510,x: Sprite type.
; - !151C,x: Unused.
; - !1528,x: Fireball counter.
; - !1534,x: Unused.
; - !1540,x: Fireball spitting timer.
; - !1558,x: Fireball wait timer.
; - !1570,x: Frame counter.
; - !157C,x: Direction.
; - !1594,x: Unused.
; - !15AC,x: Timer for moving back and forth.
; - !1602,x: Animation frame.
; - !160E,x: Horizontal/upright frame status.
; - !1626,x: Unused.
; - !163E,x: Unused.
; - !187B,x: Unused.
; - !1FD6,x: Unused.
;
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;
; defines and tables
;
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

;!GFXFile1 = $00B6
;!GFXFile2 = $00B6

!JumpRange = $10		; how close the player has to be to the sprite before it will jump
!JumpSpeed = $C0		; what speed the sprite will use when it jumps
!XSpeed = $0A			; what speed the sprite will use when moving around
!FireRange = $48		; how close the player has to be to the sprite before it will spit fireballs 
!FireWaitTimer = $60	; the Nipper won't spit fireballs when this is nonzero, even if the player is in range
!FireSound = $06		; the sound to play when the sprite is spitting a fireball
!FireSoundBank = $1DFC	; the sound bank this sound will come from
;!FireXSpeed = $10		; the X speed to spit the fireball
!FireYSpeed = $DD		; the Y speed to spit the fireball
!MoveTimer = $60		; time to move back and forth
!MoveTStop = $20		; time below which the sprite will not move back and forth

Tilemap:
;	db $00,$02,$04,$06
	db $40,$42,$44,$46	; closed mouth sideways, open, closed upright, open

InitState:
	db $00,$00,$02,$00

; 00 - stationary; waiting on the ground
; 01 - waiting to move after jumping
; 02 - moving
; 03 - spitting fire
StatePointers:
	dw S00_Stationary
	dw S01_Waiting
	dw S02_Moving
	dw S03_SpitFire

Frame:
	db $00,$00,$01,$01,$02,$03,$02,$03

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;
; init routine wrapper
;
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

print "INIT ",pc
	PHB
	PHK
	PLB
	JSR SpriteInitRt
	PLB
	RTL

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;
; init routine
;
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

SpriteInitRt:
	LDA !7FAB40,x
	STA !1510,x
	TAY
	LDA InitState,y
	STA !C2,x
	CPY #$02
	BNE .NotType2
	LDA.b #!MoveTimer
	STA !15AC,x
.NotType2
;	LDA.b #!GFXFile1
;	STA $7F88D0,x
;	LDA.b #!GFXFile1>>8
;	STA $7F88DC,x
;	LDA.b #!GFXFile2
;	STA $7F88E8,x
;	LDA.b #!GFXFile2>>8
;	STA $7F88F4,x
	RTS

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;
; main routine wrapper
;
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

print "MAIN ",pc
	PHB
	PHK
	PLB
	JSR SpriteMainRt
	PLB
	RTL

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;
; main routine
;
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

SpriteMainRt:
	LDA !160E,x			;
	ASL #2				;
	STA $00				;
	LDA !1570,x			;
	LSR #2				;
	AND #$03			;
	ORA $00				; make the sprite animate between open and closed frames
	TAY					;
	LDA Frame,y			;
	STA !1602,x			;
	LDA !1540,x			; unless, of course, it is spitting fire,
	BEQ .NotOpen			; in which case it should always have an open mouth
	LDA #$01			;
	STA !1602,x			;
.NotOpen					;
	JSR SubGFX			;
	LDA !14C8,x			;
	EOR #$08				;
	ORA $9D				;
	BNE ReturnMain		;
	LDA #$00			;
	%SubOffScreen()		;
	INC !1570,x			;
    LDA !C2,x			;
    ASL A				;
    TAX					;
    JSR.w (StatePointers,x)	;
	JSL $01802A|!BankB	; update sprite position
	JSL $01803A|!BankB	; interact with sprites and the player
	LDA !1588,x			;
	AND #$03			; if the sprite is touching a wall...
	BEQ ReturnMain		;
	LDA !157C,x			;
	EOR #$01				; flip its direction
	STA !157C,x			;
	LDA !B6,x			; and its X speed
	EOR #$FF				;
	INC					;
	STA !B6,x			;
ReturnMain:				;
	RTS					;

;------------------------------------------------
; state 00 - stationary
;------------------------------------------------

S00_Stationary:
	LDX $15E9|!Base2
	%SubHorzPos()	;
DummyLabel0:		;
	TYA				; make the sprite always face the player
	STA !157C,x		;
	LDA !1588,x		;
	AND #$04		; if the sprite isn't on the ground...
	BEQ .NoJump		;
	STZ !160E,x		;
	LDA #$10		;
	STA !AA,x		;
	LDA !1510,x		;
	CMP #$03		; if it's sprite type 3...
	BEQ .CheckForSpit	; then make the Nipper spit fire instead of jumping
	JSR Proximity1		; if the sprite is out of range...
	BEQ .NoJump		; don't make it jump
	LDA.b #!JumpSpeed	;
	STA !AA,x		; set its jumping speed
	INC !160E,x		; set the frame to upright
	LDA #$18		;
	STA !1504,x		; set the timer for it to wait before moving
	LDA !1510,x		;
	BEQ .NoJump		;
	INC !C2,x		; set the sprite state to waiting
.NoJump				;
	RTS				;
.CheckForSpit			;
	JSR Proximity2		;
	BEQ .NoSpit		;
	LDA !1558,x		; if the sprite just spat already...
	BNE .NoSpit		; don't spit any fireballs
	LDA #$0C		;
	STA !1540,x		; fireball timer
	LDA #$04		;
	STA !1528,x		; fireball counter: 4 fireballs to spit
	LDA #$03		;
	STA !C2,x		; change the sprite state to spitting
.NoSpit				;
	RTS				;

;------------------------------------------------
; state 01 - waiting to move
;------------------------------------------------

S01_Waiting:
    LDX $15E9|!Base2
	LDA !1504,x		; if the wait timer has not run out...
	BNE .NoMove		; don't start moving
	INC !C2,x		;
.NoMove				;
	LDA !1588,x		;
	AND #$04		; if the sprite is in the air...
	BEQ .InAir		;
	DEC !1504,x		; don't decrement the wait timer
	STZ !160E,x		;
.InAir				;
	%SubHorzPos()	;
	TYA				; make the sprite always face the player
	STA !157C,x		;
	RTS				;

;------------------------------------------------
; state 02 - moving
;------------------------------------------------

S02_Moving:
    LDX $15E9|!Base2
	LDA !1588,x		;
	AND #$04		; if the sprite is not on the ground...
	BEQ .NoClearFrame	; don't set its Y speed
	LDA #$EE			;
	STA !AA,x		; make the sprite hop a little
	LDA.b #!XSpeed		; give the sprite some X speed
	LDY !157C,x		;
	BEQ $03			; flip the X speed value if the sprite is facing left
	EOR #$FF			;
	INC				;
	STA !B6,x		;
	JSR Proximity1		; if the sprite is out of range...
	BEQ .NoJump		; don't make it jump
	LDA.b #!JumpSpeed	;
	STA !AA,x		; set its jumping speed
	LDA #$01		; set the frame to upright
	STA !160E,x		;
	BRA .NoClearFrame	;
.NoJump				;
	STZ !160E,x		;
.NoClearFrame			;
	LDA !1510,x		;
	CMP #$02		;
	BEQ NoFace2		;
	LDA !1570,x		;
	AND #$1F		; every few frames...
	BNE NoFace		;
	%SubHorzPos()	;
	TYA				; make the sprite turn to face the player
	STA !157C,x		;
NoFace:				;
	RTS				;
NoFace2:				;
	LDA !15AC,x		;
	BEQ .Turn			;
	CMP.b #!MoveTStop	;
	BCS NoFace		;
	STZ !B6,x		;
	RTS				;
.Turn				;
	LDA !157C,x		;
	EOR #$01			;
	STA !157C,x		;
	LDA !B6,x		;
	EOR #$FF			;
	INC				;
	STA !B6,x		;
	LDA.b #!MoveTimer	;
	STA !15AC,x		;
	RTS				;

;------------------------------------------------
; state 03 - spitting fireballs
;------------------------------------------------

S03_SpitFire:
    LDX $15E9|!Base2
	LDA !1540,x		; check the spit timer
;	AND #$07		;
	BNE .NoSpit		;
	JSR SubFireSpit		; fireball-spawning routine
	DEC !1528,x		; decrement the fireball counter
	BEQ .EndSpit		;
	LDA #$08		;
	STA !1540,x		;
	RTS				;
.EndSpit				;
	LDA.b #!FireWaitTimer
	STA !1558,x		; reset the fire-spit timer
	STZ !C2,x		;
.NoSpit				;
	RTS				;

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;
; graphics routine
;
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

SubGFX:
;	JSL !GetDrawInfoPlus
	%GetDrawInfo()
	LDA !15F6,x
	ORA $64
	STA $03
	LDA !1602,x
	STA $04
;	LDA $05
	LDA !157C,x
	ROR #3
	AND #$40
	EOR #$40
	TSB $03
	LDA !14C8,x
	CMP #$08
	BEQ +
	LDA #$80
	TSB $03
+	LDA $00
	STA $0300|!Base2,y
	LDA $01
	STA $0301|!Base2,y
	LDX $04
	LDA.w Tilemap,x
;	CLC
;	ADC $02
	STA $0302|!Base2,y
	LDA $03
	STA $0303|!Base2,y
	LDX $15E9|!Base2
	LDY #$02
	LDA #$00
	JSL $01B7B3|!BankB
	RTS

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;
; fire-spitting routine
;
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

FireXOffsetsLo:
	db $06,$FA
FireXOffsetsHi:
	db $00,$FF
!FireYOffsetLo = $03
!FireYOffsetHi = $00

SubFireSpit:
	LDY #$07
.ExSpriteLoop
	LDA $170B|!Base2,y
	BEQ .FoundExSlot
	DEY
	BPL .ExSpriteLoop
	RTS

.FoundExSlot
	LDA #$0B
	STA $170B|!Base2,y
	LDA !E4,x
	PHY
	LDY !157C,x
	CLC
	ADC FireXOffsetsLo,y
	PLY
	STA $171F|!Base2,y
	LDA !14E0,x
	PHY
	LDY !157C,x
	ADC FireXOffsetsHi,y
	PLY
	STA $1733|!Base2,y
	LDA !D8,x
	CLC
	ADC.b #!FireYOffsetLo
	STA $1715|!Base2,y
	LDA !14D4,x
	ADC.b #!FireYOffsetHi
	STA $1729|!Base2,y
;	LDA.b #!FireXSpeed
	JSR Proximity1
	REP #$20
	LDA $0C
	LSR
	SEP #$20
	PHY
	LDY !157C,x
	BEQ $03
	EOR #$FF
	INC
	PLY
	STA $1747|!Base2,y
	LDA.b #!FireYSpeed
	STA $173D|!Base2,y
	LDA #$FF
	STA $176F|!Base2,y
	LDA.b #!FireSound
	STA.w !FireSoundBank|!Base2
	RTS

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;
; miscellaneous subroutines
;
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Proximity1:				;
	LDA.b #!JumpRange		;
	BRA StoreRange		;
Proximity2:				;
	LDA.b #!FireRange		;
StoreRange:				;
	STA $0A				;
ProximityMain:			;
	LDA !14E0,x			; sprite X position high byte
	XBA					; into high byte of A
	LDA !E4,x			; sprite X position low byte into low byte of A
	REP #$20				; set A to 16-bit mode
	SEC					; subtract the player's X position
	SBC $94				; from the sprite's
	STA $0E				;
	BPL .NoInvertH			; if the result of the subtraction was negative...
	EOR #$FFFF			; then invert it
	INC					;
.NoInvertH				;
	STA $0C				;
	CMP #$0100			; if the difference is bigger than 1 screen...
	SEP #$20				;
	BCS .RangeOut1		; then the player is out of range anyway
	CMP $0A				; if not, compare the result to the desired range
	BCS .RangeOut1		;
.RangeIn1				;
	LDA #$01			;
	RTS					;
.RangeOut1				;
	LDA #$00			;
	RTS					;

Pasted: Jul 30, 2018, 11:21:18 am
Views: 4