; assembled with ACME 0.90

; Files are named Fdnn. d=disk [1-4], nn=file number. d=0 if file is same for any disk.
; Raw sectors are stored in 1K files named Rdss. d=disk [2-4], ss=sector-1 [00-FC].

DEBUG	=	0	; set to warn on code overflow

	!to	"!ultima4", cbm

	*=	$801
	!16	nextline
	!text	$0A, $00, $9E, $20, "2064", $00
nextline:	!8	$00, $00, $00, $00
	*=	2064

chrout	=	$ffd2
setnam	=	$ffbd
setlfs	=	$ffba
load	=	$ffd5
save	=	$ffd8
getin	=	$ffe4
device	=	$ba

	ldy	#0
	ldx	#6
copya0:	lda	toa000,y
storea0:	sta	$a000,y
	iny
	bne	copya0
	inc	copya0+2
	inc	storea0+2
	dex
	bne	copya0

;	ldy	#0	; y already 0
	ldx	#2
copy9d:	lda	to9d00,y
store9d:	sta	$9d00,y
	iny
	bne	copy9d
	inc	copy9d+2
	inc	store9d+2
	dex
	bne	copy9d

	lda	#$36
	sta	$01	; bank out BASIC

	ldx	#$c0
	txs	; set stack pointer to $c0 (in original - why???)

	lda	#0
	sta	$d020
	sta	$d021

	!if	DEBUG {	; ensure no reliance on color RAM init (different on V1/V2/V3 kernals...)
	tax
colorloop:
	sta	$d800,x
	sta	$d900,x
	sta	$da00,x
	sta	$db00,x
	inx
	bne	colorloop
}

;	lda	#$0f
;	sta	$d418
;	sta	soundstate	; would be overwritten by a100 copy in original (bug?)

	lda	$314
	sta	original314
	lda	$315
	sta	original315

; present patch options

msgptr	=	$fb

	lda	#$93
	jsr	chrout
	lda	#$16	; lower case
	sta	$d018
	lda	#<patchmsg
	sta	msgptr
	lda	#>patchmsg
	sta	msgptr+1
	jsr	printmsg

; print current selections

selbase	=	(yoff*40+30)+$400

updateselection:
	lda	#<selbase
	sta	offmsgaddr
	lda	#>selbase
	sta	offmsgaddr+1

	lda	#<selbase
	sta	onmsgaddr
	lda	#>selbase
	sta	onmsgaddr+1

	ldx	#0
selloop:	txa
	pha
	lda	patchenable,x
	bne	patchon

	lda	#<offmsg
	sta	msgptr
	lda	#>offmsg
	sta	msgptr+1
	jsr	printmsg
	jmp	skippatchon
patchon:
	lda	#<onmsg
	sta	msgptr
	lda	#>onmsg
	sta	msgptr+1
	jsr	printmsg
skippatchon:
	pla
	tax
	lda	offmsgaddr
	clc
	adc	#40
	sta	offmsgaddr
	lda	offmsgaddr+1
	adc	#0
	sta	offmsgaddr+1

	lda	onmsgaddr
	clc
	adc	#40
	sta	onmsgaddr
	lda	onmsgaddr+1
	adc	#0
	sta	onmsgaddr+1

	inx
	cpx	#9
	bne	selloop

; get keyboard input
	jsr	clearkeyboard
wait:	jsr	getin
	cmp	#0
	beq	wait

	cmp	#'1'
	bcc	boot
	cmp	#$3A
	bcs	boot

	sec
	sbc	#'1'
	tax
	lda	patchenable,x
	eor	#1
	sta	patchenable,x
	jmp	updateselection

patchenable:
miscenable:
	!8	1	; misc enhancements
cheatenable:
	!8	0	; unlimited food
	!8	0	; unlimited torches
	!8	0	; unlimited keys
	!8	0	; unlimited magic
	!8	0	; avoid combat
	!8	0	; control balloon
	!8	0	; add B)oard (create)
	!8	0	; add T)eleport

boot:

; disable unwanted patches

	lda	miscenable
	bne	skipmiscdisable
	ldx	#0
	lda	#$ff
disablemisc:
	sta	miscpatchtable,x
	inx
	inx
	inx
	cpx	#nummiscpatches*3
	bne	disablemisc
skipmiscdisable:

	ldx	#0
	ldy	#0
cheatdisableloop:
	lda	cheatenable,x
	bne	skipcheatdisable
	lda	#$ff
	sta	cheatpatchtable,y
