view dod.s @ 31:5a661416e322

Decoded scroll display routine. Decoded the routine used for displaying scrolls. Also decoded some variables related to players, objects, and creatures.
author William Astle <lost@l-w.ca>
date Fri, 26 Dec 2014 18:55:05 -0700
parents ce4bf9bde1f0
children 8a94218c2a4c
line wrap: on
line source
; Dungeons of Daggorath
;
; Original game copyright © 1982 by Dyna Micro
;
; The code contained in this file is not the original source code to Dungeons of Daggorath. It was
; constructed by William Astle in 2013 by disassembling the Dungeons of Daggorath ROM.
;
; According to a web page retrieved from http://frodpod.tripod.com/lisence.html on May 24, 2013,
; this endeavour is permitted. In case the web page becomes unavailable, and because it contains what
; I believe to be important credit information, I have reproduced the text of it below:
;
;***********************************************************************************************************
;* Grant of license to reproduce Dungeons of Daggorath
;*
;* My name is Douglas J. Morgan.  I was the president of DynaMicro, Inc. (since dissolved), the company
;* which conceived, created and wrote Dungeons of Daggorath, a best selling Radio Shack Color Computer
;* adventure game. 
;*
;* I have examined the contract I signed with Radio Shack for their license of the game.  The contract
;* provides that Radio Shack shall have an exclusive license to manufacture and produce the game, but
;* that said exclusive license shall revert to a non-exclusive license should Radio Shack cease to
;* produce and sell the game.  To the best of my knowledge, they have not produced the game for many
;* years.  Thus, it is my belief that the right to grant a license for the game has reverted to me. 
;*
;* I hereby grant a non-exclusive permanent world-wide license to any and all Color Computer site
;* administrators, emulator developers, programmers or any other person or persons who wish to develop,
;* produce, duplicate, emulate, or distribute the game on the sole condition that they exercise every
;* effort to preserve the game insofar as possible in its original and unaltered form. 
;*
;* The game was a labor of love.  Additional credits to Phillip C. Landmeier - who was my partner and
;* who originally conceived the vision of the game and was responsible for the (then) state of the art
;* sounds and realism, to April Landmeier, his wife - the artist who drew all the creatures as well as
;* all the artwork for the manual and game cover, and to Keith Kiyohara - a gifted programmer who helped
;* write the original game and then contributed greatly to compressing a 16K game into 8K so that it
;* could be carried and produced by Radio Shack.
;*
;* The game did very well for us.  I give it to the world with thanks to all who bought it, played it
;* or enjoyed it. 
;*
;* There is one existing copy of the original source code.  Anyone willing to pay for the copying of
;* the listing (at Kinko's) and shipment to them, who intends to use it to enhance or improve the emulator
;* versions of the game is welcome to it. 
;*
;* Verification of this license grant or requests for the listing can be made by contacting Louis Jordan,
;* Thank you.
;***********************************************************************************************************
;
; Louis Jordan's email address is given as louisgjordan@yahoo.com in a hyperlink in the above statement.
;
; It is my belief that this endeavor to disassemble Dungeons of Daggorath is in compliance with the above
; license grant. I have done so for my own amusement and for the challenge. I have also done so because
; I failed to elicit a response from Louis Jordan as described in the license grant. I am not surprised
; that I received no reply given that the page above was put online during or prior to 2006.

; some utility macros
dod		macro noexpand
		swi
		fcb \1
		ifeq \1-$1B
		fcb \2
		endc
		endm

skip2		macro noexpand
		fcb $8c
		endm


; macros for color basic ROM calls
romcall		macro noexpand
		swi2
		fcb \1
		endm

; draw a graphic with graphic data at (X)
drawgraphic	macro noexpand
		dod S01
		endm
; render a packed string (immediate data)
renderstrimmp	macro noexpand
		dod S02
		endm
; render a packed string from (X)
renderstr	macro noexpand
		dod S03
		endm
; render character in A
renderchar	macro noexpand
		dod S04
		endm
; decode a 5 bit packed string from (X) to stringbuf
decodestrsb	macro noexpand
		dod S05
		endm
; decode a 5 bit packed string from (X) to (U)
decodestr	macro noexpand
		dod S06
		endm
; generate an 8 bit random number in A
getrandom	macro noexpand
		dod S07
		endm
; clear graphics screen currently visible; return parameter pointer in U
cleargfx1	macro noexpand
		dod S08
		endm
; clear graphics screen currently used for drawing; return parameter pointer in U
cleargfx2	macro noexpand
		dod S09
		endm
; clear the status line
clearstatus	macro noexpand
		dod S0A
		endm
; clear the command entry area
clearcommand	macro noexpand
		dod S0B
		endm
; update the inventory on the status line
updatestatus	macro noexpand
		dod S0D
		endm
; do a newline, show prompt, and cursor
showprompt	macro noexpand
		dod S0F
		endm

; do a delay for about 1.33 seconds
delay		macro noexpand
		dod S10
		endm

; set a block of memory (from X to U-1) to $00
clearblock	macro noexpand
		dod S11
		endm
; set a block of memory (from X to U-1) to $ff
setblock	macro noexpand
		dod S12
		endm
; fade in the image at (X) with sound effects at scale 1.0, clear status and command area
fadeinclrst	macro noexpand
		dod S13
		endm
; fade in the image at (X) with sound effects at scale 1.0, clear command area
fadein		macro noexpand
		dod S14
		endm
; fade out image at (X) with sound effects, clear command area
fadeout		macro noexpand
		dod S15
		endm
; display the PREPARE! screen
showprepare	macro noexpand
		dod S16
		endm
; create object of type in A
createobject	macro noexpand
		dod S17
		endm
; set object specs (object pointer in U)
setobjectspecs	macro noexpand
		dod S18
		endm
; play a sound number from immediate data at full volume
playsoundimm	macro noexpand
		dod S1B,\1
		endm
; play sound specified in A, volume in B
playsound	macro noexpand
		dod S1C
		endm

; ROM call numbers
POLCAT		equ 0
CSRDON		equ 4
BLKIN		equ 6
BLKOUT		equ 8
WRTLDR		equ 12

ROMTAB		equ $A000

BLKTYP		equ $7c
BLKLEN		equ $7d
CBUFAD		equ $7e

RESVEC		equ $A027

; SWI routines
S00		equ 0
S01		equ 1
S02		equ 2
S03		equ 3
S04		equ 4
S05		equ 5
S06		equ 6
S07		equ 7
S08		equ 8
S09		equ 9
S0A		equ $0A
S0B		equ $0B
S0C		equ $0C
S0D		equ $0D
S0E		equ $0E
S0F		equ $0F
S10		equ $10
S11		equ $11
S12		equ $12
S13		equ $13
S14		equ $14
S15		equ $15
S16		equ $16
S17		equ $17
S18		equ $18
S19		equ $19
S1A		equ $1A
S1B		equ $1B
S1C		equ $1C

PIA0		equ $ff00
PIA1		equ $ff20
SAMREG		equ $ffc0
TOPRAM		equ $4000
STACK		equ $1000

; the direct page
		org $200
zero		rmb 2				; initialized to $0000
V202		rmb 1
allones		rmb 2				; initialized to $ffff
V205		rmb 1
V206		rmb 1
V207		rmb 1
V208		rmb 1
screenvis	rmb 2				; pointer to the parameter block of the currently shown screen
screendraw	rmb 2				; pointer to the parameter block of the screen to use for drawing
V20D		rmb 2				; pointer to demo game command sequence
objectfree	rmb 2				; pointer to next free object data slot
V211		rmb 2
playerloc	rmb 1				; current player position in maze (Y)
V214		rmb 1				; current player position in maze (X)
carryweight	rmb 2
powerlevel	rmb 2				; player power
V219		rmb 1
V21A		rmb 1
V21B		rmb 1
V21C		rmb 1
lefthand	rmb 2				; pointer to object carried in left hand
righthand	rmb 2				; pointer to object carried in right hand
damagelevel	rmb 2				; player damage level
V223		rmb 1
curtorch	rmb 2				; pointer to currently mounted torch
baselight	rmb 2				; base light level in dungeon
nokeyboard	rmb 1				; set if no keyboard operations should be done during IRQ
backpack	rmb 2				; pointer to first item in backpack
creaturefreeze	rmb 1				; nonzero means creatures are frozen
levbgmask	rmb 1				; the current level background colour mask
lightlevel	rmb 1				; the current light level, $ff means dark
lightcount	rmb 1				; counter between pixels when drawing lines
ybeg		rmb 2				; start Y coord for line drawing
xbeg		rmb 2				; start X coord for line drawing
yend		rmb 2				; end Y coord for line drawing
xend		rmb 2				; end X coord for line drawing
xcur		rmb 3				; current X coordinate when drawing line
ycur		rmb 3				; current Y coordinate when drawing line
xpstep		rmb 3				; difference in X coordinate between pixels when drawing line
ypstep		rmb 3				; difference in Y coordinate between pixels when drawing line
pixelcount	rmb 2				; number of pixels to draw in a line
xbstep		rmb 1				; the offset to add to pointer when moving to new byte (line drawing)
xystep		rmb 1				; the offset to add to pointer when moving to new row (line drawing)
drawstart	rmb 2				; start address of drawing area (line drawing)
drawend		rmb 2				; end address of drawing area (line drawing)
V24B		rmb 4
V24F		rmb 1
V250		rmb 1
V251		rmb 1
V252		rmb 2
V254		rmb 2
V256		rmb 3
V259		rmb 2
V25B		rmb 2
V25D		rmb 2
V25F		rmb 2
soundvol	rmb 1				; sound: volume multiplier for sound playing
V262		rmb 1
V263		rmb 2
V265		rmb 6
randomseed	rmb 3				; random number generator seed value
effectivelight	rmb 1
V26F		rmb 1
V270		rmb 3
V273		rmb 1
V274		rmb 1
V275		rmb 2
waitnewgame	rmb 1				; set if waiting for keypress to start new game
V278		rmb 1
V279		rmb 2
V27B		rmb 1
V27C		rmb 1
V27D		rmb 1
V27E		rmb 3
currentlevel	rmb 1				; currently playing dungeon level
creaturecountptr rmb 2				; pointer to creature count table for the current level
V284		rmb 2
holetabptr	rmb 2				; pointer to the hole table for this level
V288		rmb 2
V28A		rmb 1
V28B		rmb 1
V28C		rmb 1
V28D		rmb 1
parseobjtype	rmb 1
parseobjtypegen	rmb 1
parsegenobj	rmb 1
V291		rmb 1				; for iterating over object list, zero means start, nonzero means underway
V292		rmb 2				; current object pointer for iteration
V294		rmb 1				; nonzero means to show creatures when displaying a scroll
V295		rmb 2
V297		rmb 3
V29A		rmb 1
V29B		rmb 1
V29C		rmb 1
V29D		rmb 1
V29E		rmb 1
V29F		rmb 2
V2A1		rmb 10
V2AB		rmb 2
V2AD		rmb 1
V2AE		rmb 1
V2AF		rmb 1
V2B0		rmb 1
V2B1		rmb 1
displayptr	rmb 2				; pointer to routine to display the main dungeon area
pageswap	rmb 1				; nonzero means we're ready to swap graphics screens during IRQ
V2B5		rmb 1
V2B6		rmb 1
V2B7		rmb 1				; nonzero means nonstandard text location
V2B8		rmb 1				; load/save flag - <0 = ZLOAD, >0 = ZSAVE, 0 = regular init
V2B9		rmb 2
V2BB		rmb 1
keybufread	rmb 1				; keyboard buffer read offset
keybufwrite	rmb 1				; keyboard buffer write offset
		rmb 3
V2C1		rmb 1				; temporary variable used during line drawing and division
V2C2		rmb 1				; temporary variable used during division
V2C3		rmb 1				; temporary variable used during division
V2C4		rmb 1
V2C5		rmb 1
V2C6		rmb 1
V2C7		rmb 10
keybuf		rmb 32				; keyboard ring buffer
V2F1		rmb 32
V311		rmb 2
wordbuff	rmb 32
V333		rmb 2
stringbuf	rmb 34				; temporary buffer used for decoding immediate packed strings
fontbuf		rmb 10				; temporary buffer used for decoding font data
V361		rmb 31
V380		rmb 2				; screen start address of info text area
V382		rmb 2				; number of character cells in info text area
V384		rmb 2				; current cursor position in info text area
V386		rmb 1				; background colour mask for info text area
V387		rmb 1				; nonzero if info text area should not be rendered on secondary screen
V388		rmb 2				; screen start address of status line area
V38A		rmb 2				; number of character cells in status line area
V38C		rmb 2				; cursor position in status line area
V38E		rmb 1				; background colour mask for status line area
V38F		rmb 1				; nonzero if status line text should not be rendered on secondary screen
V390		rmb 2				; start offset of the command entry area
V392		rmb 2				; numer of character cells in command entry area
V394		rmb 2				; current cursor position in entry area
V396		rmb 1				; background colour mask of background area
V397		rmb 1				; nonzero if main text should not be rendered on secondary screen
creaturecounts	rmb 12				; creature counts for level 1
		rmb 12				; creature counts for level 2
		rmb 12				; creature counts for level 3
		rmb 12				; creature counts for level 4
		rmb 12				; creature counts for level 5
V3D4		rmb $220
mazedata	rmb $400
V9F4		rmb 9
V9FD		rmb $10a
emptyhand	rmb 14				; "object" information for empty hand
objecttab	rmb 72*14			; the object data table (room for 72 entries)
VF05		equ *


		org $c000
START		ldu #dodemo			; point to the demo setup routine
		bra LC008			; go handle the game
LC005		ldu #dogame			; point to the real game setup routine
LC008		lds #STACK			; put the stack somewhere safe
		ldx #PIA0			; point at PIA0
		ldd #$34fa			; initializers for the PIA
		sta 3,x				; set data mode, interrupts disabled (side B)
		sta 1,x				; set data mode, interrupts disabled (side A)
		ldx #PIA1			; point at PIA1
		sta 1,x				; set data mode, interrupts disabled (side A)
		clr 3,x				; set direction mode for side B
		stb 2,x				; set VDG and single bit sound to output
		lda #$3c			; flags for data mode, no interrupts, sound enabled
		sta 3,x				; set side B for data mode
		ldd #$2046			; SAM value for "pmode 4" graphics, screen at $1000
		jsr setSAM			; go set the SAM register
		lda #$f8			; value for "pmode 4", color set 1
		sta 2,x				; set VDG mode
		ldx #zero			; point to start of variables
LC030		clr ,x+				; clear a byte
		cmpx #TOPRAM			; are we at the top of memory?
		blo LC030			; brif not
		stu ,--s			; set return address to the game initialization routine
		lda #zero/256			; point to MSB of direct page
		tfr a,dp			; set DP appropriately
		setdp zero/256			; tell the assembler about DP
		ldy #LD7E8			; point to variable initialization table
LC041		lda ,y+				; fetch number of bytes in this initializer
		beq LC086			; brif zero - we're done
		ldx ,y++			; get address to copy bytes to
		bsr LC04B			; go copy bytes
		bra LC041			; go handle another initializer
LC04B		ldb ,y+				; fetch source byte
		stb ,x+				; stow at destination
		deca				; are we done yet?
		bne LC04B			; brif not
		rts				; return to caller
LC053		pshs cc,a,b,x,y,u		; save registers and interrupt status
		orcc #$10			; disable IRQ
		ldx #V29F			; point to start of variables to clear for level creation
LC05A		clr ,x+				; clear a byte
		cmpx #V2AD			; are we finished clearing things?
		blo LC05A			; brif not
		ldx #V9FD
		stx V2B9
LC066		clr ,x+				; clear more data
		cmpx #emptyhand			; end of area to clear?
		blo LC066			; brif not
		ldy #LD7DC
		dec V2BB
		ldd #12
LC076		ldx ,y++
		beq LC084
		jsr LC25C
		stx 3,u
		jsr LC21D
		bra LC076
LC084		puls cc,a,b,x,y,u,pc
LC086		bsr LC053			; initialize new level data
		ldu #LDA91			; point to objects to create for demo game
		clra				; initialize object type
LC08C		ldb ,u				; get object info
		andb #$0f			; get low nibble
		stb V28C			; save number to create
		ldb ,u+				; get object info again
		lsrb				; get high nibble
		lsrb
		lsrb
		lsrb
		stb V28D
LC09A		createobject			; create an object
		dec 5,x
		incb
		cmpb #5
		ble LC0A5
		ldb V28D
LC0A5		dec V28C			; created enough objects?
		bne LC09A			; brif not
		inca				; move to next object type
		cmpu #LDA91+18			; end of table?
		blo LC08C			; brif not - go to next entry
		ldu #V388			; point to text parameters for status area
		dec V2B7			; indicate nonstandard text area
		clearstatus			; blank status line (where we'll put the copyright notice)
		renderstrimmp			; display copyright message
		fcb $f8,$df,$0c,$c9		; packed string "COPYRIGHT  DYNA MICRO  MCMLXXXII"
		fcb $27,$45,$00,$02
		fcb $65,$c1,$03,$52
		fcb $39,$3c,$00,$68
		fcb $da,$cc,$63,$09
		fcb $48
		clr V2B7			; reset text rendering to standard mode
		rts					
dodemo		dec waitnewgame			; flag demo game
		bsr enablepiairq		; set up interrupts and sound
		ldx #img_wizard			; point to wizard image
		dec V29E
		fadein				; fade the wizard in
		renderstrimmp			; display <CR>"I DARE YE ENTER..."<CR>
		fcb $9f,$d2,$02,$06		; packed "\rI DARE YE ENTER...\r" string
		fcb $45,$06,$4a,$02
		fcb $ba,$85,$97,$bd
		fcb $ef,$80
		renderstrimmp			; display "...THE DUNGEONS OF DAGGORATH!!!"
		fcb $f7,$bd,$ea,$20		; packed "...THE DUNGEONS OF DAGGORATH!!!" string
		fcb $a0,$25,$5c,$72
		fcb $bd,$d3,$03,$cc
		fcb $02,$04,$e7,$7c
		fcb $83,$44,$6f,$7b
		delay				;* wait for about 2.6 seconds
		delay				;*
		fadeout				; fade the wizard out
		cleargfx2			; clear second graphics screen
		dec pageswap			; flag graphics swap ready
		sync				; wait for swap to happen
		lda #2				; create maze for level 3
		ldu #startobjdemo		; point to demo game object list
		bra LC131			; go start demo running
enablepiairq	ldd #$343c			; set up initializers for PIAs
		sta PIA1+1			; set data mode, no interrupts, cassette off
		stb PIA1+3			; set data mode, no interrupts, sound on
		inca				; adjust to enable interrupt
		sta PIA0+3			; set data mode, enable VSYNC, clear MSB of analog MUX
		cwai #$ef			; enable IRQ and wait for one
		rts				; return to caller
dogame		bsr enablepiairq		; set up interrupts and sound
		ldd #$100b			; maze position (11,16)
		std playerloc			; set start position there
		clr powerlevel			; reset power level to new game level (keeps LSB of default value)
		clra				; create maze for level 1
		ldu #startobj			; point to new game backpack object list
LC131		showprepare			; show the PREPARE! screen
		dod S1A				; create maze
		ldy #backpack			; point to backpack list head pointer
LC139		lda ,u+				; get object to create
		bmi LC14F			; brif end of list
		createobject			; create requested object
		inc 5,x
		exg x,u				; swap object pointer and list pointer
		setobjectspecs			; set the specs properly (as in fully revealed)
		exg x,u				; swap pointers back
		clr 11,x			; mark object revealed
		stx ,y				; save new object in backpack list
		tfr x,y				; move list pointer to object just created
		bra LC139			; go look for another object to create
LC14F		tst waitnewgame			; are we doing a demo game?
		beq LC166			; brif not
		dec V29B
		ldx #displayscroll		; set to scroll display
		stx displayptr
		dec V294			; set to show creatures on map
		dod S0E				; show the dungeon map
		delay				; delay for about 2.5 seconds
		delay
		clr V29B
		sync				; wait a couple of ticks
		sync
LC166		dod S19				; clear command and status areas and show the dungeon
		showprompt			; show command prompt
		jmp LC1F5			; go to main loop
LC16D		stx CBUFAD			; set address to read to
		romcall BLKIN			; read a block
		tsta				; is it the end of the file?
		lbne RESVEC			; brif so - premature end, fail with a reset
		ldb BLKTYP			; get type of block
		rts
disablepiairq	ldu #PIA0			; point to PIA0
		ldd #$343c			; set up initializers for PIA
		sta 3,u				; disable VSYNC interrupt, clear analogue mux msb
		sta PIA1+3			; disable interrupts on PIA1, cassette off
		stb PIA1+1			; disable interrupts on PIA1, sound on
		rts
busywait	ldx zero			; get long delay constant
busywait000	leax -1,x			; have we reached 0?
		bne busywait000			; brif not
		rts
LC192		bsr disablepiairq		; set up PIA for cassette I/O
		bsr busywait			; delay for a bit
		bsr busywait
		romcall WRTLDR			; write a file header
		romcall BLKOUT
		bsr busywait			; delay for a bit
		romcall WRTLDR			; write a leader for data area
		ldx #zero			; point to start of game state
LC1A6		ldd #$0180			; set block type to data, size to 128 bytes
		std BLKTYP
		stx CBUFAD			; set start of buffer to write
		romcall BLKOUT			; write a data block
		cmpx #VF05			; have we reached end of state?
		blo LC1A6			; brif not
		stu BLKTYP			; write trailing block
		romcall BLKOUT
		bsr busywait			; delay for a bit
		bra LC1EC			; go init things and restart main loop
LC1C1		bsr disablepiairq		; set up PIA for cassette I/O
		romcall CSRDON			; start tape
LC1C6		ldu screendraw			; point to drawing area
		ldx ,u				; get pointer to screen data - use as a read buffer
		bsr LC16D			; read a block
		bne LC1C6			; brif data block
		ldx ,u				; get buffer pointer
		ldu #wordbuff			; point to requested file name
		ldb #8				; 8 characters in file name
LC1D5		lda ,x+				; does character match?
		cmpa ,u+
		bne LC1C1			; brif not - look for another header
		decb				; end of file name?
		bne LC1D5			; brif not - check another
		romcall CSRDON			; start tape
		ldx #zero			; point to game state area
LC1E4		bsr LC16D			; read a block
		bpl LC1E4			; brif it was still a data block
		lds #STACK			; reset stack pointer
LC1EC		jsr enablepiairq		; make sure PIAs are set right
		clr V2B8			; flag regular operations
		dod S19				; clear command and status areas, update appropriately
		showprompt			; show command prompt
LC1F5		ldu #V2AB
		clr V2BB
LC1FA		tfr u,y
LC1FC		tst V2B8			; are we loading or saving?
		bgt LC192			; brif saving
		bmi LC1C1			; brif loading
		ldu ,u
		beq LC1F5
		pshs y,u
		jsr [3,u]
		puls y,u
		tst V2BB
		bne LC1F5
		cmpb #12
		beq LC1FA
		bsr LC238
		bsr LC21D
		tfr y,u
		bra LC1FC
LC21D		pshs cc,a,b,x
		orcc #$10
		sta 2,u
		ldx #V29F
		abx
		clra
		clrb
		std ,u
LC22B		cmpd ,x
		beq LC234
		ldx ,x
		bra LC22B
LC234		stu ,x
		puls cc,a,b,x,pc
LC238		pshs cc,x
		orcc #$10
		ldx ,u
		stx ,y
		puls cc,x,pc
LC242		pshs b,x,y,u
		tst V29B
		bne LC25A
LC248		tfr u,y
		ldu ,u
		beq LC25A
		dec 2,u
		bne LC248
		bsr LC238
		ldb #12
		bsr LC21D
		bra LC248
LC25A		puls b,x,y,u,pc
LC25C		pshs x
		ldu V2B9
		leax 7,u
		stx V2B9
		puls x,pc
; Set the SAM video mode and display offset register to the value in D. Starting at the lsb of
; D, the SAM bits are programmed from FFC0 upward. This sets bits 9-0 of the SAM register
; to match the value in D.
setSAM		pshs x,b,a			; save registers
		ldx #SAMREG			; point to SAM register
setSAM000	lsra				;* shift the bit value to set to carry
		rorb				;*
		bcs setSAM001			; brif bit set
		sta ,x				; clear the bit
		skip2				; skip next instruction
setSAM001	sta 1,x				; set the bit
		leax 2,x			; move to next SAM register bit
		cmpx #SAMREG+$14		; are we at the end of the register?
		blo setSAM000			; brif not
		puls a,b,x,pc			; restore registers and return
; IRQ service routine
LC27D		ldx #PIA1			; point to PIA1
		lda -29,x			; get interrupt status
		lbpl LC320			; brif not VSYCN
		lda #zero/256			; point to direct page MSB
		tfr a,dp			; make sure DP is set correctly
		tst pageswap			; do we have a screen swap to do?
		beq LC29D			; brif not
		ldd screenvis			; get currently visible screen pointer
		ldu screendraw			; get newly drawn screen pointer
		std screendraw			; save current screen as screen to draw
		stu screenvis			; save drawn screen as current
		ldd 4,u				; get the SAM value for the new screen
		bsr setSAM			; go program the SAM
		clr pageswap			; flag no swap needed
LC29D		tst V29C
		beq LC2A9
		com V29D
		lda V29D
		lsla
		lsla
		sta ,x
LC2A9		tst V2B1
		beq LC2DC
		dec V2AE
		bne LC2DC
		lda V2AF
		sta V2AE
		ldb 2,x
		eorb #2
		stb 2,x
		tst V2AD
		beq LC2DC
		ldu #V388
		ldx 4,u
		ldd #15
		std 4,u
		lda #$20
		com V2B0
		beq LC2D1
		lda #$22
LC2D1		jsr LCA17
		inc 5,u
		inca
		jsr LCA17
		stx 4,u
LC2DC		ldu #V2A1
		jsr LC242
		ldx #V295
		ldy #LC324
LC2E9		inc ,x
		cmpx #V29A
		beq LC2FF
		lda ,x
		cmpa ,y+
		blt LC2FF
		clr ,x+
		leau 2,u
		jsr LC242
		bra LC2E9
LC2FF		tst nokeyboard			; are we polling the keyboard?
		bne LC320			; brif not
		tst waitnewgame			; are we running a demo/waiting for keypress for game start?
		beq LC318			; brif not
		clr PIA0+2			; strobe all keyboard columns
		lda PIA0			; fetch row data
		anda #$7f			; mask off comparator input
		cmpa #$7f			; did we have any keys down?
		beq LC320			; brif not
		ldx #LC005			; pointer to game start routine
		stx 10,s			; set return to game start routine
LC318		romcall POLCAT			; poll the keyboard
		tsta				; was a key down?
		beq LC320			; brif not
		bsr writekeybuf			; go process keyboard input
LC320		lda PIA0+2			; clear interrupt status
		rti
LC324		fcb $06,$0a,$3c,$3c,$18
readkeybuf	pshs cc,b,x			; save registers and interrupt status
		orcc #$10			; disable IRQ
		clra				; flag no key pressed
		ldx #keybuf			; point to keyboard ring buffer
		ldb keybufread			; get buffer read offset
		cmpb keybufwrite		; same as buffer write offset?
		beq readkeybuf000		; brif so - no key available
		lda b,x				; fetch key from buffer
		incb				; bump buffer pointer
		andb #$1f			; wrap around if needed
		stb keybufread			; save new buffer read offset
readkeybuf000	puls cc,b,x,pc			; restore registers and interrupts
; Add a keypress to the keyboard buffer. NOTE: this does not check for buffer overflow
; which means when the buffer gets full, it just rolls over and overwrites the previous
; data.
writekeybuf	pshs cc,b,x			; save registers and interrupt status
		orcc #$10			; disable IRQ
		ldx #keybuf			; point to keyboard ring buffer
		ldb keybufwrite			; get buffer write offset
		sta b,x				; stash new key
		incb				; bump buffer pointer
		andb #$1f			; wrap around if needed
		stb keybufwrite			; save new buffer write offset
		puls cc,b,x,pc			; restore registers and interrupts
; SWI handler
LC352		andcc #$ef			; re-enable IRQ - SWI disables it
		ldx 10,s			; get return address
		lda ,x+				; get operation code
		stx 10,s			; save new return address
		ldx #LC384			; point to first SWI routine
		ldu #LC995			; point to routine offset table
LC360		ldb ,u+				; get length of previous routine
		abx				; add to routine pointer
		deca				; are we at the right routine?
		bpl LC360			; brif not
		stx ,--s			; save routine address
		ldd 3,s				; restore D register
		ldx 6,s				; restore X register
		ldu 10,s			; restore U register
		jsr [,s++]			; call the routine
		rti				; return to caller
; SWI2 handler
LC371		clrb				;* restore direct page for ROM call
		tfr b,dp			;*
		ldu 10,s			; get return address
		ldb ,u+				; get ROM routine offset
		stu 10,s			; save new return address
		ldu #ROMTAB			; point to ROM vector table
		jsr [b,u]			; call the ROM routine
		sta 1,s				;* save return values
		stx 4,s				;*
		rti				; return to caller
; SWI 0 routine
LC384		lda effectivelight
		tst V275
		beq LC38E
		lda V26F
		clr V275
LC38E		clrb
		suba #7
		suba V28B
		bge LC39F
		decb
		cmpa #$f9
		ble LC39F
		ldx #LCB96
		ldb a,x
LC39F		stb lightlevel
		rts
; SWI 1 routine
;***********************************************************************************************************
; This routine renders a line graphic from the specification stored at (X).
;
; The data at (X) is a series of operations as follows:
;
; if (X) is < $FA, then the two bytes at (X) are an absolute Y and X coordinate. If V251 is clear, this is
; the first vertex in a polygon and the coordinates are simply recorded. Otherwise, a line is drawn from
; the previous coordinates to the new coordinates. These coordinates have the Y coordinate first.
;
; If (X) is >= $FA, it is a special operation defined as follows:
;
; FA: return from a "subroutine" to the previous flow
; FB: call a subroutine at the memory address in the next two bytes
; FC: draw a series of points using relative motion. The following byte is split into nibbles with the
;	upper nibble being the Y displacement and the lower nibble being the X displacement. These values
;	are signed and will be doubled when applied to the drawing. This gives a range of -32 to +30 in
;	steps of 2 for each direction. If both displacements are zero (a zero byte), this is the end of
;	the relative sequence. The end of one of these sequences is the end of a polygon.
; FD: like FB but doesn't record the previous location
; FE: flags the end of the input and causes a return to the caller. Do not use this in a subroutine as
;	the stack will have been used to record the return data location.
; FF: mark the next coordinates as the start of a new polygon.
;
; In all cases, the X and Y coordinates actually used have a scale factor applied to them based on the
; distance from the defined centre of the graphics area which is stored in (V205,V207). The horizontal
; scale factor is at V24F and the vertical scaling factor is at V250. A factor of 128 serves as a scale
; factor of 1. 192 would be 1.5 and 64 would be 0.5.
;
; Variables used:
;
; V205		the horizontal centre point for rendering graphics and scaling
; V207		the vertical centre point for rendering graphics and scaling
; lightlevel	the light level with respect to rendering the graphic
; V24F		the horizontal scaling factor (binary point to the right of bit 7)
; V250		the vertical scaling factor (binary point to the right of bit 7)
; V251		nonzero if this is not the first coordinate in a polygon
; V252		the most recent absolute unscaled X coordinate
; V254		the most recent absolute unscaled Y coordinate
LC3A2		clr V251			; mark input as start of polygon
		lda lightlevel			; fetch dungeon light level
		inca				; is it $ff (dark)?
		beq LC3F6			; brif so - skip rendering
LC3A9		ldb ,x				; fetch input data
		subb #$fa			; adjust for operation codes
		blo LC3CF			; brif not operation code
		leax 1,x			; move on to next image data byte
		ldy #LC3B9			; point to jump table for operation codes
		ldb b,y				; get offset to operation routine
		jmp b,y				; execute operation routine
LC3B9		fcb LC3C9-LC3B9			; (FA) return from a "subroutine"
		fcb LC3BF-LC3B9			; (FB) call a "subroutine"
		fcb LC417-LC3B9			; (FC) polygon
		fcb LC3C6-LC3B9			; (FD) jump to a new "routine"
		fcb LC3F6-LC3B9			; (FE) end of input - return to caller
		fcb LC3CB-LC3B9			; (FF) next coordinates are start of new polygon
LC3BF		ldd ,x++			; get address of "subroutine" to call
		stx ,--s			; save return address
		tfr d,x				; set new "execution" address
		skip2				; skip next instruction
LC3C6		ldx ,x				; get address of "routine" to jump to
		skip2				; skip next instruction
LC3C9		ldx ,s++			; get back saved input location
LC3CB		clr V251			; reset polygon start flag to start
		bra LC3A9			; go process more input
LC3CF		tst V251			; is this the first coordinate in a polygon?
		bne LC3D9			; brif not
		bsr LC3E2			; fetch input coordinates and save them
		dec V251			; flag as not first coordinate
		bra LC3A9			; go process more input
LC3D9		bsr LC3E0			; set up coordinates to draw a line
		jsr drawline			; draw the line
		bra LC3A9			; go process more input
LC3E0		bsr LC3F7			; move last end coordinates to line start
LC3E2		ldb ,x+				; get the next Y coordinate and move pointer forward
		stb V254			; save unscaled Y coordinate
		bsr LC400			; scale the Y coordinate
		addd V207			; add in base Y coordinate
		std yend			; save scaled end coordinate for line
		ldb ,x+				; get the next X coordinate and move pointer forward
		stb V252			; save unscaled X coordinate
		bsr LC406			; scale the X coordinate
		addd V205			; add in base X coordinate
		std xend			; save scaled X coordinate for line
LC3F6		rts				; return to caller
LC3F7		ldd yend			; fetch last Y coordinate
		std ybeg			; save as begining of new line segment
		ldd xend			; fetch last X coordinate
		std xbeg			; save as beginning of new line segment
		rts				; return to caller
LC400		lda V250			; get desired vertical scaling factor
		subb V208			; find difference from Y base coordinate
		bra LC40A			; go finish calculating scale
LC406		lda V24F			; get desired horizontal scale factor
		subb V206			; find difference from X base coordinate
LC40A		bcs LC40F			; brif negative difference
		mul				; apply the scaling factor
		bra LC414			; normalize to an integer in D and return
LC40F		negb				; make coordinate difference positive
		mul				; apply the scaling factor
		jsr LCA99			; negate coordinate value
LC414		jmp LD377			; normalize to an integer in D and return
LC417		lda ,x+				; get next byte in input
		beq LC3CB			; brif NUL - end of values
		bsr LC3F7			; move last end coordinate to start coordinate for line
		ldb -1,x			; get the relative movement specifications
		asrb				;* fetch high nibble signed extended into B
		asrb				;*
		asrb				;*
		asrb				;*
		lslb				; and multiply by two
		addb V254			; add in previous Y coordinate
		stb V254			; save new Y coordinate
		bsr LC400			; go scale the Y coordinate
		addd V207			; add in the Y base coordinate
		std yend			; save new ending Y coordinate
		ldb -1,x			; get back the input byte again
		andb #$0f			; mask off the upper bits
		bitb #8				; is bit 3 set?
		beq LC438			; brif not
		orb #$f0			; sign extend to 8 bits
LC438		lslb				; multiply by two
		addb V252			; add in saved X coordinate
		stb V252			; save new X coordinate
		bsr LC406			; go scale the X coordinate
		addd V205			; add in base X coordinate
		std xend			; save new ending X coordinate
		jsr drawline			; go draw a line
		bra LC417			; look for another line segment
; swi 2 routine
; fetch a packed string immediately following the call and display it
LC448		ldx 12,s			; fetch return address - string address
		decodestrsb			; go decode string
		stx 12,s			; save new return address - after string
		ldx #stringbuf			; point to decoded string
		skip2				; skip the next instruction - nothing to display yet
LC452		renderchar			; display character in A
; swi 3 routine
; display an unpacked string pointed to by X
LC454		lda ,x+				; fetch byte from string
		bpl LC452			; brif not end of string - display it
		rts				; return to caller
; swi 4 routine
; display character in A
LC459		tst V2B7			; are we looking for standard text mode?
		bne LC460			; brif not
		ldu #V390			; point to display state information
LC460		ldx 4,u				; fetch current screen location
		jsr LC9B2			; actually display the appropriate character
		cmpx 2,u			; are we at the end of text area?
		blo LC46C			; brif not
		jsr LC9D4			; go scroll the text area
LC46C		stx 4,u				; save new screen location
		rts				; return to caller
; swi 5 routine - decode packed string at X to stringbuf
LC46F		ldu #stringbuf			; point to output buffer
; swi 6 routine - decode a packed string at X to U
; the first value is the length of the string less one
LC472		leay -1,u			; point to working data before buffer
		clr ,y				; initialize value counter
		bsr LC48C			; fetch a value
		tfr b,a				; save length
LC47A		bsr LC48C			; fetch a value
		stb ,u+				; save in output
		deca				; done yet?
		bpl LC47A			; brif not
		sta ,u				; flag end of string with $ff
		tst ,y				; did we consume an even number of bytes?
		beq LC489			; brif so
		leax 1,x			; move pointer forward
LC489		stx 6,s				; save pointer past end of input
		rts				; return to caller
LC48C		pshs a,u			; save registers
		lda ,y				; get value counter
		ldu #LC4A2			; point to value handlers
		lda a,u				; get offset to handler for this value
		jsr a,u				; call the handler for this value
		lda ,y				; get value counter
		inca				; bump it
		anda #7				; wrap it around - the pattern repeats every 8 values
		sta ,y				; save new value counter
		andb #$1f			; values are only 5 bits - clear out extra bits
		puls a,u,pc			; restore registers and return
LC4A2		fcb LC4AA-LC4A2			; value 0 handler
		fcb LC4B0-LC4A2			; value 1 handler
		fcb LC4B5-LC4A2			; value 2 handler
		fcb LC4B9-LC4A2			; value 3 handler
		fcb LC4BE-LC4A2			; value 4 handler
		fcb LC4C3-LC4A2			; value 5 handler
		fcb LC4C7-LC4A2			; value 6 handler
		fcb LC4CC-LC4A2			; value 7 handler
; value 0: upper 5 bits of current input byte
LC4AA		ldb ,x				; fetch input byte
		lsrb				;* align in low bits of B
LC4AD		lsrb				;*
LC4AE		lsrb				;*
		rts				return to caller
; value 1: lower 3 bits of current input byte and upper 2 bits of next one
; consumes a byte
LC4B0		ldd ,x+				; fetch input data and consume a byte
		jmp LD379			; align in low bits of B
; value 2: bits 5...1 of current input byte
LC4B5		ldb ,x				; fetch input byte
		bra LC4AE			; align in low bits of B
; value 3: bits 0 of current byte and upper 4 bits of next one
; consumes a byte
LC4B9		ldd ,x+				; fetch input data and consume a byte
		jmp LD37D			; align in low bits of B
; value 4: low 4 bits of input byte and high bit of next one
; consumes a byte
LC4BE		ldd ,x+				; fetch input data and consume a byte
		jmp LD377			; align in low bits of B
; value 5: bits 6...2 of current input byte
LC4C3		ldb ,x				; fetch input data
		bra LC4AD			; align in low bits of B
; value 6: low two bits of current input byte and high 3 bits of next one
; consums a byte
LC4C7		ldd ,x+				; fetch input data and consume a byte
		jmp LD37B			; align in low bits of B
; value 7: low 5 bits of current input byte
; consumes a byte
LC4CC		ldb ,x+				; fetch input data - already aligned
		rts				; return to caller
; swi 7 routine
; Generate a random number based on seed in randomseed, return 8 bit value in A
LC4CF		ldx #8
LC4D2		clrb
		ldy #8
		lda randomseed+2
		anda #$e1
LC4DB		lsla
		bcc LC4DF
		incb
LC4DF		leay -1,y
		bne LC4DB
		lsrb
		rol randomseed
		rol randomseed+1
		rol randomseed+2
		leax -1,x
		bne LC4D2
		lda randomseed
		sta 3,s				; save 8 bit random value for return
		rts				; return to caller
; swi 8 routine - clear first graphics screen
LC4F3		ldu screenvis			; point to first screen parameter block
		skip2				; skip next instruction
; swi 9 routine - clear second graphics screen
LC4F6		ldu screendraw			; point to second screen parameter block
		ldb levbgmask			; get current level background colour
		bsr LC517			; go clear the graphics area of the screen
		stu 10,s			; save pointer to parameter block for the caller
		rts				; return to caller
; swi 10 routine - clear the status line
LC4FF		ldx #V388			; point to text area parameters for the status line
		ldu #LD87C			; point to screen address table for the status line
		bra LC50D			; go clear the status line
; swi 11 routine - clear the command entry area
LC507		ldx #V390			; point to text area parameters for the command area
		ldu #LD888			; point to screen address table for the command area
LC50D		clr 4,x				;* set current cursor to start of text area
		clr 5,x				;*
		ldb 6,x				; get background colour of text area
		bsr LC517			; go clear text area
		leau 6,u			; and repeat the process for the other graphics screen
LC517		pshs a,b,x,y,u			; save regsiters
		sex				; get background colour to A
		tfr d,y				; move it into Y too (4 bytes of background colour)
		leax ,u				; point to start of parameter area
		ldu 2,u				; get address of end of text area (+1)
LC520		pshu a,b,y			; blast 4 background bytes to area
		cmpu ,x				; are we at the start of the area?
		bne LC520			; brif not
		puls a,b,x,y,u,pc		; restore registers and return
; swi 12 routine
LC529		clr V2C1
		ldd powerlevel
		std V2C2
		lda #6
LC531		lsl V2C3
		rol V2C2
		rol V2C1
		deca
		bne LC531
		clr V2C4
		ldd damagelevel
		std V2C5
		lsl V2C6
		rol V2C5
		rol V2C4
		ldd powerlevel
		addd V2C5
		std V2C5
		ldb V2C4
		adcb #0
		stb V2C4
		clr V2C7
LC554		ldd V2C2
		subd V2C5
		std V2C2
		lda V2C1
		sbca V2C4
		sta V2C1
		inc V2C7
		bcc LC554
		lda V2C7
		suba #19
		sta V2AF
		tst nokeyboard
		bne LC595
		cmpa #3
		bgt LC5AE
		clearcommand
		lda effectivelight
		sta V270
LC578		dec V26F
		jsr [displayptr]		; update the main display area
		dec pageswap			; set graphics swap required
		sync				; wait for swap to happen
		dec effectivelight
		lda effectivelight
		cmpa #$f8
		bgt LC578
		cleargfx2
		dec pageswap			; set graphics swap required
		dec nokeyboard
		clr keybufread			;* reset keyboard buffer
		clr keybufwrite			;*
		bra LC5AE
LC595		cmpa #4
		ble LC5AE
LC599		jsr [displayptr]		; update the main display area
		dec pageswap			; set graphics swap required
		sync				; wait for swap to happen
		inc V26F
		inc effectivelight
		lda effectivelight
		cmpa V270
		ble LC599
		clr nokeyboard
		showprompt
LC5AE		ldx powerlevel
		cmpx damagelevel
		blo LC5B5
		rts
; This routine handles player death
LC5B5		ldx #img_wizard			
		dec V29E
		fadeinclrst
		renderstrimmp
		fcb $ff,$c1,$92,$d0		; packed "YET ANOTHER DOES NOT RETURN..." string
		fcb $01,$73,$e8,$82
		fcb $c8,$04,$79,$66
		fcb $07,$3e,$80,$91
		fcb $69,$59,$3b,$de
		fcb $f0
		clr nokeyboard			; enable keyboard polling in IRQ
		dec waitnewgame			; set up to wait for keypress to start new game
LC5D7		bra LC5D7			; wait forever (or until the IRQ does something)
; swi 13 routine
LC5D9		ldu #V388			; point to parameters for status line
		dec V2B7			; set to nonstandard text area
		lda levbgmask			; get current level background
		coma				; invert it for status line
		sta 6,u				; set up for displaying status line
		clra				; set position to start clearing (start of line)
		clrb
		bsr LC609			; clear half the line
		std 4,u				; save display position
		ldx lefthand			; fetch object in left hand
		bsr LC617			; get name of object
		renderstr			; display left hand object
		ldd #17				; set position to start clearing
		bsr LC609			; go clear half the line
		ldx righthand			; fetch object in right hand
		bsr LC617			; get name of object
		tfr x,y				; save start pointer
		ldd #$21			; set up offset for displaying right justified
LC5FD		decb				; move cursor point left
		tst ,y+				; end of string yet?
		bpl LC5FD			; brif not - keep moving left
		std 4,u				; save render position
		renderstr			; display the right hand object
		clr V2B7			; reset to standard text rendering
		rts
LC609		pshs a,b			; save registers
		std 4,u				; save the start position
		ldd #15				; set up for a space (code 0) 15 times
LC610		renderchar			; render a space
		decb				; done yet?
		bne LC610			; brif not
		puls a,b,pc			; restore registers and return
LC617		pshs a,b,y,u			; save registers
		leay ,x				; point to object data
		bne LC622			; brif there is object data
		ldx #LC650			; point to "EMPTY" string
		bra LC63C			; return result
LC622		ldu #wordbuff			; point to word buffer
		tst 11,y			; has it been revealed?
		bne LC632			; brif not
		lda 9,y				; fetch sub type
		ldx #kw_supreme			; point to first "adjective" keyword
		bsr LC63E			; copy correct string into buffer
		clr -1,u			; make a space after adjective
LC632		lda 10,y			; get base type
		ldx #kw_flask			; point to first base type keyword
		bsr LC63E			; copy correct string into buffer
		ldx #wordbuff			; point to start of string
LC63C		puls a,b,y,u,pc			; restore registers and return
LC63E		pshs a,x			; save registers
LC640		decodestrsb			; decode the current string into buffer
		deca				; are we there yet?
		bpl LC640			; brif not
		ldx #stringbuf+1		; point to actual string (past object type)
LC648		lda ,x+				; fetch character from decoded keyword
		sta ,u+				; save in output buffer
		bpl LC648			; brif not end of string yet
		puls a,x,pc			; restore registers and return
LC650		fcb $05,$0d,$10,$14,$19,$ff	; unpacked string "EMPTY"
; swi 14 routine
LC656		tst nokeyboard
		bne LC65F
		bsr LC660			; go update the display
		dec pageswap			; flag graphics swap required
		sync				; wait for swap to happen
LC65F		rts
LC660		pshs a,b,x,y,u			; save registers
		ldd baselight			; get dungeon base lighting
		ldu curtorch			; is there a torch lit?
		beq LC66C			; brif not
		adda 7,u			; add in physical light from torch
		addb 8,u			; add in magical light from torch
LC66C		std effectivelight		; save effective light level for dungeon
		jsr [displayptr]		; update the main display area
		puls a,b,x,y,u,pc
; swi 15 routine
LC674		ldx #LC67A			; point to newline followed by prompt
		renderstr			; go display the newline and prompt
		rts				; return to caller
LC67A		fcb $1f,$1e			; unpacked string CR PERIOD UNDERSCORE BS (including following)
LC67C		fcb $1c,$24,$ff			; unpacked string UNDERSCORE BS

; swi 16 routine
; delay for 81 ticks (1.3 seconds)
LC67F		ldb #$51			; fetch delay tick count
LC681		sync				; wait for a tick
		decb				; are we done yet?
		bne LC681			; brif not
		rts
; these two routine clear an area to 0 (black) or $ff (white) starting at X and
; ending at U
; swi 17 routine
LC686		clra				; set area to $00 (clear to black)
		skip2				; skip next byte
; swi 18 routine
LC688		lda #$ff			; set area to $FF (clear to white)
LC68A		sta ,x+				; clear a byte
		cmpx 10,s			; are we done yet?
		bne LC68A			; brif not
		rts				; return to caller
; This looks like a leftover from earlier development which had the
; rom calls as a SWI call instead of using SWI2. This routine cannot
; be reached through the SWI mechanism and it cannot be called directly
LC691		clrb				;* reset direct page for ROM call
		tfr b,dp			;*
		ldu 12,s			; fetch return address
		ldb ,u+				; fetch rom call wanted
		stu 12,s			; save new return address
		ldu #ROMTAB			; point to ROM vector table
		jsr [b,u]			; call the routine
		sta 3,s				;* save return values
		stx 6,s				;*
		rts
; swi 19 routine
; fade in the image specified by (X) with sound effects, clear status line and command area
LC6A4		clr V2B1
		clearstatus			; clear the status area
; swi 20 routine
; fade in the image specified by (X) with sound effects, clear command area
LC6A8		clearcommand			; clear the command area
		ldd #$8080			;* set X and Y scale values to 1.0
		std V24F			;*
		ldb V29E
		beq LC6B7
		ldb #$20			; set apparent lighting to 32 (less apparent)
		dec V29C
LC6B7		bsr LC6D7			; go draw the image
		decb				;* reduce lighting count - make more apparent
		decb				;*
		bpl LC6B7			; brif not done 16 steps
		clr V29C
		clr V29E
LC6C1		playsoundimm $16		; play sound effect
		rts				; return to caller
; swi 21 routine
; fade out the image specified by (X) with sound effects, clear command area
LC6C5		clearcommand			; clear the command entry area
		bsr LC6C1
		clrb				; set apparent illumination to fully lit			
		dec V29C
LC6CC		bsr LC6D7			; go draw the image
		incb				;* bump lighting count (make less apparent)
		incb				;*
		cmpb #$20			; have we done 16 steps?
		bne LC6CC			; brif not
		clr V29C
		rts				; return to caller
LC6D7		pshs x,u			; save registers
		stb lightlevel			; set illumination value for graphic rendering
		stb V29D
		cleargfx2			; clear second graphics screen
		drawgraphic			; go draw graphic
		dec pageswap			; flag graphics swap required
		sync				; wait for swap to happen
		puls x,u,pc			; restore registers and return
; swi 22 routine - display the PREPARE! screen
LC6E6		jsr LD489			; clear second graphics screen and set up for text mode
		ldd #$12c			;* set cursor position to the middle of the screen
		std 4,u				;*
		renderstrimmp			; display the PREPARE! message
		fcb $3c,$24,$58,$06		; packed string "PREPARE!"
		fcb $45,$d8
		clr V2B7			; reset to standard text rendering
		dec pageswap			; set graphic swap required
		rts				; return to caller
; swi 23 routine
LC6FB		ldu objectfree			; fetch free point in object table
		stu 6,s				; save pointer for return
		leax 14,u			; move to next entry in table
		stx objectfree			; save as new free point in object table
		sta 9,u				; set object type to requested type
		stb 4,u
		setobjectspecs			; set up object specs from data tables
		ldb 10,u			; fetch object general type
		ldx #LC719			; point to modifier table
		lda b,x				; get modified type entry
		bmi LC718			; brif no modification
		ldb 11,u			; get reveal strength of original object type
		setobjectspecs			; set up object data from replacement type
		stb 11,u			; restore reveal strength
LC718		rts
LC719		fcb $ff				; flasks do not get a replacment
		fcb $ff				; rings do not get a replacement
		fcb $ff				; scrolls do not get a replacement
		fcb $10				; shields default to leather shield specs
		fcb $11				; swords default to wooden sword specs
		fcb $0f				; torches default to pine torch specs
; swi 24 routine
LC71F		lsla				; four bytes per object specs entry
		lsla
		ldx #objspecs			; point to object data table
		leay a,x			; point to correct entry in table
		leax 10,u			; point to location in data table
		lda #4				; four bytes to copy
		jsr LC04B			; copy data into new object
		ldx #objextraspecs-4		; point to extra object data
LC730		leax 4,x			; move to next entry
		lda ,x				; is it end of table?
		bmi LC742			; brif so
		cmpa 3,s			; is this entry for the object type we're creating?
		bne LC730			; brif not - try another
		ldd 1,x				; copy the ring charges and defensive values
		std 6,u
		lda 3,x
		sta 8,u
LC742		rts				; return to caller
; swi 25 routine
LC743		clearstatus
		clearcommand
		dod S0C
		inc V2AE
		dec V2AD
		dec V2B1
		updatestatus
cmd_look	ldx #LCE66
		stx displayptr
		dod S0E
		rts
; swi 26 routine
LC759		sta currentlevel		; save current dungeon level
		ldb #12				; number of entries in creature count table
		mul				; calculate offset to creature counts for this level
		addd #creaturecounts		; point to correct creature count table for this level
		std creaturecountptr		; save pointer to creature count table
		ldb currentlevel		; get back current level number
		ldx #holetab			; point to hole/ladder table
LC768		stx holetabptr			; save hole/ladder data pointer
LC76A		lda ,x+				; fetch flag
		bpl LC76A			; brif we didn't consume a flag
		decb				; are we at the right set of data for the level?
		bpl LC768			; brif not - save new pointer and search again
		ldx #V3D4			; get start address to clear
		ldu #mazedata			; get end address to clear
		clearblock			; go clear area to zeros
		jsr LC053			; initialize data for new level
		jsr createmaze			; create the maze
		ldu creaturecountptr		; point to creature counts for this level
		lda #11				; offset for wizard
LC783		ldb a,u				; get number of creatures required
		beq LC78D			; brif none
LC787		jsr LCFA5
		decb				; created enough creatures?
		bne LC787			; brif not
LC78D		deca				; move on to next creature
		bpl LC783			; brif not finished all creatures
		ldu #V3D4-17			; point to creature table
		clr V291
LC795		jsr LCF63			
		beq LC7B6
		tst 5,x
		bpl LC795
LC79E		leau 17,u
		cmpu #mazedata
		blo LC7AA
		ldu #V3D4
LC7AA		tst 12,u
		beq LC79E
		ldd 8,u
		stx 8,u
		std ,x
		bra LC795
LC7B6		lda currentlevel
		anda #1
		nega
		sta levbgmask
		sta V396
		sta V386
		coma
		sta V38E
		rts
; swi 27 routine
; play a sound specified by the immediate identifier
LC7C8		ldx 12,s			; fetch return address
		lda ,x+				; fetch immediate data
		stx 12,s			; update return address
		ldb #$ff			; set to maximum volume
; swi 28 routine
; play a sound specified by the value in A
LC7D0		stb soundvol			; set the volume for the sound playing routine
		ldx #LC7DC			; point to sound routine jump table
		lsla				; two bytes per jump table entry
		jsr [a,x]			; call the sound generator routine
		clr PIA1			; turn off sound output
		rts				; return to caller
; the jump table for sound routines
LC7DC		fdb LC82B			; sound 0
		fdb LC850			; sound 1
		fdb LC951			; sound 2
		fdb LC83C			; sound 3
		fdb LC8E2			; sound 4
		fdb LC955			; sound 5
		fdb LC84A			; sound 6
		fdb LC8DE			; sound 7
		fdb LC84D			; sound 8
		fdb LC959			; sound 9
		fdb LC877			; sound 10
		fdb LC877			; sound 11
		fdb LC80A			; sound 12 - flask sound
		fdb LC811			; sound 13 - ring sound
		fdb LC827			; sound 14 - scroll sound
		fdb LC8DA			; sound 15 - shield sound
		fdb LC8A6			; sound 16 - sword sound
		fdb LC8B2			; sound 17 - torch sound
		fdb LC93F			; sound 18 - attack hit
		fdb LC8E6			; sound 19 - ??? attack miss
		fdb LC872			; sound 20 - ??? walk into wall sound
		fdb LC86D			; sound 21 - creature death
		fdb LC88A			; sound 22 - wizard fade sound
; sound 12
LC80A		ldu #LC823			; point to 144Hz base tone
		lda #4				; repeat sound 4 times
		bra LC816			; go do the sound
; sound 13
LC811		ldu #LC81F			; point to 288Hz base tone
		lda #10				; repeat sound 10 times
LC816		sta V25F			; set repeat counter
LC818		jsr ,u				; make a sound
		dec V25F			; have we done enough of them?
		bne LC818			; brif not
		rts
; These routines produce a "sliding" tone starting at the base frequency. The specified base
; frequency is a rough estimate. The tones are created using square waves. After each full wave,
; the delay in reduced by one which increases the frequency. The last cycle is with the delay
; equal to 1 which yields an approximate frequency of 9520Hz.
LC81F		ldx #$40			; set low frequency of sliding tone to ~288Hz
		fcb $10
LC823		ldx #$80			; set low frequency of sliding tone to ~144Hz
		fcb $10
; sound 14
LC827		ldx #$100			; set low frequency of sliding tone to ~72Hz
		fcb $10
; sound 0
LC82B		ldx #$20			; set low frequency of sliding tone to ~566Hz
LC82E		bsr LC835			; do one square wave
		leax -1,x			; reduce delay (increase frequency)
		bne LC82E			; brif not yet reached maximum frequency
		rts
; Output a square wave with wave time defined by delay in X
LC835		lda #$ff			; (2~) hold DAC high for delay in X
		bsr LC869			; (7~)
		clra				; (2~) hold DAC low for delay in X
		bra LC869			; (3~)
; sound 3
; Output a series of 16 ascending tones with a base frequency descending from 14.5Hz to 9Hz.
LC83C		ldx #$500			; set for an ascending tone from 14.5Hz
LC83F		bsr LC835			; go make the sound
		leax $30,x			; decrease starting tone frequency by a bit
		cmpx #$800			; have we reached 9Hz?
		blo LC83F			; brif not
		rts
; sound 6
LC84A		lda #2
		skip2
; sound 8
LC84D		lda #1
		skip2
; sound 1
LC850		lda #10
		sta V262
LC854		ldy #$c0
LC858		bsr LC8CE
		bsr LC8C5
		leay -1,y
		bne LC858
		bsr LC8BA
		dec V262
		bne LC854
		rts
LC867		bsr LC8CE
LC869		bsr LC8C5			; (7~) program the DAC
		bra LC8BD			; (3~) count down delay non-destructively
; sound 21
LC86D		ldu #LDBDA
		bra LC893
; sound 20
LC872		ldu #LDBD2
		bra LC893
; sound 10, sound 11
LC877		lda #8
		sta V25F
LC87B		bsr LC8CE
		clra
		lsrb
		bne LC882
		incb
LC882		tfr d,x
		bsr LC82E
		dec V25F
		bne LC87B
; sound 22
LC88A		ldu #LDBD2
		bsr LC893
		bsr LC8BA
		leau 4,u
LC893		ldx ,u
LC895		ldy 2,u
LC898		bsr LC867
		leay -1,y
		bne LC898
		leax 2,x
		cmpx #$150
		bne LC895
		rts
; sound 16
LC8A6		jsr LC931
		fcb $80
LC8AA		bsr LC922
		bcs LC8B2
		bsr LC8C5
		bra LC8AA
; sound 17
LC8B2		jsr LC92E
		fcb $a0
LC8B6		bsr LC926
		bra LC8B6
LC8BA		ldx #$1000
LC8BD		pshs x				; (7~) save delay counter
LC8BF		leax -1,x			; (5~) has timer expired?
		bne LC8BF			; (3~) brif not
LC8C3		puls x,pc			; (9~) restore delay counter and return
LC8C5		ldb soundvol			; (5~) fetch volume multiplier for sound
		mul				; (11~) multiply it by the value we're trying to set
		anda #$fc			; (2~) lose the non-DAC bits
		sta PIA1			; (5~) set DAC
		rts				; (5~)
LC8CE		ldd V256
		lslb
		rola
		lslb
		rola
		addd V256
		incb
		std V256
		rts
; sound 15
LC8DA		bsr LC915
		fdb $6424
; sound 7
LC8DE		bsr LC915
		fdb $3212
; sound 4
LC8E2		bsr LC915
		fdb $AF36
; sound 19
LC8E6		bsr LC915
		fdb $1909
LC8EA		bsr LC92E
		fcb $60
LC8ED		ldx V263
		ldy V265
		clra
LC8F3		leax -1,x
		bne LC8FD
		ldx V263
		eora #$7f
		bsr LC90A
LC8FD		leay -1,y
		bne LC8F3
		ldy V265
		eora #$80
		bsr LC90A
		bra LC8F3
LC90A		sta V259
		bsr LC97E
		bls LC8C3			; skip the caller to this routine and return to its caller
		bsr LC8C5
		lda V259
		rts
; this routine doesn't return to the caller but to the caller's caller
LC915		ldx ,s++
		ldb ,x+
		clra
		std V263
		ldb ,x+
		std V265
		bra LC8EA
LC922		bsr LC8CE
		bra LC98D
LC926		bsr LC8CE
LC928		bsr LC97E
		bls LC8C3			; skip the caller to this routine and return to its caller
		bra LC8C5
LC92E		ldx allones
		fcb $10
LC931		ldx zero
LC933		stx V25B
		ldx ,s
		ldb ,x+
		clra
		std V25D
		stx ,s
		rts
; sound 18
LC93F		bsr LC92E
		fcb $60
LC942		jsr LC8CE
		lsra
		bsr LC928
		jsr LC8CE
		ora #$80
		bsr LC928
		bra LC942
; sound 2
LC951		ldx #$300
		fcb $10
; sound 5
LC955		ldx #$200
		fcb $10
; sound 9
LC959		ldx #$100
		stx V25D
		clra
		clrb
		std V25B
LC962		bsr LC922
		bcs LC971
		jsr LC8C5
		ldx #$f0
		jsr LC8BD
		bra LC962
LC971		bsr LC92E
		fcb $40
LC974		bsr LC926
		ldx #$60
		jsr LC8BD
		bra LC974
LC97E		pshs a
		ldd V25B
		subd V25D
LC984		pshs cc
		std V25B
		ldb 1,s
		mul
		puls cc,b,pc
LC98D		pshs a
		ldd V25B
		addd V25D
		bra LC984
; this is the swi routine offset table - each byte is the difference between the entry point
; of the previous routine and itself
LC995		fcb 0				; first routine has nothing before it
		fcb LC3A2-LC384
		fcb LC448-LC3A2
		fcb LC454-LC448
		fcb LC459-LC454
		fcb LC46F-LC459
		fcb LC472-LC46F
		fcb LC4CF-LC472
		fcb LC4F3-LC4CF
		fcb LC4F6-LC4F3
		fcb LC4FF-LC4F6
		fcb LC507-LC4FF
		fcb LC529-LC507
		fcb LC5D9-LC529
		fcb LC656-LC5D9
		fcb LC674-LC656
		fcb LC67F-LC674
		fcb LC686-LC67F
		fcb LC688-LC686
		fcb LC6A4-LC688
		fcb LC6A8-LC6A4
		fcb LC6C5-LC6A8
		fcb LC6E6-LC6C5
		fcb LC6FB-LC6E6
		fcb LC71F-LC6FB
		fcb LC743-LC71F
		fcb LC759-LC743
		fcb LC7C8-LC759
		fcb LC7D0-LC7C8
;***********************************************************************************************************
; The following code handles displaying text on the screen. It works as follows.
;
; The graphics screen is divided into a grid of character cells 32 columns wide by 24 rows high. Each cell
; is 8 pixels wide by 8 pixels high. Text can be rendered anywhere on the screen as long as it fits within
; a character cell. The cells line up on even bytes which makes actually rendering the characters fast.
;
; Characters are encoded in 5 bits as follows: A through Z are given codes 1 through 26. 0 is a space. 27
; is the exclamation point, 28 is the underscore, 29 is the question mark, and 30 is the period. Code 31
; is used as a carriage return. Codes 32 and 33 are the left and right parts of the contracted heart symbol
; while 34 and 35 are the left and right parts of the expanded heart symbol. 36 is backspace.
;
; Glyphs for codes 0 through 30 are encoded using the packed five bit encoding and are located at LDB1B. They
; are encoded in a 5 by 7 bitmap which is shifted to be offset one pixel from the left of the character cell
; upon decoding.
;
; The glyphs for the heart codes are in unpacked encoding and are located at LDBB6 and occupy the entire
; 8 bit width of the character cell.
;
; These routines expect a pointer to the text configuration parameters in U. At offset 0 is the start address
; of the scrollable area of the screen (memory address). At offset 2 is the ending character cell address of
; the scrollable area of the screen. At offset 4 is the current printing position. At offset 6 is a mask with
; all pixels set to the background colour. At offset 7 a flag which when nonzero inhibits rendering text to
; the secondary graphics screen area. For the ordinary command entry area at the bottom of the screen, this
; will point to V390.
LC9B2		cmpa #$24			; is it backspace?	
		beq LC9BF			; brif so
		cmpa #$1f			; vertical spacer?
		beq LC9CA			; brif so
		bsr LCA17			; go handle a glyph
		leax 1,x			; move to next character position
		rts				; return to caller
LC9BF		leax -1,x			; move display pointer back one
		cmpx allones			; did we wrap around negative?			
		bne LC9C9			; brif not
		ldx 2,u				; get end of text area
		leax -1,x			; move back one position to be in the text area
LC9C9		rts				; return to caller
LC9CA		leax $20,x			; move pointer forward one character row
		exg d,x				; move pointer so we can do math
		andb #$e0			; force pointer to the start of the line
		exg d,x				; put pointer back where it belongs
		rts				; return to caller
LC9D4		pshs a,b,x,y			; save registers
		ldx ,u				; get start of screen address
		ldd 2,u				; get end of text area
		subd #$20			; knock one character row off it
		std 2,s				; save new display location
		bsr LCA10			; multiply by 8 - 8 pixel rows per cell
		tfr d,y				; save counter
LC9E3		ldd $100,x			; get bytes 8 pixel rows ahead
		tst 7,u				; do we need to skip the second screen?
		bne LC9EF			; brif so
		std $1800,x			; save scroll data on second screen
LC9EF		std ,x++			; save scroll data and move pointer ahead
		leay -2,y			; are we done yet?
		bne LC9E3			; brif not
		ldb 6,u				; fetch current background colour
		sex				; and make A match
		ldy #$100			; number of bytes to blank bottom row
LC9FC		tst 7,u				; are we doing second screen too?
		bne LCA04			; brif not
		std $1800,x			; blank pixels in second screen
LCA04		std ,x++			; blank pixels and move pointer forward
		leay -2,y			; are we done yet?
		bne LC9FC			; brif not
		puls a,b,x,y,pc			; restore registers and return
LCA0C		lslb				;* enter here to shift D left 5 bits
		rola				;*
		lslb				;*
		rola				;*
LCA10		lslb				;* enter here to shift D left 3 bits
		rola				;*
LCA12		lslb				;* enter here to shift D left 2 bits
		rola				;*
		lslb				;*
		rola				;*
		rts
LCA17		pshs a,b,x,y,u			; save registers
		cmpa #$20			; is it a printing character?
		blo LCA29			; brif so
		suba #$20			; mask off printing characters
		ldb #7				; 7 bytes per font table entry
		mul				; get offset in table
		addd #LDBB6			; add in base address of table
		tfr d,x				; put font pointer somewhere useful
		bra LCA44			; go draw glyph
LCA29		ldb #5				; 5 bytes per font table entry
		mul				; get offset in table
		addd #LDB1B			; add in base address of table
		tfr d,x				; put pointer somewhere useful
		ldu #fontbuf			; point to buffer to decode glyph data
		decodestr			; go decode a packed string
		ldx #fontbuf+7			; point one past end of buffer
LCA39		lsl ,-x				;* centre glyph data in byte
		lsl ,x				;*
		cmpx #fontbuf			; at start of buffer?
		bhi LCA39			; brif not - keep centring
		ldu 6,s				; get back U value
LCA44		ldd 4,u				; get display address location
		bsr LCA10			; multiply by 8 - gets start of row in 11..8
		lsrb				;* and divide lsb by 8 again to get offset within
		lsrb				;* the row to bits 4..0
		lsrb				;* and force to top of character cell
		addd ,u				; add in start of text area
		tfr d,y				; put pointer somewhere useful
		ldb #7				; seven bytes to copy
LCA51		lda ,x+				; get byte from font data
		eora 6,u			; merge with background colour
		sta ,y				; save it on the screen
		tst 7,u				; do we need to update second screen?
		bne LCA5F			; brif not
		sta $1800,y			; save pixels on second screen
LCA5F		leay $20,y			; move display pointer down one pixel row
		decb				; are we done yet?
		bne LCA51			; brif not - do another
		puls a,b,x,y,u,pc		; restore registers and return
; This routine divides a 16 bit unsigned value in D by a 16 bit unsigned value in X. The result
; will be in D with the binary point to the right of A.
LCA67		pshs a,b,x			; make hole for result and save divisor
		clr ,s				;* initialize quotient
		clr 1,s				;*
		clr V2C1			; use V2C1 for extra precision on dividend
		std V2C2			; save dividend
		beq LCA97			; brif dividend is zero - nothing to do
		cmpd 2,s			; is dividend equal to divisor?
		bne LCA7C			; brif not
		inc ,s				; set quotient to 1.0
		bra LCA97			; go return
LCA7C		ldx #16				; we need to do 16 iterations
LCA7F		lsl V2C3			;* shift dividend
		rol V2C2			;*
		rol V2C1			;*
		lsl 1,s				;= shift quotient
		rol ,s				;=
		ldd V2C1			; get dividend high word
		subd 2,s			; subtract out divisor
		bcs LCA93			; brif it doesn't go
		std V2C1			; save new dividend residue
		inc 1,s				; record the fact that it went
LCA93		leax -1,x			; have we done all 16 bits?
		bne LCA7F			; brif not
LCA97		puls a,b,x,pc			; fetch result, restore registers, and return
LCA99		coma				;* do a one's complement of D
		comb				;*
		addd #1				; adding 1 turns it into negation
		rts				; return to caller
LCA9F		pshs a,b,x			; save registers
		ldx pixelcount			; get number of pixels to draw
		ldd ,s				; get the difference
		bpl LCAAE			; brif positive
		bsr LCA99			; negate difference
		bsr LCA67			; divide by number of pixels
		bsr LCA99			; negate the result
		skip2				; skip next instruction
LCAAE		bsr LCA67			; divide by number of pixels
		std ,s				; save step value
		puls a,b,x,pc			; restore registers and return
LCAB4		jmp LCB8A			; go return from the line drawing routine
; Draw a line from (xbeg,ybeg) to (xend,yend) respecting the light level in the dungeon (lightlevel)
; which is used as a step count between when to actually draw pixels.
;
; Variables used:
; lightlevel	the current light level in the dungeon
; lightcount	how many pixels left before we actually draw another
; ybeg		input start Y
; xbeg		input start X
; yend		input end Y
; xend		input end X
; xcur		X coordinate of pixel to be drawn (24 bits with 8 bits after binary point)
; ycur		U cpprdomate of pixel to be drawn (24 bits with 8 bits after binary point)
; xpstep	24 bit X coordinate difference (per pixel)
; ypstep	24 bit Y coordinate difference (per pixel)
; pixelcount	number of pixels to draw in the line
; xbstep	the offset for when X coordinate goes to a new byte
; xystep	the offset for when Y coordinate goes to a new line
; drawstart	the start address of the graphics screen area the line is within
; drawend	the end address of the graphics screen area the line is within
; V2C1		a temporary scratch variable
;
; Note: ypstep+1 and xpstep+1 are also used as temporary holding values for the
; integer difference in the Y and X coordinates respectively.
drawline	pshs a,b,x,y,u			; save registers
		inc lightlevel			; are we completely dark?
		beq LCAB4			; brif so - we can short circuit drawing entirely
		lda lightlevel			; get light level in dungeon
		sta lightcount			; save in working count (skip count for pixel drawing)
		ldd xend			; get end X coordinate
		subd xbeg			; subtract start X coordinate
		std xpstep+1			; save coordinate difference
		bpl LCACB			; brif positive difference
		bsr LCA99			; negate the difference
LCACB		std pixelcount			; save absolute value of X difference as pixel count
		ldd yend			; get end Y coordinate
		subd ybeg			; subtract start Y coordinate
		std ypstep+1			; save coordinate difference
		bpl LCAD7			; brif positive difference
		bsr LCA99			; negate the difference
LCAD7		cmpd pixelcount			; is the Y difference bigger than X?
		blt LCAE0			; brif not
		std pixelcount			; save Y difference as pixel count
		beq LCAB4			; brif no pixels to draw - short circuit
LCAE0		ldd xpstep+1			; get X difference
		bsr LCA9F			; calculate X stepping value
		std xpstep+1			; save X stepping value
		tfr a,b				; save msb of difference
		sex				; sign extend it
		ldb #1				; X stepping value - 1 for ascending
		sta xpstep			; sign extend stepping difference to 24 bits
		bpl LCAF0			; brif positive
		negb				; set stepping value to -1
LCAF0		stb xbstep			; save X byte stepping value
		ldd ypstep+1			; get Y difference
		bsr LCA9F			; calculate Y step value
		std ypstep+1			; save result
		tfr a,b				; save msb of difference
		sex				; sign extend it
		ldb #$20			; Y byte stepping value - 32 bytes per line, ascending
		sta ypstep			; sign extend the difference to 24 bits
		bpl LCB02			; brif positive
		negb				; negate the difference - -32 bytes per line, descending
LCB02		stb xystep			; save Y byte stepping value
		ldd xbeg			; get start X coordinate
		std xcur			; save in X coordinate counter
		ldd ybeg			; get start Y coordinate
		std ycur			; save in Y coordinate counter
		lda #$80			; value for low 8 bits to make the values ".5"
		sta xcur+2			; set X coordinate to ".5"
		sta ycur+2			; set Y coordinate to ".5"
		ldx 2,u				; get end of graphics area address
		stx drawend			; save it for later
		ldx ,u				; get start of graphics area address
		stx drawstart			; save it for later
		ldd ycur			; get Y coordinate for pixel
		jsr LCA0C			; shift left 5 bits - 32 bytes per row
		leax d,x			; add to screen start address
		ldd xcur			; get X coordinate for pixel
		jsr LD37F			; shift right 3 bits - 8 pixels per byte
		leax d,x			; add to row start address
		ldu #LCB8E			; point to table of pixel masks
		ldy pixelcount			; get number of pixels to draw
LCB2E		dec lightcount			; are we ready to draw another pixel (due to light level)?
		bne LCB54			; brif not
		lda lightlevel			; get light level
		sta lightcount			; reset current "pixel delay"
		tst xcur			; is X coordinate off the right of the screen?
		bne LCB54			; brif so
		cmpx drawstart			; is the pixel address before the start of the graphics area?
		blo LCB54			; brif so
		cmpx drawend			; is the pixel address after the end of the graphics area?
		bhs LCB54			; brif so
		ldb xcur+1			; get X coordinate lsb
		andb #7				; mask off low 3 bits for offset in byte
		lda b,u				; get pixel mask to use
		tst levbgmask			; currently using black background?
		beq LCB50			; brif so
		coma				; invert mask for white background
		anda ,x				; merge in existing graphics data
		skip2				; skip next instruction
LCB50		ora ,x				; merge in existing graphics data (black background)
		sta ,x				; save new graphics data on the screen
LCB54		lda xcur+1			; get X coordinate lsb
		anda #$f8			; mask off the pixel offset in the byte
		sta V2C1			; save it for later
		ldd xcur+1			; get X coordinate low bits
		addd xpstep+1			; add in X difference
		std xcur+1			; save new low bits for X coordinate
		ldb xcur			; get X coordinate high bits
		adcb xpstep			; add in difference high bits
		stb xcur			; save new X coordinate high bits
		anda #$f8			; mask off pixel offset in data byte
		cmpa V2C1			; are we in the same byte?
		beq LCB70			; brif so
		ldb xbstep			; get byte X step value 
		leax b,x			; move pointer appropriately
LCB70		ldd ycur+1			; get Y coord low bits
		sta V2C1			; save screen Y coordinate
		addd ypstep+1			; add in Y step value low bits
		std ycur+1			; save new low bits
		ldb ycur			; get Y coord high bits
		adcb ypstep			; add in Y step value high bits
		stb ycur			; save new Y coord high bits
		cmpa V2C1			; are we on the same scren row?
		beq LCB86			; brif so
		ldb xystep			; get Y byte step value
		leax b,x			; move pointer appropriately
LCB86		leay -1,y			; have we drawn all the pixels?
		bne LCB2E			; brif not - draw another
LCB8A		dec lightlevel			; compensate for "inc" above
		puls a,b,x,y,u,pc		; restore registers and return
LCB8E		fcb $80,$40,$20,$10		; pixels 0, 1, 2, 3 (left to right) in byte
		fcb $08,$04,$02,$01		; pixels 4, 5, 6, 7 (left to right) in byte
LCB96		pshs a,x,u			; save registers
		ldx V211			; get input buffer/line pointer
		ldu #wordbuff			; point to word buffer
LCB9D		lda ,x+				; get character from input
		beq LCB9D			; brif end of line
		bra LCBA5			; get on with things
LCBA3		lda ,x+				; get new character from input
LCBA5		ble LCBAF			; brif not valid character
		sta ,u+				; save filename character
		cmpu #V333			; are we at the end of the buffer?
		blo LCBA3			; brif not - check another
LCBAF		lda #$ff			; put end of word marker
		sta ,u+
		stx V211			; save new input pointer location
		tst wordbuff			; set flags for whether we have a word
		puls a,x,u,pc			; restore registers and return
; Parse an object from command line
parseobj	clr parsegenobj			; flag generic object type
		ldx #kwlist_obj			; point to object type list
		bsr LCBEC			; look up word in object type list
		bmi parseobj000			; brif no match - try matching specific type
		beq badcommandret		; brif no match - error out
		std parseobjtype		; save object type matched
		rts				; return to caller
parseobj000	dec parsegenobj			; flag specific object type found
		ldx #kwlist_adj			; point to specific object types
		bsr LCBE7			; look up word in object type list
		ble badcommandret		; brif no match
		std parseobjtype		; save object type
		ldx #kwlist_obj			; point to generic object types
		bsr LCBEC			; look up keyword
		ble badcommandret		; brif no match
		cmpb parseobjtypegen		; did the object type match?
		bne badcommandret		; brif not
		rts				; return to caller
badcommandret	leas 2,s			; don't return to caller - we're bailing out
badcommand	renderstrimmp			; display "???" for unknown command
		fcb $17,$7b,$d0			; packed "???" string
		rts				; return to caller's caller
LCBE7		pshs a,b,x,y,u			; save registers
		clra				; initialize specific type to zero
		bra LCBF4			; go look up keyword
LCBEC		pshs a,b,x,y,u			; save registers
		clra				; initialize specific type to zero
		clrb				; initialize generic type to zero
		bsr LCB96			; parse a word from the input line
		bmi LCC2D			; brif no word present
LCBF4		clr V278			; flag no match
		clr V27B			; 
		ldb ,x+				; fetch number of keywords in list
		stb V279			; save it in temp counter
LCBFC		ldu #wordbuff			; point to decode buffer
		decodestrsb			; decode the keyword string
		ldy #stringbuf+1		; point to decoded keyword string (past the object code)
LCC05		ldb ,u+				; get a character from word string
		bmi LCC17			; brif end of string
		cmpb ,y+			; does it match?
		bne LCC22			; brif not
		tst ,y				; are we at the end of the keyword?
		bpl LCC05			; brif not
		tst ,u				; are we at the end of the word?
		bpl LCC22			; brif not
LCC15		dec V27B
LCC17		tst V278			; do we already have a match?
		bne LCC2B			; brif so
		inc V278			; mark match found
		ldb stringbuf			; get the keyword code
		std ,s				; save keyword number and object code
LCC22		inca				; bump keyword count
		dec V279			; have we reached the end of the list?
		bne LCBFC			; brif not - check another keyword
		tst V278			; do we have a match?
		bne LCC2F			; brif so
LCC2B		ldd allones			; flag error (-1)
LCC2D		std ,s				; save result
LCC2F		puls a,b,x,y,u,pc		; restore registers and return value, return
LCC31		ldx #kwlist_dir			; point to direction keywords
		bsr LCBEC			; evaluate the specified keyword
		ble badcommandret		; brif no matching keyword
		ldu #righthand			; point to right hand contents
		cmpa #1				; is it right hand wanted?
		beq LCC46			; brif so - return pointer
		ldu #lefthand			; point to left hand contents
		cmpa #0				; is it left hand wanted?
		bne badcommandret		; brif not - error
LCC46		ldx ,u				; fetch object pointer to X (and set Z if nothing)
		rts
LCC49		pshs a,b,x,u			; save coordinates and registers
		deca				; look at rooms to the NE, N, NW
		bsr LCC56
		inca				; look at rooms to the E, W, <here>
		bsr LCC56
		inca				; look at rooms to the SE, S, SW
		bsr LCC56
		puls a,b,x,u,pc			; restore registers and return
LCC56		pshs a,b			; save coordinates
		decb				; look at room to W
		bsr LCC60
		incb				; look at room <here>
		bsr LCC60
		incb				; look at room E
		skip2				; skip next instruction
LCC60		pshs a,b			; save coordinates
		bsr LCC8E			; did we fall off side of map?
		bne LCC6B			; brif so
		bsr LCC7B			; get pointer to room data
		lda ,x				; fetch room data
		skip2				; skip instruction
LCC6B		lda #$ff			; flag no tunnel
		sta ,u+				; save data for this room
		puls a,b,pc			; save registers and return
LCC71		getrandom			; get a random number
		anda #$1f			; convert it to 0-31
		tfr a,b				; save it
		getrandom			; get another random number
		anda #$1f			; also convert it to 0-31
LCC7B		pshs a,b			; save coordinates
		anda #$1f			; force coordinates to range 0-31
		andb #$1f
		tfr d,x				; save coordinates for later
		ldb #32				; 32 rooms per row
		mul				; calculate row offset
		addd #mazedata			; convert to absolute pointer
		exg d,x				; get pointer to X, get back coordinates
		abx				; add offset within row
		puls a,b,pc			; restore coordinates and return pointer in X
LCC8E		pshs a,b			; save coordinates
		anda #$1f			; modulo the Y coordinate
		cmpa ,s				; does it match?
		bne LCC9A			; brif not - fell off side
		andb #$1f			; modulo the X coordinate
		cmpb 1,s			; does it match? (set flags)
LCC9A		puls a,b,pc			; return Z set if not falling off side of map
; This routine creates a maze for the specified level number.
createmaze	ldx #mazedata			; get start address to set to $ff
		ldu #mazedata+1024		; get end address
		setblock			; go set block to $ff
		ldx #levelseeds			; point to level seeds table
		ldb currentlevel		; fetch current level
		abx				; offset into table (the seeds overlap!)
		ldd ,x++			; fetch first two bytes of level seed
		std randomseed			; set random seed
		lda ,x				; fetch third byte of level seed
		sta randomseed+2		; set random seed
		ldy #500			; dig out 500 rooms
		jsr LCC71			; fetch a random starting point
		std V27C			; save starting pointer
LCCBB		getrandom			; get random number
		anda #3				; select only 4 directions
		sta V28A			; save direction we're going
		getrandom			; get random number
		anda #7				; convert to value from 1-8
		inca
		sta V27E			; save number of steps to dig out
		bra LCCD2			; go dig the tunnel
LCCCA		ldd V288			; get current coordinate
		std V27C			; save it as starting position
		dec V27E			; have we gone far enough?
		beq LCCBB			; brif so - select a new direction
LCCD2		ldd V27C			; fetch maze coordinates
		jsr LD11B			; apply direction to coordinates
		bsr LCC8E			; did we fall off the side of the map?
		bne LCCBB			; brif so - select a new direction
		std V288			; save new coordinate
		tst ,x				; is this room open?
		beq LCCCA			; brif so - move to next
		ldu #V9F4			; point to temporary storage area
		jsr LCC49			; set bytes to FF or 00 depending on whether the rooms in the 3x3 area are open
		lda 3,u				; get W room
		adda ,u				; add data for NW room
		adda 1,u			; add data for N room
		beq LCCBB			; brif all open - get new direction
		lda 1,u				; get data for N room
		adda 2,u			; add data for NE room
		adda 5,u			; add data for E room
		beq LCCBB			; brif all open - get new direction
		lda 5,u				; get data for E room
		adda 8,u			; add data for SE room
		adda 7,u			; add data for S room
		beq LCCBB			; brif all open - get new direction
		lda 7,u				; get data for S room
		adda 6,u			; add data for SW room
		adda 3,u			; add data for W room
		beq LCCBB			; brif all open - get new direction
		clr ,x				; mark this room open
		leay -1,y			; have we dug out enough rooms?
		bne LCCCA			; brif not - keep digging
		clr V27C			; set coordinates to top left
		clr V27D
LCD11		ldd V27C			; get current coordinates
		jsr LCC7B			; convert to pointer
		lda ,x				; get room data
		inca				; is ot open?
		beq LCD41			; brif not
		ldd V27C			; get coordinates
		ldu #V9F4			; point to temp area
		jsr LCC49			; calculate neighbors
		lda ,x				; get room data at current room
		ldb #$ff			; data for "no room"
		cmpb 1,u			; is there a room N?
		bne LCD2D			; brif so
		ora #3				; flag as no exit N
LCD2D		cmpb 3,u			; is there a room W?
		bne LCD33			; brif so
		ora #$c0			; flag as no exit W
LCD33		cmpb 5,u			; is there a room E
		bne LCD39			; brif so
		ora #$0c			; flag as no exit E
LCD39		cmpb 7,u			; is there a room S?
		bne LCD3F			; brif so
		ora #$30			; flag as no exit S
LCD3F		sta ,x				; save adjusted room data
LCD41		ldb #32				; 32 rooms per row
		inc V27D			; bump X coordinate
		cmpb V27D			; did we wrap?
		bne LCD11			; brif not
		clr V27D			; reset to left edge
		inc V27C			; bump Y coordinate
		cmpb V27C			; did we wrap?
		bne LCD11			; brif not - fix another room's exits
		ldb #70				; create 70 doors
		ldu #doormasks			; pointer to routine to make a normal door
LC056		bsr LCD6D			; go create a door
		decb				; are we done yet?
		bne LC056			; brif not
		ldb #$2d			; create 45 magic doors
		ldu #mdoormasks			; pointer to routine to make a magic door
LCD60		bsr LCD6D			; go create a door
		decb				; done yet?
		bne LCD60			; brif not
		ldb V297			; get number of times to spin the random number generator
LCD67		getrandom			; fetch a random number
		decb				; have we done enough randoms?
		bne LCD67			; brif not, do another
		rts				; return to caller
LCD6D		pshs a,b,x,y,u			; save registers
		ldy #dirmasks			; point to direction masks
LCD73		jsr LCC71			; get a random location
		std V288			; save coordinates
		ldb ,x				; get room data at location
		cmpb #$ff			; is there a room?
		beq LCD73			; brif not - try again
		getrandom			; get random number
		anda #3				; normalize to direction
		sta V28A			; save direction
		bitb a,y			; is there a door or wall at that direction?
		bne LCD73			; brif so - try again
		orb a,u				; mark the direction as having a door of desired type
		stb ,x				; save new room data
		ldd V288			; get back coordinates
		jsr LD11B			; get pointer to neighbor
		ldb V28A			; get direction back
		addb #2				; calculate opposite direction
		andb #3
		lda ,x				; get data at neighboring room
		ora b,u				; set it to the right type of door
		sta ,x				; save new neighbor data
		puls a,b,x,y,u,pc		; restore data and return
; These are the random seeds for the level mazes. Note that the seeds overlap by two
; bytes. The actual seed values are:
; Level 1: 73c75d
; Level 2: c75d97
; Level 3: 5d97f3
; Level 4: 97f313
; Level 5: f31387
levelseeds	fcb $73,$c7,$5d,$97,$f3,$13,$87
dirmasks	fcb $03,$0c,$30,$c0		; direction masks
doormasks	fcb $01,$04,$10,$40		; direction masks to create doors
mdoormasks	fcb $02,$08,$20,$80		; direction masks to create magic doors
; This routine draws the display for a scroll.
;
; If V294 is set to nonzero, it displays creature and object information (SEER SCROLL)
; otherwise it shows only the maze, holes, and player location (VISION SCROLL).
;
; V27C is used as a temporary scratch counter for displaying the maze itself.
displayscroll	ldu screendraw			; point to screen we're using to draw on
		ldd #$1f1f			; maximum X and Y coordinates
		std V27C			; save coordinates
LCDB9		ldd V27C			; fetch current coordinates
		bsr LCE11			; calculate absolute pointer to screen location
		jsr LCC7B			; fetch pointer to room data
		clrb				; initialize to black
		lda ,x				; fetch room data
		inca				; is it an empty room?
		bne LCDC7			; brif not
		decb				; set to white
LCDC7		lda #6				; set 6 rows
LCDC9		stb ,y				; set a row
		leay $20,y			; move to next row
		deca				; done all rows?
		bne LCDC9			; brif not
		dec V27D			; move left one space
		bpl LCDB9			; brif not at left yet
		lda #$1f			; max right coord
		sta V27D			; reset X coordinate to far right
		dec V27C			; move back a row
		bpl LCDB9			; brif still in map
		tst V294			; are we showing creatures and objects?
		beq LCE2B			; brif not
		clr V291			; start iteration from scratch
LCDE3		jsr LCF63			; go fetch object
		beq LCDF7			; brif no more objects
		tst 5,x				; is the object equipped/carried?
		bne LCDE3			; brif so
		ldd 2,x				; get coordinates of object
		bsr LCE11			; get absolute address of location
		ldd #8				; object location symbol
		bsr LCE1D			; display symbol
		bra LCDE3			; go check another object
LCDF7		ldx #V3D4-17			; point to creature table
LCDFA		leax $11,x			; move to next creature
		cmpx #mazedata			; are we at the end of the creature table?
		beq LCE2B			; brif so
		tst 12,x			; is creature alive?
		beq LCDFA			; brif not
		ldd 15,x			; get current creature location
		bsr LCE11			; turn location into pointer
		ldd #$1054			; symbol for creature
		bsr LCE1D			; go display symbol
		bra LCDFA			; go check another creature
LCE11		tfr d,y				; save requested coordinates
		ldb #$c0			; calculate row offset based on display height of 6 px
		mul				; now we have the offset from the start of the screen
		addd ,u				; now D has the absolute address of the start of the line
		exg d,y				; put pointer in Y and get back coordinates
		leay b,y			; offset in the X direction for real pointer
		rts				; return to caller
LCE1D		sta $20,y			; set top row of symbol
		stb $40,y			; set second row of symbol
		stb $60,y			; set third row of symbol
		sta $80,y			; set bottom row of symbol
LCE2A		rts				; return to caller
LCE2B		ldd playerloc			; get current player position
		bsr LCE11			; calculate absolute address
		ldd #$2418			; bit patterns to create a *
		bsr LCE1D			; go mark the player position
		ldx holetabptr			; point to the hole table for this level
		bsr LCE38			; go display holes going up then fall through for holes going down
LCE38		lda ,x+				; get hole type flag
		bmi LCE2A			; brif end of this table (return)
		ldd ,x++			; get coordinates
		bsr LCE11			; calculate absolute address
		ldd #$3c24			; symbol for displaying a hole
		bsr LCE1D			; go display symbol
		bra LCE38			; go check another entry
LCE47		pshs a,x
		ldx #LCF48
		tst V273
		bne LCE5C
		leax >1,x
		tst V274
LCE56		bne LCE5C
		leax $fff5,x
LCE5C		lda V28B
		lda a,x
		sta V24F
		sta V250
		puls a,x,pc
LCE66		cleargfx2
		clr V28B
		ldd playerloc
		std V27C
LCE6E		bsr LCE47
		ldd V27C
		jsr LCC7B
		lda ,x
		ldu #V9F4
		ldx #4
LCE7D		tfr a,b
		andb #3
		stb 4,u
		stb ,u+
		lsra
		lsra
		leax -1,x
		bne LCE7D
		ldb V223
		ldu #V9F4
		leau b,u
		ldy #LDBDE
LCE96		lda ,y+
		bmi LCED8
		ldb a,u
		lslb
		cmpb #4
		bne LCEA9
		ldx b,y
		dec V275
		bsr LCECE
		ldb #6
LCEA9		ldx b,y
		bsr LCECE
		leay 8,y
		bra LCE96
LCEB1		rts
LCEB2		tfr x,y
		tst b,u
		bne LCEB1
		addb V223
		stb V28A
		ldd V27C
		jsr LD11B
		jsr LCF82
		beq LCEB1
		exg x,y
LCEC8		tst 2,y
		beq LCECE
		dec V275
LCECE		pshs u
		dod S00
		ldu screendraw
		drawgraphic
		puls u,pc
LCED8		ldd V27C
		jsr LCF82
		beq LCEEB
		tfr x,y
		ldb 13,y
		lslb
		ldx #LDAA3
		ldx b,x
		bsr LCEC8
LCEEB		ldb #3
		ldx #LDCB0
		bsr LCEB2
		ldb #1
		ldx #LDCB9
		bsr LCEB2
		ldx #LDD3C
		ldd V27C
		jsr LCFE1
		bmi LCF09
		ldx #LDCC2
		lsla
		ldx a,x
LCF09		bsr LCECE
		clr V291
LCF0D		ldd V27C
		jsr LCF53
		beq LCF24
		lda 10,x
		lsla
		ldx #LD9EE
		ldx a,x
		dec V275
		bsr LCECE
		bsr LCECE
		bra LCF0D
LCF24		tst ,u
		bne LCF3D
		lda V223
		sta V28A
		ldd V27C
		jsr LD11B
		std V27C
		inc V28B
		lda V28B
		cmpa #9
		lble LCE6E
LCF3D		rts
LCF3E		fcb $c8,$80,$50,$32
		fcb $1f,$14
LCF44		fcb $0c,$08,$04,$02
LCF48		fcb $ff,$9c,$64,$41
		fcb $28,$1a,$10,$0a
LCF50		fcb $06,$03,$01
LCF53		bsr LCF63
		beq LCF62
		cmpd 2,x
		bne LCF53
		tst 5,x
		bne LCF53
		andcc #$fb
LCF62		rts
LCF63		pshs a				; save register
		lda currentlevel		; fetch current level
		ldx V292			; fetch object pointer
		tst V291			; are we starting at beginning?
		bne LCF72			; brif not
		ldx #objecttab-14		; point to start of table
		dec V291			; mark not at beginning any more
LCF72		leax 14,x			; move to next object
		stx V292			; save object pointer for iteration
		cmpx objectfree			; are we at the end of the table?
		beq LCF80			; brif so - return
		cmpa 4,x			; is the object on this level?
		bne LCF72			; brif not - look for another object
		andcc #$fb			; turn off Z flag for object found
LCF80		puls a,pc			; restore registers and return
LCF82		ldx #V3D4-17
LCF85		leax $11,x
		cmpx #mazedata
		beq LCF96
		cmpd 15,x
		bne LCF85
		tst 12,x
		beq LCF85
LCF96		rts
LCF97		pshs a,b,x
LCF99		jsr LCC71
		std ,s
		lda ,x
		inca
		beq LCF99
		puls a,b,x,pc
LCFA5		pshs a,b,x,y,u
LCFA7		ldu #V3D4-17
LCFAA		leau $11,u
		tst 12,u
		bne LCFAA
		dec 12,u
		sta 13,u
		ldb #8
		mul
		addd #LDABB
		tfr d,y
		tfr u,x
		lda #8
		jsr LC04B
LCFC4		bsr LCF97
		bsr LCF82
		bne LCFC4
		std 15,u
		tfr u,x
		jsr LC25C
		stx 5,u
		ldd #LD041
		std 3,u
		lda 6,x
		ldb #4
		jsr LC21D
		puls a,b,x,y,u,pc
LCFE1		pshs a,b,x,u
		ldu holetabptr
		bsr LCFF2
		tsta
		bpl LCFEE
		bsr LCFF2
		adda #2
LCFEE		sta ,s
		puls a,b,x,u,pc
LCFF2		lda ,u+
		bmi LCFFC
		ldx ,u++
		cmpx 2,s
		bne LCFF2
LCFFC		rts
; This is the "hole/ladder" table. Each entry is suffixed by $80. Each set specifies the
; holes and ladders between two levels. The first is between levels 1 and 2. The second is
; between levels 2 and 3. And so on. You will not that the table includes references to
; level 0 (above the dungeon) and level 6 (below the dungeon) - they are simply empty
; table entries which prevents having to have special cases to handle them.
holetab		fcb $80				; marker for end of "level 0" to level 1
		fcb 1,0,23
		fcb 0,15,4
		fcb 0,20,17
		fcb 1,28,30
		fcb $80				; marker for end of level 1-2
		fcb 1,2,3
		fcb 0,3,31
		fcb 0,19,20
		fcb 0,31,0
		fcb $80				; marker for end of level 2-3
		fcb $80				; marker for end of level 3-4
		fcb 0,0,31
		fcb 0,5,0
		fcb 0,20,28
		fcb 0,31,16
		fcb $80				; marker for end of level 4-5
		fcb $80				; marker for end of level 5-6
LD027		ldx creaturecountptr
		ldb #11
		clra
LD02C		adda b,x
		decb
		bpl LD02C
		cmpa #$20
		bhs LD03D
		getrandom
		anda #7
		adda #2
		inc a,x
LD03D		ldd #$0508
		rts
LD041		ldy 5,u
		tst creaturefreeze
		bne LD06A
		ldb 12,y
		bne LD04D
		rts
LD04D		lda 13,y
		cmpa #6
		beq LD06D
		cmpa #10
		bge LD06D
		ldd 15,y
		clr V291
		jsr LCF53
		beq LD06D
		ldd 8,y
		stx 8,y
		std ,x
		dec 5,x
		dod S0E
LD06A		jmp LD103
LD06D		ldd 15,y
		cmpd playerloc
		bne LD0B2
		lda 13,y
		ldb #$ff
		playsound
		ldd #$8080
		ldx lefthand
		bsr LD09E
		ldx righthand
		bsr LD09E
		sta V21A
		stb V21C
		tfr y,x
		ldu #powerlevel
		jsr LD3D7
		bmi LD099
		playsoundimm $13
		jsr LD40C
LD099		dod S0C
		jmp LD10F
LD09E		pshs a,b,x
		beq LD0B0
		lda 10,x
		cmpa #3
		bne LD0B0
		ldx 6,x
		cmpx ,s
		bhs LD0B0
		stx ,s
LD0B0		puls a,b,x,pc
LD0B2		cmpa playerloc
		bne LD0C3
		lda 16,y
		ldb #1
		suba playerloc+1
		bmi LD0D0
		ldb #3
		bra LD0D0
LD0C3		ldd 15,y
		cmpb playerloc+1
		bne LD0E4
		ldb #2
		suba playerloc
		bmi LD0D0
		clrb
LD0D0		stb V28A
		ldd 15,y
LD0D4		bsr LD136
		bne LD0E4
		cmpd playerloc
		bne LD0D4
		ldb V28A
		stb 14,y
		clrb
		bra LD101
LD0E4		ldx #LD114
		getrandom
		tsta
		bmi LD0EE
		leax 3,x
LD0EE		anda #3
		bne LD0F4
		leax 1,x
LD0F4		lda #3
LD0F6		ldb ,x+
		bsr LD14F
		beq LD103
		deca
		bne LD0F6
		ldb #2
LD101		bsr LD14F
LD103		lda 6,y
		ldx 15,y
		cmpx playerloc
		bne LD111
		dod S0E
		clr V2B5
LD10F		lda 7,y
LD111		ldb #4
		rts
LD114		fcb $00,$03,$01,$00
		fcb $01,$03,$00		
LD11B		pshs a,b			; save coordinates
		ldb V28A			; get direction to move
		andb #3				; force it to 0-3
		lslb				; two bytes per direction adjuster
		ldx #LD12E			; point to direction adjusters
		ldd b,x				; get adjuster
		adda ,s+			; apply north/south adjustment
		addb ,s+			; apply east/west adjustment
		jmp LCC7B			; convert to pointer in X
LD12E		fdb $ff00			; move north (-1, 0)
		fdb 1				; move east (0, +1)
		fdb $100			; move south (+1, 0)
		fdb $ff				; move west (0, -1)
LD136		pshs a,b,x,y,u
		bsr LD11B
		jsr LCC8E
		bne LD14D
		tfr d,u
		lda ,x
		inca
		beq LD14C
		stu ,s
		stx 2,s
		lda #1
LD14C		deca
LD14D		puls a,b,x,y,u,pc
LD14F		pshs a,b,x
		addb 14,y
		andb #3
		stb V28A
		ldd 15,y
		bsr LD136
		bne LD199
		jsr LCF82
		bne LD199
		std 15,y
		ldb V28A
		stb 14,y
		ldd 15,y
		suba playerloc
		bpl LD16F
		nega
LD16F		subb playerloc+1
		bpl LD174
		negb
LD174		stb V2C1
		cmpa V2C1
		bge LD17C
		exg a,b
LD17C		sta V2C1
		cmpa #8
		bgt LD198
		cmpb #2
		bgt LD198
		getrandom
		bita #1
		beq LD196
		lda V2C1
		ldb #$1f
		mul
		comb
		lda 13,y
		playsound
LD196		dec V2B5
LD198		clra
LD199		puls a,b,x,pc
LD19B		ldu curtorch
		beq LD1BC
		lda 6,u
		beq LD1BC
		deca
		sta 6,u
		cmpa #5
		bgt LD1B0
		ldb #$18
		stb 9,u
		clr 11,u
LD1B0		cmpa 7,u
		bge LD1B6
		sta 7,u
LD1B6		cmpa 8,u
		bge LD1BC
		sta 8,u
LD1BC		dec V2B5
		ldd #$0108
		rts
LD1C2		tst V2B5
		bne LD1CD
		ldx #displayscroll
		cmpx displayptr
		bne LD1D1
LD1CD		clr V2B5
		dod S0E
LD1D1		ldd #$0304
		rts
LD1D5		clra
		clrb
		subd damagelevel
		jsr LD379
		addd damagelevel
		bgt LD1E2
		clra
		clrb
LD1E2		std damagelevel
		dod S0C
		lda V2AF
		ldb #2
		rts
LD1EB		tst waitnewgame
		bne LD21B
LD1EF		jsr readkeybuf
		tsta
		beq LD248
		tst nokeyboard
		bne LD1EF
		cmpa #$20
		beq LD215
		ldb #$1f
		cmpa #$0d
		beq LD212
		ldb #$24
		cmpa #8
		beq LD212
		clrb
		cmpa #$41
		blo LD212
		cmpa #$5a
		bls LD215
LD212		tfr b,a
		skip2
LD215		anda #$1f
		bsr LD24C
		bra LD1EF
LD21B		ldy V20D			; fetch pointer to command sequence
		ldb ,y+				; do we have a command to do?
		bpl LD229			; brif so
		delay				; wait for a bit
		delay				; wait for a bit more
		jmp START			; go start over again with the splash and demo
LD229		ldx ,y++			; get pointer to the word
		ldu #V361			; point to command decode buffer
		decodestr			; decode the keyword
		leau 1,u			; move past the "object type" flag
		delay				; wait a bit
		skip2				; skip next instruction
LD235		bsr LD24C
		lda ,u+				; fetch a character from the decoded string
		bpl LD235			; brif not end of string
		clra				; code for a space
		bsr LD24C			
		decb				; have we consumed all the words in this command?
		bne LD229			; brif not - get another
		lda #$1f			; code for carriage return
		bsr LD24C
		sty V20D			; save new command stream pointer
LD248		ldd #$0102
		rts
LD24C		pshs a,b,x,y,u
		tst V2AD
		bne LD256
		dod S19
		showprompt
LD256		ldu V211
		cmpa #$1f
		beq LD26F
		cmpa #$24
		beq LD27D
		renderchar
		sta ,u+
		ldx #LC67C
		renderstr
		cmpu #V311
		bne LD2B4
LD26F		clra
		renderchar
		ldd allones
		std ,u++
		ldu #V2F1
		stu V211
		bra LD292
LD27D		cmpu #V2F1
		beq LD2B4
		leau -1,u
		ldx #LD28C
		renderstr
		bra LD2B4
LD28C		fcb $00,$24,$24,$1c
		fcb $24,$ff
LD292		ldx #kwlist_cmd
		jsr LCBEC
		beq LD2A7
		bpl LD2A1
		jsr badcommand
		bra LD2A7
LD2A1		lsla
		ldx #LD9D0
		jsr [a,x]
LD2A7		ldu #V2F1
		tst V2AD
		beq LD2B4
		tst nokeyboard
		bne LD2B4
		showprompt
LD2B4		stu V211
		puls a,b,x,y,u,pc
cmd_attack	jsr LCC31			; get pointer to specified hand
		ldu ,u				; fetch item in specified hand
		bne LD2C2			; brif item there
		ldu #emptyhand			; point to data for emtpy hand
LD2C2		tfr u,y				; save object data pointer
		lda 12,u			
		sta V219
		lda 13,u
		sta V21B
		adda V219			; calculate sum of magical and physical damage
		rora				; divide by 8
		lsra
		lsra
		ldx powerlevel			; fetch current player power
		jsr applyscale			; apply the scale factor calculated above
		addd damagelevel		; apply the wielding cost to play damage
		std damagelevel			; save new damage value
		lda 10,u			; get object type
		adda #12			; offset into sound table
		ldb #$ff			; set full volume
		playsound			; play the attack sound for the object
		lda 9,u				; get object subtype
		cmpa #$13			; is it less than "ENERGY"?
		blt LD2F7			; brif so - not an expiring ring
		cmpa #$15			; is it more than "FIRE"?
		bgt LD2F7			; brif so - not an expiring ring
		dec 6,u				; count down ring usages
		bne LD2F7			; brif not used up
		lda #$16			; type for "GOLD"
		sta 9,u				; set to GOLD ring
		jsr LD638			; update object stats appropriately
LD2F7		ldd playerloc
		jsr LCF82
		beq LD375
		ldu #powerlevel
		exg x,u
		lda 10,y			; fetch object type
		cmpa #1				; is it a ring?
		beq LD31F			; go do successful attack if so - rings never miss
		jsr LD3D7
		bmi LD375
		ldy curtorch			; do we have a torch burning?
		beq LD319			; brif not
		lda 9,y				; get torch type
		cmpa #$18			; is it "DEAD"?
		bne LD31F			; brif not
LD319		getrandom			; get random number
		anda #3				; 1 in 4 chance of a hit in the dark
		bne LD375			; brif we didn't hit
LD31F		playsoundimm $12		; play the "HIT" sound
		renderstrimmp			; display the "!!!" for a successful hit
		fcb $16,$f7,$b0			; packed "!!!" string
		jsr LD40C			; calculate damage, apply to victim
		bhi LD375
		leax 8,u
LD32E		ldx ,x
		beq LD33A
		clr 5,x
		ldd 15,u
		std 2,x
		bra LD32E
LD33A		ldx creaturecountptr		; point to creature count table for this level
		ldb 13,u			; get type of creature killed
		dec b,x				; reduce number of this creature type
		clr 12,u			
		dod S0E
		playsoundimm $15		; play the "kill" sound
		ldd ,u				; fetch creature power level
		bsr LD37F			; divide by 8
		addd powerlevel			; add gained power to current power level
		bpl LD351			; brif power level did not overflow
		lda #$7f			; maximize power level at 32767
LD351		std powerlevel			; save adjusted power level for player
		lda 13,u			; get the dead creature type
		cmpa #10			; is dead creature wizard's image?
		beq LD386			; brif so - do the annoyed wizard
		cmpa #11			; is dead creature the wizard?
		bne LD375			; brif not
		dec creaturefreeze		; stop the creatures
		ldd #$713			; constants for physical light 7, magical light 19
		std baselight			; set base light level in dungeon
		ldx #objecttab+14		; pointer to second object slot in object table
		stx objectfree			; mark end of object table at just past first object
		ldd zero			; NULL pointer
		std backpack			; mark backpack empty
		std curtorch			; mark no torch burning
		std righthand			; mark right hand empty
		std lefthand			; mark left hand empty
		dod S19
LD375		dod S0C
LD377		asra
		rorb
LD379		asra
		rorb
LD37B		asra
		rorb
LD37D		asra
		rorb
LD37F		asra
		rorb
LD381		asra
		rorb
LD383		asra
		rorb
		rts
LD386		ldx #img_wizard			; point to Wizard graphic
		fadeinclrst			; fade in the wizard
		renderstrimmp			; dipslay "ENOUGH! I TIRE OF THIS PLAY..."
		fcb $ff,$c0,$57,$3e		; packed string "ENOUGH! I TIRE OF THIS PLAY..."
		fcb $a7,$46,$c0,$90
		fcb $51,$32,$28,$1e
		fcb $60,$51,$09,$98
		fcb $20,$c0,$e7,$de
		fcb $f0
		renderstrimmp			; also display "PREPARE TO MEET THY DOOM!!!"
		fcb $e8,$00,$08,$48		; packed string "PREPARE TO MEET THY DOOM!!!"
		fcb $b0,$0c,$8a,$0a
		fcb $3c,$0d,$29,$68
		fcb $0a,$23,$20,$23
		fcb $de,$dd,$ef,$60
		delay				; delay a bit
		ldu curtorch			; fetch current torch
		stu backpack			; put it in the backpack
		beq LD3C4			; brif no torch
		clra				; make sure the torch is the only thing in the backpack
		clrb
		std ,u
LD3C4		ldd #200			; set player carry weight to 200
		std carryweight
		lda #3				
		dod S1A
		jsr LCF97
		std playerloc
		fadeout				; fade out the wizard
		dod S19
		rts
LD3D7		pshs a,b,x,u
		lda #15
		sta V2C1
		ldd ,u
		subd 10,u
		jsr LCA12
LD3E4		subd ,x
		bcs LD3EC
		dec V2C1
		bne LD3E4
LD3EC		ldb V2C1
		subb #3
		bpl LD3FB
		negb
		lda #$19
		mul
		jsr LCA99
		bra LD3FE
LD3FB		lda #10
		mul
LD3FE		std ,--s
		getrandom
		tfr a,b
		clra
		addd ,s++
		subd #$7f
		puls a,b,x,u,pc
LD40C		pshs a,b,x,y,u
		tfr x,y
		ldx ,y
		lda 2,y
		bsr applyscale
		tfr d,x
		lda 3,u
		bsr applyscale
		addd 10,u
		std 10,u
		ldx ,y
		lda 4,y
		bsr applyscale
		tfr d,x
		lda 5,u
		bsr applyscale
		addd 10,u
		std 10,u
		ldx ,u
		cmpx 10,u
		puls a,b,x,y,u,pc
; Multiply X by the value in A, where the binary point in A is to the left of bit 6. Return only the
; integer result in D (rounded down).
applyscale	pshs a,b,x			; save parameters and registers
		clr V2C1			; blank out temp storage area
		ldb 3,s				; get LSB of X
		mul				; multiply LSB
		std V2C2			; save in scratch variable
		lda ,s				; fetch muliplier
		ldb 2,s				; fetch MSB of X
		mul				; multiply it
		addd V2C1			; add in partial product
		lsl V2C3			;* shift product left so binary point is to the right of
		rolb				;* of the upper 16 bits - leave interger result in D.
		rola
		std ,s				; save integer result for return
		puls a,b,x,pc			; clean up parameters, fetch product, and return
cmd_climb	ldd playerloc
		jsr LCFE1
		bmi LD46F
		sta V2C1
		ldx #kwlist_dir
		jsr LCBEC
		ble LD46F
		ldb V2C1
		cmpa #4
		beq LD472
		cmpa #5
		bne LD46F
		lda #1
		bitb #2
		bne LD478
LD46F		jmp badcommand
LD472		lda #$ff
		cmpb #1
		bne LD46F
LD478		showprepare
		adda currentlevel
		dod S1A
		dod S19
		rts
cmd_examine	ldx #LD495			; pointer to the inventory display routine
		stx displayptr			; set up the display update routine
		dod S0E				; update the display
		rts
LD489		cleargfx2			; clear graphics
		ldx ,u
		ldu #V380
		stx ,u
		dec V2B7			; set to nonstandard text rendering
		rts
LD495		bsr LD489			; clear the graphics area and set up for text rendering
		clr V2B6			; flag column zero in object list
		ldd #10				; set up to centre "IN THIS ROOM"
		std 4,u
		renderstrimmp			; show the "IN THIS ROOM" heading
		fcb $62,$5c,$0a,$21		; packed string "IN THIS ROOM"
		fcb $33,$04,$9e,$f6
		fcb $fc
		ldd playerloc
		jsr LCF82
		beq LD4C0
		ldx 4,u
		leax 11,x
		stx 4,u
		renderstrimmp			; show the "!CREATURE!" string if a creature is present
		fcb $56,$c7,$22,$86		; packed string "!CREATURE!"
		fcb $95,$91,$77,$f0
LD4C0		clr V291
LD4C2		ldd playerloc
		jsr LCF53
		beq LD4CD
		bsr LD505
		bra LD4C2
LD4CD		tst V2B6
		beq LD4D3
		bsr LD4FE
LD4D3		ldd #$1b20			; set up for displaying a row of !!!!
LD4D6		renderchar			; display a !
		decb				; done enough of them?
		bne LD4D6			; brif not
		ldx 4,u				; set up to centre "BACKPACK"
		leax 12,x
		stx 4,u
		renderstrimmp			; display "BACKPACK" heading
		fcb $40,$82,$35,$c0		; packed string "BACKPACK"
		fcb $23,$5f,$c0
		ldx #backpack			; point to backpack head pointer
LD4ED		ldx ,x				; get next item in backpack
		beq LD4FB			; brif nothing else in backpack
		cmpx curtorch			; is the object the currently burning torch?			
		bne LD4F7			; brif not
		com 6,u				; invert video if it is
LD4F7		bsr LD505			; display ojbect name
		bra LD4ED			; go display another object
LD4FB		clr V2B7			; reset to standard text rendering
		rts
LD4FE		lda #$1f			; character code for newline
		renderchar			; go move to next line
		clr V2B6			; flag column 1
		rts
LD505		pshs a,b,x			; save registers
		jsr LC617			; fetch object name string (decoded)
		renderstr			; display object name
		lda levbgmask			; restore the proper text coloring
		sta 6,u
		com V2B6			; are we on column 1 or 2?
		beq LD51E			; brif back at column 1
		ldd 4,u				; get cursor position
		addd #$10			; move right 16 cells
		andb #$f0			; round down to multiple of 16
		std 4,u				; save new cursor position
		skip2				; move on with routine
LD51E		bsr LD4FE			; do a newline
		puls a,b,x,pc			; restore registers and return
cmd_get		bsr LD576
		bne LD573
		jsr parseobj
		clr V291
LD52B		ldd playerloc
		jsr LCF53
		beq LD573
		tst parsegenobj
		bne LD53C
		lda 10,x
		cmpa parseobjtypegen
		bra LD540
LD53C		lda 9,x
		cmpa parseobjtype
LD540		bne LD52B
		stx ,u
		inc 5,x
		ldb 10,x
		ldx #LD9FA
		ldb b,x
		clra
		bra LD56B
cmd_drop	bsr LD576
		beq LD573
		clra
		clrb
		std ,u
		clr 5,x
		ldd playerloc
		std 2,x
		lda currentlevel
		sta 4,x
		ldb 10,x
		ldx #LD9FA
		ldb b,x
		negb
		sex
LD56B		addd carryweight
		std carryweight
		dod S0C
		bra LD5B7
LD573		jmp badcommand
LD576		jmp LCC31
cmd_stow	bsr LD576			; get pointer to object in requested hand
		beq LD573			; brif no object in the hand
LD57D		ldd backpack			; add this item to the start of the backpack list
		std ,x
		stx backpack
		clra				; mark the selected hand as empty
		clrb
		std ,u
		bra LD5B7			; update status line, etc.
cmd_pull	bsr LD576			; fetch pointer to object in specified hand
		bne LD573			; brif there is something in that hand
		jsr parseobj			; parse object name
		ldx #backpack			; point to backpack head pointer
LD593		tfr x,y				; save previous pointer location
		ldx ,x				; fetch pointer to next item
		beq LD573			; brif end of list
		tst parsegenobj			; is a specific object type requested?
		bne LD5A3			; brif so
		lda 10,x			; get object type (general) requested
		cmpa parseobjtypegen		; does the object match?
		bra LD5A7			; finish up the loop
LD5A3		lda 9,x				; get object type (specific) requested
		cmpa parseobjtype		; does it match requested object type?
LD5A7		bne LD593			; brif not matching object
		ldd ,x				; get next pointer
		std ,y				; put in previous next pointer (remove from backpack)
		stx ,u				; save object in the specified hand
LD5AF		clra				; set up NULL pointer
		clrb
		cmpx curtorch			; is this object the current torch?
		bne LD5B7			; brif not
		std curtorch			; turn off current torch
LD5B7		updatestatus			; update status line to reflect new hand contents
		dod S0E
		rts
cmd_incant	ldx #kwlist_adj
		jsr LCBEC
		ble LD5EF
		tst V27B
		beq LD5EF
		std parseobjtype
		ldu lefthand
		bsr LD5D0
		ldu righthand
LD5D0		beq LD5EF
		lda 10,u
		cmpa #1
		bne LD5EF
		lda 7,u
		beq LD5EF
		cmpa parseobjtype
		bne LD5EF
		sta 9,u
		setobjectspecs
		playsoundimm $0D
		updatestatus
		clr 7,u
		cmpa #$12
		beq LD5F0
LD5EF		rts
LD5F0		ldx #img_goodwiz
		dec V29E
		fadeinclrst
		renderstrimmp
		fcb $ff,$c4,$54,$3d		; packed string victory message line 1
		fcb $84,$d8,$08,$59
		fcb $D1,$2e,$c8,$03
		fcb $70,$a6,$93,$05
		fcb $10,$50,$20,$2e
		fcb $20
		renderstrimmp
		fcb $c8,$00,$00,$00		; packed string victory message line 2
		fcb $00,$03,$cc,$00
		fcb $81,$c5,$b8,$2e
		fcb $9d,$06,$44,$f7
		fcb $bc
LD621		bra LD621
cmd_reveal	jsr LCC31
		ldu ,u
		beq LD63E
		lda 11,u
		beq LD63E
		ldb #$19
		mul
		cmpd powerlevel
		bgt LD63E
		lda 9,u
LD638		setobjectspecs
		clr 11,u
		updatestatus
LD63E		rts
cmd_turn	ldx #kwlist_dir
		jsr LCBEC
		ble LD693
		ldb V223
		cmpa #0
		bne LD654
		decb
		bsr LD66D
		bsr LD674
		bra LD669
LD654		cmpa #1
		bne LD65D
		incb
		bsr LD66D
		bra LD667
LD65D		cmpa #3
		bne LD693
		addb #2
		bsr LD66D
		bsr LD684
LD667		bsr LD684
LD669		dec pageswap			; set graoguc swao required
		sync				; wait for swap to happen
		rts
LD66D		andb #3
		stb V223
		jmp LC660
LD674		bsr LD696
		bne LD683
		ldd #8
LD67B		bsr LD6BA
		addd #$20
		tsta
		beq LD67B
LD683		rts
LD684		bsr LD696
		bne LD692
		ldd #$f8
LD68B		bsr LD6BA
		subd #$20
		bpl LD68B
LD692		rts
LD693		jmp badcommand
LD696		ldu displayptr
		cmpu #LCE66
		bne LD6B9
		ldx #$8080
		stx V24F
		clr V28B
		dod S00
		cleargfx1
		ldx #LD6C6
		drawgraphic
		ldx #$11
		stx ybeg
		ldx #$87
		stx yend
		clra
LD6B9		rts
LD6BA		std xbeg
		std xend
		bsr LD6C0
LD6C0		jsr drawline
		com levbgmask
		rts
LD6C6		fcb $10,$00,$10,$ff
		fcb $ff,$88,$00,$88
		fcb $ff,$fe
cmd_move	ldx #kwlist_dir
		jsr LCBEC
		blt LD693
		bgt LD6E3
		dec V273
		dod S0E
		clrb
		clr V273
		bra LD6EF
LD6E3		cmpa #2
		bne LD6F3
		dec V274
		dod S0E
		ldb #2
		clr V274
LD6EF		bsr LD720
		bra LD70E
LD6F3		cmpa #1
		bne LD701
		ldb #1
		bsr LD720
		bne LD70E
		bsr LD684
		bra LD70E
LD701		cmpa #0
		bne LD693
		ldb #3
		bsr LD720
		bne LD70E
		jsr LD674
LD70E		ldd carryweight
		jsr LD37F
		addd #3
		addd damagelevel
		std damagelevel
		dod S0C
		dec pageswap			; set graphics swap required
		sync				; wait for swap to happen
		rts
LD720		pshs a,b
		clr ,-s
		addb V223
		andb #3
		stb V28A
		ldd playerloc
		jsr LD136
		beq LD738
		playsoundimm $14
		dec ,s
		ldd playerloc
LD738		std playerloc
		jsr LC660
		tst ,s+
		puls a,b,pc
cmd_use		jsr LCC31			; fetch pointer to object in specified hand
		beq LD767			; brif nothing in the hand
		ldd 9,x				; fetch object type and subtype
		cmpb #5				; is it a torch?
		bne LD757			; brif not
		stx curtorch			; set object as currently mounted
		jsr LD57D			; go place the object in the backpack
		playsoundimm $11		; play the torch sound
		dod S0E
		rts
LD757		tfr x,u				; save object pointer
		ldx #LD76B			; point to jump table
LD75C		cmpa ,x				; does the sub type match?
		beq LD768			; brif so
		leax 3,x			; move to next entry
		cmpx #LD77A			; end of table?
		blo LD75C			; brif not - try another
LD767		rts				; no match - do nothing
LD768		jmp [1,x]			; transfer control to specified routine
LD76B		fcb $05				; "THEWS" (thews flask)
		fdb LD77A
		fcb $09				; "HALE" (hale flask)
		fdb LD783
		fcb $08				; "ABYE" (abye flask)
		fdb LD787
		fcb $04				; "SEER" (seer scroll)
		fdb LD7A2
		fcb $07				; "VISION" (vision scroll)
		fdb LD7A0
LD77A		ldd #1000			; thews increases player power by 1000
		addd powerlevel			; add to existing power value
		std powerlevel			; save new power value
		bra LD792			; go empty the flask and update things
LD783		clra				; new damage level = 0
		clrb
		bra LD790			; go set damage level and clean up flask
LD787		ldx powerlevel			; fetch player power level
		lda #$66			; roughly 0.8
		jsr applyscale			; go calculate 80% of player power level
		addd damagelevel		; add that to the current damage level
LD790		std damagelevel			; save new damage level
LD792		ldb #$17			; type for "EMPTY"
		stb 9,u				; change flask to EMPTY
		clr 11,u
		playsoundimm $0c		; play the flask sound
		updatestatus			; update status line to reflect changed flask state
		dod S0C
		rts
LD7A0		clra				; flag for not showing creatures
		skip2				; skip over next instruction
LD7A2		lda #$ff			; flag for do show creatures
		sta V294			; set creature display flag
		tst 11,u
		bne LD7B6
		playsoundimm $0e		; play the scroll sound
		clr V2AD
		ldx #displayscroll		; point to scroll display routine
		stx displayptr			; set the display handler
		dod S0E
LD7B6		rts
cmd_zload	bsr LD7BC			; parse the file name
		dec V2B8			; flag ZLOAD
		rts
LD7BC		ldx #wordbuff			; get start address to set to $ff
		leau $20,x			; set $20 bytes
		setblock			; go clear block to $ff
		jmp LCB96
cmd_zsave	bsr LD7BC			; parse the file name
		stx CBUFAD			
		ldd #$0f
		std BLKTYP
		inc V2B8			; flag ZSAVE
		rts
; Objects in backpack for demo game
startobjdemo	fcb 13				; iron sword
		fcb 15				; pine torch
		fcb 16				; leather shield
		fcb $ff				; end of list
; Objects in backpack for normal game
startobj	fcb 17				; wooden sword
		fcb 15				; pine torch
		fcb $ff				; end of list
LD7DC		fdb LD1EB
		fdb LD1C2
		fdb LD1D5
		fdb LD19B
		fdb LD027
		fdb 0
; cold start variable initializers
LD7E8		fcb 12
		fdb $103
		jmp LC371
		jmp LC352
		jmp LC27D
		jmp LC27D
		fcb $17
		fdb V202
		fcb $01				; V202
		fdb $ffff			; allones - 16 bit all ones value, or -1
		fcb $00				; V205
		fcb $80				; V206
		fcb 0				; V207
		fcb $4c				; V208
		fdb LD870			; screenvis - pointer to primary display screen info
		fdb LD876			; screendraw - pointer to secondary display screen info
		fdb demogame			; V20D - pointer to demo game command sequence
		fdb objecttab			; objectfree - next free object entry
		fdb V2F1			; V211
		fcb 12,22			; playerloc - starting coordinates in maze (y, x)
		fdb $23				; carryweight - the weight of objects the player is carrying
		fdb $17a0			; powerlevel - player power level
		fcb $54	
		fdb V380
		fdb $1000			; V380 - text area starts at top of screen
		fdb $0260			; V382 - text area ends after 19 lines
		fdb 0				; V384 - text cursor position at top of screen
		fcb 0				; V386 - black background
		fcb $ff				; V387 - do not render on secondary screen
		fdb $2300			; V388 - text area starts at row 19 on screen
		fdb $40				; V38A - text area goes for two lines
		fdb 0				; V38C - text cursor is at top of area
		fcb $ff				; V38E - background is white
		fcb 0				; V38F - do render on secondary screen
		fdb $2400			; V390 - text area starts at row 20 on screen
		fdb $80				; V392 - text area goes for four lines
		fdb 0				; V394 - text cursor is at top of area
		fcb 0				; V396 - background is black
		fcb 0				; V397 - do render on secondary screen
		fcb 9,9,4,2,0,0,0,0,0,0,0,0	; initial creature counts for level 1
		fcb 2,4,0,6,6,6,0,0,0,0,0,0	; initial creature counts for level 2
		fcb 0,0,0,4,0,6,8,4,0,0,1,0	; initial creature counts for level 3
		fcb 0,0,0,0,0,0,8,6,6,4,0,0	; initial creature counts for level 4
		fcb 2,2,2,2,2,2,2,4,4,8,0,1	; initial creature counts for level 5
		fcb 4
		fdb emptyhand+10
		fcb $04,$00,$00,$05		; empty hand attack data
		fcb 0

; these tables are used for clearing and otherwise setting up the graphics screens
LD870		fdb $1000			; primary screen start address
		fdb $2300			; primary screen gfx area end address
		fdb $2046			; primary screen SAM register value
LD876		fdb $2800			; secondary screen start address
		fdb $3b00			; secondary screen gfx area end address
		fdb $20a6			; secondary screen SAM register value
LD87C		fdb $2300			; start address of status line on first screen
		fdb $2400			; end address of status line on first screen
		fdb 0				; dummy (SAM regster setting)
		fdb $3b00			; start address of status line on second screen
		fdb $3c00			; end address of status line on second screen
		fdb 0				; dummy (SAM register setting)
LD888		fdb $2400			; start address of command area on first screen
		fdb $2800			; end address of command area on first screen
		fdb 0				; dummy (SAM register setting)
		fdb $3c00			; start address of command area on second screen
		fdb $4000			; end address of command area on second screen
		fdb 0				; dummy (SAM register setting)

; This is the keyword table used for command parsing. Each keyword is stored in packed format.
; Each keyword is preceded by a value which indicates the object type. Where the object type is
; not relevant, that value will be zero. The value is shown in parentheses below.
kwlist_cmd	fcb 15				; 15 keywords in the command list
kw_attack	fcb $30,$03,$4a,$04,$6b		; "ATTACK" keyword
		fcb $28,$06,$c4,$b4,$40		; "CLIMB" keyword
		fcb $20,$09,$27,$c0		; "DROP" keyword
kw_examine	fcb $38,$0b,$80,$b5,$2e,$28	; "EXAMINE" keyword
		fcb $18,$0e,$5a,$00		; "GET" keyword
		fcb $30,$12,$e1,$85,$d4		; "INCANT" keyword
kw_look		fcb $20,$18,$f7,$ac		; "LOOK" keyword
kw_move		fcb $20,$1A,$fb,$14		; "MOVE" keyword
kw_pull		fcb $20,$21,$56,$30		; "PULL" keyword
		fcb $30,$24,$5b,$14,$2c		; "REVEAL" keyword
		fcb $20,$27,$47,$dc		; "STOW" keyword
kw_turn		fcb $20,$29,$59,$38		; "TURN" keyword
kw_use		fcb $18,$2b,$32,$80		; "USE" keyword
		fcb $28,$34,$c7,$84,$80		; "ZLOAD" keyword
		fcb $28,$35,$30,$d8,$a0		; "ZSAVE" keyword
kwlist_dir	fcb 6				; 6 keywords in direction list
kw_left		fcb $20,$18,$53,$50		; "LEFT" keyword
kw_right	fcb $28,$24,$93,$a2,$80		; "RIGHT" keyword
		fcb $20,$04,$11,$ac		; "BACK" keyword
		fcb $30,$03,$27,$d5,$c4		; "AROUND" keyword		
		fcb $10,$2b,$00			; "UP" keyword
		fcb $20,$08,$fb,$b8		; "DOWN" keyword
kwlist_adj	fcb 25				; 25 keywords in the misc keywords list
kw_supreme	fcb $38,$67,$58,$48,$ad,$28	; "SUPREME" keyword (1)
		fcb $28,$54,$fa,$b0,$a0		; "JOULE" keyword (1)
		fcb $31,$0a,$cb,$26,$68		; "ELVISH" keyword (4)
		fcb $38,$da,$9a,$22,$49,$60	; "MITHRIL" keyword (3)
		fcb $20,$a6,$52,$c8		; "SEER" keyword (2)
		fcb $28,$28,$82,$de,$60		; "THEWS" keyword (0)
		fcb $20,$64,$96,$94		; "RIME" keyword (1)
		fcb $30,$ac,$99,$a5,$ee		; "VISION" keyword (2)
		fcb $20,$02,$2c,$94		; "ABYE" keyword (0)
		fcb $20,$10,$16,$14		; "HALE" keyword (0)
		fcb $29,$66,$f6,$06,$40		; "SOLAR" keyword (5)
		fcb $30,$c5,$27,$bb,$45		; "BRONZE" keyword (3)
		fcb $30,$6d,$56,$0c,$2e		; "VULCAN" keyword (1)
		fcb $21,$13,$27,$b8		; "IRON" keyword (4)
		fcb $29,$59,$57,$06,$40		; "LUNAR" keyword (5)
		fcb $21,$60,$97,$14		; "PINE" keyword (5)
		fcb $38,$d8,$50,$d1,$05,$90	; "LEATHER" keyword (3)
		fcb $31,$2e,$f7,$90,$ae		; "WOODEN" keyword (4)
		fcb $28,$4c,$97,$05,$80		; "FINAL" keyword (1)
		fcb $30,$4a,$e2,$c8,$f9		; "ENERGY" keyword (1)
		fcb $18,$52,$32,$80		; "ICE" keyword (1)
		fcb $20,$4c,$99,$14		; "FIRE" keyword (1)
		fcb $20,$4e,$f6,$10		; "GOLD" keyword (1)
		fcb $28,$0a,$d8,$53,$20		; "EMPTY" keyword (0)
		fcb $21,$48,$50,$90		; "DEAD" keyword (5)
kwlist_obj	fcb 6				; 6 object types in the following list
kw_flask	fcb $28,$0c,$c0,$cd,$60		; "FLASK" keyword (0)
		fcb $20,$64,$97,$1c		; "RING" keyword (1)
		fcb $30,$a6,$39,$3d,$8c		; "SCROLL" keyword (2)
kw_shield	fcb $30,$e6,$84,$95,$84		; "SHIELD" keyword (3)
kw_sword	fcb $29,$27,$77,$c8,$80		; "SWORD" keyword (4)
kw_torch	fcb $29,$68,$f9,$0d,$00		; "TORCH" keyword (5)
; The following is the sequence of commands used in the demo game
demogame	fcb 1				; EXAMINE
		fdb kw_examine
		fcb 3				; PULL RIGHT TORCH
		fdb kw_pull
		fdb kw_right
		fdb kw_torch
		fcb 2				; USE RIGHT
		fdb kw_use
		fdb kw_right
		fcb 1				; LOOK
		fdb kw_look
		fcb 1				; MOVE
		fdb kw_move
		fcb 3				; PULL LEFT SHIELD
		fdb kw_pull
		fdb kw_left
		fdb kw_shield
		fcb 3				; PULL RIGHT SWORD
		fdb kw_pull
		fdb kw_right
		fdb kw_sword
		fcb 1				; MOVE
		fdb kw_move
		fcb 1				; MOVE
		fdb kw_move
		fcb 2				; ATTACK RIGHT
		fdb kw_attack
		fdb kw_right
		fcb 2				; TURN RIGHT
		fdb kw_turn
		fdb kw_right
		fcb 1				; MOVE
		fdb kw_move
		fcb 1				; MOVE
		fdb kw_move
		fcb 1				; MOVE
		fdb kw_move
		fcb 2				; TURN RIGHT
		fdb kw_turn
		fdb kw_right
		fcb 1				; MOVE
		fdb kw_move
		fcb 1				; MOVE
		fdb kw_move
		fcb $ff
; jump table for commands
LD9D0		fdb cmd_attack			; ATTACK
		fdb cmd_climb			; CLIMB
		fdb cmd_drop			; DROP
		fdb cmd_examine			; EXAMINE
		fdb cmd_get			; GET
		fdb cmd_incant			; INCANT
		fdb cmd_look			; LOOK
		fdb cmd_move			; MOVE
		fdb cmd_pull			; PULL
		fdb cmd_reveal			; REVEAL
		fdb cmd_stow			; STOW
		fdb cmd_turn			; TURN
		fdb cmd_use			; USE
		fdb cmd_zload			; ZLOAD
		fdb cmd_zsave			; ZSAVE
; pointers to the image data for object types
LD9EE		fdb img_flask			; flask
		fdb img_ring			; ring
		fdb img_scroll			; scroll
		fdb img_shield			; shield
		fdb img_sword			; sword
		fdb img_torch			; torch

LD9FA		fcb $05,$01

LD9FC		fcb $0A,$19,$19,$0A
; This is the object data table. Each entry is four bytes as follows:
; 0	object type
; 1	reveal strength required
; 2	magical offense multiplier	
; 3	physical offense multiplier
objspecs	fcb $01,$FF,$00,$05		; supreme ring
		fcb $01,$AA,$00,$05		; joule ring
		fcb $04,$96,$40,$40		; elvish sword
		fcb $03,$8C,$0D,$1A		; mithril shield
		fcb $02,$82,$00,$05		; seer scroll
		fcb $00,$46,$00,$05		; thews flask
		fcb $01,$34,$00,$05		; rime ring
		fcb $02,$32,$00,$05		; vision scroll
		fcb $00,$30,$00,$05		; abye flask
		fcb $00,$28,$00,$05		; hale flask
		fcb $05,$46,$00,$05		; solar torch
		fcb $03,$19,$00,$1A		; bronze shield
		fcb $01,$0D,$00,$05		; vulcan ring
		fcb $04,$0D,$00,$28		; iron sword
		fcb $05,$19,$00,$05		; lunar torch
		fcb $05,$05,$00,$05		; pine torch
		fcb $03,$05,$00,$0A		; leather shield
		fcb $04,$05,$00,$10		; wooden sword
		fcb $01,$00,$00,$00		; final ring
		fcb $01,$00,$FF,$FF		; energy ring
		fcb $01,$00,$FF,$FF		; ice ring
		fcb $01,$00,$FF,$FF		; fire ring
		fcb $01,$00,$00,$05		; gold ring
		fcb $00,$00,$00,$05		; empty flask
		fcb $05,$05,$00,$05		; dead torch
; This table has additional object data including ring charges, etc, organized as follows:
; 0	object number
; 1	burn time (torch), charges (ring), magical defense (shield)
; 2	physical light (torch), physical defense (shield)
; 3	magical ight (torch)
objextraspecs	fcb $00,$03,$12,$00		; supreme ring
		fcb $01,$03,$13,$00		; joule ring
		fcb $03,$40,$40,$00		; mithril shield
		fcb $06,$03,$14,$00		; rime ring
		fcb $0A,$3C,$0D,$0B		; solar torch
		fcb $0B,$60,$80,$00		; bronze shield
		fcb $0C,$03,$15,$00		; vulcan ring
		fcb $0E,$1E,$0A,$04		; lunar torch
		fcb $0F,$0F,$07,$00		; pine torch
		fcb $10,$6C,$80,$00		; leather shield
		fcb $18,$00,$00,$00		; dead torch
		fcb $FF				; end of table

LDA91		fcb $41,$31,$31

LDA94		fcb $32,$23,$23,$11
LDA98		fcb $13,$16,$14,$14
LDA9C		fcb $16,$01,$04,$08
LDAA0		fcb $08,$03,$04

; pointers to creature images
LDAA3		fdb LDE26
		fdb LDFCA
		fdb LDD41
		fdb LDE59
		fdb LDE82
		fdb LDD51
		fdb LDE3F
		fdb LDE9D
		fdb LDE07
		fdb LDDA3
		fdb img_wizardgen
		fdb img_wizard

LDABB		fcb $00

LDABC		fcb $20,$00,$FF,$80
LDAC0		fcb $FF,$17,$0B,$00
LDAC4		fcb $38,$00,$FF,$50
LDAC8		fcb $80,$0F,$07,$00
LDACC		fcb $C8,$00,$FF,$34
LDAD0		fcb $C0,$1D,$17,$01
LDAD4		fcb $30,$00,$FF,$60
LDAD8		fcb $A7,$1F,$1F,$01
LDADC		fcb $F8,$00,$80,$60
LDAE0		fcb $3C,$0D,$07,$02
LDAE4		fcb $C0,$00,$80,$80
LDAE8		fcb $30,$11,$0D,$01
LDAEC		fcb $90,$FF,$80,$FF
LDAF0		fcb $80,$05,$04,$03
LDAF4		fcb $20,$00,$40,$FF
LDAF8		fcb $08,$0D,$07,$03
LDAFC		fcb $20,$C0,$10,$C0
LDB00		fcb $08,$03,$03,$03
LDB04		fcb $E8,$FF,$05,$FF
LDB08		fcb $03,$04,$03,$03
LDB0C		fcb $E8,$FF,$06,$FF
LDB10		fcb $00,$0D,$07,$1F
LDB14		fcb $40,$FF,$06,$FF
LDB18		fcb $00,$0D,$07

; This is the text font - these values are in packed format
LDB1B		fcb $30,$00,$00,$00,$00		; char code 0 - space
		fcb $31,$15,$18,$fe,$31		; char code 1 - A
		fcb $37,$a3,$1f,$46,$3e		; char code 2 - B
		fcb $33,$a3,$08,$42,$2e		; char code 3 - C
		fcb $37,$a3,$18,$c6,$3e		; char code 4 - D	
		fcb $37,$e1,$0f,$42,$1f		; char code 5 - E
		fcb $37,$e1,$0f,$42,$10		; char code 6 - F
		fcb $33,$e3,$08,$4e,$2f		; char code 7 - G
		fcb $34,$63,$1f,$c6,$31		; char code 8 - H
		fcb $33,$88,$42,$10,$8e		; char code 9 - I
		fcb $30,$42,$10,$86,$2e		; char code 10 - J
		fcb $34,$65,$4c,$52,$51		; char code 11 - K
		fcb $34,$21,$08,$42,$1f		; char code 12 - L
		fcb $34,$77,$5a,$d6,$31		; char code 13 - M
		fcb $34,$63,$9a,$ce,$31		; char code 14 - N
		fcb $33,$a3,$18,$c6,$2e		; char code 15 - O
		fcb $37,$a3,$1f,$42,$10		; char code 16 - P
		fcb $33,$a3,$18,$d6,$4d		; char code 17 - Q
		fcb $37,$a3,$1f,$52,$51		; char code 18 - R
		fcb $33,$a3,$07,$06,$2e		; char code 19 - S
		fcb $37,$ea,$42,$10,$84		; char code 20 - T
		fcb $34,$63,$18,$c6,$2e		; char code 21 - U
		fcb $34,$63,$15,$28,$84		; char code 22 - V
		fcb $34,$63,$1a,$d7,$71		; char code 23 - W
		fcb $34,$62,$a2,$2a,$31		; char code 24 - X
		fcb $34,$62,$a2,$10,$84		; char code 25 - Y
		fcb $37,$c2,$22,$22,$1f		; char code 26 - Z
		fcb $31,$08,$42,$10,$04		; char code 27 - !
		fcb $30,$00,$00,$00,$1f		; char code 28 - underscore
		fcb $33,$a2,$13,$10,$04		; char code 29 - ?
		fcb $30,$00,$00,$00,$04		; char code 30 - .
; some special glyphs
LDBB6		fcb $00,$00,$01,$01,$00,$00,$00	; char code 32 - left part of contracted heart
		fcb $00,$a0,$f0,$f0,$e0,$40,$00	; char code 33 - right part of contracted heart
		fcb $00,$01,$03,$03,$01,$00,$00	; char code 34 - left half of expanded heart
		fcb $00,$b0,$f8,$f8,$f0,$e0,$40	; char code 35 - right part of expanded heart

LDBD2		fcb $00,$80

LDBD4		fcb $00,$01,$00,$50
LDBD8		fcb $00,$04

LDBDA		fcb $00,$50

LDBDC		fcb $00,$05

LDBDE		fcb 3
		fdb LDC4F
		fdb LDC6B
		fdb LDC9B
		fdb LDC33
		fcb 0
		fdb LDC6A
		fdb LDC8B
		fdb LDCA9
		fdb LDC45
		fcb 1
		fdb LDC5D
		fdb LDC7B
		fdb LDCA2
		fdb LDC3C
		fcb $ff

; image data for a shield
img_shield	fcb 134,172
		fcb 128,192
		fcb 122,186
		fcb 128,168
		fcb $fc
		fcb $3e,$04,$00
		fcb $fe
; image data for a torch
img_torch	fcb 118,60
		fcb $fc
		fcb $f7,$ff,$2a,$00
		fcb $fe
; image data for a sword
img_sword	fcb 114,80
		fcb 124,100
		fcb $ff
		fcb 118,82
		fcb 114,86
		fcb $fe

; image data for a flask
img_flask	fcb 110,162
		fcb $fc
		fcb $51,$0e,$b1,$00
		fcb $fe
; image data for a ring
img_ring	fcb 122,60
		fcb $fc
		fcb $11,$1f,$ff,$f1,$00
		fcb $fe
; image data for a scroll
img_scroll	fcb 118,194
		fcb $fc
		fcb $1f,$34,$f1,$dc,$00
		fcb $fe

; Creature around corner to the left indicator graphic
LDC33		fcb 16,27		
		fcb 38,64
		fcb 114,64
		fcb 136,27
		fcb $fe
; Creature around corner to the right indicator graphic
LDC3C		fcb 16,229
		fcb 38,192
		fcb 114,192
		fcb 136,229
		fcb $fe
LDC45		fcb 38,64
		fcb 38,192
		fcb $ff
		fcb 114,64
		fcb 114,192
		fcb $fe
LDC4F		fcb 38,29
		fcb 38,64
		fcb 114,64
		fcb 114,27
		fcb $ff
		fcb 16,27
		fcb 38,64
		fcb $fe
LDC5D		fcb 38,229
		fcb 38,192
		fcb 114,192
		fcb 114,229
		fcb $ff
		fcb 16,229
		fcb 38,192
LDC6A		fcb $fe
LDC6B		fcb 128,40
		fcb 65,40
		fcb 68,56
		fcb 119,56
		fcb $ff
		fcb 92,48
		fcb 93,52
		fcb $fd
		fdb LDC33
LDC7B		fcb 128,216
		fcb 65,216
		fcb 68,200
		fcb 119,200
		fcb $ff
		fcb 92,208
		fcb 93,204
		fcb $fd
		fdb LDC3C
LDC8B		fcb 114,108
		fcb 67,108
		fcb 67,148
		fcb 114,148
		fcb $ff
		fcb 94,126
		fcb 94,130
		fcb $fd
		fdb LDC45
LDC9B		fcb 128,40
		fcb 66,50
		fcb 117,58
		fcb $fe
LDCA2		fcb 128,216
		fcb 66,206
		fcb 117,198
		fcb $fe
LDCA9		fcb 113,108
		fcb 67,128
		fcb 114,148
		fcb $fe
LDCB0		fcb 100,28
		fcb $fc
		fcb $44,$2e,$42,$4c,$00
		fcb $fe
LDCB9		fcb 100,228
		fcb $fc
		fcb $4c,$22,$4e,$44,$00
		fcb $fe
LDCC2		fcb 221,14
		fcb 220,202
		fcb 221,42
		fcb 220,208
		fcb $fb
		fdb LDCD6
		fcb $fd
		fdb LDD0E
LDCD0		fcb $fb
		fdb LDCD6
		fcb $fd
		fdb LDD2A
LDCD6		fcb 24,116
		fcb 128,116
		fcb $ff
		fcb 24,140
		fcb 128,140
		fcb $ff
		fcb 28,116
		fcb 28,140
		fcb $ff
		fcb 40,116
		fcb 40,140
		fcb $ff
		fcb 52,116
		fcb 52,140
		fcb $ff
		fcb 64,116
		fcb 64,140
		fcb $ff
		fcb 76,116
		fcb 76,140
		fcb $ff
		fcb 88,116
		fcb 88,140
		fcb $ff
		fcb 100,116
		fcb 100,140
		fcb $ff
		fcb 112,116
		fcb 112,140
		fcb $ff
		fcb 123,116
		fcb 123,140
		fcb $ff
		fcb $fa
LDD0E		fcb 34,100
		fcb 24,92
		fcb 24,164
		fcb 34,156
		fcb 34,100
		fcb 24,100
		fcb $ff
		fcb 34,156
		fcb 24,156
		fcb $ff
		fcb 28,47
		fcb 28,96
		fcb $ff
		fcb 28,161
		fcb 28,210
		fcb $fe
LDD2A		fcb 118,100
		fcb 128,92
		fcb 128,164
		fcb 118,156
		fcb 118,100
		fcb 128,100
		fcb $ff
		fcb 118,156
		fcb 128,156
		fcb $ff
LDD3C		fcb 28,47
		fcb 28,210
		fcb $fe
LDD41		fcb 104,98
		fcb $fc
		fcb $d7,$d4,$14,$12,$30,$1d,$0d,$fd
		fcb $29,$00
		fcb $fd
		fdb LDD62
LDD51		fcb 104,98
		fcb 94,124
		fcb 96,126
		fcb 106,100
		fcb $ff
		fcb 102,132
		fcb 92,114
		fcb 102,118
		fcb 110,114
LDD62		fcb 102,132
		fcb $fc
		fcb $02,$56,$56,$17,$ee,$02,$ea,$bb
		fcb $bb,$ea,$ea,$00
		fcb 78,92
		fcb $fc
		fcb $c2,$51,$3e,$cf,$fc,$42,$13,$00
		fcb 106,90
		fcb $fc
		fcb $1e,$11,$f3,$62,$39,$e2,$0c,$e4
		fcb $8a,$e2,$00
		fcb 86,84
		fcb $fc
		fcb $54,$65,$2e,$ca,$ba,$a1,$d4,$ee
		fcb $12,$d2,$13,$e1,$20,$f6,$24,$72
		fcb $58,$ee,$c5,$be,$00
		fcb $fe
LDDA3		fcb 80,124
		fcb 94,114
		fcb 110,120
		fcb 132,112
		fcb 104,78
		fcb 132,48
		fcb 68,72
		fcb 84,32
		fcb 22,88
		fcb 52,114
		fcb 92,128
		fcb 52,142
		fcb 22,168
		fcb 88,224
		fcb 68,184
		fcb 132,208
		fcb 112,178
		fcb 132,144
		fcb 110,136
		fcb 94,142
		fcb 80,132
		fcb $ff
		fcb 132,112
		fcb $fc
		fcb $c5,$92,$be,$c3,$43,$5e,$72,$45
		fcb $00
		fcb 82,122
		fcb $fc
		fcb $78,$e9,$8d,$ec,$33,$0c,$24,$72
		fcb $47,$e7,$00
		fcb 22,168
		fcb $fc
		fcb $2d,$c2,$3d,$30,$4b,$4b,$ed,$b2
		fcb $9d,$71,$3d,$dd,$91,$7d,$52,$63
		fcb $a3,$2d,$ed,$2d,$cb,$cb,$d0,$dd
		fcb $42,$ed,$00
		fcb $fe
LDE07		fcb 62,68
		fcb 68,88
		fcb 56,100
		fcb $ff
		fcb 74,90
		fcb 70,74
		fcb $fc
		fcb $33,$f5,$f5,$c1,$5a,$62,$0e,$00
		fcb 100,80
		fcb $fc
		fcb $b3,$17,$34,$eb,$0a,$3d,$00
		fcb $fe
LDE26		fcb 124,160
		fcb $fc
		fcb $c2,$22,$e4,$24,$2c,$ec,$04,$04
		fcb $e2,$42,$00
		fcb 124,168
		fcb $fc
		fcb $c1,$21,$12,$f2,$e1,$41,$00
		fcb $fe
LDE3F		fcb 112,74
		fcb $fc
		fcb $e0,$ee,$2c,$42,$14,$14,$20,$0c
		fcb $cc,$22,$0c,$22,$00
		fcb 124,90
		fcb $fc
		fcb $e0,$0c,$2c,$20,$04,$00
		fcb $fe
LDE59		fcb 82,130
		fcb $fc
		fcb $28,$7d,$5f,$50,$5b,$f5,$2f,$d5
		fcb $17,$17,$f3,$22,$e1,$14,$dd,$8f
		fcb $8d,$db,$ec,$00
		fcb 86,130
		fcb $fc
		fcb $33,$31,$1b,$91,$3b,$5f,$f5,$00
		fcb 108,116
		fcb 114,118
		fcb 120,144
		fcb $fe
LDE82		fcb 34,124
		fcb $fc
		fcb $04,$1f,$0e,$ff,$00
		fcb 80,142
		fcb 64,136
		fcb 46,146
		fcb 64,156
		fcb 82,140
		fcb 76,136
		fcb 64,146
		fcb 58,140
		fcb $fd
		fdb LDEB3
LDE9D		fcb 30,126
		fcb $fc
		fcb $50,$0f,$e0,$00
		fcb 44,150
		fcb 52,166
		fcb 76,164
		fcb 92,150
		fcb 76,136
		fcb 52,134
		fcb 44,150
		fcb $ff
LDEB3		fcb 80,140
		fcb 128,152
		fcb 132,160
		fcb 132,144
		fcb 126,144
		fcb 84,130
		fcb $ff
		fcb 84,126
		fcb 126,110
		fcb 132,110
		fcb 132,92
		fcb 128,102
		fcb 80,116
		fcb $ff
		fcb 80,140
		fcb $fc
		fcb $3a,$d9,$83,$de,$ad,$e6,$a1,$e2
		fcb $22,$61,$26,$ea,$20,$3d,$dd,$e0
		fcb $00
		fcb 52,128
		fcb 20,128
		fcb $fc
		fcb $0e,$21,$02,$e1,$0e,$00
		fcb 74,102
		fcb $fc
		fcb $e0,$02,$d0,$08,$30,$02,$20,$01
		fcb $30,$02,$d0,$01,$87,$00
		fcb 46,110
		fcb 64,102
		fcb 64,100
		fcb 30,102
		fcb 20,98
		fcb 30,94
		fcb 64,96
		fcb 64,98
		fcb 20,98
		fcb $FE
; Image for the Wizard
img_wizard	fcb 46,98
		fcb $fc
		fcb $21,$2f,$2d,$fd,$ce,$c2,$f2,$12
		fcb $0f,$1e,$3f,$21,$12,$e3,$e0,$00
		fcb 104,154
		fcb $fc
		fcb $21,$2f,$2d,$fd,$ce,$c2,$f2,$12
		fcb $0f,$1e,$3f,$22,$12,$e2,$e0,$00
		fcb $fd
		fdb img_wizardgen
; Image for the "good" wizard
img_goodwiz	fcb 40,86
		fcb 64,92
		fcb 42,100
		fcb 54,82
		fcb 56,104
		fcb 40,86
		fcb $ff
		fcb 66,140
		fcb $fc
		fcb $70,$ad,$35,$1b,$b3,$00
		fcb 96,146
		fcb 120,148
		fcb 100,136
		fcb 106,154
		fcb 116,138
		fcb 96,146
		fcb $ff
		fcb 80,116
		fcb $fc
		fcb $53,$ec,$e4,$4d,$b0,$00
img_wizardgen	fcb 64,124
		fcb $fc
		fcb $4e,$c0,$7b,$9c,$d4,$e4,$e1,$e1
		fcb $dd,$1c,$96,$03,$00
		fcb 28,130
		fcb $fc
		fcb $03,$45,$71,$da,$1e,$11,$e1,$00
		fcb 48,134
		fcb 54,142
		fcb 116,164
		fcb 132,132
		fcb 130,118
		fcb 120,94
		fcb 90,110
		fcb 132,132
		fcb 72,106
		fcb $ff
		fcb 64,102
		fcb $fc
		fcb $1f,$bd,$f1,$53,$00
		fcb 66,102
		fcb $fc
		fcb $1e,$32,$11,$73,$00
		fcb 88,112
		fcb 72,120
		fcb $ff
		fcb 62,132
		fcb 20,128
		fcb 52,122
		fcb 64,122
		fcb 60,124
		fcb 114,128
		fcb 80,130
		fcb 68,130
		fcb 62,132
		fcb $ff
		fcb 40,130
		fcb $fc
		fcb $ff,$1e,$11,$f2,$3f,$20,$0f,$c0
		fcb $ff,$31,$00
		fcb $fe
LDFCA		fcb 132,130
		fcb 112,122
		fcb 92,124
		fcb 94,126
		fcb 94,130
		fcb 92,132
		fcb 112,130
		fcb 128,140
		fcb 132,136
		fcb 132,114
		fcb 120,108
		fcb 106,118
		fcb 120,112
		fcb 124,116
		fcb 124,126
		fcb $ff
		fcb 100,120
		fcb $fc
		fcb $e0,$e2,$ee,$e0,$f1,$22,$ee,$06
		fcb $2e,$e2,$11,$20,$2e,$22,$20,$00
		fcb $fe
		fcc 'KSK'