Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
executable file 1353 lines (1132 sloc) 17.1 KB
* specialk
EditorDisk = 0
FinalDisk = 0 ;removes all cheat keys
DebugKeys = 0
tr on
lst off
org = $d900
*-------------------------------
*
* PRINCE OF PERSIA
* Copyright 1989 Jordan Mechner
*
*-------------------------------
org org
jmp KEYS
jmp CLRJSTK
jmp ZEROSOUND
jmp ADDSOUND
jmp FACEJSTK
jmp SAVESELECT
jmp LOADSELECT
jmp SAVEDESEL
jmp LOADDESEL
jmp INITINPUT
jmp DEMOKEYS
jmp LISTTORCHES
jmp BURN
jmp GETMINLEFT
jmp KEEPTIME
jmp SHORTENTIME
jmp CUESONG
jmp DoSaveGame
jmp LoadLevelX
jmp decstr
jmp DLOOP
jmp STROBE
*-------------------------------
lst
put eq
lst
put gameeq
lst
put soundnames
lst
put movedata
lst off
*-------------------------------
initAMtimer = 10 ;antimatter cheat key timer
dum locals
]temp ds 1
]count ds 2
dend
POPside1 = $a9
POPside2 = $ad
FirstSideB = 3
*-------------------------------
min = 725 ;# frames per "minute"
;(actual frame rate approx. 11 fps)
sec = min/60
t = 60 ;game time limit
*-------------------------------
* Key equates
CTRL = $60
ESC = $9b
DELETE = $7f
SHIFT = $20
* Player control keys
kleft = "j"
kdown = "k"
kright = "l"
kupleft = "u"
kup = "i"
kupright = "o"
* Special keys (legit)
kfreeze = ESC
krestart = "r"-CTRL
kabort = "a"-CTRL
ksound = "s"-CTRL
kmusic = "n"-CTRL
ksetkbd = "k"-CTRL
ksetjstk = "j"-CTRL
ksavegame = "g"-CTRL
kversion = "v"-CTRL
kreturn = "m"-CTRL ;editor disk only
kshowtime = " "
kflipx = "x"-CTRL
kflipy = "y"-CTRL
* Special keys (development)
knextlevel = ")"
kclean = "m"-CTRL
kscreendump = "@"
kreload = "c"-CTRL
kreboot = "z"-CTRL
kforceredraw = "f"-CTRL
kblackout = "B"
kspeedup = "]"
kslowdown = "["
kantimatter = "q"-CTRL
kupone = "e"-CTRL
kautoman = "A"
kincstr = "S"
kdecstr = "D"
kincmax = "F"
kzapgard = "Z"
kplayback = "p"-CTRL
kskip5 = "+"
ktimeback = "<"
ktimefwd = ">"
ktimeup = "M"
kerasegame = "*"
*-------------------------------
*
* K E Y S
*
* Detect & respond to keypresses
*
*-------------------------------
KEYS
lda SINGSTEP
beq KEYS1
freeze lda $C000
bpl freeze
cmp #kfreeze
beq :fradv
ldx #0
stx SINGSTEP
lda #0 ;ignore the keypress that breaks ESC
beq KEYS2
:fradv lda #1
sta SINGSTEP
sta $C010
sta keypress
]rts rts
KEYS1 lda $C000 ;ASCII value of last keypress
;(Hibit is keyboard strobe)
KEYS2 sta keypress
lda $C010 ;Hibit is any-key-down flag
;(Clears keyboard strobe)
sta keydown
jsr KREAD ;Keyboard control
lda keypress
bpl ]rts
do DebugKeys
ldx develment
beq :nogo ;GO codes work only in cheat mode
cmp #"0"
bcc :nogo
cmp #"9"+1
bcs :nogo
* We have a keypress 0-9
* Check if it follows a "GO" key sequence
lda #C_go0
ldx #>C_go0
jsr checkcode
bne :nogo0
lda #0 ;1st digit
:golevel clc
adc keypress
sec
sbc #"0" ;2-key value
cmp #4 ;only levels 4-12 accessible
bcc ]rts
cmp #13
bcs ]rts
sta NextLevel
jsr shortentime
]rts rts
:nogo0 lda #C_go1
ldx #>C_go1
jsr checkcode
bne :nogo
lda #10
bne :golevel
fin
* Normal key handling
:nogo lda keypress
jsr addkey ;Add key to kbd buffer
do FinalDisk
else
* Set development flag?
lda #C_devel
ldx #>C_devel
jsr checkcode
bne :1
lda #1
sta develment
jmp gtone
:1
fin
* Skip to next level?
lda #C_skip
ldx #>C_skip
jsr checkcode
bne :2
lda #3 ;up to level 4
ldx develment
beq :limit
lda #11 ;or level 12 in cheat mode
:limit cmp level
bcc :2
inc NextLevel
jsr shortentime
:2
fin
* Special keys
jsr LegitKeys
jsr DevelKeys
jsr TempDevel
]rts rts
*-------------------------------
*
* L E G I T K E Y S
*
*-------------------------------
LegitKeys
lda keypress
cmp #kfreeze
bne :1
jmp freeze
:1 cmp #krestart
bne :1a
jmp goattract ;in topctrl
:1a cmp #kabort
bne :1b
jmp restart
:1b do EditorDisk
cmp #kreturn
bne :2
jmp gobuild
fin
* Keyboard/joystick
:2 cmp #ksetkbd
bne :30
lda #0
sta joyon
]sk1 jmp gtone
:30 cmp #ksetjstk
bne :31
jsr setcenter
jmp ]sk1
:31 cmp #kflipx
bne :32
lda jhoriz
eor #1
sta jhoriz
bpl ]sk1
:32 cmp #kflipy
bne :3
lda jvert
eor #1
sta jvert
bpl ]sk1
* Sound on/off
:3 cmp #ksound
bne :16
]togsound
jsr zerosound
lda soundon
eor #1
sta soundon
bne ]sk1
rts
:16 cmp #kmusic
bne :26
lda musicon
eor #1
sta musicon
bne ]sk1
rts
:26 cmp #kversion
bne :17
jmp dispversion ;display version #
* Save/load game
:17 cmp #ksavegame
bne :18
lda level
sta SavLevel
jmp DoSaveGame
* Show time left
:18 cmp #kshowtime
bne :19
lda #3
sta timerequest
rts
:19
]rts rts
*-------------------------------
*
* D E V E L O P M E N T - O N L Y K E Y S
*
*-------------------------------
DevelKeys
lda develment ;development flag
beq ]rts
jsr checkcodes ;secret codes
lda keypress
cmp #kclean
bne :1
lda #0
sta develment
rts
:1
]rts rts
*-------------------------------
* Temp development keys
* (remove for final version)
*-------------------------------
TempDevel
do DebugKeys
lda develment ;development flag
beq ]rts
lda keypress
cmp #kforceredraw
bne :10
lda #2
sta redrawflg
lda #0
sta blackflag
rts
:10 cmp #kblackout
bne :9
lda blackflag
eor #$ff
sta blackflag
]rts rts
:9 cmp #kantimatter
bne :17
lda #initAMtimer
sta AMtimer
rts
:17 cmp #kincstr
bne :20
inc ChgKidStr
inc ChgOppStr
rts
:20 cmp #kincmax
bne :36
jmp boostmeter
:36 cmp #knextlevel
bne :28
inc NextLevel
rts
:28 cmp #kskip5
bne :30
lda level
clc
adc #5
sta NextLevel
rts
:30
* keys 0-9
lda keypress
cmp #"0"
bcc :non
cmp #"9"+1
bcs :non
sec
sbc #"0"
sta guardprog
]sk1 jmp gtone
* non-numeric keys
:non cmp #kreload
bne :8
jsr preload
lda #2
sta redrawflg
jsr reload
jmp postload
* speed up/slow down delay loop
:8 cmp #kspeedup
bne :13
lda SPEED
cmp #5
bcc :12
sec
sbc #4
sta SPEED
jmp ]sk1
:12 lda #1 ;fastest
sta SPEED
]rts rts
:13 cmp #kslowdown
bne :14
jsr gtone
lda SPEED
clc
adc #4
sta SPEED
rts
* Screen dump
:14 cmp #kscreendump
bne :15
lda PAGE
jmp screendump
:15 cmp #kupone
bne :19
lda KidY
sec
sbc #63 ;BlockHeight
sta KidY
dec KidBlockY
rts
:19 cmp #kdecstr
bne :21
dec ChgKidStr
]rts rts
:21 cmp #kautoman
bne :23
lda ManCtrl
eor #$ff
sta ManCtrl
rts
* Change levels
:23
cmp #kplayback
bne :24
lda #1
sta level
lda #2
sta NextLevel
rts
:24 cmp #ktimeback
bne :31
lda #-2
:chgtime clc
adc FrameCount+1
sta FrameCount+1
rts
:31 cmp #ktimefwd
bne :32
lda #2
bne :chgtime
:32 cmp #kerasegame
bne :33
lda #$ff
sta SavLevel
jmp DoSaveGame
:33 cmp #ktimeup
bne :34
lda #$ff
sta FrameCount+1
rts
:34
fin
]rts rts
*-------------------------------
* Temporarily change BBundID to reload code & data from side 1
postload
]sm lda #$a9
sta BBundID
rts
preload
lda BBundID
sta ]sm+1
lda #POPside1
sta BBundID
rts
*-------------------------------
*
* A D D K E Y
*
* In: A = key value
*
*-------------------------------
addkey
ldx keybufptr ;index to last key entry
inx
cpx #keybuflen
bcc :ok
ldx #0 ;wrap around
:ok stx keybufptr
sta keybuf,x
]rts rts
*-------------------------------
*
* C H E C K C O D E S
*
* Only work in devel mode
*
*-------------------------------
checkcodes
do FinalDisk
rts
else
lda #C_boost
ldx #>C_boost
jsr checkcode
bne :1
jsr boostmeter
lda MaxKidStr
sta origstrength
rts
:1 lda #C_restore
ldx #>C_restore
jsr checkcode
bne :2
jmp rechargemeter
:2 lda #C_zap2
ldx #>C_zap2
jsr checkcode
bne :3
;zap guard down to 0
lda #0
sec
sbc OppStrength
sta ChgOppStr
rts
:3 lda #C_zap1
ldx #>C_zap1
jsr checkcode
bne :4
;zap guard down to 1
lda #1
sec
sbc OppStrength
sta ChgOppStr
rts
:4 lda #C_tina
ldx #>C_tina
jsr checkcode
bmi :5
lda #14
sta NextLevel
jsr shortentime
rts
:5
]rts rts
fin
*-------------------------------
*
* Compare keybuf sequence against code sequence
*
* In: A-X = code sequence address lo-hi
* Return A = 0 if it matches, else ff
*
*-------------------------------
checkcode
sta :smod+1
stx :smod+2
ldx keybufptr ;last key entry
ldy #0 ;last char of code seq
:loop
:smod lda $ffff,y ;smod
beq ]rts ;0 = code seq delimiter
cmp keybuf,x
beq :match
cmp #"A" ;alpha?
bcc :fail
cmp #"Z"+1
bcs :fail
ora #$20 ;yes--try LC too
cmp keybuf,x
bne :fail
:match iny
dex
bpl :loop
ldx #keybuflen-1 ;wrap around
bpl :loop
:fail lda #$ff
]rts rts
*-------------------------------
*
* Key sequence codes
*
* Use all caps; LC will be accepted too
*
*-------------------------------
C_skip rev "SKIP"
db 0
do FinalDisk
else
C_devel rev "POP"
db 0
C_go0 rev "GO0"
db 0
C_go1 rev "GO1"
db 0
C_zap2 rev "ZAP"
db 0
C_boost rev "BOOST"
db 0
C_restore rev "R"
db 0
C_zap1 rev "Z"
db 0
C_tina rev "TINA"
db 0
fin
*-------------------------------
*
* K R E A D
*
* Keyboard player control
*
* (Register a keypress for as long as key is held down)
*
* Out: kbdX, kbdY
*
*-------------------------------
KREAD
lda #0
sta kbdX
sta kbdY
lda keypress
bmi :cont ;fresh press
ldx keydown
bpl ]rts ;No fresh press & no key down
ora #$80 ;stale press, key still down
:cont
cmp #kleft
beq :left
cmp #kleft-SHIFT
bne :1
:left lda #-1
:setx sta kbdX
rts
:1 cmp #kright
beq :right
cmp #kright-SHIFT
bne :2
:right lda #1
bne :setx
:2 cmp #kup
beq :up
cmp #kup-SHIFT
bne :3
:up lda #-1
:sety sta kbdY
rts
:3 cmp #kdown
beq :down
cmp #kdown-SHIFT
bne :4
:down lda #1
bne :sety
:4 cmp #kupleft
beq :ul
cmp #kupleft-SHIFT
bne :5
:ul lda #-1
sta kbdX
bne :sety
:5 cmp #kupright
beq :ur
cmp #kupright-SHIFT
bne :6
:ur lda #1
sta kbdX
lda #-1
sta kbdY
bne :sety
:6
]rts rts
*-------------------------------
FACEJSTK
lda #0
sec
sbc JSTKX
sta JSTKX ;reverse jstk x
ldx clrF
lda clrB
sta clrF
stx clrB ;& switch clrF/clrB
]rts rts
*-------------------------------
*
* Note: Jstk-push flags are saved as if back = R, fwd = L
* (i.e., char is facing L)
*
*-------------------------------
SAVESELECT
ldx #4
:loop lda clrF,x
sta clrSEL,x
dex
bpl :loop
rts
*-------------------------------
LOADSELECT
ldx #4
:loop lda clrSEL,x
sta clrF,x
dex
bpl :loop
rts
*-------------------------------
SAVEDESEL
ldx #4
:loop lda clrF,x
sta clrDESEL,x
dex
bpl :loop
rts
*-------------------------------
LOADDESEL
ldx #4
:loop lda clrDESEL,x
sta clrF,x
dex
bpl :loop
rts
*-------------------------------
INITINPUT
lda #0
ldx #4
:loop sta clrDESEL,x
sta clrSEL,x
dex
bpl :loop
]rts rts
*-------------------------------
*
* C L E A R J O Y S T I C K
*
* In/out: JSTKX, JSTKY, btn
* clrF-B-U-D-btn
*
* clr = 0: no press
* clr = 1: used press
* clr = -1: unused press
*
* Assume char is facing L
*
*-------------------------------
*
* Input consists of 5 "buttons": forward, back, up, down,
* and the real button. Each button has its own "clr" flag:
* clrF,B,U,D & btn.
*
* When ClrJstk sees a button down:
* If clr = 1 or -1... leave it alone
* If clr = 0... set clr = -1
*
* When ClrJstk sees a button up:
* If clr = 0 or -1... leave it alone
* If clr = 1... set clr = 0
*
* When GenCtrl acts on a button press, it sets clr = 1.
*
*-------------------------------
CLRJSTK
lda clrF
bmi :1 ;leave it set at -1
ldx JSTKX ;jstk fwd?
bmi :yesF ;yes--if clr = 0, set clr = -1
;no--set clr = 0
lda #0
beq :staF
:yesF cmp #0
bne :1
lda #-1
:staF sta clrF
*-------------------------------
:1 lda clrB
bmi :2
ldx JSTKX
cpx #1
beq :yesB
lda #0
beq :staB
:yesB cmp #0
bne :2
lda #-1
:staB sta clrB
*-------------------------------
:2 lda clrU
bmi :3
ldx JSTKY
bmi :yesU
lda #0
beq :staU
:yesU cmp #0
bne :3
lda #-1
:staU sta clrU
*-------------------------------
:3 lda clrD
bmi :4
ldx JSTKY
cpx #1
beq :yesD
lda #0
beq :staD
:yesD cmp #0
bne :4
lda #-1
:staD sta clrD
*-------------------------------
:4 lda clrbtn
bmi :5
ldx btn
bmi :yesbtn
lda #0
beq :stabtn
:yesbtn cmp #0
bne :5
lda #-1
:stabtn sta clrbtn
:5
]rts rts
*-------------------------------
*
* Z E R O S O U N D
*
* Zero sound table
*
*-------------------------------
ZEROSOUND
lda #0 ;# sounds in table
sta soundtable
rts
*-------------------------------
*
* A D D S O U N D
*
* Add sound to sound table
* (preserve registers)
*
* In: A = sound #
*
*-------------------------------
]temp1 ds 1
ADDSOUND
stx ]temp1
ldx soundtable
cpx #maxsfx
bcs :rts ;sound table full
inx
sta soundtable,x
stx soundtable ;# sounds in table
:rts ldx ]temp1
rts
*-------------------------------
*
* Demo keys (Call immediately after regular KEYS routine)
*
* All keys interrupt demo except ESC and CTRL-S
*
* Out: FF if interrupt, else 00
*
*-------------------------------
DEMOKEYS
lda level
bne :cont ;not in demo
lda $c061
ora $c062 ;button?
bmi :interrupt
lda keypress
bpl :cont
cmp #ESC
beq :cont
cmp #ksound
beq :cont
:interrupt
lda #$ff
rts
:cont lda #0
rts
*-------------------------------
*
* Special routine for use by BURN
*
* Make a list of visible torches--don't disturb trans list
*
*-------------------------------
maxtorches = 8
torchx ds maxtorches+1
torchy ds maxtorches+1
torchstate ds maxtorches+1
torchclip ds maxtorches+1
]numtorches = locals
torchcount ds 1
LISTTORCHES
lda #0
sta ]numtorches
lda VisScrn
jsr calcblue
ldy #29
:loop jsr :sub
ldx ]numtorches
cpx #maxtorches
bcs :max
dey
bpl :loop
ldx ]numtorches
:max lda #$ff
sta torchx,x
sta torchcount ;start BURNing with torch #0
]rts rts
:sub lda (BlueType),y
and #idmask
cmp #torch
bne ]rts
lda fredbuf+1,y
sta BOTCUT ;temp
tya
pha
jsr unindex
;Out: A = tempblockx, X = tempblocky
pha
txa
ldx ]numtorches
tay
lda BlockBot+1,y
sec
sbc #3
sta torchy,x
lda BOTCUT ;0 or non0
sta torchclip,x
pla
clc
adc #1
cmp #10
bcs ]rts
asl
asl
sta torchx,x
pla
tay
lda (BlueSpec),y
sta torchstate,x
inc ]numtorches
]rts rts
*-------------------------------
*
* B U R N
*
* Animate torch flames (for use while music is playing)
*
* NOTE--this routine bypasses normal graphics system
* and draws directly on the displayed page
* Leaves trans list, redraw buffers, etc. undisturbed
*
*-------------------------------
BURN
lda torchx
bmi ]rts ;no torches on this screen
ldx torchcount ;last torch burned
inx
lda torchx,x
bpl :ok ;torchx = $ff means "end of torch list"
ldx #0 ;start again at beginning of list
:ok stx torchcount
lda torchx,x
sta XCO
lda torchy,x
sta YCO
lda torchclip,x
sta BOTCUT
lda torchstate,x
jsr getflameframe
sta torchstate,x
tax
jsr setupflame
lda BOTCUT
bne :partial
:whole jmp fastlay ;<---DIRECT HIRES CALL
]rts rts
* If bottom portion of flame would overlap with someone's
* head, clip it (use LAY)
:partial
jsr initlay
lda #0
sta OFFSET
lda YCO
sec
sbc #4
sta BOTCUT
jmp lay ;<---DIRECT HIRES CALL
*-------------------------------
*
* Get # of minutes (or seconds) left
*
* In: FrameCount (0-65535)
* Out: MinLeft (BCD byte: $00-99) = # of minutes left
* SecLeft = # of seconds left (during final minute)
*
*-------------------------------
GETMINLEFT
lda #0
sta ]count
sta ]count+1
lda #min
sta :sm1+1
lda #>min
sta :sm2+1
jsr :sub ;get MinLeft
sty MinLeft
cpy #2
bcs ]rts
* Final minute only: count seconds
lda #59*min
sta ]count
lda #>59*min
sta ]count+1
lda #sec
sta :sm1+1
lda #>sec
sta :sm2+1
jsr :sub ;get SecLeft
sty SecLeft
rts
* Sub returns min/sec left
:sub ldy #$61 ;counter
:loop lda ]count+1
cmp FrameCount+1
bcc :1
bne ]rts
lda ]count
cmp FrameCount
bcs ]rts
:1
lda ]count
clc
:sm1 adc #min
sta ]count
lda ]count+1
:sm2 adc #>min
sta ]count+1
sed
tya
sec
sbc #1
cld
tay
bpl :loop
ldy #0
]rts rts
*-------------------------------
timetable
:0 dw t-60*min
dw t-55*min
dw t-50*min
dw t-45*min
dw t-40*min
dw t-35*min
dw t-30*min
dw t-25*min
dw t-20*min
dw t-15*min
:20 dw t-10*min
dw t-5*min
dw t-4*min
dw t-3*min
dw t-2*min
dw t-1*min+1
dw t*min+5 ;5 frames after t=0: game over
dw 65535
nummsg = *-timetable
*-------------------------------
*
* Keep track of time remaining
*
*-------------------------------
]rts rts
KEEPTIME
; lda autopilot
; bne ]rts
lda level
beq ]rts ;not in demo or during playback
lda KidLife
bpl ]rts ;clock stops when kid is dead
* Inc frame counter
inc FrameCount
bne :1
inc FrameCount+1
:1 bne :2
lda #$ff
sta FrameCount
sta FrameCount+1 ;don't wrap around
* time for next message yet?
:2 ldy NextTimeMsg ;0-2-4 for 1st, 2nd, 3rd msgs
cpy #nummsg
bcs ]rts ;no more msgs
lda FrameCount+1
cmp timetable+1,y
bcc ]rts ;not yet
lda FrameCount
cmp timetable,y
bcc ]rts
* Yes--is this a convenient time to show msg?
lda msgtimer
bne ]rts ;wait till other msgs are gone
* Yes--show msg (& inc NextTimeMsg)
inc NextTimeMsg
inc NextTimeMsg
lda #2
sta timerequest
]rts rts
*-------------------------------
*
* Shorten remaining time to 15 minutes
* (e.g., 1st time player cheats by skipping a level)
*
*-------------------------------
SHORTENTIME
ldy NextTimeMsg
cpy #20
bcs ]rts ;time is already short enough
ldy #18
sty NextTimeMsg
lda timetable,y
sta FrameCount
lda timetable+1,y
sta FrameCount+1
]rts rts
*-------------------------------
*
* Cue song
*
* In: A = song #
* X = # of cycles within which song must be played
*
*-------------------------------
CUESONG
sta SongCue
stx SongCount
rts
*-------------------------------
*
* Strobe keyboard
*
*-------------------------------
DLOOP
STROBE jsr keys ;Detect & respond to keypresses
jsr controller
]rts rts
*-------------------------------
lst
eof ds 1
usr $a9,19,$b00,*-org
lst off