skipcheatdisable:
	inx
	iny
	iny
	iny
	cpx	#numcheatpatches
	bne	cheatdisableloop

; print intro and load
	lda	#$93
	jsr	chrout
	lda	#<intromsg
	sta	msgptr
	lda	#>intromsg
	sta	msgptr+1
	lda	#1
	sta	color
	jsr	printmsg
	jmp	loadmain

getc:
	ldy	#0
	lda	(msgptr),y
	inc	msgptr
	bne	getcrts
	inc	msgptr+1
getcrts:	rts

color:	!8	7

printmsg:
	jsr	getc
	cmp	#0
	beq	getcrts
	cmp	#$ff
	beq	position
scrsta:	sta	$ffff,x
	lda	color
colorsta:	sta	$ffff,x
	inx
	jmp	printmsg
position:	jsr	getc
	sta	scrsta+1
	sta	colorsta+1
	jsr	getc
	sta	scrsta+2
	clc
	adc	#$d4
	sta	colorsta+2
	jsr	getc
	tax
	jmp	printmsg

	!macro y .y {
	!8	$ff
	!16	.y*40+$400
}

offmsg:
	!8	$ff
offmsgaddr:
	!16	0
	!scr	0, "OFF"
	!8	0

onmsg:
	!8	$ff
onmsgaddr:
	!16	0
	!scr	0, "ON "
	!8	0

xoff	=	6
yoff	=	4
patchmsg:
	+y	0
	!scr	12,            "Ultima IV IDE64"

	+y	yoff
	!scr	xoff, "1. Misc enhancements"
	+y	yoff+1
	!scr	xoff, "2. Unlimited food"
	+y	yoff+2
	!scr	xoff, "3. Unlimited torches"
	+y	yoff+3
	!scr	xoff, "4. Unlimited keys"
	+y	yoff+4
	!scr	xoff, "5. Unlimited magic"
	+y	yoff+5
	!scr	xoff, "6. Avoid combat"
	+y	yoff+6
	!scr	xoff, "7. Control balloon"
	+y	yoff+7
	!scr	xoff, "8. Add B)oard (create)"
	+y	yoff+8
	!scr	xoff, "9. Add T)eleport"

	+y	yoff+12
	!scr	00, "New commands"
	+y	yoff+13
	!8	00, $63, $63, $63, $63, $63, $63, $63, $63, $63, $63, $63, $63
	+y	yoff+14
	!scr	00, "B) B)alloon, S)hip, H)orse"
	+y	yoff+16
	!scr	00, "T) T)owne, D)ungeon, S)hrine, L)ocation,"
	+y	yoff+17
	!scr	03,    "C)oord"

	+y	24
	!scr	03,    "Patches from U4 Gold by MagerValp"
	!8	0

intromsg:
	+y	6
	!scr	13,             "ORIGIN SYSTEMS"
	+y	8
	!scr	12,            "PROUDLY PRESENTS"

	+y	11
	!scr	05,     "ULTIMA IV: QUEST OF THE AVATAR"

	+y	14
	!scr	08,        "DESIGNED BY LORD BRITISH"
	+y	16
	!scr	02,  "COMMODORE 64 CONVERSION BY  CHUCKLES"
	+y	18
	!scr	02,  "MUSIC COMPOSED BY  KENNETH W. ARNOLD"


	+y	22
	!scr	01, "COPYRIGHT (C) 1985 ORIGIN SYSTEMS, INC."
	!8	0

