mirror of
https://github.com/badvision/lawless-legends.git
synced 2024-09-30 18:54:47 +00:00
1500 lines
38 KiB
Plaintext
1500 lines
38 KiB
Plaintext
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Copyright (C) 2015 The 8-Bit Bunch. Licensed under the Apache License, Version 1.1
|
|
// (the "License"); you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at <http://www.apache.org/licenses/LICENSE-1.1>.
|
|
// Unless required by applicable law or agreed to in writing, software distributed under
|
|
// the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
|
// ANY KIND, either express or implied. See the License for the specific language
|
|
// governing permissions and limitations under the License.
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Handy constants.
|
|
const FALSE = 0
|
|
const TRUE = 1
|
|
const NULL = 0
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Fixed memory locations
|
|
const seed = $4E // Incremented continuously by keyboard read routine
|
|
const displayEngine = $6000 // main mem (raycaster and tile engine at same location)
|
|
const expandVec = $2000 // aux mem (only for raycaster)
|
|
const fontEngine = $E000 // main mem
|
|
const heapStart = $F000 // main mem
|
|
|
|
const heapSize = $800
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Resource numbers
|
|
const RES_NUM_RAYCASTER = 1
|
|
const RES_NUM_EXPAND_VEC = 2
|
|
const RES_NUM_FONT_ENGINE = 3
|
|
const RES_NUM_TILE_ENGINE = 4
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Memory manager definitions
|
|
|
|
// Resource types
|
|
const RES_TYPE_CODE = 1
|
|
const RES_TYPE_2D_MAP = 2
|
|
const RES_TYPE_3D_MAP = 3
|
|
const RES_TYPE_TILE = 4
|
|
const RES_TYPE_TEXTURE = 5
|
|
const RES_TYPE_SCREEN = 6
|
|
const RES_TYPE_FONT = 7
|
|
const RES_TYPE_MODULE = 8
|
|
const RES_TYPE_BYTECODE = 9
|
|
const RES_TYPE_FIXUP = 10
|
|
const RES_TYPE_PORTRAIT = 11
|
|
|
|
// Command codes
|
|
const RESET_MEMORY = $10
|
|
const REQUEST_MEMORY = $11
|
|
const LOCK_MEMORY = $12
|
|
const UNLOCK_MEMORY = $13
|
|
const SET_MEM_TARGET = $14
|
|
const START_LOAD = $15
|
|
const QUEUE_LOAD = $16
|
|
const FINISH_LOAD = $17
|
|
const FREE_MEMORY = $18
|
|
const CALC_FREE = $19
|
|
const DEBUG_MEM = $1A
|
|
const CHECK_MEM = $1B
|
|
const CHAIN_LOADER = $1E
|
|
const FATAL_ERROR = $1F
|
|
const HEAP_SET = $20
|
|
const HEAP_ADD_TYPE = $21
|
|
const HEAP_ALLOC = $22
|
|
const HEAP_INTERN = $23
|
|
const HEAP_COLLECT = $24
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Other constants
|
|
const callbacks = $300
|
|
|
|
include "playtype.plh"
|
|
//include "heaptest.plh"
|
|
|
|
word global // the global heap object, from which all live objects must be reachable
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Predefined functions, for circular calls or out-of-order calls
|
|
predef setWindow2, initCmds
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Global variables
|
|
byte mapNum
|
|
byte mapIs3D
|
|
word mapNameHash = 0
|
|
word totalMapWidth
|
|
word totalMapHeight
|
|
|
|
word skyNum = 9
|
|
word groundNum = 10
|
|
byte portraitNum = 1
|
|
|
|
word triggerOriginX, triggerOriginY
|
|
word triggerTbl
|
|
|
|
word cmdTbl[64]
|
|
byte frameLoaded = 0
|
|
byte textDrawn = FALSE
|
|
byte needRender = FALSE
|
|
|
|
// Queue setMap / teleport, since otherwise script might be replaced while executing
|
|
byte q_mapIs3D
|
|
byte q_mapNum = 0
|
|
word q_x
|
|
word q_y
|
|
byte q_dir
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Definitions used by assembly code
|
|
asm __defs
|
|
|
|
; Use hi-bit ASCII for Apple II
|
|
!convtab "../../include/hiBitAscii.ct"
|
|
|
|
; Headers
|
|
!source "../../include/global.i"
|
|
!source "../../include/plasma.i"
|
|
!source "../../include/mem.i"
|
|
!source "../../include/fontEngine.i"
|
|
|
|
; Optional debug printing support
|
|
DEBUG = 0
|
|
|
|
; General use
|
|
tmp = $2
|
|
pTmp = $4
|
|
|
|
; 16-bit random number seed - incremented by ROM kbd routine
|
|
seed = $4E
|
|
magic = $2227 ; there are 2048 magic values that work; this one caught my eye.
|
|
|
|
; NOTE ABOUT ABSOLUTE ADDRESSES
|
|
; You cannot use them: this code, including variable space, can be loaded *anywhere*.
|
|
; So don't declare any variables as !byte or !word here.
|
|
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// API to call rendering engine (same API for raycaster and tile engine)
|
|
asm initDisplay // params: mapNum, pMapData, x, y, dir
|
|
+asmPlasm 5
|
|
jmp $6000
|
|
end
|
|
asm flipToPage1 // no params
|
|
+asmPlasm 0
|
|
jmp $6003
|
|
end
|
|
asm getPos // params: @x, @y
|
|
+asmPlasm 2
|
|
jmp $6006
|
|
end
|
|
asm setPos // params: x, y
|
|
+asmPlasm 2
|
|
jmp $6009
|
|
end
|
|
asm getDir // no params; returns: dir (0-15)
|
|
+asmPlasm 0
|
|
jmp $600C
|
|
end
|
|
asm setDir // params: dir (0-15)
|
|
+asmPlasm 1
|
|
jmp $600F
|
|
end
|
|
asm advance // no params; return: 0 if same pos, 1 if new pos, 2 if new pos and scripted
|
|
+asmPlasm 0
|
|
jmp $6012
|
|
end
|
|
asm setColor // params: slot (0=sky/1=ground), color (0-17)
|
|
+asmPlasm 2
|
|
jmp $6015
|
|
end
|
|
asm render // no params
|
|
+asmPlasm 0
|
|
jmp $6018
|
|
end
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
asm pushAuxStr // params: none; ret: $200 (inbuf)
|
|
stx tmp ; save PLASMA's X reg eval stack index
|
|
tsx
|
|
lda $103,x ; get PLASMA's Y-reg value from its place in the stack
|
|
tay
|
|
|
|
; Create the following subroutine, used to copy chars from aux to main:
|
|
;0010- 8D 03 C0 STA $C003
|
|
;0013- B1 F4 LDA ($F4),Y
|
|
;0015- 8D 02 C0 STA $C002
|
|
;0018- 60 RTS
|
|
lda #$8D
|
|
sta $10
|
|
sta $15
|
|
ldx #2
|
|
stx $16
|
|
inx
|
|
stx $11
|
|
lda #$C0
|
|
sta $12
|
|
sta $17
|
|
lda #$B1
|
|
sta $13
|
|
lda #$F4
|
|
sta $14
|
|
lda #$60
|
|
sta $18
|
|
|
|
; Get string length and save it
|
|
iny ; advance to next code byte
|
|
bne +
|
|
inc $F5 ; next pg if necessary
|
|
tsx
|
|
inc $105,x ; also PLASMA's copy of the page pointer
|
|
+ jsr $10
|
|
sta $200
|
|
ldx #0
|
|
; Copy entire string
|
|
.lup cpx $200
|
|
beq ++
|
|
iny ; advance to next code byte
|
|
bne +
|
|
inc $F5 ; next pg if necessary
|
|
stx tmp+1
|
|
tsx
|
|
inc $105,x ; also PLASMA's copy of the page pointer
|
|
ldx tmp+1
|
|
+ jsr $10 ; now fetch the byte from aux mem
|
|
inx
|
|
sta $200,x ; and stuff it in the string / input buffer
|
|
bne .lup ; always taken
|
|
++ tsx
|
|
tya
|
|
sta $103,x ; modify PLASMA's Y reg so it picks up code execution just after the string
|
|
ldx tmp ; retrieve PLASMA's eval stack ptr
|
|
dex ; make room for ret value
|
|
lda #0
|
|
sta evalStkL,x ; return value lo (<$200)
|
|
lda #2
|
|
sta evalStkH,x ; and hi (>$200)
|
|
rts
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
asm blitPortrait // params: srcData, dstScreenPtr
|
|
+asmPlasm 2
|
|
|
|
; Save the dest pointer
|
|
sta pTmp
|
|
sty pTmp+1
|
|
|
|
; Save the source pointer
|
|
lda evalStkL+1,x
|
|
sta tmp
|
|
lda evalStkH+1,x
|
|
sta tmp+1
|
|
|
|
; Create the following subroutine, used to copy pixels from aux to main:
|
|
; 0010- 8D 03 C0 STA $C003
|
|
; 0013- B1 02 LDA ($02),Y
|
|
; 0015- 91 04 STA ($04),Y
|
|
; 0017- 88 DEY
|
|
; 0018- 10 F9 BPL $0013
|
|
; 001A- 8D 02 C0 STA $C002
|
|
; 001D- 60 RTS
|
|
lda #$8D
|
|
sta $10
|
|
sta $1A
|
|
ldx #2
|
|
stx $14
|
|
stx $1B
|
|
inx
|
|
stx $11
|
|
lda #$C0
|
|
sta $12
|
|
sta $1C
|
|
lda #$B1
|
|
sta $13
|
|
lda #$91
|
|
sta $15
|
|
inx
|
|
stx $16
|
|
lda #$88
|
|
sta $17
|
|
lda #$10
|
|
sta $18
|
|
lda #$F9
|
|
sta $19
|
|
lda #$60
|
|
sta $1D
|
|
|
|
; Outer copy loop
|
|
ldx #128 ; line count
|
|
.loop ldy #17 ; byte count minus 1
|
|
jsr $10 ; copy pixel bytes
|
|
|
|
; Advance to next row of data
|
|
lda tmp
|
|
clc
|
|
adc #18
|
|
sta tmp
|
|
bcc +
|
|
inc tmp+1
|
|
+
|
|
; Fun code to advance to the next hi-res line
|
|
ldy pTmp+1
|
|
iny
|
|
iny
|
|
iny
|
|
iny
|
|
cpy #$40
|
|
bcc .ok2
|
|
tya
|
|
sbc #$20 ; carry already set
|
|
tay
|
|
lda pTmp
|
|
eor #$80
|
|
bmi .ok
|
|
iny
|
|
cpy #$24
|
|
bcc .ok
|
|
ldy #$20
|
|
adc #$27 ; carry was set, so actually adding $28
|
|
.ok sta pTmp
|
|
.ok2 sty pTmp+1
|
|
|
|
; Loop until we've done all rows.
|
|
dex
|
|
bne .loop
|
|
|
|
rts
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Simply retrieve the X register. Used to double-check that we're not leaking PLASMA eval
|
|
// stack entries.
|
|
asm getXReg
|
|
+asmPlasm 0
|
|
txa
|
|
ldy #0
|
|
rts
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Calculate 16-bit hash of a string
|
|
asm hashString
|
|
+asmPlasm 1
|
|
sta pTmp
|
|
sty pTmp+1
|
|
ldy #0
|
|
sty tmp+1
|
|
lda (pTmp),y
|
|
tax
|
|
iny
|
|
- clc
|
|
adc (pTmp),y
|
|
bcc +
|
|
inc tmp+1
|
|
+ asl
|
|
rol tmp+1
|
|
bcc +
|
|
ora #1
|
|
+ asl
|
|
rol tmp+1
|
|
bcc +
|
|
ora #1
|
|
+ asl
|
|
rol tmp+1
|
|
bcc +
|
|
ora #1
|
|
+ iny
|
|
dex
|
|
bne -
|
|
ldy tmp+1
|
|
rts
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Print a string
|
|
asm puts
|
|
+asmPlasm 1
|
|
sta pTmp
|
|
sty pTmp+1
|
|
ldy #0
|
|
lda (pTmp),y
|
|
tax
|
|
iny
|
|
- lda (pTmp),y
|
|
ora #$80
|
|
jsr cout
|
|
iny
|
|
dex
|
|
bne -
|
|
rts
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Get a character from the keyboard
|
|
asm rdkey
|
|
+asmPlasm 0
|
|
jmp rdkey
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Print part of a string, until we hit the end or a '%' code. Return how far we got, or -1 for end.
|
|
asm partialPrintf
|
|
!zone {
|
|
+asmPlasm 2
|
|
lda evalStkL+1,x ; get string pointer
|
|
sta pTmp
|
|
lda evalStkH+1,x
|
|
sta pTmp+1
|
|
ldy #0
|
|
lda (pTmp),y ; get length byte
|
|
sec
|
|
sbc evalStkL,x ; minus offset
|
|
sta tmp ; to count of characters left to print
|
|
bcc .eos ; avoid overrunning
|
|
beq .eos
|
|
lda evalStkL,x ; get desired offset into string
|
|
tay
|
|
iny ; increment past length byte
|
|
- lda (pTmp),y
|
|
ora #$80
|
|
cmp #'%' ; stop if we hit % code
|
|
beq +
|
|
jsr cout
|
|
iny
|
|
dec tmp ; otherwise go until end of string
|
|
bne -
|
|
.eos ldy #$FF ; if we hit end of string, return -1
|
|
tya
|
|
rts
|
|
+ dey ; adjust back for length byte
|
|
tya ; that's the lo byte of return
|
|
ldy #0 ; hi byte of return is zero
|
|
rts
|
|
}
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Print a 16-bit hex value
|
|
asm printHex
|
|
+asmPlasm 1
|
|
tax
|
|
tya
|
|
jmp prntax
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Print a single character
|
|
asm printChar
|
|
+asmPlasm 1
|
|
ora #$80
|
|
jmp cout
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Print a carriage return
|
|
asm crout
|
|
+asmPlasm 0
|
|
jmp crout
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Ring the bell
|
|
asm beep
|
|
+asmPlasm 0
|
|
jmp bell
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Read a string from the keyboard, turn it into a PLASMA string and return a pointer to the string.
|
|
asm readStr
|
|
+asmPlasm 0
|
|
jsr getln1
|
|
txa
|
|
pha
|
|
beq +
|
|
- lda inbuf-1,x
|
|
and #$7F
|
|
sta inbuf,x
|
|
dex
|
|
bne -
|
|
+ pla
|
|
sta inbuf,x
|
|
lda #<inbuf
|
|
ldy #>inbuf
|
|
rts
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Send a command to the memory manager
|
|
// Params: cmd, wordParam
|
|
asm mmgr
|
|
+asmPlasm 2
|
|
lda evalStkL+1,x ; command code
|
|
pha
|
|
ldy evalStkH,x ; address (or other param)... hi byte in Y
|
|
lda evalStkL,x
|
|
tax ; ...lo byte in X
|
|
pla
|
|
jsr mainLoader ; ret value in X=lo/Y=hi
|
|
txa ; to A=lo/Y=hi for asmPlasm
|
|
rts
|
|
end
|
|
|
|
// Aux version of memory manager command
|
|
asm auxMmgr
|
|
+asmPlasm 2
|
|
lda evalStkL+1,x ; command code
|
|
pha
|
|
ldy evalStkH,x ; address (or other param)
|
|
lda evalStkL,x
|
|
tax
|
|
pla
|
|
jsr auxLoader ; ret value in X=lo/Y=hi
|
|
txa ; to A=lo/Y=hi for asmPlasm
|
|
rts
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Jump straight to the system monitor
|
|
// Params: None
|
|
asm goMon
|
|
jmp $FF69
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Execute a monitor breakpoint
|
|
// Params: None
|
|
asm brk
|
|
bit setText
|
|
bit page1
|
|
brk
|
|
end
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Set up the font engine
|
|
// Params: pFont
|
|
asm setFont
|
|
+asmPlasm 1
|
|
bit setLcRW+lcBank2
|
|
bit setLcRW+lcBank2
|
|
jmp SetFont
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Use the font engine to clear the current text window
|
|
asm setWindow
|
|
+asmPlasm 4
|
|
bit setLcRW+lcBank2
|
|
bit setLcRW+lcBank2
|
|
jmp SetWindow
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Use the font engine to clear the current text window
|
|
// Params: None
|
|
asm clearWindow
|
|
+asmPlasm 0
|
|
bit setLcRW+lcBank2
|
|
bit setLcRW+lcBank2
|
|
jmp ClearWindow
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Use the font engine to copy the current text window to hi-res page 2
|
|
// Params: None
|
|
asm copyWindow
|
|
+asmPlasm 0
|
|
bit setLcRW+lcBank2
|
|
bit setLcRW+lcBank2
|
|
jmp CopyWindow
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Display a character using the font engine.
|
|
// Params: ch
|
|
asm displayChar
|
|
+asmPlasm 1
|
|
bit setLcRW+lcBank2
|
|
bit setLcRW+lcBank2
|
|
jmp DisplayChar
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Display a string using the font engine.
|
|
// Params: pStr
|
|
asm displayStr
|
|
+asmPlasm 1
|
|
bit setLcRW+lcBank2
|
|
bit setLcRW+lcBank2
|
|
jmp DisplayStr
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Display a string using the font engine but not its parser.
|
|
// Params: pStr
|
|
asm rawDisplayStr
|
|
+asmPlasm 1
|
|
bit setLcRW+lcBank2
|
|
bit setLcRW+lcBank2
|
|
sta pTmp
|
|
sty pTmp+1
|
|
ldy #0
|
|
lda (pTmp),y
|
|
sta tmp
|
|
- cpy tmp
|
|
bcc +
|
|
rts
|
|
+ iny
|
|
lda (pTmp),y
|
|
ora #$80
|
|
cmp #"^"
|
|
bne +
|
|
iny
|
|
lda (pTmp),y
|
|
and #$1F
|
|
ora #$80
|
|
+ sty tmp+1
|
|
jsr DisplayChar
|
|
ldy tmp+1
|
|
bne -
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Random number generator
|
|
// Adapted from http://codebase64.org/doku.php?id=base:small_fast_16-bit_prng
|
|
asm rand16
|
|
+asmPlasm 0
|
|
|
|
lda seed
|
|
beq .lowZero ; $0000 and $8000 are special values to test for
|
|
|
|
; Do a normal shift
|
|
asl seed
|
|
lda seed+1
|
|
rol
|
|
bcc .noEor
|
|
|
|
.doEor:
|
|
; high byte is in .A
|
|
eor #>magic
|
|
sta seed+1
|
|
tay ; for asmPlasm, return hi byte in Y, lo byte in A
|
|
lda seed
|
|
eor #<magic
|
|
sta seed
|
|
rts
|
|
|
|
.lowZero:
|
|
lda seed+1
|
|
beq .doEor ; High byte is also zero, so apply the EOR
|
|
; For speed, you could store 'magic' into 'seed' directly
|
|
; instead of running the EORs
|
|
|
|
; wasn't zero, check for $8000
|
|
asl
|
|
beq .noEor ; if $00 is left after the shift, then it was $80
|
|
bcs .doEor ; else, do the EOR based on the carry bit as usual
|
|
|
|
.noEor:
|
|
sta seed+1
|
|
tay ; for asmPlasm, return hi byte in Y, lo byte in A
|
|
lda seed
|
|
rts
|
|
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// General methods
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Fatal error: print message and stop the system.
|
|
def fatal(msg)
|
|
mmgr(FATAL_ERROR, msg)
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Print a signed decimal word
|
|
def printDec(n)
|
|
word n0
|
|
if n < 0; printChar('-'); n = -n; fin
|
|
n0 = n
|
|
if n0 > 9999; printChar('0' + n/10000); n = n%10000; fin
|
|
if n0 > 999; printChar('0' + n/1000); n = n%1000; fin
|
|
if n0 > 99; printChar('0' + n/100); n = n%100; fin
|
|
if n0 > 9; printChar('0' + n/10); n = n%10; fin
|
|
printChar('0' + n)
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Print a formatted string a'la C printf, with up to four parameters.
|
|
def printf4(str, arg1, arg2, arg3, arg4)
|
|
word pos
|
|
word curArg
|
|
word p
|
|
pos = 0
|
|
curArg = @arg1
|
|
while TRUE
|
|
pos = partialPrintf(str, pos)
|
|
if pos < 0
|
|
break
|
|
fin
|
|
p = str + pos + 2
|
|
when ^p
|
|
is 'c'
|
|
printChar(*curArg); break
|
|
is 'd'
|
|
printDec(*curArg); break
|
|
is 's'
|
|
puts(*curArg); break
|
|
is 'x'
|
|
printHex(*curArg); break
|
|
is '%'
|
|
printChar('%'); break
|
|
otherwise
|
|
printHex(^p); fatal("Unknown % code")
|
|
wend
|
|
curArg = curArg + 2
|
|
pos = pos + 2
|
|
loop
|
|
end
|
|
|
|
def printf1(str, arg1); printf4(str, arg1, 0, 0, 0); end
|
|
def printf2(str, arg1, arg2); printf4(str, arg1, arg2, 0, 0); end
|
|
def printf3(str, arg1, arg2, arg3); printf4(str, arg1, arg2, arg3, 0); end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
def parseDec(str)
|
|
word n
|
|
word pend
|
|
word p
|
|
byte neg
|
|
neg = FALSE
|
|
n = 0
|
|
p = str + 1
|
|
pend = p + ^str
|
|
while p < pend
|
|
if p == (str+1) and ^p == '-'
|
|
neg = TRUE
|
|
elsif ^p >= '0' and ^p <= '9'
|
|
n = (n*10) + (^p - '0')
|
|
else
|
|
break
|
|
fin
|
|
p = p+1
|
|
loop
|
|
|
|
if neg; return -n; fin
|
|
return n
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
def parseDecWithDefault(str, default)
|
|
if ^str == 0
|
|
return default
|
|
fin
|
|
return parseDec(str)
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Get a keystroke and convert it to upper case
|
|
def getUpperKey()
|
|
byte key
|
|
word oldSeed
|
|
oldSeed = *seed // for now, make the seed stay consistent, for randomized heap testing
|
|
key = rdkey() & $7F
|
|
*seed = oldSeed
|
|
if key >= $60
|
|
key = key - $20
|
|
fin
|
|
return key
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Set the sky color (relevant to 3D display only)
|
|
def setSky(num)
|
|
skyNum = num
|
|
setColor(0, skyNum)
|
|
needRender = TRUE
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Switch to the next sky color (3D only)
|
|
def nextSky()
|
|
setSky((skyNum + 1) % 18)
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Set the ground color (relevant to 3D display only)
|
|
def setGround(num)
|
|
groundNum = num
|
|
setColor(1, groundNum)
|
|
needRender = TRUE
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Switch to the next ground color (3D only)
|
|
def nextGround()
|
|
setGround((groundNum + 1) % 18)
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Establish a keystroke -> command association in the command table
|
|
def initCmd(key, func)
|
|
if key >= $60
|
|
key = key - $20
|
|
fin
|
|
cmdTbl[key-$20] = func
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Load the Frame Image, and lock it.
|
|
def loadFrameImg()
|
|
byte img
|
|
img = mapIs3D+2
|
|
if frameLoaded <> img
|
|
if frameLoaded
|
|
mmgr(UNLOCK_MEMORY,$2000)
|
|
mmgr(FREE_MEMORY, $2000)
|
|
fin
|
|
mmgr(SET_MEM_TARGET, $2000)
|
|
mmgr(QUEUE_LOAD, img<<8 | RES_TYPE_SCREEN)
|
|
mmgr(LOCK_MEMORY, $2000)
|
|
frameLoaded = img
|
|
fin
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Window for the map name bar
|
|
def setWindow1()
|
|
setWindow(8, 18, 35, 119)
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Window for the large upper right bar
|
|
def setWindow2()
|
|
setWindow(24, 136, 154, 266)
|
|
displayChar('N'-$40) // Set normal mode - clear all special modes
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Window for the mid-size lower right bar
|
|
def setWindow3()
|
|
setWindow(144, 184, 154, 266)
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Window for the map area (used for clearing it)
|
|
def setMapWindow()
|
|
if mapIs3D
|
|
setWindow(24, 153, 14, 140)
|
|
else
|
|
setWindow(24, 169, 14, 140)
|
|
fin
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Show some faked-up data for player characters
|
|
def fakeChars()
|
|
setWindow3()
|
|
rawDisplayStr("^LName^T065Life^T090Gun^L\n")
|
|
rawDisplayStr("Black Bart^T06512^T0904\n")
|
|
rawDisplayStr("Wyld Bill^T0658^T0902\n")
|
|
rawDisplayStr("Lucy Lawls^T0659^T0906")
|
|
if mapIs3D; copyWindow(); fin
|
|
setWindow2()
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Load code and data, set up everything to display a 3D map
|
|
def initMap(x, y, dir)
|
|
word pFont
|
|
word pMap
|
|
|
|
// Set up the command table
|
|
initCmds()
|
|
|
|
// Reset memory (our module will stay since memory manager locked it upon load)
|
|
mmgr(RESET_MEMORY, 0)
|
|
|
|
// Load the font engine and its font
|
|
mmgr(SET_MEM_TARGET, fontEngine)
|
|
mmgr(QUEUE_LOAD, RES_NUM_FONT_ENGINE<<8 | RES_TYPE_CODE)
|
|
|
|
mmgr(SET_MEM_TARGET, $9000)
|
|
pFont = mmgr(QUEUE_LOAD, 1<<8 | RES_TYPE_FONT)
|
|
|
|
// Queue loading of the raycaster or tile engine and the map data
|
|
mmgr(SET_MEM_TARGET, displayEngine)
|
|
if mapIs3D
|
|
mmgr(QUEUE_LOAD, RES_NUM_RAYCASTER<<8 | RES_TYPE_CODE)
|
|
pMap = mmgr(QUEUE_LOAD, mapNum<<8 | RES_TYPE_3D_MAP)
|
|
auxMmgr(SET_MEM_TARGET, expandVec)
|
|
auxMmgr(QUEUE_LOAD, RES_NUM_EXPAND_VEC<<8 | RES_TYPE_CODE)
|
|
else
|
|
mmgr(QUEUE_LOAD, RES_NUM_TILE_ENGINE<<8 | RES_TYPE_CODE)
|
|
pMap = mmgr(QUEUE_LOAD, mapNum<<8 | RES_TYPE_2D_MAP)
|
|
fin
|
|
|
|
// Load everything that we just queued
|
|
mmgr(FINISH_LOAD, 1) // 1 = keep open
|
|
|
|
// Load the frame image (and lock it there)
|
|
loadFrameImg()
|
|
mmgr(FINISH_LOAD, 1) // 1 = keep open
|
|
|
|
// Tell the font engine where to find its font
|
|
setFont(pFont)
|
|
|
|
// Start up the display engine with map data and starting position. This will also load and
|
|
// init the script module, if any, which will end up calling us back at the setScriptInfo
|
|
triggerTbl = NULL
|
|
setWindow2()
|
|
initDisplay(mapNum, pMap, x, y, dir)
|
|
needRender = FALSE
|
|
|
|
// Display some fake character data.
|
|
fakeChars()
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Check for script(s) attached to the current location, and call them if there are any.
|
|
def checkScripts()
|
|
word x
|
|
word y
|
|
word p
|
|
word pNext
|
|
word script
|
|
|
|
if !triggerTbl; return; fin
|
|
setWindow2()
|
|
getPos(@x, @y)
|
|
x = x - triggerOriginX
|
|
y = y - triggerOriginY
|
|
p = triggerTbl
|
|
while TRUE
|
|
if ^p == $FF
|
|
return
|
|
fin
|
|
pNext = p + p->1
|
|
if ^p == y
|
|
p = p + 2
|
|
while p < pNext
|
|
if x == ^p
|
|
script = p=>1
|
|
script()
|
|
fin
|
|
p = p + 3
|
|
loop
|
|
fin
|
|
p = pNext
|
|
loop
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Advance one step forward (3D maps only)
|
|
def moveForward()
|
|
byte val
|
|
val = advance()
|
|
|
|
// If not blocked, render at the new position.
|
|
if val > 0
|
|
if !mapIs3D
|
|
render()
|
|
if textDrawn and mapIs3D; copyWindow(); fin
|
|
needRender = FALSE
|
|
else
|
|
needRender = TRUE
|
|
fin
|
|
fin
|
|
|
|
// If we're on a new map tile, clear text from script(s) on the old tile.
|
|
if val >= 2 and textDrawn
|
|
clearWindow()
|
|
if textDrawn and mapIs3D; copyWindow(); fin
|
|
textDrawn = FALSE
|
|
fin
|
|
|
|
// If there are script(s) on the new tile, run them.
|
|
if val == 3
|
|
checkScripts()
|
|
fin
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Adjust player's direction plus or minus n increments
|
|
def adjustDir(n)
|
|
setDir((getDir() + n) & 15)
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Move backward one step (3D mode)
|
|
def moveBackward()
|
|
adjustDir(8)
|
|
moveForward()
|
|
adjustDir(8)
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Turn left (3D mode)
|
|
def rotateLeft()
|
|
adjustDir(-1)
|
|
needRender = TRUE
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Rotate to the right (3D mode)
|
|
def rotateRight()
|
|
adjustDir(1)
|
|
needRender = TRUE
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Sidestep to the right (3D mode)
|
|
def strafeRight()
|
|
adjustDir(4)
|
|
moveForward()
|
|
adjustDir(-4)
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Sidestep to the left (3D mode)
|
|
def strafeLeft()
|
|
adjustDir(-4)
|
|
moveForward()
|
|
adjustDir(4)
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
def moveNorth()
|
|
word x, y
|
|
getPos(@x, @y)
|
|
if y > 4
|
|
setDir(0)
|
|
moveForward()
|
|
else
|
|
beep()
|
|
fin
|
|
end
|
|
|
|
def moveEast()
|
|
word x, y
|
|
getPos(@x, @y)
|
|
if x < totalMapWidth-5
|
|
setDir(4)
|
|
moveForward()
|
|
else
|
|
beep()
|
|
fin
|
|
end
|
|
|
|
def moveSouth()
|
|
word x, y
|
|
getPos(@x, @y)
|
|
if y < totalMapHeight-5
|
|
setDir(8)
|
|
moveForward()
|
|
else
|
|
beep()
|
|
fin
|
|
end
|
|
|
|
def moveWest()
|
|
word x, y
|
|
getPos(@x, @y)
|
|
if x > 4
|
|
setDir(12)
|
|
moveForward()
|
|
else
|
|
beep()
|
|
fin
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Switch to a new map (2D or 3D) and establish position on it
|
|
def setMap(is3D, num, x, y, dir)
|
|
if is3D == mapIs3D and num == mapNum
|
|
setPos(x, y)
|
|
setDir(dir)
|
|
needRender = TRUE
|
|
else
|
|
flipToPage1()
|
|
setWindow1(); clearWindow()
|
|
displayChar('Y'-$40) // center mode
|
|
displayStr("Traveling...")
|
|
mapNameHash = 0 // because we replaced the title text
|
|
displayChar('N'-$40) // normal mode
|
|
setMapWindow(); clearWindow()
|
|
setWindow2(); clearWindow()
|
|
mapIs3D = is3D
|
|
mapNum = num
|
|
initMap(x, y, dir)
|
|
fin
|
|
// Don't check scripts, because we often land on an "Exit to wilderness?" script
|
|
//NO:checkScripts()
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
def kbdTeleport()
|
|
byte d3, num
|
|
word x, y
|
|
byte dir
|
|
|
|
flipToPage1()
|
|
^$c053
|
|
if ^$25 < 23; ^$25 = 23; fin
|
|
getPos(@x, @y)
|
|
printf3("\nCurrent: X=%d Y=%d Facing=%d\n", x, y, getDir())
|
|
|
|
printf1("3D [%d]: ", mapIs3D)
|
|
d3 = parseDecWithDefault(readStr(), mapIs3D)
|
|
if d3 > 1; d3 = 1; fin
|
|
printf1("Map [%d]: ", mapNum)
|
|
num = parseDecWithDefault(readStr(), mapNum)
|
|
printf1("X [%d] : ", x)
|
|
x = parseDecWithDefault(readStr(), x)
|
|
printf1("Y [%d] : ", y)
|
|
y = parseDecWithDefault(readStr(), y)
|
|
printf1("Facing [%d]: ", dir)
|
|
dir = parseDecWithDefault(readStr(), dir)
|
|
|
|
^$c052
|
|
|
|
setMap(d3, num, x, y, dir)
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
def showPos()
|
|
word x, y
|
|
byte dir
|
|
|
|
flipToPage1()
|
|
^$c053
|
|
if ^$25 < 23; ^$25 = 23; fin
|
|
getPos(@x, @y)
|
|
printf2("\nX=%d Y=%d ", x, y)
|
|
if mapIs3D
|
|
printf3("Facing=%d Sky=%d Ground=%d", getDir(), skyNum, groundNum)
|
|
fin
|
|
puts("\nHit any key.\n")
|
|
getUpperKey()
|
|
^$c052
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
def queue_setMap(is3D, num, x, y, dir)
|
|
q_mapIs3D = is3D
|
|
q_mapNum = num
|
|
q_x = x
|
|
q_y = y
|
|
q_dir = dir
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
def queue_teleport(x, y, dir)
|
|
queue_setMap(mapIs3D, mapNum, x, y, dir)
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Get a key and dispatch it to a command. Then do it again, forever.
|
|
def kbdLoop()
|
|
word key, func
|
|
byte xreg, tmp
|
|
xreg = getXReg()
|
|
while TRUE
|
|
tmp = getXReg()
|
|
if tmp <> xreg
|
|
printf2("Error: x reg changed from %x to %x\n", xreg, tmp)
|
|
brk()
|
|
fin
|
|
key = getUpperKey()
|
|
key = key - $20
|
|
if key >= 0 and key < $40
|
|
func = cmdTbl[key]
|
|
if func; func(); fin
|
|
fin
|
|
if q_mapNum
|
|
setMap(q_mapIs3D, q_mapNum, q_x, q_y, q_dir)
|
|
q_mapNum = 0
|
|
fin
|
|
if needRender
|
|
render()
|
|
if textDrawn and mapIs3D; copyWindow(); fin
|
|
needRender = FALSE
|
|
fin
|
|
loop
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Set initial info for the scripts on this map: the name of the map, its trigger table, and the
|
|
// maximum extent (width, height). This is called by the init function for the scripts.
|
|
def setScriptInfo(mapName, trigTbl, wdt, hgt)
|
|
word newNameHash
|
|
|
|
// Grab the trigger table origins (used so the table can be more compact)
|
|
triggerOriginX = trigTbl=>0
|
|
triggerOriginY = trigTbl=>2
|
|
|
|
// Record the trigger table pointer
|
|
triggerTbl = trigTbl + 4
|
|
|
|
// Record the maximum width and height
|
|
totalMapWidth = wdt
|
|
totalMapHeight = hgt
|
|
|
|
// Display map name
|
|
newNameHash = hashString(mapName)
|
|
if newNameHash <> mapNameHash
|
|
setWindow1()
|
|
clearWindow()
|
|
displayChar('Y'-$40) // center mode
|
|
displayStr(mapName)
|
|
displayChar('N'-$40) // normal mode
|
|
if mapIs3D; copyWindow(); fin
|
|
mapNameHash = newNameHash
|
|
fin
|
|
|
|
// Back to the main text window.
|
|
setWindow2()
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Called by scripts to display a string. We set the flag noting that something has been
|
|
// displayed, then use an assembly routine to do the work.
|
|
def scriptDisplayStr(str)
|
|
textDrawn = TRUE
|
|
flipToPage1()
|
|
displayStr(str)
|
|
end
|
|
|
|
def scriptDisplayStrNL(str)
|
|
scriptDisplayStr(str)
|
|
displayStr("\n")
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Get a key, and don't return until it's Y or N (or lower-case of those). Returns 1 for Y.
|
|
def getYN()
|
|
byte key
|
|
while TRUE
|
|
key = getUpperKey()
|
|
if key == 'Y'
|
|
return 1
|
|
elsif key == 'N'
|
|
clearWindow()
|
|
if textDrawn and mapIs3D; clearWindow(); fin
|
|
textDrawn = FALSE
|
|
return 0
|
|
fin
|
|
beep()
|
|
loop
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Display a portrait drawing (typically called from scripts)
|
|
def setPortrait(portraitNum)
|
|
word srcData
|
|
byte cx, cy
|
|
|
|
flipToPage1()
|
|
|
|
// We're going to switch windows. Save the cursor pos in the text window.
|
|
//FIXME: This is from old font engine, need to change for new eng.
|
|
//cx = ^cursh
|
|
//cy = ^cursv
|
|
|
|
// Now clear out the map area
|
|
setMapWindow()
|
|
clearWindow()
|
|
|
|
// Restore the cursor position
|
|
setWindow2()
|
|
//FIXME: This is from old font engine, need to change for new eng.
|
|
//^cursh = cx
|
|
//^cursv = cy
|
|
|
|
// Load the portrait image and display it
|
|
srcData = auxMmgr(QUEUE_LOAD, portraitNum<<8 | RES_TYPE_PORTRAIT)
|
|
mmgr(FINISH_LOAD, 0) // 0 = close
|
|
|
|
if mapIs3D
|
|
blitPortrait(srcData, $2182) // start at 3rd text line
|
|
else
|
|
blitPortrait(srcData, $2202) // start at 4th text line
|
|
fin
|
|
|
|
needRender = FALSE // suppress display of map for this frame
|
|
|
|
auxMmgr(FREE_MEMORY, srcData)
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Clear the displayed portrait drawing
|
|
def clrPortrait()
|
|
render()
|
|
if textDrawn and mapIs3D; copyWindow(); fin
|
|
needRender = FALSE
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Test out portrait drawing
|
|
def testPortrait()
|
|
setPortrait(portraitNum)
|
|
portraitNum = portraitNum + 1
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Set up the command table for 3D mode
|
|
def initCmds()
|
|
|
|
// Clear the command table
|
|
byte i
|
|
for i = 0 to 63
|
|
cmdTbl[i] = 0
|
|
next
|
|
|
|
// Commands common to both 2D and 3D
|
|
initCmd('T', @kbdTeleport)
|
|
initCmd('P', @showPos)
|
|
initCmd('/', @testPortrait)
|
|
|
|
// Commands handled differently in 3D vs 2D
|
|
if mapIs3D
|
|
initCmd('W', @moveForward)
|
|
initCmd('A', @rotateLeft)
|
|
initCmd('D', @rotateRight)
|
|
initCmd('S', @moveBackward)
|
|
initCmd('X', @moveBackward)
|
|
initCmd('Z', @strafeLeft)
|
|
initCmd('C', @strafeRight)
|
|
|
|
initCmd('I', @moveForward)
|
|
initCmd('J', @rotateLeft)
|
|
initCmd('L', @rotateRight)
|
|
initCmd('K', @moveBackward)
|
|
initCmd(',', @moveBackward)
|
|
initCmd('M', @strafeLeft)
|
|
initCmd('.', @strafeRight)
|
|
|
|
initCmd('Y', @nextSky)
|
|
initCmd('G', @nextGround)
|
|
else
|
|
initCmd('W', @moveNorth)
|
|
initCmd('D', @moveEast)
|
|
initCmd('S', @moveSouth)
|
|
initCmd('X', @moveSouth)
|
|
initCmd('A', @moveWest)
|
|
|
|
initCmd('I', @moveNorth)
|
|
initCmd('J', @moveWest)
|
|
initCmd('L', @moveEast)
|
|
initCmd('K', @moveSouth)
|
|
initCmd(',', @moveSouth)
|
|
fin
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Load and display the title screen.
|
|
def loadTitle()
|
|
puts("Loading Lawless Legends.\n")
|
|
|
|
// Load the title screen
|
|
mmgr(UNLOCK_MEMORY, $2000)
|
|
mmgr(FREE_MEMORY, $2000)
|
|
mmgr(SET_MEM_TARGET, $2000)
|
|
mmgr(QUEUE_LOAD, 1<<8 | RES_TYPE_SCREEN) // title screen is fixed at #1
|
|
mmgr(LOCK_MEMORY, $2000)
|
|
mmgr(FINISH_LOAD, 1) // 1 = keep open
|
|
frameLoaded = 1
|
|
^$C050 // graphics
|
|
^$C057 // hi-res
|
|
^$C054 // page 1
|
|
^$C052 // full screen
|
|
// Hack for real (not emulated) IIc: sometimes displays only lo-bit graphics
|
|
// unless we do this. *HUGE* thanks to Brendan Robert for the fix!
|
|
^$C07E=0 // disable double-hi-res
|
|
^$C05F // disable double-hi-res
|
|
|
|
// Wait for a key.
|
|
getUpperKey()
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Set vectors so that scripts in PLASMA can call back to do things with this engine.
|
|
def setCallbacks()
|
|
|
|
// $300
|
|
callbacks.0 = $4c
|
|
callbacks:1 = @setScriptInfo
|
|
|
|
// $303
|
|
callbacks.3 = $4c
|
|
callbacks:4 = @pushAuxStr
|
|
|
|
// $306
|
|
callbacks.6 = $4c
|
|
callbacks:7 = @scriptDisplayStr
|
|
|
|
// $309
|
|
callbacks.9 = $4c
|
|
callbacks:10 = @scriptDisplayStrNL
|
|
|
|
// $30C
|
|
callbacks.12 = $4c
|
|
callbacks:13 = @getYN
|
|
|
|
// $30F
|
|
callbacks.15 = $4c
|
|
callbacks:16 = @queue_setMap
|
|
|
|
// $312
|
|
callbacks.18 = $4c
|
|
callbacks:19 = @setSky
|
|
|
|
// $315
|
|
callbacks.21 = $4c
|
|
callbacks:22 = @setGround
|
|
|
|
// $318
|
|
callbacks.24 = $4c
|
|
callbacks:25 = @queue_teleport
|
|
|
|
// $31B
|
|
callbacks.27 = $4c
|
|
callbacks:28 = @setPortrait
|
|
|
|
// $31E
|
|
callbacks.30 = $4c
|
|
callbacks:31 = @clrPortrait
|
|
|
|
// $321
|
|
callbacks.33 = $4c
|
|
callbacks:34 = @moveBackward
|
|
|
|
// $324
|
|
callbacks.36 = $4c
|
|
callbacks:37 = @getUpperKey
|
|
|
|
// $327
|
|
callbacks.39 = $4c
|
|
callbacks:40 = @clearWindow
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Call like this: addToList(player + items, itemToAdd)
|
|
def addToList(addTo, p)
|
|
p=>p_nextObj = *addTo
|
|
*addTo = p
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Call like this: removeFromList(player + items, itemToRemove)
|
|
def removeFromList(pList, toRemove)
|
|
word p
|
|
|
|
p = *pList
|
|
while p and p <> toRemove
|
|
pList = p + p_nextObj
|
|
p = *pList
|
|
loop
|
|
|
|
if p
|
|
*pList = p=>p_nextObj
|
|
p=>p_nextObj = NULL
|
|
else
|
|
fatal("InvalUnlink")
|
|
fin
|
|
end
|
|
|
|
include "playtype.pla"
|
|
//include "heaptest.pla"
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Set up the small-object heap
|
|
def initHeap()
|
|
mmgr(SET_MEM_TARGET, heapStart)
|
|
mmgr(REQUEST_MEMORY, heapSize)
|
|
mmgr(LOCK_MEMORY, heapStart)
|
|
mmgr(HEAP_SET, heapStart)
|
|
addTypes()
|
|
end
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Main code.
|
|
//
|
|
initHeap()
|
|
addToList(global + p_players, new_Player_Hue_Hauser())
|
|
addToList(global + p_enemyGroups, new_EnemyGroup_Dirt_Bags())
|
|
loadTitle()
|
|
setCallbacks()
|
|
// Start map/loc per Seth. Need to have this in a script in the futurecheckScripts()
|
|
mapIs3D = 0
|
|
mapNum = 1
|
|
initMap(6, 123, 12)
|
|
kbdLoop()
|
|
|
|
done |