Prince-of-Persia-Apple-II/01 POP Source/Source/CTRLSUBS.S

2121 lines
27 KiB
ArmAsm
Executable File

* ctrlsubs
org = $d000
tr on
lst off
*-------------------------------
*
* PRINCE OF PERSIA
* Copyright 1989 Jordan Mechner
*
*-------------------------------
*
* Misc. subroutines relating to character control & movement
*
*-------------------------------
org org
jmp GETFRAME
jmp GETSEQ
jmp GETBASEX
jmp GETBLOCKX
jmp GETBLOCKXP
jmp GETBLOCKY
jmp GETBLOCKEJ
jmp ADDCHARX
jmp GETDIST
jmp GETDIST1
jmp GETABOVEBEH
jmp RDBLOCK
jmp RDBLOCK1
jmp SETUPSWORD
jmp GETSCRNS
jmp ADDGUARDOBJ
jmp OPJUMPSEQ
jmp GETEDGES
jmp INDEXCHAR
jmp QUICKFG
jmp CROPCHAR
jmp GETLEFT
jmp GETRIGHT
jmp GETUP
jmp GETDOWN
jmp CMPSPACE
jmp CMPBARR
jmp ADDKIDOBJ
jmp ADDSHADOBJ
jmp ADDREFLOBJ
jmp LOADKID
jmp LOADSHAD
jmp SAVEKID
jmp SAVESHAD
jmp SETUPCHAR
jmp GETFRAMEINFO
jmp INDEXBLOCK
jmp MARKRED
jmp MARKFRED
jmp MARKWIPE
jmp MARKMOVE
jmp MARKFLOOR
jmp UNINDEX
jmp QUICKFLOOR
jmp UNEVENFLOOR
jmp MARKHALF
jmp ADDSWORDOBJ
jmp GETBLOCKYP
jmp CHECKLEDGE
jmp GET2INFRONT
jmp CHECKSPIKES
jmp RECHARGEMETER
jmp ADDFCHARX
jmp FACEDX
jmp JUMPSEQ
jmp GETBASEBLOCK
jmp LOADKIDWOP
jmp SAVEKIDWOP
jmp GETOPDIST
jmp LOADSHADWOP
jmp SAVESHADWOP
jmp BOOSTMETER
jmp GETUNDERFT
jmp GETINFRONT
jmp GETBEHIND
jmp GETABOVE
jmp GETABOVEINF
jmp CMPWALL
*-------------------------------
lst
put eq
lst
put gameeq
lst
put movedata
lst
put seqdata
lst
put soundnames
lst off
*-------------------------------
dum locals
tempright ds 1
ztemp ds 2
tempstate ds 1
]cutdir ds 1
dend
*-------------------------------
* Misc. data
plus1 db -1,1
minus1 db 1,-1
maxmaxstr = 10 ;strength meter maximum
thinner = 3
*-------------------------------
*
* R E A D B L O C K
*
* In: A = screen #
* X = block x (0-9 onscreen)
* Y = block y (0-2 onscreen)
*
* Out: A,X = objid
* Y = block # (0-29)
* BlueType, BlueSpec set
* tempscrn,tempblockx,tempblocky = onscreen block coords
*
* - Offscreen block values are traced to their home screen
* - Screen 0 is treated as a solid mass
*
*-------------------------------
RDBLOCK
sta tempscrn
stx tempblockx
sty tempblocky
RDBLOCK1
jsr handler ;handle offscreen references
lda tempscrn
beq :nullscrn ;screen 0
jsr calcblue ;returns BlueType/Spec
ldy tempblocky
lda Mult10,y
clc
adc tempblockx
tay
lda (BlueType),y
and #idmask
tax ;return result in X & A
rts
:nullscrn lda #block
tax
rts
*-------------------------------
* Handle offscreen block references (recursive)
handler lda tempblockx
bpl :1
jsr offleft
jmp handler
:1 cmp #10
bcc :2
jsr offrt
jmp handler
:2 lda tempblocky
bpl :3
jsr offtop
jmp handler
:3 cmp #3
bcc :rts
jsr offbot
jmp handler
:rts rts
offtop clc
adc #3
sta tempblocky
lda tempscrn
jsr GETUP
sta tempscrn
rts
offbot sec
sbc #3
sta tempblocky
lda tempscrn
jsr GETDOWN
sta tempscrn
rts
offleft clc
adc #10
sta tempblockx
lda tempscrn
jsr GETLEFT
sta tempscrn
rts
offrt sec
sbc #10
sta tempblockx
lda tempscrn
jsr GETRIGHT
sta tempscrn
]rts rts
*-------------------------------
*
* Get adjacent screen numbers
*
* In: A = original screen #
* Out: A = adjacent screen #
*
*-------------------------------
GETLEFT
beq ]rts
asl
asl
tax
lda MAP-4,x
]rts rts
GETRIGHT
beq ]rts
asl
asl
tax
lda MAP-3,x
rts
GETUP
beq ]rts
asl
asl
tax
lda MAP-2,x
rts
GETDOWN
beq ]rts
asl
asl
tax
lda MAP-1,x
rts
*-------------------------------
*
* G E T S C R E E N S
*
* Get VisScrn's 8 surrounding screens from map
* (Store in scrnAbove, scrnBelow, etc.)
*
*-------------------------------
GETSCRNS
lda VisScrn
jsr GETLEFT
sta scrnLeft
lda VisScrn
jsr GETRIGHT
sta scrnRight
lda VisScrn
jsr GETUP
sta scrnAbove
lda VisScrn
jsr GETDOWN
sta scrnBelow
* and diagonals
lda scrnBelow
jsr GETLEFT
sta scrnBelowL
lda scrnBelow
jsr GETRIGHT
sta scrnBelowR
lda scrnAbove
jsr GETLEFT
sta scrnAboveL
lda scrnAbove
jsr GETRIGHT
sta scrnAboveR
]rts rts
*-------------------------------
*
* G E T B A S E X
*
* In: Char data; frame data
*
* Out: A = character's base X-coord
*
*-------------------------------
GETBASEX
lda Fcheck
and #Ffootmark
;# pixels to count in from left edge of image
eor #$ff
clc
adc #1 ;- Fcheck
clc
adc Fdx ;Fdx (+ = fwd, - = bkwd)
jmp ADDCHARX ;Add to CharX in direction char is facing
*-------------------------------
*
* Add A to CharX in direction char is facing
*
* In: A = # pixels to add (+ = fwd, - = bkwd)
* CharX = original char X-coord
* CharFace = direction char is facing
*
* Out: A = new char X-coord
*
*-------------------------------
ADDCHARX
bit CharFace ;-1 = left (normal)
bpl :right ;0 = right (mirrored)
eor #$ff
clc
adc #1 ;A := -A
:right clc
adc CharX
rts
*-------------------------------
*
* Add A to FCharX
* (A range: -127 to 127)
*
* In: A; FChar data
* Out: FCharX
*
*-------------------------------
ADDFCHARX
sta ztemp
bpl :1 ;hibit clr
lda #0
sec
sbc ztemp
sta ztemp ;make it posititve
lda #$ff ;hibit set
:1 eor FCharFace
bmi :left
lda ztemp
clc
adc FCharX
sta FCharX
lda FCharX+1
adc #0
sta FCharX+1
rts
:left lda FCharX
sec
sbc ztemp
sta FCharX
lda FCharX+1
sbc #0
sta FCharX+1
rts
*-------------------------------
*
* In: CharFace,CharBlockX,CharBlockY,CharScrn
*
* Out: Results of RDBLOCK for block underfoot/in front/etc.
*
*-------------------------------
GETUNDERFT
ldx CharBlockX
ldy CharBlockY
lda CharScrn
jmp RDBLOCK
GETINFRONT
ldx CharFace
inx
lda CharBlockX
clc
adc plus1,x
sta infrontx
tax
ldy CharBlockY
lda CharScrn
jmp RDBLOCK
GET2INFRONT
ldx CharFace
inx
lda CharBlockX
clc
adc plus1,x
clc
adc plus1,x
tax
ldy CharBlockY
lda CharScrn
jmp RDBLOCK
GETBEHIND
ldx CharFace
inx
lda CharBlockX
clc
adc minus1,x
sta behindx
tax
ldy CharBlockY
lda CharScrn
jmp RDBLOCK
GETABOVE
ldy CharBlockY
dey
sty abovey
ldx CharBlockX
lda CharScrn
jmp RDBLOCK
GETABOVEINF
ldx CharFace
inx
lda CharBlockX
clc
adc plus1,x
sta infrontx
tax
ldy CharBlockY
dey
sty abovey
lda CharScrn
jmp RDBLOCK
GETABOVEBEH
ldx CharFace
inx
lda CharBlockX
clc
adc minus1,x
sta behindx
tax
ldy CharBlockY
dey
sty abovey
lda CharScrn
jmp RDBLOCK
*-------------------------------
*
* G E T D I S T A N C E
*
* In: Char data
*
* Out: A = # of pixels (0-13) to add to CharX to move
* char base X-coord to end of current block
*
*-------------------------------
GETDIST
jsr GETBASEX ;returns A = base X-coord
GETDIST1
jsr GETBLOCKXP ;returns A = block #, OFFSET = pixel #
lda CharFace ;0=right, -1=left
beq :facingright
:facingleft
lda OFFSET
rts
:facingright
lda #13
sec
sbc OFFSET
rts
*-------------------------------
*
* G E T B L O C K E D G E
*
* In: A = block # (-5 to 14)
* Out: A = screen X-coord of left edge
*
*-------------------------------
GETBLOCKEJ
clc
adc #5
tax
lda BlockEdge,x
rts
*-------------------------------
*
* G E T B L O C K X
*
* In: A = X-coord
*
* Out: A = # of the 14-pixel-wide block within which
* this pixel falls (0-9 onscreen)
*
* OFFSET = pixel within this block
*
* - Use GETBLOCKXP for objects on center plane
* - Use GETBLOCKX for absolute X-coords & foreground plane
*
*-------------------------------
GETBLOCKXP
sec
sbc #angle
GETBLOCKX
tay
lda PixelTable,y
sta OFFSET
lda BlockTable,y
rts
*-------------------------------
*
* G E T B L O C K Y
*
* In: A = screen Y-coord (0-255)
*
* Out: A = block y (3 = o.s.)
*
* - Use GETBLOCKYP for objects on center plane
* - Use GETBLOCKY for absolute Y-coords & foreground plane
*
*-------------------------------
GETBLOCKY
ldx #3
:loop cmp BlockTop+1,x
bcs :gotY
dex
bpl :loop
:gotY txa
rts
GETBLOCKYP
ldx #3
:loop cmp FloorY+1,x
bcs :gotY
dex
bpl :loop
:gotY txa
]rts rts
*-------------------------------
*
* I N D E X B L O C K
*
* Index (tempblockx,tempblocky)
*
* Return y = block # (0-29) and cc if block is onscreen
* y = 0 to 9 and cs if block is on screen above
* y = 30 and cs if block is o.s.
*
*-------------------------------
INDEXBLOCK
ldy tempblocky
bmi :above
cpy #3
bcs :os
lda tempblockx
cmp #10
bcs :os ;0 <= tempblockx <= 9
clc
adc Mult10,y
tay ;return y = block #
clc ;and carry clr
rts
:os ldy #30
sec ;and carry set
rts
:above ldy tempblockx
sec
]rts rts
*-------------------------------
*
* U N I N D E X
*
* In: A = block index (0-29)
* Out: A = blockx, X = blocky
*
*-------------------------------
UNINDEX
ldx #0
:loop cmp #10
bcc ]rts
sec
sbc #10
inx
bne :loop
]rts rts
*-------------------------------
*
* G E T B A S E B L O C K
*
* In: Char data
* Out: CharBlockX
*
*-------------------------------
GETBASEBLOCK
jsr getbasex
jsr getblockxp
sta CharBlockX
]rts rts
*-------------------------------
*
* F A C E D X
*
* In: CharFace; A = DX
*
* Out: DX if char is facing right, -DX if facing left
*
*-------------------------------
FACEDX
bit CharFace
bmi ]rts
eor #$ff
clc
adc #1 ;negate
]rts rts
*-------------------------------
*
* J U M P S E Q
*
* Jump to some other point in sequence table
*
* In: A = sequence # (1-127)
*
*-------------------------------
JUMPSEQ
sec
sbc #1
asl
tax ;x = 2(a-1)
lda seqtab,x
sta CharSeq
lda seqtab+1,x
sta CharSeq+1
]rts rts
*-------------------------------
*
* Similar routine for Opponent
*
*-------------------------------
OPJUMPSEQ
sec
sbc #1
asl
tax ;x = 2(a-1)
lda seqtab,x
sta OpSeq
lda seqtab+1,x
sta OpSeq+1
]rts rts
*-------------------------------
*
* I N D E X C H A R
*
* In: Char data; GETEDGES results
*
* Out: FCharIndex = character block index
*
*-------------------------------
INDEXCHAR
lda CharAction
cmp #1
bne :4
;If CharAction = 1 (on solid ground)
;use leftblock/bottomblock
lda bottomblock
sta tempblocky
lda leftblock
:1 sta tempblockx
lda CharPosn
cmp #135
bcc :2
cmp #149
bcc :climbup
:2 cmp #2
beq :fall
cmp #3
beq :fall
cmp #4
beq :fall
cmp #6
bne :3
:fall
:climbup dec tempblockx ;if falling or climbing up
:3 jsr indexblock
sty FCharIndex
rts
* else use CharBlockX/Y
:4 lda CharBlockY
sta tempblocky
lda CharBlockX
jmp :1
*-------------------------------
*
* S E T U P C H A R
*
* Set up character for FRAMEADV
*
* In: Char data
* Out: FChar data
*
* Translate char data into the form "addchar" expects
* (Decode image #; get actual 280 x 192 screen coords)
*
*-------------------------------
SETUPCHAR
jsr zerocrop ;(can call cropchar later)
jsr GETFRAMEINFO
lda CharFace
sta FCharFace
jsr decodeim ;get FCharImage & Table from
;encoded Fimage & Fsword data
lda #0
sta FCharX+1
lda Fdx
jsr addcharx ;A := CharX + Fdx
sec
sbc #ScrnLeft ;different coord system
sta FCharX
asl FCharX
rol FCharX+1
beq :pos
lda FCharX
cmp #$f0
bcc :pos
lda #$ff
sta FCharX+1
:pos ;X := 2X
lda Fdy
clc
adc CharY
sec
sbc #ScrnTop
sta FCharY
lda Fcheck
eor FCharFace ;Look only at the hibits
bmi :ok ;They don't match-->even X-coord
;They match-->odd X-coord
lda FCharX
clc
adc #1
sta FCharX
bcc :ok
inc FCharX+1
:ok
]rts rts
*-------------------------------
*
* S E T U P S W O R D
*
* In: Char & FChar data
*
* If character's sword is visible, add it to obj table
*
*-------------------------------
SETUPSWORD
lda CharID
cmp #2
bne :3
lda CharLife
bmi :2 ;live guard's sword is always visible
:3 lda CharPosn
cmp #229
bcc :1
cmp #238
bcc :2 ;sheathing
:1 lda CharSword
beq ]rts
:2
lda Fsword
and #$3f ;frame #
beq ]rts ;no sword for this frame
jsr getswordframe
ldy #0
lda (framepoint),y
beq ]rts
jsr decodeswim ;get FCharImage & Table
iny
lda (framepoint),y
sta Fdx
iny
lda (framepoint),y
sta Fdy
lda Fdx
jsr ADDFCHARX ;A := FCharX + Fdx
lda Fdy
clc
adc FCharY
sta FCharY
jmp ADDSWORDOBJ
*-------------------------------
*
* G E T F R A M E
*
* In: A = frame # (1-192)
* Out: framepoint = 2-byte pointer to frame def table
*
*-------------------------------
GETFRAME ;Kid uses main char set
jsr getfindex
lda framepoint
clc
adc #Fdef
sta framepoint
lda framepoint+1
adc #>Fdef
sta framepoint+1
rts
*-------------------------------
getaltframe1 ;Enemy uses alt set 1
jsr getfindex
lda framepoint
clc
adc #altset1
sta framepoint
lda framepoint+1
adc #>altset1
sta framepoint+1
rts
*-------------------------------
getaltframe2 ;Princess & Vizier use alt set 2
jsr getfindex
lda framepoint
clc
adc #altset2
sta framepoint
lda framepoint+1
adc #>altset2
sta framepoint+1
rts
*-------------------------------
getfindex
sec
sbc #1
sta ztemp
sta framepoint
lda #0
sta ztemp+1
sta framepoint+1
asl framepoint
rol framepoint+1
asl framepoint
rol framepoint+1 ;2-byte multiply by 4
lda framepoint
clc
adc ztemp
sta framepoint
lda framepoint+1
adc ztemp+1
sta framepoint+1 ;make it x5
rts
*-------------------------------
*
* getswordframe
*
* In: A = frame #
* Out: framepoint
*
*-------------------------------
getswordframe
sec
sbc #1
sta ztemp
sta framepoint
lda #0
sta ztemp+1
sta framepoint+1
asl framepoint
rol framepoint+1 ;x2
lda framepoint
clc
adc ztemp
sta framepoint
lda framepoint+1
adc ztemp+1
sta framepoint+1 ;+1 is 3
lda framepoint
clc
adc #swordtab
sta framepoint
lda framepoint+1
adc #>swordtab
sta framepoint+1
rts
*-------------------------------
*
* Decode char image
*
* In: Fimage, Fsword (encoded)
*
* Out: FCharImage (image #, 0-127)
* FCharTable (table #, 0-7)
*
*-------------------------------
decodeim
lda Fimage
and #%10000000 ;bit 2 of table #
sta ztemp
lda Fsword
and #%11000000 ;bits 0-1 of table #
lsr
adc ztemp
lsr
lsr
lsr
lsr
lsr
sta FCharTable
lda Fimage
and #$7f
ora timebomb ;must be 0!
sta FCharImage
rts
*-------------------------------
*
* Decode sword image
*
* In: A = image #
*
* Out: FCharImage, FCharTable
*
*-------------------------------
decodeswim
sta FCharImage ;image #
lda #2 ;chtable3
sta FCharTable
rts
*-------------------------------
*
* G E T E D G E S
*
* Get edges of character image
*
* In: FChar data as set by "setframe"
*
* Out: leftej/rightej/topej = boundaries of image (140-res)
* leftblock, rightblock, topblock, bottomblock
* CDLeftEj, CDRightEj (for coll detection)
* imheight, imwidth
*
*-------------------------------
GETEDGES
lda FCharImage
ldx FCharTable
jsr dimchar ;return A = image width, x = height
stx imheight
tax ;image width in bytes
lda Mult7,x ;in 1/2 pixels
clc
adc #1 ;add 1/2 pixel
lsr ;and divide by 2
sta imwidth ;to get width in pixels
lda FCharX+1
lsr
lda FCharX
ror
clc
adc #ScrnLeft ;convert back to 140-res
* (If facing LEFT, X-coord is leftmost pixel of LEFTMOST byte
* of image; if facing RIGHT, leftmost pixel of RIGHTMOST byte.)
ldx CharFace
bmi :ok ;facing L
;facing R
sec
sbc imwidth
:ok sta leftej
clc
adc imwidth
sta rightej
lda FCharY
sec
sbc imheight
clc
adc #1
cmp #192
bcc :ok2
lda #0
:ok2 sta topej
jsr getblocky
cmp #3
bne :1
lda #-1 ;if o.s., call it -1
:1 sta topblock
lda FCharY
jsr getblocky ;if o.s., call it 3
sta bottomblock
lda leftej
jsr getblockx ;leftmost affected block
sta leftblock
lda rightej
jsr getblockx ;rightmost affected block
sta rightblock
* get leading edge (for collision detection)
lda #0
sta ztemp
lda Fcheck
and #Fthinmark
beq :nothin
lda #thinner ;make character 3 bits thinner
sta ztemp ;on both sides
:nothin lda leftej
clc
adc ztemp
sta CDLeftEj
lda rightej
sec
sbc ztemp
sta CDRightEj
]rts rts
*===============================
*
* Q U I C K F L O O R
*
* Mark for redraw whatever floorpieces character might be
* impinging on
*
* In: CharData; GETEDGES results
*
*-------------------------------
QUICKFLOOR
lda CharPosn
cmp #135
bcc :2
cmp #149
bcc :climbup
:2 lda CharAction
cmp #1
bne :1
lda CharPosn
cmp #78
bcc ]rts
cmp #80
bcc :fall
]rts rts
:1 cmp #2
beq :fall
cmp #3
beq :fall
cmp #4
beq :fall
cmp #6
bne ]rts
:fall lda #markfloor
ldx #>markfloor
bne :cont1
:climbup
lda #markhalf
ldx #>markhalf
* Mark floorbuf/halfbuf for up to 6 affected blocks
* Start with rightblock, work left to leftblock
:cont1
sta marksm1+1
sta marksm2+1
stx marksm1+2
stx marksm2+2
lda rightblock
:loop sta tempblockx
jsr markul
lda tempblockx
cmp leftblock
beq ]rts
sec
sbc #1
bpl :loop
]rts rts
* mark upper & lower blocks for this blockx
markul
lda bottomblock
sta tempblocky
jsr indexblock ;lower block
lda #2
marksm1 jsr markhalf
lda topblock
cmp bottomblock
beq ]rts
sta tempblocky
jsr indexblock ;upper block
lda #2
marksm2 jmp markhalf
*-------------------------------
*
* Q U I C K F G
*
* Mark for redraw any f.g. elements char (or his sword)
* might be impinging on
*
* In: Char data; left/right/top/bottomblock
*
*-------------------------------
QUICKFG
* Quick fix to cover sword
lda CharSword
cmp #2
bcc :cont
lda CharFace
bpl :faceR
dec leftblock
jmp :cont
:faceR inc rightblock
* Continue
:cont lda bottomblock
:outloop
sta tempblocky
lda rightblock
:loop sta tempblockx
jsr indexblock
lda #3
jsr MARKFRED
lda tempblockx
cmp leftblock
beq :end
sec
sbc #1
bpl :loop
:end
lda tempblocky
cmp topblock
beq ]rts
sec
sbc #1
bpl :outloop
rts
]bug jmp showpage
*-------------------------------
*
* C R O P C H A R A C T E R
*
* In: FChar data as set by "setframe"
* leftej,rightej, etc. as set by "getedges"
*
* Out: FCharCL/CR/CU/CD
*
*-------------------------------
CROPCHAR
* If char is climbing stairs, mask door
lda CharPosn
cmp #224
bcc :nost
cmp #229
bcs :nost
lda doortop ;set by drawexitb
clc
adc #2
cmp FCharY
bcs :bug ;temp!
sta FCharCU
]rts rts
:bug ldy #$F0
jsr showpage
:nost
* If char is under solid (a&b) floor, crop top
ldx leftblock
ldy topblock
lda CharScrn
jsr rdblock
cmp #block
beq :1
jsr cmpspace
beq :not
* Special case (more lenient): if char is jumping
* up to touch ceiling
:1 lda CharAction
bne :10
lda CharPosn
cmp #79
beq :2
cmp #81
bne :10
beq :2
* Otherwise, both left & right topblocks must be solid
:10 ldx rightblock
ldy topblock
lda CharScrn
jsr rdblock
cmp #block
beq :2
jsr cmpspace
beq :not
:2 ldx CharBlockY
inx
cpx #1
beq :ok
lda BlockTop,x
cmp FCharY
bcs :not
sec
sbc #floorheight
cmp topej
bcs :not
:ok lda BlockTop,x
sta FCharCU
sta topej
:not
* If char is standing left of a panel, crop R
* Char is considered "left" if CDLeftEj falls within
* panel block
lda CDLeftEj
jsr getblockx
sta blockx
tax
ldy CharBlockY
lda CharScrn
jsr rdblock
cmp #panelwof
beq :r
cmp #panelwif
bne :nor
* Char's foot is within panel block
* Special case: If character is hanging R, we don't
* need to check his head
:r lda CharFace
bmi :cont
lda CharAction
cmp #2
beq :r2 ;yes--hanging R
* Check block to right of char's head
:cont
ldx blockx
ldy topblock
lda CharScrn
jsr rdblock
cmp #block
beq :r2
cmp #panelwof
beq :r2
cmp #panelwif
bne :nor
* Also a panel -- make a wall
:r2 lda tempblockx
asl
asl
clc
adc #4
sta FCharCR
rts
* Is char standing to L of solid block?
* (i.e. does CDRightEj fall within block?)
:nor
lda CDRightEj
jsr getblockx
sta blockx
tax
ldy CharBlockY
lda CharScrn
jsr rdblock
cmp #block
bne :nob
* Foot is under block--what about head?
ldx blockx
ldy topblock
lda CharScrn
jsr rdblock
cmp #block
bne :nob
* Also a panel -- make a wall
:yescrop
lda tempscrn
cmp CharScrn
bne :nob
lda tempblockx
asl
asl
sta FCharCR
:nob
rts
*-------------------------------
*
* Z E R O C R O P
*
*-------------------------------
zerocrop
lda #0
sta FCharCU
sta FCharCL
lda #40
sta FCharCR
lda #192
sta FCharCD
rts
*===============================
*
* C O M P A R E S P A C E
*
* Is it a space (can you pass thru)?
* NOTE: Solid block is considered a space (it has no floor)
*
* In: A = objid
* Out: 0 = space, 1 = floor
*
*-------------------------------
CMPSPACE
cmp #space
beq :space
cmp #pillartop
beq :space
cmp #panelwof
beq :space
cmp #block
beq :space
cmp #archtop1
bcs :space
lda #1
rts
:space lda #0
rts
*-------------------------------
*
* C O M P A R E B A R R I E R
*
* Is it a barrier?
*
* Return A = 0 if clear, else A = barrier code #
*
*-------------------------------
CMPBARR
cmp #panelwif
beq :b1
cmp #panelwof
beq :b1
cmp #gate
bne :2
:b1 lda #1 ;panel/gate
rts
:2 cmp #mirror
beq :yes3
cmp #slicer
bne :3
:yes3 lda #3 ;mirror/slicer
rts
:3 cmp #block
bne :4
lda #4 ;block
rts
:4
:clear lda #0
:rts rts
:barr lda #1
]rts rts
*-------------------------------
*
* Is it a wall? Return 0 if yes, 1 if no
* (Solid block, or panel if you're facing L)
*
*-------------------------------
CMPWALL
cmp #block
beq :yes
ldx CharFace
bpl :no
cmp #panelwif
beq :yes
cmp #panelwof
beq :yes
:no lda #1
rts
:yes lda #0
rts
*-------------------------------
*
* Add kid/reflection/shadowman/guard to object table
*
* In: FChar data
*
*-------------------------------
ADDKIDOBJ
lda #TypeKid
jmp addcharobj
*-------------------------------
ADDREFLOBJ
lda #TypeReflect
jmp addcharobj
*-------------------------------
ADDSHADOBJ
lda #TypeShad
jmp addcharobj
*-------------------------------
ADDGUARDOBJ
lda #TypeGd
jmp addcharobj
*-------------------------------
*
* Add sword to object table
* In: FChar data for character holding sword
*
*-------------------------------
ADDSWORDOBJ
lda #TypeSword
jmp addcharobj
*-------------------------------
*
* G E T S E Q
*
* Get next byte from seqtable & advance CharSeq
* (2-byte pointer to sequence table)
*
*-------------------------------
GETSEQ
ldy #0
lda (CharSeq),y
pha
inc CharSeq
bne :done
inc CharSeq+1
:done pla
rts
*-------------------------------
*
* G E T F R A M E I N F O
*
* Get frame info for char (based on CharPosn)
*
*-------------------------------
GETFRAMEINFO
lda CharPosn
jsr GETFRAME ;set framepoint
jsr usealtsets ;if appropriate
ldy #0
lda (framepoint),y
sta Fimage
iny
lda (framepoint),y
sta Fsword
iny
lda (framepoint),y
sta Fdx
iny
lda (framepoint),y
sta Fdy
iny
lda (framepoint),y
sta Fcheck
]rts rts
*-------------------------------
*
* Use alternate character image sets
* (if appropriate)
*
* In: Char data; framepoint
* Out: framepoint
*
*-------------------------------
usealtsets
ldx CharID
beq ]rts ;kid uses main set, enemy uses alt set 1
cpx #24
beq ]rts ;mouse uses main set
cpx #5
bcs :usealt2 ;princess & vizier use alt set 2
lda CharPosn
cpx #2
bcc :1
cmp #102
bcc ]rts
cmp #107
bcs :1
;frames 102-106 (falling): substitute 172-176 altset
clc
adc #70
:1 cmp #150
bcc ]rts
cmp #190
bcs ]rts
;frames 150-189: use altset
sec
sbc #149
jmp getaltframe1
:usealt2
lda CharPosn
jmp getaltframe2
*===============================
*
* M A R K
*
* In: A = mark value (usually 2)
* Results of INDEXBLOCK:
* Y = block #; carry set or clear
*
* Out: Preserve A, Y, carry
*
*-------------------------------
]os cpy #10 ;top line from scrn above?
bcs ]rts ;no
sta topbuf,y
sec ;preserve cs
]rts rts
MARKRED
bcs ]os
sta redbuf,y
rts
MARKFRED
bcs ]rts
sta fredbuf,y
rts
MARKWIPE
bcs ]rts
pha
lda wipebuf,y
beq :2
lda height
cmp whitebuf,y ;if wipebuf is already marked,
bcc :1 ;use larger of 2 whitebuf values
:2 lda height
sta whitebuf,y
:1 pla
sta wipebuf,y
clc ;return with cc
rts
MARKMOVE
bcs ]os
sta movebuf,y
rts
MARKFLOOR
bcs ]os
sta floorbuf,y
rts
MARKHALF
bcs ]os
sta halfbuf,y
rts
*-------------------------------
*
* Z E R O R E D
*
* zero redraw buffers
*
*-------------------------------
ZERORED
lda #0
ldy #29
:loop sta redbuf,y
sta fredbuf,y
sta floorbuf,y
sta wipebuf,y
sta movebuf,y
sta objbuf,y
sta halfbuf,y
dey
bpl :loop
ldy #9
:dloop sta topbuf,y
dey
bpl :dloop
rts
*-------------------------------
*
* C H E C K L E D G E
*
* In: blockid = block that must be clear;
* A = RDBLOCK results for block that must be ledge
*
* Out: A = 1 if grabbable, 0 if not
*
*-------------------------------
CHECKLEDGE
sta ztemp
lda (BlueSpec),y
sta tempstate
lda blockid ;must be clear
cmp #block
beq :no
cmp #panelwof ;CMPSPACE considers panel w/o floor
bne :cont ;to be clear--
bit CharFace ;but it isn't if char wants to grab
bpl :no ;floorpiece to right
:cont
jsr cmpspace
bne :no
* Clear above -- is there a ledge in front?
lda ztemp ;must be a solid floorpiece
;with exposed ledge
cmp #loose
bne :notloose
bit tempstate
bne :no ;floor is already loose
:notloose
cmp #panelwif
bne :cont2 ;panel w/floor can be grabbed
;only if facing right
bit CharFace
bmi :no
:cont2 jsr cmpspace
beq :no
:yes lda #1
rts
:no lda #0
]rts rts
*-------------------------------
*
* C H E C K S P I K E S
*
* Spikes spring out when char passes over them (at any
* height).
*
*-------------------------------
CHECKSPIKES
lda rightej
jsr getblockxp
bmi ]rts
sta tempright
* for blockx = leftblock to rightblock
lda leftej
jsr getblockxp
:loop sta blockx
jsr sub
lda blockx
cmp tempright
beq ]rts
clc
adc #1
jmp :loop
sub sta tempblockx
lda CharBlockY
sta tempblocky
lda CharScrn
sta tempscrn
:loop jsr rdblock1
cmp #spikes
bne :again
jmp trigspikes
:again jsr cmpspace
bne ]rts
lda tempscrn
beq ]rts ;null scrn
cmp CharScrn
bne ]rts ;wait till he's on same screen
inc tempblocky
jmp :loop ;check 1 level below
*===============================
*
* Load/save kid/shad vars
*
*-------------------------------
numvars = 16
LOADKID
ldx #numvars-1
:loop lda Kid,x
sta Char,x
dex
bpl :loop
]rts rts
SAVEKID
ldx #numvars-1
:loop lda Char,x
sta Kid,x
dex
bpl :loop
]rts rts
LOADSHAD
ldx #numvars-1
:loop lda Shad,x
sta Char,x
dex
bpl :loop
]rts rts
SAVESHAD
ldx #numvars-1
:loop lda Char,x
sta Shad,x
dex
bpl :loop
rts
* Load kid w/ opponent
LOADKIDWOP
ldx #numvars-1
:loop lda Kid,x
sta Char,x
lda Shad,x
sta Op,x
dex
bpl :loop
rts
SAVEKIDWOP
ldx #numvars-1
:loop lda Char,x
sta Kid,x
lda Op,x
sta Shad,x
dex
bpl :loop
rts
* Load shadowman w/ opponent
LOADSHADWOP
ldx #numvars-1
:loop lda Shad,x
sta Char,x
lda Kid,x
sta Op,x
dex
bpl :loop
rts
SAVESHADWOP
ldx #numvars-1
:loop lda Char,x
sta Shad,x
lda Op,x
sta Kid,x
dex
bpl :loop
rts
*-------------------------------
*
* Recharge strength meter to max
*
*-------------------------------
RECHARGEMETER
lda MaxKidStr
sec
sbc KidStrength
sta ChgKidStr
]rts rts
*-------------------------------
*
* Boost strength meter max by 1 and recharge
*
*-------------------------------
BOOSTMETER
lda MaxKidStr
cmp #maxmaxstr
bcs :1
clc
adc #1
sta MaxKidStr
:1 jmp RECHARGEMETER
*-------------------------------
*
* Get distance between char & opponent
* (# pixels char must move fwd to reach opponent)
* If dist is greater than 127, return 127 (+ or -)
*
*-------------------------------
estwidth = 13 ;rough est of char width
GETOPDIST
lda CharScrn
cmp OpScrn
bne :safe
* First, get A = OpX-CharX (abs. value <= 127)
lda OpX
cmp CharX
bcc :neg
sec
sbc CharX
bpl :got
lda #127
bpl :got
:neg lda CharX
sec
sbc OpX
bpl :1
lda #127
:1 eor #$ff
clc
adc #1 ;negate
* If CharFace = left, negate
:got ldx CharFace
bpl :cont
eor #$ff
clc
adc #1
* If chars are facing in opposite directions,
* adjust by estimate of width of figure
:cont tax
lda CharFace
eor OpFace
bpl :done
txa
cmp #127-estwidth
bcs :done2
clc
adc #estwidth
:done2 tax
rts
:safe ldx #127 ;arbitrary large dist.
:done txa ;return value in A
]rts rts
*-------------------------------
*
* Adjust CharY for uneven floor
*
*-------------------------------
UNEVENFLOOR
jsr getunderft
cmp #dpressplate
bne ]rts
inc CharY
]rts rts
*-------------------------------
lst
ds 1
usr $a9,19,$200,*-org
lst off