toa000:
	!pseudopc	$a000 {

; input parameters to sector read
rwflag:	!8	0	; 1=read, 2=write (always 1)
numsectors:	!8	0	; always 1
addrlow:	!8	0	; always 0
addrhigh:	!8	0
sectorlow:	!8	0	; range: 1-256
sectorhigh:	!8	0

buffer	=	$a600
fileaddrlow	=	$0e
fileaddrhigh	=	$0f

; file tables
smallfileaddr:	; 58 bytes
	!8	$50, $00, $40, $AE, $40, $AE, $40, $AE, $40, $AE, $40, $AE, $40, $AE, $40
	!8	$AE, $40, $AE, $40, $AE, $40, $AE, $40, $AE, $40, $AE, $40, $AE, $40, $AE
	!8	$40, $AE, $40, $AE, $40, $AE, $40, $AE, $40, $AE, $40, $AE, $40, $AE, $40
	!8	$AE, $20, $AF, $10, $00, $00, $88, $10, $00, $FF, $FF, $80, $AE

largefilelengthhigh:	; 96 bytes
	!8	$16, $20, $04, $1E, $1E, $1D, $1D, $1D, $1D, $1D, $1D, $1D, $04, $01, $02
	!8	$18, $13, $34, $23, $01, $02, $08, $0B, $0A, $0A, $09, $06, $50, $05, $05
	!8	$05, $05, $05, $05, $05, $05, $05, $05, $05, $05, $05, $05, $05, $05, $05
	!8	$0C, $08, $04, $09, $06, $07, $08, $05, $02, $10, $05, $07, $04, $06, $03
	!8	$FF, $FF, $01, $01, $02, $FF, $0F, $FF, $FF, $02, $FF, $12, $0A, $02, $FF
	!8	$FF, $02, $02, $02, $02, $02, $02, $02, $02, $FF, $10, $FF, $FF, $FF, $FF
	!8	$14, $1B, $FF, $FF, $04, $05

; Note: This is redundant with the first 2 bytes of the PRGs and could be eliminated.
largefileaddrhigh:	; 96 bytes
	!8	$08, $B0, $E4, $40, $74, $40, $40, $40, $40, $40, $40, $40, $E0, $9F, $40
	!8	$08, $60, $64, $40, $AC, $AA, $EC, $F4, $F4, $F4, $F4, $F4, $40, $8B, $8B
	!8	$8B, $8B, $8B, $8B, $8B, $8B, $8B, $8B, $8B, $8B, $8B, $8B, $8B, $8B, $8B
	!8	$88, $88, $88, $88, $88, $88, $88, $88, $88, $88, $90, $88, $88, $88, $88
	!8	$FF, $FF, $AC, $AC, $AA, $FF, $88, $FF, $FF, $88, $FF, $88, $88, $88, $FF
	!8	$FF, $E8, $E8, $E8, $E8, $E8, $E8, $E8, $E8, $FF, $8C, $FF, $FF, $FF, $FF
	!8	$88, $40, $FF, $FF, $04, $98

; u4 main game
reqdisk	=	$5e

; value of A at entry of fileio
cmdrun	=	$d2
cmdload	=	$cc
cmdsave	=	$d3

	!align	$ffff, $a100

	jmp	fileio
	jmp	readsector
	jmp	loadmain
	jmp	togglesound
	jmp	bankinkernal
	jmp	bankoutkernal
	jmp	clearkeyboard
jsysirq:	jmp	sysirq

; toggle sound on/off
; used for generating Apple II style sound effects
togglesound:
	pha
	lda	soundstate
	eor	#$0f
	sta	soundstate
	sta	$d418
	pla
	rts

soundstate:
;	!8	$a5	; original - is this correct?
	!8	$0f	; u4gold

; clear keyboard buffer
clearkeyboard:
	pha
	lda	#0
	sta	$c6
	pla
	rts

sysirq:
	lda	#$36
	sta	$01
	jmp	($fffe)

; load main program
loadmain:
; init
	lda	#<irqfffe
	sta	$fffe
	lda	#>irqfffe
	sta	$ffff
	lda	#<nmi
	sta	$fffa
	lda	#>nmi
	sta	$fffb
	jsr	bankoutkernal

	lda	#1
	sta	$50
	sta	$5f
	lda	#0
	sta	$38
	lda	#cmdload
	ldx	#$17
	jsr	fileio
	ldx	#$4f
	jsr	fileio
	ldx	#$4d
	jsr	fileio
	ldx	#$41
	jsr	fileio
	ldx	#$4c
	jsr	fileio
	ldx	#$42
	jsr	fileio
	lda	#cmdrun
	ldx	#$50
	jsr	fileio	; does not return
; no return

readsector:
; read sector (1-256)
; return C clear on success

; defeat copy protection
;	sec
;	lda	reqdisk
;	beq	dorts

	lda	#'R'
	sta	filetype
	ldx	sectorlow
	dex
	txa
	and	#%00000011
	sta	sectorindex
	txa
	and	#%11111100

; already in buffer?
	ldx	reqdisk
	cmp	sectorinbuf
	bne	notinbuffer
	cpx	diskbuf
	beq	inbuffer
notinbuffer:
	sta	sectorinbuf
	stx	diskbuf

	jsr	buildfilename

; load 1K into buffer
	jsr	bankinkernal

	lda	#2
	ldx	device
	ldy	#0	; file load address ignored
	jsr	setlfs
	lda	#4
	ldx	#<loadfile
	ldy	#>loadfile
	jsr	setnam
	lda	#0
	ldx	#<buffer
	ldy	#>buffer
	jsr	load

	jsr	bankoutkernal
inbuffer:

; copy 256 bytes to destination
	lda	addrlow
	sta	fileaddrlow
	lda	addrhigh
	sta	fileaddrhigh

	lda	sectorindex
	clc
	adc	#>buffer
	sta	L1+2

	ldy	#0
L1:	lda	buffer,y
	sta	(fileaddrlow),y
	iny
	bne	L1

	clc
dorts:	rts

fileio:
; read or write a file
; A = run/load/save
; X = file#
	sta	filecmd
	stx	filenum
	sty	savey

	jsr	bankinkernal

	ldy	#'F'
	sty	filetype

	ldy	#0

	cpx	#$40
	bcs	bigfile    ; go if >= 64

; small file
	lda	#$ff
	sta	diskbuf	; invalidate sector cache
	lda	smallfilelengthlow,x
	sta	filelengthlow
	sty	filelengthhigh
	txa
	asl
	tax
	lda	smallfileaddr,x
	sta	smallfileaddrlowcopy
	lda	smallfileaddr+1,x
	sta	smallfileaddrhighcopy

	lda	filecmd
	cmp	#cmdsave
	bne	smallload
; save - copy to buffer
	lda	smallfileaddrlowcopy
	sta	fileaddrlow
	lda	smallfileaddrhighcopy
	sta	fileaddrhigh
	ldy	filelengthlow
	dey
savecopy:	lda	(fileaddrlow),y
	sta	buffer,y
	dey
	cpy	#$ff
	bne	savecopy
smallload:
	lda	#<buffer
	sta	fileaddrlow
	lda	#>buffer
	sta	fileaddrhigh
	jmp	skipbigfile

bigfile:
	txa
	sec
	sbc	#$40
	tax
	lda	largefilelengthhigh,x
	sta	filelengthhigh
	sty	filelengthlow
	lda	largefileaddrhigh,x
	sta	fileaddrhigh
	sty	fileaddrlow
skipbigfile:

	lda	filenum
	jsr	buildfilename

; handle files that are different on different disks
	lda	filenum
	ldx	#numspecialfiles-1
L3:	cmp	specialfiles,x
	beq	special
	dex
	bpl	L3
	lda	#'0'
	sta	disk
special:

	lda	#2
	ldx	device
	ldy	#0	; file load address ignored
	jsr	setlfs

	lda	filecmd
	cmp	#cmdsave
	beq	dosave

; load file
	lda	#4
	ldx	#<loadfile
	ldy	#>loadfile
	jsr	setnam
	lda	#0
	ldx	fileaddrlow
	ldy	fileaddrhigh
	jsr	load

	ldx	filenum
	cpx	#$40
	bcs	notsmall    ; go if >= 64

; if small file, copy from buffer to dest
	lda	smallfileaddrlowcopy
	sta	fileaddrlow
	lda	smallfileaddrhighcopy
	sta	fileaddrhigh
	ldy	filelengthlow
	dey
loadcopy:	lda	buffer,y
	sta	(fileaddrlow),y
	dey
	cpy	#$ff
	bne	loadcopy
notsmall:
	jsr	patch

	lda	filecmd
	cmp	#cmdrun
	bne	exitfileio
	jsr	bankoutkernal
	jmp	(fileaddrlow)

dosave:
; save file
	lda	#6
	ldx	#<savefile
	ldy	#>savefile
	jsr	setnam
	lda	fileaddrlow
	clc
	adc	filelengthlow
	tax
	lda	fileaddrhigh
	adc	filelengthhigh
	tay
	lda	#fileaddrlow
	jsr	save

exitfileio:
	jsr	bankoutkernal
	lda	filecmd
	ldx	filenum
	ldy	savey
	rts

buildfilename:
; enter with file# or sector#-1 in A
	tay
	lsr
	lsr
	lsr
	lsr
	tax
	lda	hextable,x
	sta	filehigh
	tya
	and	#$0f
	tax
	lda	hextable,x
	sta	filelow
	ldx	reqdisk
	lda	hextable,x
	sta	disk
	rts

original314	!8	0
original315	!8	0

bankoutkernal:
	lda	#$35
	!8	$2c
bankinkernal:
	lda	#$36
installint:
	sta	$01
	lda	$315
	cmp	original315
	bne	skipinstallint
	php
	sei
	lda	#<irq314
	sta	$314
	lda	#>irq314
	sta	$315
	plp
skipinstallint:
	rts

; The interrupt stuff is a little convoluted. We can enter from $FFFE (when kernal is
; banked out) or $314 (when kernal is banked in). This allows music to play while loading,
; assuming that the load routine doesn't disable interrupts (IDE64 doesn't).

