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

1956 lines
27 KiB
ArmAsm
Executable File

* auto
DemoDisk = 0
org = $5400
tr on
lst off
*-------------------------------
*
* PRINCE OF PERSIA
* Copyright 1989 Jordan Mechner
*
*-------------------------------
org org
jmp AUTOCTRL
jmp CHECKSTRIKE
jmp CHECKSTAB
jmp AUTOPLAYBACK
jmp CUTCHECK
jmp CUTGUARD
jmp ADDGUARD
jmp CUT
*-------------------------------
lst
put eq
lst
put gameeq
lst
put seqdata
lst
put soundnames
lst
put movedata
lst off
dum $f0
ztemp ds 1
prob ds 1
]cutdir ds 1
ProgStart ds 2
dend
plus1 db -1,1
minus1 db 1,-1
* Thresholds for cut to new screen
TopCutEdgePl = ScrnTop+10
TopCutEdgeMi = ScrnTop-16
BotCutEdge = ScrnBottom+24
LeftCutEdge = ScrnLeft-4
RightCutEdge = ScrnRight+4
*-------------------------------
* Locations of special objects
flaskscrn = 24
flaskx = 3
flasky = 0
mirscrn = 4
mirx = 4
miry = 0
swordscrn = 15
swordx = 1
swordy = 0
mousetimer = 150 ;from topctrl
*-------------------------------
* Strike/block ranges
strikerange1 = 12
strikerange2 = 29
blockrange1 = 0
blockrange2 = 29 ;from TestStrike
*-------------------------------
* Other constants:
swordthres = 90
engardethres = 60
strikethres1 = strikerange1
strikethres2 = strikerange2
blockthres1 = 10
blockthres2 = blockrange2
tooclose = strikethres1
toofar = strikethres2+6 ;min dist at which you can advance safely
offguardthres = 8
jumpthres = 50
runthres = 40
blocktime = 4
*-------------------------------
*
* Fighter params (indexed by guardprog #)
*
* strikeprob = probability x255 of striking from ready posn
* restrikeprob = prob x 255 of restriking after blocking
* blockprob = prob x255 of blocking opponent's strike
* advprob = of advancing to within striking range
* refractimer = length of refractory period after being hit
*
* 0 1 2 3 4 5 6 7 8 9 10 11
strikeprob
db 075,100,075,075,075,050,100,220,000,060,040,060
restrikeprob
db 000,000,000,005,005,175,020,010,000,255,255,150
blockprob
db 000,150,150,200,200,255,200,250,000,255,255,255
impblockprob
db 000,075,075,100,100,145,100,250,000,145,255,175
advprob
db 255,200,200,200,255,255,200,000,000,255,100,100
refractimer
db 020,020,020,020,010,010,010,010,000,010,000,000
specialcolor
db 000,000,000,001,000,001,001,000,000,000,000,001
extrastrength
db 000,000,000,000,001,000,000,000,000,000,000,000
numprogs = 12
*-------------------------------
* Basic guard strength & uniform color (indexed by level #)
basicstrength
db 4,3,3,3,3,4,5 ;levels 0-6
db 4,4,5,5,5,4,6 ;levels 7-13
basiccolor
db 1,0,0,0,1,1,1 ;0 = blue, 1 = red
db 0,0,0,1,1,0,0
shadstrength = 4
*-------------------------------
*
* 10: kid (demo)
* 11: enemy (demo)
*
*-------------------------------
*
* Automatic enemy control routine
*
* In: Char vars reflect position in PRECEDING frame;
* Op vars reflect position in UPCOMING frame
* guardprog = program #
*
* (Exception: When used by kid fighting in demo, both
* Char & Op vars reflect preceding frame.)
*
*-------------------------------
]rts rts
AUTOCTRL
jsr DoRelease
lda CharID
beq :5 ;control kid in demo
lda justblocked
beq :jb0
dec justblocked
:jb0 lda gdtimer
beq :gt0
dec gdtimer
:gt0
lda refract ;refractory period after being hit
beq :2
dec refract
:2
lda CharID
cmp #24 ;mouse?
beq :6
cmp #4 ;skel?
beq :3
cmp #2 ;guard?
bcc :1
lda level
cmp #13 ;vizier?
beq :4
jmp GuardProg
:1 jmp ShadowProg
:3 jmp SkelProg
:4 jmp VizierProg
:5 jmp KidProg
:6 jmp MouseProg
*-------------------------------
* M O U S E
*-------------------------------
MouseProg
lda CharFace
cmp #86
beq ]rts
lda CharAction
beq :1 ;already stopped
lda CharX
cmp #166
bcs ]rts
lda #Mleave
jsr jumpseq
jmp animchar ;sets CharAction = 0
:1 lda CharX
cmp #200
bcc ]rts
jmp VanishChar
*-------------------------------
* S H A D O W M A N
*-------------------------------
do DemoDisk
ShadowProg
SkelProg
VizierProg
brk
else
ShadowProg
lda level
cmp #4
bne :0
jmp ShadLevel4
:0 cmp #5
bne :1
jmp ShadLevel5
:1 cmp #6
bne :2
jmp ShadLevel6
:2 cmp #12
bne :3
jmp FinalShad
:3
]rts rts
*-------------------------------
* Level-specific code for:
* Level 6 (plunge)
*-------------------------------
ShadLevel6
lda CharScrn
cmp #1
beq Shad6a
rts
* Level 6, screen 1
* When kid jumps chasm, step on plate
Shad6a
lda KidPosn
cmp #43
bne ]rts
lda KidX
cmp #$80
bcs ]rts
jsr DoPress
jmp DoFwd ;step fwd
*-------------------------------
* Level 5 (THIEF)
*-------------------------------
ShadLevel5
lda CharScrn
cmp #flaskscrn
beq Shad5
]rts rts
* Level 5, screen 24
* When gate opens, steal potion
Shad5
lda PlayCount
bne :1 ;continue playback
lda #flaskscrn
ldx #1 ;x
ldy #0 ;y
jsr rdblock ;gate
lda (BlueSpec),y
cmp #20
bcc ]rts
;begin playback
lda #0
sta PreRecPtr
:1 lda #ShadProg5
ldx #>ShadProg5
jsr AutoPlayback
lda CharX
cmp #15
bcs ]rts
jmp VanishChar
*-------------------------------
* Level 4 (mirror)
*-------------------------------
ShadLevel4
lda CharScrn
cmp #4
bne ]rts
lda CharX
cmp #80
bcc :gone
jmp DoFwd ;run o.s.
:gone jmp VanishChar
*-------------------------------
* Level 12 (final battle)
*-------------------------------
FinalShad
* Screen 15: Jump on top of kid
lda CharScrn
cmp #swordscrn
bne :cont
lda shadowaction
bne :cont ;already did it
lda OpX
cmp #150
bcs :hold ;hold shad at top until kid arrives
lda #1
sta shadowaction
bne :cont
:hold lda #shadpos12
ldx #>shadpos12
jmp csps
]rts rts
* Continue
:cont lda CharSword
cmp #2
bcs :fight
lda OpSword
cmp #2
bcs :hostile
lda offguard
bne :face
:hostile
lda EnemyAlert
cmp #2
bcc :2
jsr getopdist
cmp #swordthres
bcs :2 ;wait until kid gets close
lda CharPosn
cmp #15
bne ]rts
jmp DoEngarde ;draw on kid
* turn to face kid
:2 jsr getopdist
bpl ]rts
jmp DoBack
* Normal fighting
:fight
lda offguard
beq :1 ;has kid put up sword?
lda refract
bne :1 ;yes--wait a moment--
jmp DoDown ;--then lower your guard
:1 jmp EnGarde ;normal fighting
* Face to face--swords down
:face jsr getopdist
bmi :merge ;whammo!
lda EnemyAlert
cmp #2
bne :wait
lda OpPosn
cmp #3
bcc :wait
cmp #15
bcc :go
cmp #127
bcc :wait
cmp #133
bcs :wait
* If kid starts moving towards you, reciprocate
* (Accept startrun & stepfwd)
:go jmp DoFwd
* Kid & shadow reunite
:merge
lda #$ff ;white
sta lightcolor
lda #10
sta lightning
jsr boostmeter
lda #s_Rejoin
ldx #85
jsr cuesong
lda #42
sta mergetimer
lda #0
sta CharID
jsr SaveKid ;shadow turns into kid
jmp VanishChar
:wait
]rts rts
*-------------------------------
* S K E L E T O N
*-------------------------------
SkelProg
lda #2
sta CharSword
jmp GuardProg
*-------------------------------
* V I Z I E R
*-------------------------------
VizierProg
jmp GuardProg
fin ;DemoDisk
*-------------------------------
* K I D (in demo)
*-------------------------------
KidProg
jmp GuardProg
*-------------------------------
* G U A R D
*-------------------------------
GuardProg
lda CharSword
cmp #2 ;Are you already en garde?
bcc Alert ;no
jmp EnGarde ;yes
]rts rts
*-------------------------------
*
* Alert (not en garde)
*
*-------------------------------
Alert
lda KidLife
bpl ]rts ;kid's dead--relax
* If kid is behind you, turn to face him
jsr getopdist
ldx OpBlockY
cpx CharBlockY
bne :difflevel
cmp #-8 ;if kid is right on top of you, go en garde!
bcs :eng
:difflevel
ldx alertguard
beq :ok ;otherwise wait for a sound to alert you
ldx #0
stx alertguard
:alert
cmp #128
bcc :eng
cmp #-4
bcs :ok ;overlapping--stand still
jmp DoTurn ;turn around
* If you can see kid, go en garde
:ok cmp #128
bcs ]rts ;kid is behind you
:eng lda EnemyAlert
beq ]rts
lda level
cmp #13
bne :1 ;Vizier only: wait for music to finish
lda SongCue
bne ]rts
:1 jmp DoEngarde
]rts rts
*-------------------------------
*
* En garde
*
*-------------------------------
EnGarde
lda CharPosn
cmp #166
beq ]rts
cmp #150
bcc ]rts ;wait till you're ready
lda EnemyAlert
cmp #2
bcs :ea2
cmp #1 ;EnemyAlert = 1: Kid is in sight, but a
beq ]rts ;gap or barrier separates you--stay put
* Kid is out of sight (EnemyAlert = 0)
* If kid has "dropped out" of fight, follow him down
lda droppedout ;flag set by CHECKFLOOR
beq :1
jmp FollowKid
* else return to alert position
:1 lda CharID
cmp #4
beq ]rts ;(except skeleton)
jmp DoDropguard
* EnemyAlert = 2: Clear stretch of floor to player
* If kid is stunned, let him recover...
:ea2 jsr getopdist
bmi :norec
cmp #12
bcc :norec ;unless he's right on top of you
lda OpPosn
cmp #102
bcc :norec
cmp #118
bcs :norec
lda OpAction
cmp #5
beq ]rts
:norec
* Advance to closest safe distance
jsr getopdist
cmp #toofar
bcs :outofrange
ldx CharSword
cpx #2
bcc :offg
cmp #tooclose
bcc :tooclose
jmp InRange
:offg cmp #offguardthres
bcc :tooclose
jmp InRange
]rts rts
* Out of range
:outofrange
lda refract
bne ]rts
lda CharFace
cmp OpFace
beq :nojump ;chase him
lda OpPosn
cmp #7
bcc :norun
cmp #15
bcc :runwait
:norun
cmp #34
bcc :nojump
cmp #44
bcc :jumpwait ;If kid is running towards you, stay put
:nojump
jsr getinfront
jsr cmpspace ;Don't advance unless solid floor
beq :gap
jsr get2infront
jsr cmpspace
bne :solid
:gap jmp DoRetreat
:solid jmp DoAdvance
* Kid is trying to get past you--cut him down!
:jumpwait
jsr getopdist
cmp #jumpthres
bcs ]rts ;wait
jmp DoStrike
:runwait
jsr getopdist
cmp #runthres
bcs ]rts
:strike jmp DoStrike
* Too close to hit him
:tooclose
lda CharFace
cmp OpFace
beq :ret
jmp DoAdvance
:ret jmp DoRetreat
*-------------------------------
*
* Kid has "dropped out" of fight
* Advance until you run out of floor--
* then decide whether to jump down after him
*
*-------------------------------
FollowKid
lda OpAction
cmp #2
beq :hanging
cmp #6
beq :hanging ;wait--kid is hanging on ledge
jsr getinfront
sta ztemp
jsr cmpbarr
bne :stopped
lda ztemp
jsr cmpspace
beq :atedge
jmp DoAdvance
* At edge of floor. Follow kid down ONLY if:
* (1) it's a 1-story drop to solid floor
* (2) kid is still down there
:atedge
jsr getinfront
inc tempblocky
jsr rdblock1
sta ztemp ;is it safe?
cmp #spikes
beq :stopped
cmp #loose
beq :stopped
jsr cmpbarr
bne :stopped
lda ztemp
jsr cmpspace
beq :stopped
lda CharBlockY
clc
adc #1
cmp OpBlockY
bne :stopped ;kid's not down there
* It looks safe--follow him down
jmp DoAdvance
:stopped lda #0
sta droppedout
jmp DoRetreat ;so you can kill him if he climbs up
:hanging
]rts rts
*-------------------------------
*
* In range
*
*-------------------------------
InRange
lda OpSword ;is opponent armed & en garde?
cmp #2
beq :fight ;yes
* Opponent is unarmed or off guard--maul him!
lda refract
bne ]rts
jsr getopdist
cmp #strikethres2
bcc :1
jmp DoAdvance ;advance until within range...
:1 jmp DoStrike ;then strike
* Opponent is en garde--use strategy
:fight
jmp GenFight
*-------------------------------
*
* General Fighting Routine
*
* (Fighters are en garde, face to face, and too close to
* advance safely)
*
*-------------------------------
GenFight
jsr getopdist
cmp #blockthres1
bcc :outofrange
cmp #blockthres2
bcs :outofrange
jsr MaybeBlock ;block opponent's strike?
lda refract
bne ]rts
jsr getopdist
cmp #strikethres1
bcc :outofrange
cmp #strikethres2
bcs :outofrange
jmp MaybeStrike ;strike?
:outofrange
jmp MaybeAdvance ;advance to within strike range?
]rts rts
*-------------------------------
*
* Advance to within strike range?
* (Only consider it if gdtimer = 0)
*
*-------------------------------
MaybeAdvance
lda guardprog
beq :dumb ;Guard #0 is too dumb to care
lda gdtimer
bne ]rts
:dumb jsr rndp
cmp advprob,x
bcs ]rts
jmp DoAdvance
*-------------------------------
*
* Block opponent's strike?
*
*-------------------------------
MaybeBlock
lda OpPosn
cmp #152 ;guy4
beq :99
cmp #153 ;guy5
beq :99
cmp #162 ;guy22 (block to strike)
bne ]rts
:99 lda justblocked
bne :impaired
jsr rndp
cmp blockprob,x
bcc :block
]rts rts
:impaired
jsr rndp
cmp impblockprob,x
bcs ]rts
:block jmp DoBlock
*-------------------------------
*
* Strike?
*
*-------------------------------
MaybeStrike
ldx OpPosn
cpx #169
beq ]rts
cpx #151 ;opponent starting to strike?
beq ]rts ;yes--don't strike
ldx CharPosn
cpx #161 ;have I just blocked?
beq :restrike
cpx #150
beq :restrike ;yes--restrike?
jsr rndp
cmp strikeprob,x
bcs ]rts
jmp DoStrike
:restrike
jsr rndp
cmp restrikeprob,x
bcs ]rts
jmp DoStrike
*-------------------------------
DoRelease
lda #0
sta clrF
sta clrB
sta clrU
sta clrD
sta clrbtn
sta JSTKX
sta JSTKY
sta btn
rts
DoAdvance
DoFwd
lda #-1
sta clrF
sta JSTKX
rts
DoRetreat
DoBack
lda #-1
sta clrB
lda #1
sta JSTKX
rts
DoBlock
DoUp lda #-1
sta clrU
sta JSTKY
rts
DoTurn
DoDown lda #-1
sta clrD
lda #1
sta JSTKY
rts
DoStandup
lda #-1
sta clrU
jmp DoBack
DoDropguard
DoRunaway
lda #-1
sta clrD
jmp DoBack
DoEngarde
lda #-1
sta clrD
jmp DoFwd
DoStrike
DoPress
lda #-1
sta clrbtn
sta btn
rts
DoRelBtn
lda #0
sta btn
]rts rts
*-------------------------------
*
* R N D P
*
* Return X = guardprog, A = rnd #
*
*-------------------------------
rndp
ldx guardprog
jmp rnd
*-------------------------------
*
* C H E C K S T R I K E
*
* Check for sword contact
*
* Going in: Kid & Shad vars represent position in
* UPCOMING frame
*
* Out: Kid & Shad vars
* (Return Action = 99 if stabbed)
*
*-------------------------------
CHECKSTRIKE
lda KidPosn
beq ]rts
cmp #219
bcc :noclimb
cmp #229
bcc ]rts ;on staircase
:noclimb
jsr LoadShadwOp
jsr TestStrike
jsr SaveShadwOp
jsr LoadKidwOp
jsr TestStrike
jsr SaveKidwOp
]rts rts
*-------------------------------
TestStrike
lda CharSword
cmp #2 ;in fighting mode?
bne ]rts ;no
lda CharBlockY
cmp OpBlockY
bne ]rts
* Am I on a test (strike) frame?
lda CharPosn
cmp #153 ;guy5 (frame before full ext.)
beq :test
cmp #154 ;guy6 (full ext.)
bne ]rts
* I'm striking--is opponent blocking?
:test
jsr getopdist
cmp #blockrange1
bcc :nobloc
cmp #blockrange2
bcs :nobloc
lda OpPosn
cmp #161
beq :11
cmp #150 ;blocking?
bne :nobloc ;no
* Yes -- opponent blocks my strike
:1 lda #161
sta OpPosn ;change opp to "successful block"
:11 lda CharID
beq :12 ;am I a guard?
lda #blocktime ;yes--impair my blocking ability for a while
sta justblocked
:12 lda #blockedstrike
jsr jumpseq
jmp animchar
* Skewer opponent?
:nobloc
lda CharPosn
cmp #154 ;full ext
bne ]rts
jsr getopdist
ldx OpSword
cpx #2
bcs :ong
cmp #offguardthres
bcs :cont1
rts
:ong cmp #strikerange1
bcc ]rts
:cont1 cmp #strikerange2
bcs ]rts
lda #99 "stabbed"
sta OpAction
]rts rts
*-------------------------------
* C H E C K S T A B
*-------------------------------
CHECKSTAB
lda ShadAction
cmp #99
bne :1
lda KidAction
cmp #99
beq :doublestab
:2
jsr LoadShad
jsr StabChar
jsr SaveShad
jsr rndp
lda refractimer,x
sta refract
:1 lda KidAction
cmp #99
bne ]rts
jsr LoadKid
jsr StabChar
jmp SaveKid
* Both chars finish lunge simultaneously
:doublestab
lda #1
sta KidAction
bne :2 ;player wins a tie
]rts rts
*-------------------------------
* Change shadowman posn
* In: A-X = shadpos L-H
* Out: Char data
*-------------------------------
chgshadposn
sta ztemp
stx ztemp+1
ldy #6
:loop lda (ztemp),y
sta Char,y
dey
bpl :loop
ldy #7
lda (ztemp),y
jsr jumpseq
lda #1
sta CharID
lda #0
sta PlayCount ;zero playback counter
rts
* ... & save
csps jsr chgshadposn
lda #3
sta guardprog
lda #shadstrength
sta MaxOppStr
sta OppStrength
jmp SaveShad
*-------------------------------
* (Posn, X, Y, Face, BlockX, BlockY, Action)
* 0 1 2 3 4 5 6
shadpos6a hex 0f,51,76,00,00,01,00
db stand
shadpos5 hex 0f,37,37,00,ff,00,00
db stand ;just o.s. to L
shadpos12 hex 0f,51,f0,00,00,00,00
db stepfall
*-------------------------------
EndProg = -2
EndDemo = -1
Ctr = 0
Fwd = 1
Back = 2
Up = 3
Down = 4
Upfwd = 5
Press = 6
Release = 7
* Commands:
*
* -2 - end of programmed sequence
* -1 - end of demo
* 0 - center jstk & release btn
* 1 - jstk fwd
* 2 - jstk back
* 3 - jstk up
* 4 - jstk down
* 5 - jstk up & fwd
* 6 - press & hold btn
* 7 - release btn
*-------------------------------
*
* Prerecorded sequence format:
*
* 1. Frame # (1 byte)
* 2. Command (1 byte)
*
* 255 frames = approx. 25-30 seconds
*
*-------------------------------
* Level 5 (THIEF): Steal potion
ShadProg5
db 0,Ctr
db 1,Fwd
db 14,Ctr
db 18,Press
db 29,Release
db 45,Back
db 49,Fwd
db 255,EndProg
*-------------------------------
*
* Play back prerecorded movement sequence
*
* In: A-X = program start addr
* PlayCount = frame #
* PreRecPtr = pointer to next command
*
*-------------------------------
AUTOPLAYBACK
sta ProgStart
stx ProgStart+1
* Inc frame counter
lda PlayCount
cmp #254
bcs :rts
inc PlayCount
* Look up time of next command
ldy PreRecPtr
lda PlayCount
cmp (ProgStart),y
bcs :next
* Not there yet--repeat last command
dey
lda (ProgStart),y
jmp :ex
* We're there--
:next iny
lda (ProgStart),y ;command
iny
sty PreRecPtr
* Execute command
:ex cmp #-1
beq :enddemo
cmp #0
beq :ctr
cmp #1
beq :fwd
cmp #2
beq :back
cmp #3
beq :up
cmp #4
beq :down
cmp #5
beq :upfwd
cmp #6
beq :press
cmp #7
beq :release
:rts
]rts rts
* Commands
:ctr jmp DoRelease
:fwd jmp DoFwd
:back jmp DoBack
:up jmp DoUp
:down jmp DoDown
:upfwd jsr DoUp
jmp DoFwd
:press jmp DoPress
:release jmp DoRelBtn
:enddemo ; lda autopilot
; bne :endpb
jmp attractmode ;Game: end demo
:endpb ; lda #0 ;Editor: end playback
; sta autopilot
; rts
*-------------------------------
*
* C U T C H E C K
*
* Cut with kid
*
*-------------------------------
CUTCHECK
lda CUTTIMER
beq :ok
dec CUTTIMER
]rts rts
:ok
jsr LoadKid
jsr setupchar
jsr getedges
jsr cutchar ;cut with character
bmi ]rts ;no cut
sta ]cutdir
jsr SaveKid
lda CharScrn
sta cutscrn
lda ShadFace
cmp #86 ;is there a guard on old screen?
beq ]rts ;no
* What to do with guard? Two choices:
*
* (1) UPDATE -- leave guard behind on old screen (& update
* his coords so he'll still be there when we come back)
* (2) TRANSFER -- transfer guard to new screen (& delete his
* coords from old screen)
lda ShadLife
bpl :update ;dead guard on old screen--leave him behind
lda ShadSword
cmp #2
bne :update
* Is there a live guard on new screen?
ldx KidScrn
lda GdStartBlock-1,x
cmp #30
bcs :nonew ;no
lda GdStartSeqH-1,x
beq :update ;yes
* If guard is too far o.s., leave him behind
:nonew
lda ]cutdir
beq :left
cmp #1
beq :right
cmp #2
beq :up
:down lda ShadBlockY
cmp #3
bcs :transfer
bcc :update
:up lda ShadBlockY
bmi :transfer
bpl :update
:right lda ShadX
cmp #ScrnWidth+25 ;25 is safety factor
bcc :update
bcs :transfer
:left lda ShadX
cmp #256-ScrnWidth-25
bcs :update
* Take him with us
:transfer jmp transferguard
* Leave him behind
:update jmp updateguard
*-------------------------------
*
* Transfer guard from old screen to new screen
* (Also remove any dead guards from new scrn)
*
*-------------------------------
transferguard
lda #-1
ldx KidScrn ;new scrn
sta GdStartBlock-1,x
ldx ShadScrn ;old scrn
sta GdStartBlock-1,x
jsr LoadShad
lda ]cutdir
jsr cut
jmp SaveShad
]rts rts
*-------------------------------
*
* Leaving guard behind on old screen--
* update guard coords
*
*-------------------------------
updateguard
lda ShadFace
cmp #86
beq ]rts ;no guard
lda ShadID
cmp #1
beq ]rts ;not for shadman
cmp #24
beq ]rts ;or mouse
:gd
lda #0 ;arbitrary--ADDGUARD will reconstruct
sta tempblockx ;CharBlockX from CharX
lda ShadBlockY
sta tempblocky
jsr indexblock
tya
ldx ShadScrn
sta GdStartBlock-1,x
lda ShadX
sta GdStartX-1,x
lda ShadFace
sta GdStartFace-1,x
lda guardprog
sta GdStartProg-1,x
lda ShadLife
bpl :ok
lda #0
sta GdStartSeqH-1,x
beq :cont
:ok lda ShadSeq
sta GdStartSeqL-1,x
lda ShadSeq+1
sta GdStartSeqH-1,x
* and deactivate enemy char
:cont lda #86
sta ShadFace
lda #0
sta OppStrength
]rts rts
*-------------------------------
*
* If enemy has fallen to screen below, catch him before
* he wraps around to top of VisScrn
*
*-------------------------------
CUTGUARD
lda ShadFace
cmp #86
beq ]rts
lda ShadY
cmp #BotCutEdge
bcc ]rts
* If guard, remove him altogether
lda ShadID
cmp #4
beq :skel
cmp #1
beq :shad
]RemoveGd
jsr deadenemy ;music, etc.
ldx VisScrn
lda #-1
sta GdStartBlock-1,x
lda #86
sta ShadFace
lda #0
sta OppStrength
lda #-1
sta ChgOppStr
]rts rts
* If shad, vanish him
:shad lda ShadAction
cmp #4
bne ]rts
jsr LoadShad
jsr VanishChar
jmp SaveShad
* If skel, change scrn
:skel lda ShadScrn
jsr getdown
sta ShadScrn
cmp #3
bne ]RemoveGd
* Skel lands on scrn 3
lda #Splat
jsr addsound
lda #$85
sta ShadX
lda #1
sta ShadBlockY
lda #0
sta ShadFace
lda #-1
sta ShadLife
jmp updateguard
*-------------------------------
*
* C U T C H A R
*
* Is character passing o.s.? If so, cut with him to next scrn
*
* Change CharX,Y,BlockY,Scrn to reflect posn on new scrn
*
* Return A = direction of cut, -1 if no cut
*
*-------------------------------
cutchar
lda CharY
ldx CharAction
cpx #5
beq :notup
cpx #4
beq :notup ;In freefall--cut only down
cpx #3
beq :notup
* Cut up/down?
cmp #TopCutEdgePl
bcc :CUTUP
cmp #TopCutEdgeMi
bcs :CUTUP
:notup
cmp #BotCutEdge
bcs :CUTDOWN
* Cut left/right?
ldx CharPosn
cpx #135
bcc :nocu
cpx #150
bcc :nocut ;don't cut L/R on climbup
:nocu cpx #110
bcc :nosu
cpx #120
bcc :nocut ;or on standup
:nosu cpx #150
bcc :nost
cpx #163
bcc :nocut
cpx #166
bcc :nost
cpx #169
bcc :nocut ;or on strike/block
:nost lda CharAction
cmp #7
beq :nocut ;or on turning
ldx CharFace ;-1=left, 0=right
beq :faceR
;facing left
lda leftej
cmp #LeftCutEdge
bcc :CUTLEFT
beq :CUTLEFT
cmp #ScrnRight+1
bcs :CUTRIGHT
bcc :nocut
:faceR
lda CharScrn
ldx #9
ldy CharBlockY
jsr rdblock
cmp #panelwif
beq :nocutr
cmp #panelwof
beq :nocutr ;don't cut R if a panel blocks view
lda rightej
cmp #RightCutEdge
bcs :CUTRIGHT
:nocutr lda rightej
cmp #ScrnLeft-1
bcc :CUTLEFT
beq :CUTLEFT
:nocut lda #-1
rts
:CUTLEFT jsr mirrmusic
jsr milestone3
lda #0
bpl :cut
:CUTRIGHT jsr stealsword
jsr jaffmusic
lda #1
bpl :cut
:CUTUP lda #2
bpl :cut
* Level 6 ("Plunge"): Kid falls off screen 1 into next level
:CUTDOWN
jsr infinity
lda level
cmp #6
bne :no6
lda CharScrn
cmp #1
beq :nocut
:no6
lda #3
:cut pha
jsr cut
pla
]rts rts
*-------------------------------
* Level 12--fall off into infinity
*-------------------------------
infinity rts
*-------------------------------
* Passed Level 3 milestone?
*-------------------------------
milestone3
lda level
cmp #3
bne ]rts
lda #7 ;scrn to R of gate
]mcheck cmp CharScrn
bne ]rts
lda #1
sta milestone
lda MaxKidStr
sta origstrength
rts
*-------------------------------
* Level 12: Shadow steals sword
*-------------------------------
stealsword
lda level
cmp #12
bne ]rts
lda CharScrn
cmp #18 ;scrn below swordscrn
bne ]rts
lda #swordscrn
ldx #swordx
ldy #swordy
jsr rdblock
lda #floor
sta (BlueType),y
rts
*-------------------------------
* Level 13: Play Jaffar's Theme
*-------------------------------
jaffmusic
lda level
cmp #13
bne ]rts
lda exitopen
bne ]rts
lda CharScrn
cmp #3
bne ]rts
lda #s_Jaffar
ldx #25
jmp cuesong
*-------------------------------
* Level 4 ("Mirror"): Play danger theme for mirror
*-------------------------------
mirrmusic
lda exitopen
beq :no4
cmp #77
beq :no4
lda level
cmp #4
bne :no4
lda CharBlockY
cmp #miry
bne :no4
lda CharScrn
cmp #11 ;scrn to R of mirscrn
bne :no4
lda #s_Danger
ldx #50
jsr cuesong
lda #77
sta exitopen ;so we don't repeat theme
:no4
]rts rts
*-------------------------------
*
* C U T
*
* Move char from CharScrn to adjacent screen
*
* In: A = cut dir: 0 = left, 1 = right, 2 = up, 3 = down
*
*-------------------------------
CUT
cmp #3
beq Cdown
cmp #1
beq Cright
cmp #2
beq Cup
Cleft
lda CharScrn
jsr getleft ;get new screen #
sta CharScrn
lda #140
clc
adc CharX
sta CharX
ldx #1 ;new FromDir
rts
Cright
lda CharScrn
jsr getright
sta CharScrn
lda CharX
sec
sbc #140
sta CharX
ldx #0
rts
Cup
lda CharScrn
jsr getup
sta CharScrn
lda CharBlockY
clc
adc #3
sta CharBlockY
lda CharY
clc
adc #189
sta CharY
ldx #3
rts
Cdown
lda CharScrn
jsr getdown
sta CharScrn
lda CharBlockY
sec
sbc #3
sta CharBlockY
lda CharY
sec
sbc #189
sta CharY
ldx #2
]rts rts
*-------------------------------
*
* A D D G U A R D
*
* On cut to new screen--if guard is there, bring him to life
* Also handles hard-wired shadowman appearances
*
* In: VisScrn
*
*-------------------------------
ADDGUARD
lda #0
sta offguard
* Level 12
lda level
cmp #12
bne :not12
lda exitopen ;set when shadow drops
bne ]rts
lda mergetimer
bne :1 ;shadow has been reabsorbed
lda VisScrn
cmp #swordscrn
:1 bne ]rts
sta CharScrn
ldx #swordx
ldy #swordy
jsr rdblock
cmp #sword
beq ]rts ;sword is still there
lda #0
sta shadowaction
lda #1
sta exitopen
lda #shadpos12
ldx #>shadpos12
jmp csps
* Level 6 (Plunge)
:not12
lda level
cmp #6 ;plunge
bne :not6
lda VisScrn
sta CharScrn
cmp #1
bne AddNormalGd
lda exitopen
cmp #77
beq :norepeat
lda #s_Danger
ldx #50
jsr cuesong
lda #77
sta exitopen
:norepeat
lda #shadpos6a
ldx #>shadpos6a
jmp csps
* Level 5 (Thief)
:not6 lda level
cmp #5 ;thief
bne :not5
lda VisScrn
sta CharScrn
cmp #flaskscrn
bne AddNormalGd
ldx #flaskx
ldy #flasky
jsr rdblock
cmp #flask
bne ]rts ;potion is gone
lda #shadpos5
ldx #>shadpos5
jmp csps
]rts rts
:not5
*-------------------------------
AddNormalGd
ldx VisScrn
lda GdStartBlock-1,x
cmp #30
bcs ]rts ;no guard on this scrn
* Bring guard to life (or death)
stx CharScrn
jsr unindex ;return A = blockx, X = blocky
stx CharBlockY
lda FloorY+1,x
sta CharY
ldx VisScrn
lda GdStartX-1,x
sta CharX
jsr getblockxp
sta CharBlockX
ldx VisScrn
lda GdStartFace-1,x
sta CharFace
lda level
cmp #3
bne :3
lda #4 ;skel
bne :4
:3 lda #2 ;guard
:4 sta CharID
lda GdStartSeqH-1,x
bne :1 ;0 is code for fresh start
lda CharID
cmp #4
bne :5
lda #2
sta CharSword
lda #landengarde ;skel (ready)
bne :6
:5 lda #0
sta CharSword
lda #alertstand ;guard
:6 jsr jumpseq
jmp :2
:1 sta CharSeq+1
lda GdStartSeqL-1,x
sta CharSeq
:2 jsr animchar
lda CharPosn
cmp #185 ;killed
beq :dead
cmp #177 ;impaled
beq :dead
cmp #178 ;halved
beq :dead
* Live guard
lda #-1
sta CharLife
lda #0
sta alertguard
sta refract
sta justblocked
jsr getgdstrength
jmp :cont
* Dead guard
:dead lda #1
sta CharLife
lda #0
sta OppStrength
* Continue
:cont lda #0
sta CharXVel
sta CharYVel
lda #1
sta CharAction
ldx VisScrn
lda GdStartProg-1,x
cmp #numprogs
bcc :ok
lda #3 ;default
:ok sta guardprog
ldx level
lda basiccolor,x
ldx guardprog
eor specialcolor,x ;0 = normal, 1 = special
sta GuardColor ;0 = blue, 1 = red
jmp SaveShad ;save ShadVars
*-------------------------------
* Get guard fighting strength
*-------------------------------
getgdstrength
ldx level
lda basicstrength,x
ldx guardprog
clc
adc extrastrength,x
sta MaxOppStr
sta OppStrength
]rts rts
*-------------------------------
lst
ds 1
usr $a9,17,$800,*-org
lst off