1516 lines
21 KiB
ArmAsm
Executable File
1516 lines
21 KiB
ArmAsm
Executable File
* coll
|
|
org = $4500
|
|
tr on
|
|
lst off
|
|
*-------------------------------
|
|
*
|
|
* PRINCE OF PERSIA
|
|
* Copyright 1989 Jordan Mechner
|
|
*
|
|
*-------------------------------
|
|
org org
|
|
|
|
jmp CHECKBARR
|
|
jmp COLLISIONS
|
|
jmp GETFWDDIST
|
|
jmp CHECKCOLL
|
|
jmp ANIMCHAR
|
|
|
|
jmp CHECKSLICE
|
|
jmp CHECKSLICE2
|
|
jmp markmeters ;temp
|
|
jmp CHECKGATE
|
|
jmp firstguard ;temp
|
|
|
|
jmp ENEMYCOLL
|
|
|
|
*-------------------------------
|
|
lst
|
|
put eq
|
|
lst
|
|
put gameeq
|
|
lst
|
|
put seqdata
|
|
lst
|
|
put soundnames
|
|
lst
|
|
put movedata
|
|
lst off
|
|
|
|
dum $f0
|
|
ztemp ds 1
|
|
CollFace ds 1
|
|
tempobjid ds 1
|
|
tempstate ds 1
|
|
dend
|
|
|
|
*-------------------------------
|
|
* Distance in pixels from either edge of block to barrier
|
|
* BarL + BarR + BarWidth == 14
|
|
*
|
|
* Indexed by barrier code:
|
|
* 0 = clear, 1 = panel/gate, 2 = flask, 3 = mirror/slicer
|
|
* 4 = block
|
|
|
|
BarL db 0,12,2,0,0
|
|
BarR db 0,0,9,11,0
|
|
|
|
*-------------------------------
|
|
DeathVelocity = 33
|
|
OofVelocity = 22
|
|
|
|
gatemargin = 6 ;higher = more generous
|
|
|
|
]rts rts
|
|
*-------------------------------
|
|
*
|
|
* C H E C K B A R R I E R
|
|
*
|
|
* Check for collisions with vertical barriers
|
|
*
|
|
*-------------------------------
|
|
CHECKBARR
|
|
lda #-1 ;"no-collision" flag
|
|
sta collideL
|
|
sta collideR
|
|
|
|
* Check for situations where character is temporarily
|
|
* "collision-proof"
|
|
|
|
lda CharAction
|
|
cmp #7 ;turning?
|
|
beq ]rts
|
|
|
|
* Initialize CD/SN buffers
|
|
* (Copy "lastframe" data from "thisframe", "above", or "below";
|
|
* init "thisframe" with FF)
|
|
|
|
lda CharBlockY
|
|
sta BlockYthis
|
|
|
|
jsr initCDbufs
|
|
|
|
lda BlockYthis
|
|
sta BlockYlast
|
|
|
|
* Get beginning & end of range
|
|
|
|
lda CDRightEj
|
|
jsr getblockxp
|
|
clc
|
|
adc #2
|
|
cmp #11
|
|
bcc :ok
|
|
lda #11
|
|
;Last (rightmost) block in range +1
|
|
:ok sta endrange
|
|
|
|
lda CDLeftEj
|
|
jsr getblockxp
|
|
tax
|
|
dex ;First (leftmost) block in range
|
|
stx begrange
|
|
|
|
* Get CD & SN data for every block in range [begrange..endrange]
|
|
* on this level (BlockYthis) and on levels below & above
|
|
|
|
* This level...
|
|
|
|
lda BlockYthis
|
|
sta blocky
|
|
|
|
lda #SNthisframe
|
|
ldx #CDthisframe
|
|
jsr getCData
|
|
|
|
* Level below...
|
|
|
|
lda BlockYthis
|
|
clc
|
|
adc #1
|
|
sta blocky
|
|
|
|
lda #SNbelow
|
|
ldx #CDbelow
|
|
jsr getCData
|
|
|
|
* ...and level above
|
|
|
|
lda BlockYthis
|
|
sec
|
|
sbc #1
|
|
sta blocky
|
|
|
|
lda #SNabove
|
|
ldx #CDabove
|
|
jsr getCData
|
|
|
|
* Got new data... now compare thisframe with lastframe
|
|
* If a nybble has changed from 0 to 1, we have a collision.
|
|
|
|
ldx #9
|
|
:loop2
|
|
lda SNthisframe,x
|
|
bmi :no ;ff = no data for this frame
|
|
cmp SNlastframe,x
|
|
bne :no ;no corresponding data for last frame
|
|
|
|
lda CDlastframe,x
|
|
and #$0f ;low nybble first (L edge of barr)
|
|
bne :noL
|
|
|
|
lda CDthisframe,x
|
|
and #$0f
|
|
beq :noL
|
|
|
|
stx collideL ;We have collision w/ L edge
|
|
;x = block # (0-9)
|
|
|
|
:noL lda CDlastframe,x
|
|
and #$f0 ;hi nybble (R edge of barr)
|
|
bne :noR
|
|
|
|
lda CDthisframe,x
|
|
and #$f0
|
|
beq :noR
|
|
|
|
stx collideR ;collision w/ R edge
|
|
:noR
|
|
:no dex
|
|
bpl :loop2
|
|
|
|
ldx collideL
|
|
ldy collideR
|
|
|
|
]rts rts
|
|
|
|
*-------------------------------
|
|
*
|
|
* G E T C D A T A
|
|
*
|
|
* Get "thisframe" data for specified blocky
|
|
*
|
|
*-------------------------------
|
|
getCData
|
|
sta :smodSN+1
|
|
stx :smodCD+1
|
|
|
|
lda begrange
|
|
jsr getblockej ;left edge of block
|
|
clc
|
|
adc #angle ;perspective
|
|
sta blockedge
|
|
|
|
ldx begrange
|
|
:loop stx bufindex
|
|
|
|
* First compare L edge of barr with R edge of char
|
|
|
|
lda CharScrn
|
|
ldx bufindex
|
|
ldy blocky
|
|
jsr getleftbar ;Get left edge of barrier
|
|
|
|
cmp CDRightEj
|
|
bcc :RofL
|
|
;= means L of L
|
|
:LofL lda #0
|
|
beq :cont1
|
|
|
|
:RofL lda #$f
|
|
:cont1 sta ztemp
|
|
|
|
* Now compare R edge of barr with L edge of char
|
|
|
|
lda CharScrn
|
|
ldx bufindex
|
|
ldy blocky
|
|
jsr getrightbar ;Get right edge of barrier
|
|
|
|
cmp CDLeftEj
|
|
bcc :RofR
|
|
beq :RofR ;= means R of R
|
|
|
|
:LofR lda #$f0
|
|
bne :cont2
|
|
|
|
:RofR lda #0
|
|
:cont2 ora ztemp
|
|
|
|
ldx tempblockx ;guaranteed 0-9 by rdblock
|
|
:smodCD sta CDthisframe,x
|
|
|
|
lda tempscrn
|
|
:smodSN sta SNthisframe,x ;screen #
|
|
|
|
lda blockedge
|
|
clc
|
|
adc #14
|
|
sta blockedge
|
|
|
|
ldx bufindex
|
|
inx
|
|
cpx endrange
|
|
bne :loop
|
|
|
|
]rts rts
|
|
|
|
*-------------------------------
|
|
*
|
|
* I N I T C D B U F S
|
|
*
|
|
* Initialize SN and CD buffers
|
|
* (Take "lastframe" data from "thisframe", "above", or "below";
|
|
* init "thisframe" with FF)
|
|
*
|
|
*-------------------------------
|
|
initCDbufs
|
|
lda BlockYthis
|
|
cmp BlockYlast ;same BlockY as last frame?
|
|
beq :usethis ;yes--copy data from "thisframe"
|
|
|
|
clc
|
|
adc #3
|
|
cmp BlockYlast
|
|
beq :usethis
|
|
|
|
sec
|
|
sbc #6
|
|
cmp BlockYlast
|
|
beq :usethis
|
|
|
|
* BlockY has changed--copy data from "above" or "below"
|
|
|
|
lda BlockYthis
|
|
clc
|
|
adc #1
|
|
cmp BlockYlast
|
|
beq :useabove
|
|
sec
|
|
sbc #3
|
|
cmp BlockYlast
|
|
beq :useabove
|
|
|
|
:usebelow
|
|
lda #SNbelow
|
|
ldx #CDbelow
|
|
jmp :cont
|
|
|
|
:useabove lda #SNabove
|
|
ldx #CDabove
|
|
jmp :cont
|
|
|
|
:usethis lda #SNthisframe
|
|
ldx #CDthisframe
|
|
|
|
:cont sta :smodSN+1
|
|
stx :smodCD+1
|
|
|
|
* Copy contents of appropriate SN & CD buffers (thisframe,
|
|
* below, or above) into lastframe buffers...
|
|
* and initialize SN buffers with $ff
|
|
|
|
ldx #9
|
|
:zloop
|
|
:smodSN lda SNbelow,x
|
|
sta SNlastframe,x
|
|
|
|
:smodCD lda CDbelow,x
|
|
sta CDlastframe,x
|
|
|
|
lda #$ff
|
|
sta SNthisframe,x
|
|
sta SNabove,x
|
|
sta SNbelow,x
|
|
|
|
dex
|
|
bpl :zloop
|
|
|
|
]rts rts
|
|
|
|
*-------------------------------
|
|
*
|
|
* G E T L E F T B A R
|
|
*
|
|
* Get X-coord of left edge of barrier
|
|
*
|
|
* In: X/Y/A = blockx/blocky/scrn
|
|
* blockedge
|
|
*
|
|
* Out: A = screen X-coord (140)
|
|
* Return A = 255 if this block is no barrier
|
|
*
|
|
*-------------------------------
|
|
getleftbar
|
|
jsr rdblock ;get block ID
|
|
|
|
jsr cmpbarr ;return A = barrier code #
|
|
beq :clear ;or -1 if clear
|
|
tay
|
|
|
|
lda blockedge
|
|
clc
|
|
adc BarL,y ;barr dist from L edge of block
|
|
sec
|
|
rts
|
|
|
|
:clear lda #255
|
|
clc
|
|
rts
|
|
|
|
*-------------------------------
|
|
*
|
|
* G E T R I G H T B A R
|
|
*
|
|
* Get right edge of barrier, 0 if clear
|
|
*
|
|
*-------------------------------
|
|
getrightbar
|
|
jsr rdblock
|
|
|
|
jsr cmpbarr
|
|
beq :clear
|
|
tay
|
|
|
|
lda blockedge
|
|
clc
|
|
adc #13
|
|
sec
|
|
sbc BarR,y ;barr dist from R edge of block
|
|
sec
|
|
rts
|
|
|
|
:clear lda #0
|
|
clc
|
|
]rts rts
|
|
|
|
*-------------------------------
|
|
*
|
|
* C O L L I S I O N S
|
|
*
|
|
* If a collision was detected, act on it
|
|
*
|
|
* In: collideL/R: - if no coll, 0-9 refers to block in
|
|
* which collision occurred
|
|
*
|
|
* (CollideL is collision with LEFT EDGE of barrier
|
|
* CollideR is collision with RIGHT EDGE of barrier)
|
|
*
|
|
*-------------------------------
|
|
COLLISIONS
|
|
lda AMtimer ;antimatter timer
|
|
beq :cont
|
|
lda $c030
|
|
dec AMtimer
|
|
rts
|
|
:cont
|
|
|
|
* Check for situations where we let character
|
|
* pass thru barrier (e.g., climbing up onto ledge)
|
|
|
|
lda CharAction
|
|
cmp #2 ;hanging?
|
|
beq ]rts
|
|
cmp #6 ;hanging?
|
|
beq ]rts
|
|
lda CharPosn
|
|
cmp #135
|
|
bcc :cont2
|
|
cmp #149
|
|
bcc ]rts ;climbing?
|
|
|
|
:cont2
|
|
ldx collideL
|
|
bmi :noL
|
|
stx collX
|
|
jmp leftcoll
|
|
|
|
:noL ldx collideR
|
|
bmi :noR
|
|
stx collX
|
|
jmp rightcoll
|
|
:noR
|
|
]rts rts
|
|
|
|
*-------------------------------
|
|
*
|
|
* R I G H T C O L L I S I O N
|
|
*
|
|
*-------------------------------
|
|
rightcoll
|
|
lda CharSword
|
|
cmp #2 ;if in fighting mode,
|
|
beq :1 ;waive front-facing requirement
|
|
|
|
lda CharFace
|
|
bpl ]rts
|
|
:1
|
|
jsr checkcoll1
|
|
bcc ]rts
|
|
|
|
lda tempscrn
|
|
ldx tempblockx
|
|
ldy tempblocky
|
|
|
|
jsr getrightbar ;edge of barr
|
|
sec
|
|
sbc CDLeftEj ;dist to char
|
|
|
|
ldx #0 ;right
|
|
jmp collide
|
|
|
|
*-------------------------------
|
|
*
|
|
* L E F T C O L L I S I O N
|
|
*
|
|
*-------------------------------
|
|
leftcoll
|
|
lda CharSword
|
|
cmp #2
|
|
beq :1
|
|
|
|
lda CharFace
|
|
bne ]rts
|
|
:1
|
|
jsr checkcoll1
|
|
bcc ]rts
|
|
|
|
lda tempscrn
|
|
ldx tempblockx
|
|
ldy tempblocky
|
|
jsr getleftbar
|
|
sec
|
|
sbc CDRightEj ;- dist to char
|
|
|
|
ldx #-1 ;left
|
|
jmp collide
|
|
|
|
*-------------------------------
|
|
*
|
|
* Call CHECKCOLL for block #X
|
|
*
|
|
* In: CD data; X = blockx
|
|
*
|
|
*-------------------------------
|
|
checkcoll1
|
|
stx tempblockx
|
|
|
|
lda CharBlockY
|
|
bpl :2
|
|
clc
|
|
adc #3
|
|
bne :1
|
|
|
|
:2 cmp #3
|
|
bcc :1
|
|
sec
|
|
sbc #3
|
|
:1 sta tempblocky
|
|
|
|
lda SNthisframe,x
|
|
sta tempscrn
|
|
|
|
jsr rdblock1
|
|
|
|
jmp CHECKCOLL
|
|
|
|
*-------------------------------
|
|
*
|
|
* C H E C K C O L L
|
|
*
|
|
* In: RDBLOCK results (A = objid)
|
|
*
|
|
* Out: tempblockx,tempblocky,tempscrn
|
|
* cs if collision, cc if not
|
|
*
|
|
*-------------------------------
|
|
CHECKCOLL
|
|
cmp #flask
|
|
beq :no ;flask is not really a barrier
|
|
|
|
cmp #gate
|
|
beq :gate
|
|
|
|
cmp #slicer
|
|
beq :slicer
|
|
|
|
cmp #mirror
|
|
beq :mirror
|
|
bne :c1
|
|
|
|
* You can pass thru mirror from R only if you take a
|
|
* running jump
|
|
|
|
:mirror
|
|
lda CharID
|
|
bne :c1 ;must be kid
|
|
lda CharPosn
|
|
cmp #39
|
|
bcc :c1
|
|
cmp #44
|
|
bcs :c1
|
|
lda CharFace
|
|
bpl :c1
|
|
|
|
jsr smashmirror
|
|
lda #$ff
|
|
sta createshad ;set flag
|
|
|
|
clc
|
|
rts
|
|
|
|
* Is slicer closed?
|
|
|
|
:slicer lda (BlueSpec),y
|
|
cmp #slicerExt
|
|
bne :no ;no--pass thru
|
|
beq :c1
|
|
|
|
* Is gate low enough to bar you?
|
|
|
|
:gate jsr gatebarr? ;return cc if gate bars you
|
|
bcc :c1
|
|
|
|
* no collision--pass thru barrier
|
|
|
|
:no clc
|
|
rts
|
|
|
|
* Yes, collision--get blockedge & return cs
|
|
|
|
:c1
|
|
lda tempblockx
|
|
jsr getblockej
|
|
jsr AdjustScrn
|
|
clc
|
|
adc #angle
|
|
sta blockedge
|
|
:yes sec
|
|
]rts rts
|
|
|
|
*-------------------------------
|
|
*
|
|
* AdjustScrn
|
|
*
|
|
* In: tempscrn, VisScrn
|
|
* scrnLeft/Right/BelowL/BelowR
|
|
* A = X-coord on tempscrn
|
|
*
|
|
* Out: A = X=coord on VisScrn
|
|
*
|
|
*-------------------------------
|
|
AdjustScrn
|
|
ldx tempscrn
|
|
cpx VisScrn
|
|
beq ]rts
|
|
cpx scrnLeft
|
|
beq :osL
|
|
cpx scrnBelowL
|
|
beq :osL
|
|
cpx scrnRight
|
|
beq :osR
|
|
cpx scrnBelowR
|
|
beq :osR
|
|
rts
|
|
:osR clc
|
|
adc #ScrnWidth
|
|
rts
|
|
:osL sec
|
|
sbc #ScrnWidth
|
|
]rts rts
|
|
|
|
*-------------------------------
|
|
*
|
|
* C O L L I D E
|
|
*
|
|
* In: A = distance from barrier to character
|
|
* X = coll direction (-1 = left, 0 = right)
|
|
* tempblockx,y,scrn set for collision block
|
|
*
|
|
*-------------------------------
|
|
collide
|
|
stx CollFace ;temp var
|
|
|
|
ldx CharLife ;dead?
|
|
bpl ]rts ;yes--let him finish falling (or whatever)
|
|
|
|
ldx CharPosn
|
|
cpx #177 ;impaled?
|
|
beq ]rts ;yes--ignore collision
|
|
|
|
clc
|
|
adc CharX
|
|
sta CharX
|
|
|
|
* In midair or on the ground?
|
|
|
|
jsr rdblock1
|
|
|
|
ldx CollFace
|
|
bpl :faceL
|
|
|
|
cmp #block ;If this block has no floor,
|
|
beq :2 ;use the one in front of it
|
|
bne :1
|
|
|
|
:2 dec tempblockx
|
|
jmp :3
|
|
|
|
:faceL cmp #panelwof ;Panelwof is only a problem
|
|
beq :4 ;when facing L
|
|
cmp #panelwif
|
|
beq :4
|
|
cmp #block
|
|
bne :1
|
|
|
|
:4 inc tempblockx
|
|
lda tempscrn
|
|
bne :3
|
|
lda tempblockx
|
|
cmp #10
|
|
bne :3
|
|
lda CharScrn
|
|
sta tempscrn
|
|
lda #0
|
|
sta tempblockx ;screen 0 block 10 = CharScrn block 0
|
|
|
|
:3 jsr rdblock1
|
|
|
|
:1 jsr cmpspace
|
|
bne GroundBump
|
|
|
|
*-------------------------------
|
|
* Bump into barrier w/o floor
|
|
|
|
AirBump
|
|
lda #-4
|
|
jsr addcharx
|
|
sta CharX
|
|
|
|
lda CharAction
|
|
cmp #4 ;already falling?
|
|
bne :3
|
|
;yes--just rebound off wall
|
|
lda #0
|
|
sta CharXVel
|
|
beq :smackwall
|
|
|
|
:3 lda #bumpfall
|
|
jsr jumpseq
|
|
jsr animchar
|
|
|
|
:smackwall
|
|
|
|
BumpSound
|
|
lda #1
|
|
sta alertguard
|
|
lda #SmackWall
|
|
jmp addsound
|
|
|
|
*-------------------------------
|
|
* Bump into barrier w/floor
|
|
|
|
GroundBump
|
|
ldx CharBlockY
|
|
|
|
lda CharSword
|
|
cmp #2
|
|
beq :skipair ;no airbump if en garde
|
|
|
|
lda FloorY+1,x
|
|
sec
|
|
sbc CharY
|
|
cmp #15 ;constant
|
|
bcs AirBump
|
|
:skipair
|
|
lda FloorY+1,x
|
|
sta CharY
|
|
|
|
lda CharYVel
|
|
cmp #OofVelocity
|
|
bcc :okvel
|
|
lda #-5
|
|
jsr addcharx
|
|
sta CharX
|
|
rts ;let checkfloor take care of it
|
|
|
|
:okvel lda #0
|
|
sta CharYVel
|
|
|
|
lda CharLife
|
|
beq :deadbump
|
|
|
|
* Is he en garde?
|
|
|
|
lda CharSword
|
|
cmp #2
|
|
beq :CollideEng ;yes--collide en garde
|
|
|
|
* Should it be a hard or a soft bump?
|
|
|
|
:normal
|
|
ldx CharPosn ;last frame
|
|
|
|
cpx #24
|
|
beq :hard
|
|
cpx #25
|
|
beq :hard ;standjump-->hard
|
|
|
|
cpx #40
|
|
bcc :1
|
|
cpx #43
|
|
bcc :hard ;runjump-->hard
|
|
|
|
:1 cpx #102
|
|
bcc :2
|
|
cpx #107
|
|
bcc :hard ;freefall-->hard
|
|
|
|
:2
|
|
|
|
:soft lda #bump
|
|
jsr jumpseq
|
|
jsr BumpSound ;soft bump sound?
|
|
jmp animchar
|
|
|
|
:hard lda #hardbump
|
|
:doit jsr jumpseq
|
|
jsr animchar
|
|
|
|
jmp BumpSound
|
|
|
|
* dead when he hits the wall
|
|
|
|
:deadbump
|
|
]rts rts
|
|
|
|
*-------------------------------
|
|
* Collide en garde
|
|
|
|
:CollideEng
|
|
lda CollFace
|
|
cmp CharFace
|
|
beq :collback
|
|
|
|
lda #bumpengfwd
|
|
bne :doit
|
|
|
|
* Char is en garde & trying to back into barrier
|
|
|
|
:collback
|
|
lda #bumpengback
|
|
jsr jumpseq
|
|
jsr animchar ;get new frame
|
|
|
|
lda #1
|
|
jsr addcharx
|
|
sta CharX
|
|
rts
|
|
|
|
*-------------------------------
|
|
*
|
|
* G E T F W D D I S T
|
|
*
|
|
* In: Char data
|
|
*
|
|
* Out: A = size of "careful step" forward (0-14 pixels)
|
|
* X = what you're stepping up to
|
|
* (0 = edge, 1 = barrier, 2 = clear)
|
|
* RDBLOCK results for that block
|
|
*
|
|
*-------------------------------
|
|
GETFWDDIST
|
|
|
|
* Get edges
|
|
|
|
jsr GetBaseBlock
|
|
jsr setupchar
|
|
jsr getedges
|
|
|
|
* If this block contains barrier, get distance
|
|
|
|
jsr getunderft ;read block underfoot
|
|
sta tempobjid
|
|
|
|
jsr cmpbarr
|
|
beq :nextb ;This block is clear
|
|
|
|
lda CharBlockX
|
|
sta tempblockx
|
|
jsr DBarr ;returns A = dist to barrier
|
|
tax
|
|
bpl :tobarr
|
|
|
|
* If next block contains barrier, get distance
|
|
|
|
:nextb
|
|
jsr getinfront
|
|
sta tempobjid
|
|
cmp #panelwof
|
|
bne :99 ;Panelwof is special case
|
|
ldx CharFace ;if you're facing R
|
|
bpl :toEOB
|
|
|
|
:99 jsr cmpbarr
|
|
beq :nobarr
|
|
|
|
lda infrontx
|
|
sta tempblockx
|
|
jsr DBarr
|
|
tax
|
|
bpl :tobarr
|
|
|
|
* If next block is dangerous (e.g., empty space)
|
|
* or sword or potion, step to end of this block
|
|
|
|
:nobarr
|
|
jsr getinfront ;read block in front
|
|
sta tempobjid
|
|
|
|
cmp #loose
|
|
beq :toEOB ;step to end of block
|
|
|
|
cmp #pressplate
|
|
beq :toEOB1
|
|
|
|
cmp #sword
|
|
beq :toEOB1
|
|
cmp #flask
|
|
beq :toEOB1
|
|
|
|
jsr cmpspace
|
|
beq :toEOB
|
|
|
|
* All clear--take a full step forward
|
|
|
|
:fullstep lda #11 ;natural step size
|
|
|
|
ldx #2 ;clear
|
|
bne :done
|
|
|
|
* Step to end of block (no "testfoot")
|
|
|
|
:toEOB1 jsr getdist
|
|
beq :fullstep
|
|
ldx #0
|
|
beq :done
|
|
|
|
* Step to end of block
|
|
|
|
:toEOB jsr getdist ;returns # pixels to end of block (0-13)
|
|
|
|
ldx #0 ;edge
|
|
|
|
:done ldy tempobjid
|
|
]rts rts
|
|
|
|
* Step up to barrier
|
|
|
|
:tobarr
|
|
cmp #14
|
|
bcs :fullstep
|
|
|
|
ldx #1 ;barrier
|
|
bne :done
|
|
|
|
*-------------------------------
|
|
*
|
|
* Get distance to barrier
|
|
*
|
|
* In: rdblock results; tempobjid
|
|
* Must have called setupchar/getedges
|
|
* Out: A = distance to barrier (- if barr is behind char)
|
|
*
|
|
*-------------------------------
|
|
DBarr
|
|
lda tempobjid
|
|
cmp #gate
|
|
bne :ok
|
|
;treat gate as barrier only if down
|
|
jsr gatebarr? ;returns cs if open
|
|
bcs :clr
|
|
|
|
:ok lda tempblockx
|
|
jsr getblockej
|
|
clc
|
|
adc #angle
|
|
sta blockedge ;L edge of this block
|
|
|
|
lda CharFace
|
|
bmi :checkL
|
|
|
|
* Char facing R -- get distance to barrier
|
|
|
|
:checkR
|
|
lda tempobjid ;block ID
|
|
|
|
jsr cmpbarr ;return A = barrier code #
|
|
beq :clr
|
|
tay
|
|
|
|
lda blockedge
|
|
clc
|
|
adc BarL,y
|
|
sta ztemp ;left edge of barr
|
|
|
|
sec
|
|
sbc CDRightEj
|
|
rts ;If -, barr is behind char
|
|
|
|
:clr lda #-1
|
|
rts
|
|
|
|
* Char facing L -- get distance to barr
|
|
|
|
:checkL
|
|
lda tempobjid
|
|
|
|
jsr cmpbarr
|
|
beq :clr
|
|
tay
|
|
|
|
lda blockedge
|
|
clc
|
|
adc #13
|
|
sec
|
|
sbc BarR,y
|
|
sta ztemp ;R edge of barr
|
|
|
|
lda CDLeftEj
|
|
sec
|
|
sbc ztemp
|
|
|
|
]rts rts
|
|
|
|
*-------------------------------
|
|
*
|
|
* A N I M C H A R
|
|
*
|
|
* Get next frame from sequence table;
|
|
* update char data accordingly.
|
|
* We're now ready to draw this frame.
|
|
*
|
|
*-------------------------------
|
|
ANIMCHAR
|
|
|
|
:next jsr getseq ;get next byte from seqtab
|
|
;& increment CharSeq
|
|
|
|
cmp #chx ;"change x" instruction?
|
|
bne :no1
|
|
|
|
jsr getseq ;next byte is delta-x
|
|
|
|
jsr addcharx
|
|
sta CharX
|
|
|
|
jmp :next
|
|
|
|
*-------------------------------
|
|
:no1 cmp #chy
|
|
bne :no2
|
|
|
|
jsr getseq
|
|
|
|
clc
|
|
adc CharY
|
|
sta CharY
|
|
|
|
jmp :next
|
|
|
|
*-------------------------------
|
|
:no2 cmp #aboutface
|
|
bne :no3
|
|
|
|
lda CharFace
|
|
eor #$ff
|
|
sta CharFace
|
|
|
|
jmp :next
|
|
|
|
*-------------------------------
|
|
:no3 cmp #goto
|
|
bne :no4
|
|
|
|
:goto jsr getseq ;low byte of address
|
|
pha
|
|
|
|
jsr getseq ;high byte
|
|
|
|
sta CharSeq+1
|
|
pla
|
|
sta CharSeq
|
|
|
|
jmp :next
|
|
|
|
*-------------------------------
|
|
:no4 cmp #up
|
|
bne :no5
|
|
|
|
dec CharBlockY
|
|
|
|
jsr addslicers
|
|
|
|
jmp :next
|
|
|
|
*-------------------------------
|
|
:no5 cmp #down
|
|
bne :no6
|
|
|
|
inc CharBlockY
|
|
|
|
jsr addslicers
|
|
|
|
jmp :next
|
|
|
|
*-------------------------------
|
|
:no6 cmp #act
|
|
bne :no7
|
|
|
|
jsr getseq
|
|
sta CharAction
|
|
|
|
jmp :next
|
|
|
|
:no7 cmp #setfall
|
|
bne :no8
|
|
|
|
jsr getseq
|
|
sta CharXVel
|
|
|
|
jsr getseq
|
|
sta CharYVel
|
|
|
|
jmp :next
|
|
|
|
:no8 cmp #ifwtless
|
|
bne :no9
|
|
|
|
lda weightless ;weightless?
|
|
bne :goto ;yes--branch
|
|
|
|
jsr getseq
|
|
jsr getseq ;skip 2 bytes
|
|
jmp :next ;& continue
|
|
|
|
:no9 cmp #die
|
|
bne :no10
|
|
jmp :next
|
|
|
|
:no10 cmp #jaru
|
|
bne :no11
|
|
|
|
lda #1
|
|
sta jarabove ;jar floorboards above
|
|
jmp :next
|
|
|
|
:no11 cmp #jard
|
|
bne :no12
|
|
|
|
lda #-1
|
|
sta jarabove ;jar floorboards below
|
|
jmp :next
|
|
|
|
*-------------------------------
|
|
:no12 cmp #tap
|
|
bne :no13
|
|
|
|
jsr getseq ;sound #
|
|
cmp #0 ;0: alert guard
|
|
beq :0
|
|
|
|
cmp #1 ;1: footstep
|
|
bne :1
|
|
lda #Footstep
|
|
:tap jsr addsound
|
|
:0 lda #1
|
|
sta alertguard
|
|
jmp :next
|
|
|
|
:1 cmp #2 ;2: smack wall
|
|
bne :2
|
|
lda #SmackWall
|
|
bne :tap
|
|
:2 jmp :next
|
|
|
|
:no13 cmp #nextlevel
|
|
bne :no14
|
|
|
|
jsr GoneUpstairs
|
|
jmp :next
|
|
|
|
:no14 cmp #effect
|
|
bne :no15
|
|
|
|
jsr getseq ;effect #
|
|
cmp #1
|
|
bne :fx0
|
|
|
|
jsr potioneffect
|
|
:fx0 jmp :next
|
|
|
|
:no15
|
|
*-------------------------------
|
|
sta CharPosn ;frame #
|
|
|
|
]rts rts
|
|
|
|
*-------------------------------
|
|
* Char has gone upstairs
|
|
* What do we do?
|
|
*-------------------------------
|
|
GoneUpstairs
|
|
lda level
|
|
cmp #13
|
|
beq :ok ;no music for level 13
|
|
cmp #4
|
|
bne :1 ;mirror level is special
|
|
:3 lda #s_Shadow
|
|
bne :2
|
|
|
|
:1 lda #s_Upstairs
|
|
:2 ldx #25
|
|
jsr cuesong
|
|
|
|
:ok inc NextLevel
|
|
rts
|
|
|
|
*-------------------------------
|
|
*
|
|
* Sliced by slicer? (Does CD buf show char overlapping
|
|
* with a closed slicer?)
|
|
*
|
|
* In: Char data, CD data
|
|
*
|
|
*-------------------------------
|
|
CHECKSLICE
|
|
lda CharBlockY
|
|
sta tempblocky
|
|
|
|
ldx #9
|
|
|
|
:loop stx tempblockx
|
|
|
|
lda CDthisframe,x
|
|
cmp #$ff ;char overlapping barr?
|
|
bne :ok ;no
|
|
|
|
* Yes--is it a slicer?
|
|
|
|
lda SNthisframe,x
|
|
sta tempscrn
|
|
|
|
jsr rdblock1
|
|
cmp #slicer
|
|
bne :ok
|
|
|
|
lda (BlueSpec),y
|
|
and #$7f
|
|
cmp #slicerExt ;slicer closed?
|
|
beq :slice ;yes--slice!
|
|
|
|
* No--keep checking
|
|
|
|
:ok ldx tempblockx
|
|
dex
|
|
bpl :loop
|
|
]rts rts
|
|
|
|
* Slice!
|
|
* In: rdblock results for slicer block
|
|
|
|
:slice
|
|
]slice
|
|
lda (BlueSpec),y
|
|
ora #$80
|
|
sta (BlueSpec),y ;set hibit (smear)
|
|
|
|
:cont lda CharPosn
|
|
cmp #178 ;if already cut in half (e.g. by another slicer),
|
|
beq ]rts ;leave him alone
|
|
|
|
lda tempblockx
|
|
jsr getblockej ;edge of slicer block
|
|
clc
|
|
adc #7
|
|
sta CharX
|
|
|
|
lda #8
|
|
jsr addcharx
|
|
sta CharX ;align char w/slicer
|
|
|
|
ldx CharBlockY
|
|
inx
|
|
lda FloorY,x
|
|
sta CharY ;align char w/floor
|
|
|
|
lda #100
|
|
jsr decstr
|
|
|
|
lda #Splat
|
|
jsr addsound
|
|
|
|
lda #halve
|
|
jsr jumpseq
|
|
jmp animchar
|
|
|
|
*-------------------------------
|
|
*
|
|
* Sliced by slicer?
|
|
*
|
|
* (Use this routine for enemy, who has no CD data)
|
|
*
|
|
* In: Char data; GETEDGES results
|
|
*
|
|
*-------------------------------
|
|
CHECKSLICE2
|
|
jsr getunderft
|
|
jsr :slice? ;return cs if sliced
|
|
bcs ]rts
|
|
|
|
inc tempblockx
|
|
jsr rdblock1
|
|
|
|
:slice?
|
|
cmp #slicer
|
|
bne :safe
|
|
lda (BlueSpec),y
|
|
and #$7f
|
|
cmp #slicerExt
|
|
bne :safe ;slicer open
|
|
|
|
lda tempblockx
|
|
jsr getblockej
|
|
clc
|
|
adc #angle
|
|
sta blockedge
|
|
|
|
lda tempscrn
|
|
ldx tempblockx
|
|
ldy tempblocky
|
|
jsr getleftbar
|
|
cmp CDRightEj
|
|
bcs :safe
|
|
|
|
lda tempscrn
|
|
ldx tempblockx
|
|
ldy tempblocky
|
|
jsr getrightbar
|
|
cmp CDLeftEj
|
|
bcc :safe
|
|
beq :safe
|
|
|
|
jsr rdblock1
|
|
jsr ]slice
|
|
sec
|
|
rts
|
|
|
|
:safe clc
|
|
]rts rts
|
|
|
|
*-------------------------------
|
|
*
|
|
* Special situation: If char is standing directly under closing
|
|
* gate, it knocks him aside when it shuts.
|
|
*
|
|
* In: Char data, CD data
|
|
*
|
|
*-------------------------------
|
|
CHECKGATE
|
|
lda CharAction
|
|
cmp #7 ;turning
|
|
beq :1
|
|
lda CharPosn
|
|
cmp #15 ;standing?
|
|
beq :1
|
|
cmp #108
|
|
bcc ]rts
|
|
cmp #111 ;crouching?
|
|
bcs ]rts
|
|
:1
|
|
jsr getunderft
|
|
cmp #gate
|
|
beq :check
|
|
|
|
dec tempblockx
|
|
jsr rdblock1
|
|
cmp #gate
|
|
bne ]rts
|
|
:check
|
|
ldx tempblockx
|
|
lda CDthisframe,x
|
|
and CDlastframe,x
|
|
cmp #$ff
|
|
bne ]rts
|
|
|
|
jsr gatebarr?
|
|
bcs ]rts
|
|
|
|
jsr BumpSound
|
|
|
|
* bump him left or right?
|
|
|
|
lda tempblockx
|
|
sta collX
|
|
jsr getunderft
|
|
lda tempblockx
|
|
cmp collX
|
|
beq :left
|
|
bcs :right
|
|
|
|
:left lda #-5
|
|
bne :10
|
|
:right lda #5
|
|
:10 clc
|
|
adc CharX
|
|
sta CharX
|
|
]rts rts
|
|
|
|
*-------------------------------
|
|
*
|
|
* Return cc if gate bars you, cs if clear
|
|
*
|
|
*-------------------------------
|
|
gatebarr?
|
|
lda (BlueSpec),y
|
|
lsr
|
|
lsr
|
|
clc
|
|
adc #gatemargin
|
|
cmp imheight
|
|
]rts rts
|
|
|
|
*-------------------------------
|
|
*
|
|
* Limited collision detection for enemies
|
|
* (backing into wall or gate while fighting)
|
|
*
|
|
*-------------------------------
|
|
ENEMYCOLL
|
|
lda AMtimer ;antimatter timer
|
|
bne ]rts
|
|
|
|
lda CharAction
|
|
cmp #1
|
|
bne ]rts ;must be on ground
|
|
lda CharLife
|
|
bpl ]rts ;& alive
|
|
lda CharSword
|
|
cmp #2
|
|
bcc ]rts ;& en garde
|
|
|
|
jsr getunderft
|
|
cmp #block
|
|
beq :collide
|
|
cmp #panelwif
|
|
beq :collide
|
|
cmp #gate
|
|
bne :1
|
|
jsr gatebarr?
|
|
bcc :collide
|
|
|
|
* If facing R, check block behind too
|
|
|
|
:1 lda CharFace
|
|
bmi ]rts
|
|
dec tempblockx
|
|
jsr rdblock1
|
|
cmp #panelwif
|
|
beq :collide
|
|
cmp #gate
|
|
bne ]rts
|
|
jsr gatebarr?
|
|
bcc :collide
|
|
]rts rts
|
|
|
|
* Char is en garde & trying to back into barrier
|
|
* Put him right at edge
|
|
|
|
:collide
|
|
jsr setupchar
|
|
jsr getedges ;get edges
|
|
|
|
lda tempscrn
|
|
ldx tempblockx
|
|
ldy tempblocky
|
|
jsr rdblock
|
|
sta tempobjid
|
|
jsr checkcoll
|
|
bcc ]rts
|
|
|
|
jsr DBarr2 ;get A = dist to barrier
|
|
tax
|
|
bpl ]rts
|
|
eor #$ff
|
|
clc
|
|
adc #1
|
|
jsr addcharx
|
|
sta CharX
|
|
|
|
lda #bumpengback
|
|
jsr jumpseq
|
|
jsr animchar ;get new frame
|
|
jmp rereadblocks
|
|
|
|
*-------------------------------
|
|
*
|
|
* Special version of DBarr for enemy collisions
|
|
*
|
|
* In: checkcoll results; tempobjid
|
|
* Must have called setupchar/getedges
|
|
* Out: A = distance to barrier (- if barr is behind char)
|
|
*
|
|
*-------------------------------
|
|
DBarr2
|
|
lda CharFace
|
|
bpl :checkL ;Note: reversed from DBarr
|
|
|
|
* Char's back facing R -- get distance to barrier
|
|
|
|
:checkR
|
|
lda tempobjid ;block ID
|
|
|
|
jsr cmpbarr ;return A = barrier code #
|
|
beq :clr
|
|
tay
|
|
|
|
lda blockedge
|
|
clc
|
|
adc BarL,y
|
|
sta ztemp ;left edge of barr
|
|
|
|
sec
|
|
sbc CDRightEj
|
|
rts ;If -, barr is behind char
|
|
|
|
:clr lda #-1
|
|
rts
|
|
|
|
* Char facing L -- get distance to barr
|
|
|
|
:checkL
|
|
lda tempobjid
|
|
|
|
jsr cmpbarr
|
|
beq :clr
|
|
tay
|
|
|
|
lda blockedge
|
|
clc
|
|
adc #13
|
|
sec
|
|
sbc BarR,y
|
|
sta ztemp ;R edge of barr
|
|
|
|
lda CDLeftEj
|
|
sec
|
|
sbc ztemp
|
|
|
|
]rts rts
|
|
|
|
*-------------------------------
|
|
lst
|
|
ds 1
|
|
usr $a9,16,$b00,*-org
|
|
lst off
|