; Normally the game doesn't use $314. But the "initiate game" sequence does (raster
; interrupt for split screen). We detect this and bypass our special interrupt handling.

irq314:
	lda	$315
	cmp	#>irq314
	beq	irq314cont
	jmp	(original314)

irqfffe:
	pha
	txa
	pha
	tya
	pha

irq314cont:
	lda	$01
	pha
	lda	#>retirq
	pha
	lda	#<retirq
	pha
	lda	#4	; keep interrupts disabled after RTI
	pha

	lda	#$35
	sta	$01
	lda	$315
	cmp	#>irq314
	bne	skiporiginal
	lda	original314
	sta	$314
	lda	original315
	sta	$315
skiporiginal:
	jmp	(jsysirq+1)	; do U4 IRQ (also executes $314 code)
retirq:
	pla
	jsr	installint
	pla
	tay
	pla
	tax
	pla
nmi:	rti

patchptr	=	getpatchbyte+1
destptr	=	putpatchbyte+1

getpatchbyte:
	lda	$ffff
	inc	patchptr
	bne	nocarry
	inc	patchptr+1
nocarry:	rts

putpatchbyte:
	sta	$ffff
	inc	destptr
	bne	nodestptrcarry
	inc	destptr+1
nodestptrcarry:
	rts

; apply patches
patch:
	ldy	#0
nextpatch:
	lda	patchtable,y
	cmp	filenum
	bne	donepatch

	lda	patchtable+1,y
	sta	patchptr
	lda	patchtable+2,y
	sta	patchptr+1

patchloop:
	jsr	getpatchbyte
	tax
	beq	donepatch
	jsr	getpatchbyte
	sta	destptr
	jsr	getpatchbyte
	sta	destptr+1

patchcopyloop:
	jsr	getpatchbyte
	jsr	putpatchbyte
	dex
	bne	patchcopyloop
	beq	patchloop
donepatch:
	iny
	iny
	iny
	cpy	#numpatches*3
	bne	nextpatch
	rts

patchtable:

; mandatory patches
	!8	$4f
	!16	mandatorypatch4f
	!8	$50
	!16	mandatorypatch50

; misc patches
miscpatchtable:
	!8	$4f
	!16	miscpatch4f
	!8	$51
	!16	miscpatch51
	!8	$5b
	!16	miscpatch5b
endmiscpatchtable:

; cheat patches
cheatpatchtable:
	!8	$5b
	!16	unlimitedfoodpatch

	!8	$5b
	!16	unlimitedtorchespatch

	!8	$5b
	!16	unlimitedkeyspatch

	!8	$5b
	!16	unlimitedspellspatch

	!8	$5b
	!16	avoidpatch

	!8	$5b	; also 4f
	!16	controlballoonpatch

	!8	$5b
	!16	boardpatch

	!8	$5b
	!16	teleportpatch
endcheatpatchtable:
endpatchtable:
numpatches	=	(endpatchtable-patchtable)/3
nummiscpatches	=	(endmiscpatchtable-miscpatchtable)/3
numcheatpatches	=	(endcheatpatchtable-cheatpatchtable)/3

player_xpos	=	$10
player_ypos	=	$11
game_mode	=	$1b
player_transport	=	$1e
music_volume	=	$4D
movement_mode	=	$74

print_only_on_foot	=	$4139
cmd_done	=	$621E
move_north	=	$080F
move_south	=	$080C
move_west	=	$0809
move_east	=	$0806
primm	=	$0821
getandprintkey	=	$8398
waitkey	=	$0800
console_out	=	$0824
player_teleport	=	$0803
music_ctl	=	$af20
request_disk	=	$0842
update_status	=	$0845

; game modes
britannia	=	1
towne	=	2
dungeon	=	3

mandatorypatch4f:
	!8	1
	!16	$1916	; kill disk change requests
	rts
	!8	0

mandatorypatch50:
	!8	4
	!16	$680f	; suppress "number of drives" stuff
	jmp	$6829
	nop

	!8	1
	!16	$682c	; suppress "number of drives" stuff
	!8	$12

	!8	1
	!16	$6842	; suppress "number of drives" stuff
	!8	$13

	!8	7
	!16	$688d	; suppress "number of drives" stuff
	nop
	nop
	nop
	nop
	nop
	nop
	nop

	!8	10
	!16	$6c8c	; copy protection
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop

	!8	0

scankeypatch	=	$1580
miscpatch4f:
	!8	7
	!16	scankeypatch
	jsr	scankey
	ora	#$80
	cmp	#$80

	!8	1
	!16	$159d
	rts

	!8	0

numchars	=	$c6
keybuf	=	$277
jiffy	=	$a2

scankey:
	sei
	ldy	numchars
	beq	nokeys
	ldy	keybuf
	ldx	#0

shiftbuffer:
	lda	keybuf+1,x
	sta	keybuf,x
	inx
	cpx	numchars
	bne	shiftbuffer
	dec	numchars

processkey:
	tya
	ldy	#3

checkmovement:
	cmp	movementtable,y
	beq	foundmovement
	dey
	bpl	checkmovement
	bmi	donekey

foundmovement:
	lda	keyremap,y

donekey:	cli
	rts

keyremap:
	!8	$40, $2F, $3A, $3B

movementtable:
	!8	$40, $2F, $3A, $3B

nokeys:
	lda	jiffy
	sec
	sbc	time
	cmp	#5
	bcc	processkey
	lda	jiffy
	sta	time

; joystick control
	lda	$DC00
	lsr
	bcc	up
	lsr
	bcc	down
	lsr
	bcc	left
	lsr
	bcc	right
	lsr
	bcs	processkey
	lda	game_mode
	bmi	attackkey
	cmp	#britannia
	beq	enter
	cmp	#towne
	beq	talk
	cmp	#dungeon
	beq	nothing

	ldy	#0
	!8	$2c
enter:	ldy	#'E'
	!8	$2c
talk:	ldy	#'T'
	!8	$2c
nothing:	ldy	#0
	!8	$2c
attackkey:
	ldy	#'A'
	!8	$2c
up:	ldy	#'@'
	!8	$2c
down:	ldy	#'/'
	!8	$2c
left:	ldy	#':'
	!8	$2c
right:	ldy	#';'
	jmp	processkey

time:	!8	0

; f051 patch
miscpatch51:
	!8	2
	!16	$6450
	!16	scpu1

	!8	2
	!16	$645a
	!16	scpu2

	!8	0

scpu1:
	sta	$D07A	; 1Mhz
	jsr	$6740
	sta	$D07B	; 20Mhz
	rts
scpu2:
	sta	$D07A	; 1Mhz
	jsr	$6872
	sta	$D07B	; 20Mhz
	rts

exitnorthpatch	=	$42E1
exitsouthpatch	=	$43EF
exitwestpatch	=	$44B9
exiteastpatch	=	$4591

miscpatch5b:
	!8	4
	!16	exitnorthpatch
	jsr	exitnorth
	nop

	!8	4
	!16	exitsouthpatch
	jsr	exitsouth
	nop

	!8	4
	!16	exitwestpatch
	jsr	exitwest
	nop

	!8	4
	!16	exiteastpatch
	jsr	exiteast
	nop

dungeonsavepatch	=	$582e
	!8	2
	!16	dungeonsavepatch+1
	!16	dungeonsave

dungeonloadpatch	=	$405C
	!8	4
	!16	dungeonloadpatch
	jsr	dungeonload
	nop

scpupatch	=	$85fd
	!8	23
	!16	scpupatch
	sta	$D07A	; 1Mhz
	lda	#$04
	sta	$8614
s1:	jsr	$8645
	jsr	$8616
	dec	$8614
	bne	s1
	sta	$D07B	; 20Mhz
	rts

	!8	0

; save in dungeons

dungeonsave:
	lda	game_mode
	cmp	#dungeon
	beq	indungeon
	jmp	$4178	; continue, print "not here"
indungeon:
	lda	#0
	jsr	music_ctl
	lda	#2
	jsr	request_disk
	lda	#cmdsave
	ldx	#$7F
	jsr	fileio
	ldx	#$80
	jsr	fileio
	ldx	#$1a
	jsr	fileio
	lda	#4
	jsr	request_disk
	lda	#1
	jsr	music_ctl
	jmp	cmd_done

dungeonload:
	lda	game_mode
	cmp	#dungeon
	beq	dodungeonload
	lda	#0	; code displaced by patch
	sta	$1D
	rts
dodungeonload:
	pla
	pla
	lda	#4
	jsr	request_disk
	lda	#cmdload
	ldx	#$95
	jsr	fileio
	jsr	update_status
	jsr	$50AD	; load dungeon
	lda	#$FF
	sta	music_volume
	lda	#$C4
	jsr	music_ctl	; play dungeon music
	jmp	cmd_done

; exit prompt patch

exitnorth:
	lda	player_ypos
	bne	noexitnorth
	jsr	prompt
noexitnorth:
	dec	player_ypos
	lda	player_ypos
	rts

exitsouth:
	lda	player_ypos
	cmp	#$1f
	bne	noexitsouth
	jsr	prompt
noexitsouth:
	inc	player_ypos
	lda	player_ypos
	rts

exitwest:
	lda	player_xpos
	bne	noexitwest
	jsr	prompt
noexitwest:
	dec	player_xpos
	lda	player_xpos
	rts

exiteast:
	lda	player_xpos
	cmp	#$1f
	bne	noexiteast
	jsr	prompt
noexiteast:
	inc	player_xpos
	lda	player_xpos
	rts

prompt:	jsr	primm
	!text	"EXIT? ",0
	jsr	waitkey
;	jsr	getandprintkey
	bne	checkkey
noexit:
	lda	#'N'
	jsr	console_out
	lda	#$8d
	jsr	console_out
	pla
	pla
	pla
	pla
	rts

checkkey:	and	#$7f
	cmp	#'Y'
	bne	noexit
	lda	#'Y'
	jsr	console_out
	lda	#$8d
	jmp	console_out

; list of files that differ between disks
specialfiles:
	!8	$00, $0f, $77, $79, $7a, $82
endspecialfiles:
numspecialfiles	=	endspecialfiles-specialfiles

hextable:
	!text	"0123456789ABCDEF"

savefile:
	!text	"@:"
loadfile:
filetype:
	!8	0
disk:	!8	0
filehigh:	!8	0
filelow:	!8	0

diskbuf	!8	$ff

; my storage
sectorinbuf:	!8	0	; sector in buf - 1 (divisable by 4)
filelengthlow:	!8	0
filelengthhigh:	!8	0
sectorindex:	!8	0	; 0-3
smallfileaddrlowcopy:	!8	0
smallfileaddrhighcopy:	!8	0
temp:	!8	0
filecmd:	!8	0
filenum:	!8	0
savey:	!8	0

smallfilelengthlow:	; 29 bytes
	!8	$01, $C0, $C0, $C0, $C0, $C0, $C0, $C0, $C0, $C0, $C0, $C0, $C0, $C0, $C0
	!8	$C0, $C0, $C0, $C0, $C0, $C0, $C0, $C0, $E0, $20, $80, $20, $FF, $80

	!if	DEBUG {
		!align	$ffff, $a600
	}
}

to9d00:
	!pseudopc	$9d00 {

balloonnorthpatch	=	$424e
balloonsouthpatch	=	$434f
balloonwestpatch	=	$4428
ballooneastpatch	=	$44f1

controlballoonpatch:
	!8	2
	!16	balloonnorthpatch
	!16	balloonnorth

	!8	2
	!16	balloonsouthpatch
	!16	balloonsouth

	!8	2
	!16	balloonwestpatch
	!16	balloonwest

	!8	2
	!16	ballooneastpatch
	!16	ballooneast

	!8	1
	!16	$b15	; prevent balloon drift (note: file 4f)
	rts
	!8	0

boardpatch:
bcommandpatch	=	$47ac
	!8	2
	!16	bcommandpatch
	!16	board
	!8	0

tcommandpatch	=	$59cf
teleportpatch:
	!8	2
	!16	tcommandpatch
	!16	teleport
	!8	0

trollattackpatch	=	$62D7
avoidpatch:
	!8	4
	!16	trollattackpatch
	jsr	trollattack
	nop

attackpatch	=	$66FB
	!8	2
	!16	attackpatch+1
	!16	attack
	!8	0

; unlimited spells
spellspatch	=	$48a1
unlimitedspellspatch:
	!8	3
	!16	spellspatch
	jmp	$48dd
	!8	0

torchpatch	=	$5518
unlimitedtorchespatch:
	!8	3
	!16	torchpatch
	sec
	nop
	nop
	!8	0

keyspatch	=	$5550
unlimitedkeyspatch:
	!8	1
	!16	keyspatch+1
	!8	$0d	; change branch target
	!8	0

foodpatch	=	$6500
unlimitedfoodpatch:
	!8	2
	!16	foodpatch
	sec
	rts
	!8	0

attack:
	jsr	$8357	; print name (displaced by patch)
	jsr	askavoid
	bcc	skipavoidattack
	pla
	pla
skipavoidattack:
	rts

trollattack:
	jsr	askavoid
	bcc	skipavoidtroll
	pla
	pla
skipavoidtroll:
	lda	#$a4	; code displaced by patch
	sta	$40
	rts

askavoid:
	jsr	primm
	!text	"AVOID? ",0
	jsr	getandprintkey
	bne	askavoidcheck
dontavoid:
	clc
	rts
askavoidcheck:
	and	#$7f
	cmp	#'Y'
	bne	dontavoid
	sec
	rts

towney	=	$51be
townex	=	$519e
dungeony	=	$51CA
dungeonx	=	$51AA
shriney	=	$51D2
shrinex	=	$51B2
locationy	=	$51BA
locationx	=	$519A

; teleport

teleport:
	lda	game_mode
	cmp	#britannia
	beq	inbrit
	jmp	primm
inbrit:
	pla
	pla
	lda	player_transport
	cmp	#$14
	bcs	notonship
	jmp	print_only_on_foot
notonship:
	jsr	primm
	!text	"TELEPORT-",0
	jsr	getandprintkey
	beq	doneteleport
	and	#$7f
	cmp	#'T'
	beq	teleporttowne
	cmp	#'D'
	beq	teleportdungeon
	cmp	#'S'
	beq	teleportshrine
	cmp	#'L'
	beq	teleportlocation
	cmp	#'C'
	beq	teleportoordinate
doneteleport:
	jmp	cmd_done

teleporttowne:
	jsr	primm
	!text	"TOWNE-",0
	jsr	getnum
	ldy	towney,x
	lda	townex,x
	jmp	newlocation

teleportdungeon:
	jsr	primm
	!text	"DUNGEON-",0
	jsr	getnum
	ldy	dungeony,x
	lda	dungeonx,x
	jmp	newlocation

teleportshrine:
	jsr	primm
	!text	"SHRINE-",0
	jsr	getnum
	ldy	shriney,x
	lda	shrinex,x
	jmp	newlocation

teleportlocation:
	jsr	primm
	!text	"LOCATION-",0
	jsr	getnum
	cmp	#4
	bcc	teleportcastle
; village
	clc
	adc	#8
teleportcastle:
	tax
	ldy	locationy,x
	lda	locationx,x
	jmp	newlocation

teleportoordinate:
	jsr	primm
	!text	"COORD-",0
	jsr	getcoord
	pha
	jsr	primm
	!8	$22, " ",0
	jsr	getcoord
	pha
	lda	#'"'
	jsr	console_out
	pla
	tay
	pla
; fall through to newlocation

newlocation:
	sta	player_xpos
	sty	player_ypos
	ldx	#0
	txa
clearloc:	sta	$ac00,x
	inx
	bne	clearloc
	jsr	player_teleport
	jmp	cmd_done

getnum:
	jsr	getandprintkey
	beq	getnumerror
	sec
	sbc	#'1'+$80
	bmi	getnumerror
	cmp	#8
	bcs	getnumerror
	tax
	rts
getnumerror:
	pla
	pla
	jmp	cmd_done

getcoord:
	jsr	getalpha
	asl
	asl
	asl
	asl
	sta	temp
	lda	#$27
	jsr	console_out
	jsr	getalpha
	ora	temp
	rts

getalpha:
	jsr	waitkey
	beq	getalphaerror
	pha
	jsr	console_out
	pla
	sec
	sbc	#'A'+$80
	bmi	getalphaerror
	cmp	#'Q'-'A'
	bcs	getalphaerror
	rts
getalphaerror:
	pla
	pla
	jmp	getnumerror

; create horse/ship/balloon

board:
	jsr	primm
	!text	"WHAT? ",0
	jsr	getandprintkey
	beq	noboard
	and	#$7f
	ldx	#$1f	; on foot
	cmp	#'H'
	bne	nothorse
	ldx	#$14	; horse
nothorse:
	cmp	#'S'
	bne	notship
	ldx	#$10	; ship
notship:	cmp	#'B'
	bne	notballoon
	ldx	#$18	; balloon
	lda	#0
	sta	movement_mode
notballoon:
	stx	player_transport
noboard:	jmp	cmd_done

; balloon control patch

balloonnorth:
	lda	movement_mode
	beq	onground
	jsr	move_north
onground:	jmp	cmd_done
balloonsouth:
	lda	movement_mode
	beq	onground
	jsr	move_south
	jmp	cmd_done
balloonwest:
	lda	movement_mode
	beq	onground
	jsr	move_west
	jmp	cmd_done
ballooneast:
	lda	movement_mode
	beq	onground
	jsr	move_east
	jmp	cmd_done

	!if	DEBUG {
		!align	$ffff, $9f00
	}
}	; end $9d00
