shithub: pokecrystal

Download patch

ref: 75a4b16a1824595a1671bdc68494f7ab1e0b05ed
parent: f860c98d26d8d3babe1ec123a72ee9d5f3ddd145
parent: f56f340ce115d049374678bffc7509e89a6d31ca
author: Bryan Bishop <[email protected]>
date: Fri Feb 22 12:51:43 EST 2013

Merge pull request #114 from yenatch/master

Split out files and write comments.

--- a/audio/engine.asm
+++ b/audio/engine.asm
@@ -16,27 +16,27 @@
 	push bc
 	push af
 	call MusicOff
-	ld hl, $ff24 ; channel control registers
+	ld hl, rNR50 ; channel control registers
 	xor a
-	ld [hli], a ; ff24 ; volume/vin
-	ld [hli], a ; ff25 ; sfx channels
+	ld [hli], a ; rNR50 ; volume/vin
+	ld [hli], a ; rNR51 ; sfx channels
 	ld a, $80 ; all channels on
 	ld [hli], a ; ff26 ; music channels
 
-	ld hl, $ff10 ; sound channel registers
+	ld hl, rNR10 ; sound channel registers
 	ld e, $04 ; number of channels
 .clearsound
 ;   sound channel   1      2      3      4
 	xor a
-	ld [hli], a ; $ff10, $ff15, $ff1a, $ff1f ; sweep = 0
+	ld [hli], a ; rNR10, $ff15, rNR30, $ff1f ; sweep = 0
 
-	ld [hli], a ; $ff11, $ff16, $ff1b, $ff20 ; length/wavepattern = 0
+	ld [hli], a ; rNR11, rNR21, rNR31, rNR41 ; length/wavepattern = 0
 	ld a, $08
-	ld [hli], a ; $ff12, $ff17, $ff1c, $ff21 ; envelope = 0
+	ld [hli], a ; rNR12, rNR22, rNR32, rNR42 ; envelope = 0
 	xor a
-	ld [hli], a ; $ff13, $ff18, $ff1d, $ff22 ; frequency lo = 0
+	ld [hli], a ; rNR13, rNR23, rNR33, rNR43 ; frequency lo = 0
 	ld a, $80
-	ld [hli], a ; $ff14, $ff19, $ff1e, $ff23 ; restart sound (freq hi = 0)
+	ld [hli], a ; rNR14, rNR24, rNR34, rNR44 ; restart sound (freq hi = 0)
 	dec e
 	jr nz, .clearsound
 
@@ -208,10 +208,10 @@
 	call FadeMusic
 	; write volume to hardware register
 	ld a, [Volume]
-	ld [$ff24], a
+	ld [rNR50], a
 	; write SO on/off to hardware register
 	ld a, [SoundOutput]
-	ld [$ff25], a
+	ld [rNR51], a
 	ret
 ; e8125
 
@@ -251,7 +251,7 @@
 	jr z, .asm_e8159
 	;
 	ld a, [SoundInput]
-	ld [$ff10], a
+	ld [rNR10], a
 .asm_e8159
 	bit 5, [hl] ; rest
 	jr nz, .ch1rest
@@ -264,34 +264,34 @@
 	jr .asm_e8175
 .asm_e816b
 	ld a, [$c294]
-	ld [$ff13], a
+	ld [rNR13], a
 	ld a, [$c295]
-	ld [$ff14], a
+	ld [rNR14], a
 .asm_e8175
 	bit 0, [hl]
 	ret z
 	ld a, [$c292]
 	ld d, a
-	ld a, [$ff11]
+	ld a, [rNR11]
 	and a, $3f ; sound length
 	or d
-	ld [$ff11], a
+	ld [rNR11], a
 	ret
 .asm_e8184
 	ld a, [$c292]
 	ld d, a
-	ld a, [$ff11]
+	ld a, [rNR11]
 	and a, $3f ; sound length
 	or d
-	ld [$ff11], a
+	ld [rNR11], a
 	ld a, [$c294]
-	ld [$ff13], a
+	ld [rNR13], a
 	ret
 .ch1rest
-	ld a, [$ff26]
+	ld a, [rNR52]
 	and a, %10001110 ; ch1 off
-	ld [$ff26], a
-	ld hl, $ff10
+	ld [rNR52], a
+	ld hl, rNR10
 	call ClearChannel
 	ret
 .asm_e81a2
@@ -298,14 +298,14 @@
 	ld hl, $c292
 	ld a, $3f ; sound length
 	or [hl]
-	ld [$ff11], a
+	ld [rNR11], a
 	ld a, [$c293]
-	ld [$ff12], a
+	ld [rNR12], a
 	ld a, [$c294]
-	ld [$ff13], a
+	ld [rNR13], a
 	ld a, [$c295]
 	or a, $80
-	ld [$ff14], a
+	ld [rNR14], a
 	ret
 
 .Channel2
@@ -322,31 +322,31 @@
 	ret z
 	ld a, [$c292]
 	ld d, a
-	ld a, [$ff16]
+	ld a, [rNR21]
 	and a, $3f ; sound length
 	or d
-	ld [$ff16], a
+	ld [rNR21], a
 	ret
 .asm_e81db ; unused
 	ld a, [$c294]
-	ld [$ff18], a
+	ld [rNR23], a
 	ld a, [$c295]
-	ld [$ff19], a
+	ld [rNR24], a
 	ret
 .asm_e81e6
 	ld a, [$c292]
 	ld d, a
-	ld a, [$ff16]
+	ld a, [rNR21]
 	and a, $3f ; sound length
 	or d
-	ld [$ff16], a
+	ld [rNR21], a
 	ld a, [$c294]
-	ld [$ff18], a
+	ld [rNR23], a
 	ret
 .ch2rest
-	ld a, [$ff26]
+	ld a, [rNR52]
 	and a, %10001101 ; ch2 off
-	ld [$ff26], a
+	ld [rNR52], a
 	ld hl, $ff15
 	call ClearChannel
 	ret
@@ -354,14 +354,14 @@
 	ld hl, $c292
 	ld a, $3f ; sound length
 	or [hl]
-	ld [$ff16], a
+	ld [rNR21], a
 	ld a, [$c293]
-	ld [$ff17], a
+	ld [rNR22], a
 	ld a, [$c294]
-	ld [$ff18], a
+	ld [rNR23], a
 	ld a, [$c295]
 	or a, $80 ; initial (restart)
-	ld [$ff19], a
+	ld [rNR24], a
 	ret
 
 .Channel3
@@ -377,34 +377,34 @@
 	ret
 .asm_e822f ; unused
 	ld a, [$c294]
-	ld [$ff1d], a
+	ld [rNR33], a
 	ld a, [$c295]
-	ld [$ff1e], a
+	ld [rNR34], a
 	ret
 .asm_e823a
 	ld a, [$c294]
-	ld [$ff1d], a
+	ld [rNR33], a
 	ret
 .ch3rest
-	ld a, [$ff26]
+	ld a, [rNR52]
 	and a, %10001011 ; ch3 off
-	ld [$ff26], a
-	ld hl, $ff1a
+	ld [rNR52], a
+	ld hl, rNR30
 	call ClearChannel
 	ret
 .asm_e824d
 	ld a, $3f
-	ld [$ff1b], a
+	ld [rNR31], a
 	xor a
-	ld [$ff1a], a
+	ld [rNR30], a
 	call .asm_e8268
 	ld a, $80
-	ld [$ff1a], a
+	ld [rNR30], a
 	ld a, [$c294]
-	ld [$ff1d], a
+	ld [rNR33], a
 	ld a, [$c295]
 	or a, $80
-	ld [$ff1e], a
+	ld [rNR34], a
 	ret
 .asm_e8268
 	push hl
@@ -458,7 +458,7 @@
 	ld a, [$c293]
 	and a, $f0
 	sla a
-	ld [$ff1c], a
+	ld [rNR32], a
 	ret
 
 .Channel4
@@ -472,24 +472,24 @@
 	ret
 .asm_e82c1 ; unused
 	ld a, [$c294]
-	ld [$ff22], a
+	ld [rNR43], a
 	ret
 .ch4rest
-	ld a, [$ff26]
+	ld a, [rNR52]
 	and a, %10000111 ; ch4 off
-	ld [$ff26], a
+	ld [rNR52], a
 	ld hl, $ff1f
 	call ClearChannel
 	ret
 .asm_e82d4
 	ld a, $3f ; sound length
-	ld [$ff20], a
+	ld [rNR41], a
 	ld a, [$c293]
-	ld [$ff21], a
+	ld [rNR42], a
 	ld a, [$c294]
-	ld [$ff22], a
+	ld [rNR43], a
 	ld a, $80
-	ld [$ff23], a
+	ld [rNR44], a
 	ret
 ; e82e7
 
@@ -535,15 +535,15 @@
 	ld hl, Tablee8350
 .updatehw
 	xor a
-	ld [$ff10], a ; sweep off
+	ld [rNR10], a ; sweep off
 	ld a, [hli]
-	ld [$ff11], a ; sound length / duty cycle
+	ld [rNR11], a ; sound length / duty cycle
 	ld a, [hli]
-	ld [$ff12], a ; ch1 volume envelope
+	ld [rNR12], a ; ch1 volume envelope
 	ld a, [hli]
-	ld [$ff13], a ; ch1 frequency lo
+	ld [rNR13], a ; ch1 frequency lo
 	ld a, [hli]
-	ld [$ff14], a ; ch1 frequency hi
+	ld [rNR14], a ; ch1 frequency hi
 .asm_e8335
 	ld a, d
 	inc a
@@ -1192,7 +1192,7 @@
 	jr nz, .ok
 	; ????
 	xor a
-	ld [$ff10], a ; sweep = 0
+	ld [rNR10], a ; sweep = 0
 .ok
 ; stop playing
 	; turn channel off
@@ -2454,16 +2454,16 @@
 	jr z, .ch6
 	res 0, [hl] ; turn it off
 	xor a
-	ld [$ff11], a ; length/wavepattern = 0
+	ld [rNR11], a ; length/wavepattern = 0
 	ld a, $08
-	ld [$ff12], a ; envelope = 0
+	ld [rNR12], a ; envelope = 0
 	xor a
-	ld [$ff13], a ; frequency lo = 0
+	ld [rNR13], a ; frequency lo = 0
 	ld a, $80
-	ld [$ff14], a ; restart sound (freq hi = 0)
+	ld [rNR14], a ; restart sound (freq hi = 0)
 	xor a
 	ld [SoundInput], a ; global sound off
-	ld [$ff10], a ; sweep = 0
+	ld [rNR10], a ; sweep = 0
 .ch6
 	ld hl, $c1fe ; ch6 on?
 	bit 0, [hl]
@@ -2470,13 +2470,13 @@
 	jr z, .ch7
 	res 0, [hl] ; turn it off
 	xor a
-	ld [$ff16], a ; length/wavepattern = 0
+	ld [rNR21], a ; length/wavepattern = 0
 	ld a, $08
-	ld [$ff17], a ; envelope = 0
+	ld [rNR22], a ; envelope = 0
 	xor a
-	ld [$ff18], a ; frequency lo = 0
+	ld [rNR23], a ; frequency lo = 0
 	ld a, $80
-	ld [$ff19], a ; restart sound (freq hi = 0)
+	ld [rNR24], a ; restart sound (freq hi = 0)
 .ch7
 	ld hl, $c230 ; ch7 on?
 	bit 0, [hl]
@@ -2483,14 +2483,14 @@
 	jr z, .ch8
 	res 0, [hl] ; turn it off
 	xor a
-	ld [$ff1a], a ; sound mode #3 off
-	ld [$ff1b], a ; length/wavepattern = 0
+	ld [rNR30], a ; sound mode #3 off
+	ld [rNR31], a ; length/wavepattern = 0
 	ld a, $08
-	ld [$ff1c], a ; envelope = 0
+	ld [rNR32], a ; envelope = 0
 	xor a
-	ld [$ff1d], a ; frequency lo = 0
+	ld [rNR33], a ; frequency lo = 0
 	ld a, $80
-	ld [$ff1e], a ; restart sound (freq hi = 0)
+	ld [rNR34], a ; restart sound (freq hi = 0)
 .ch8
 	ld hl, $c262 ; ch8 on?
 	bit 0, [hl]
@@ -2497,13 +2497,13 @@
 	jr z, .chscleared
 	res 0, [hl] ; turn it off
 	xor a
-	ld [$ff20], a ; length/wavepattern = 0
+	ld [rNR41], a ; length/wavepattern = 0
 	ld a, $08
-	ld [$ff21], a ; envelope = 0
+	ld [rNR42], a ; envelope = 0
 	xor a
-	ld [$ff22], a ; frequency lo = 0
+	ld [rNR43], a ; frequency lo = 0
 	ld a, $80
-	ld [$ff23], a ; restart sound (freq hi = 0)
+	ld [rNR44], a ; restart sound (freq hi = 0)
 	xor a
 	ld [NoiseSampleAddressLo], a
 	ld [NoiseSampleAddressHi], a
@@ -3126,13 +3126,13 @@
 ClearChannels: ; e8fe9
 ; runs ClearChannel for all 4 channels
 ; doesn't seem to be used, but functionally identical to SoundRestart
-	ld hl, $ff24
+	ld hl, rNR50
 	xor a
 	ld [hli], a
 	ld [hli], a
 	ld a, $80
 	ld [hli], a
-	ld hl, $ff10
+	ld hl, rNR10
 	ld e, $04
 .loop
 	call ClearChannel
@@ -3142,19 +3142,19 @@
 ; e8ffe
 
 ClearChannel: ; e8ffe
-; input: hl = beginning hw sound register ($ff10, $ff15, $ff1a, $ff1f)
+; input: hl = beginning hw sound register (rNR10, $ff15, rNR30, $ff1f)
 ; output: 00 00 80 00 80
 
 ;   sound channel   1      2      3      4
 	xor a
-	ld [hli], a ; $ff10, $ff15, $ff1a, $ff1f ; sweep = 0
+	ld [hli], a ; rNR10, $ff15, rNR30, $ff1f ; sweep = 0
 
-	ld [hli], a ; $ff11, $ff16, $ff1b, $ff20 ; length/wavepattern = 0
+	ld [hli], a ; rNR11, rNR21, rNR31, rNR41 ; length/wavepattern = 0
 	ld a, $08
-	ld [hli], a ; $ff12, $ff17, $ff1c, $ff21 ; envelope = 0
+	ld [hli], a ; rNR12, rNR22, rNR32, rNR42 ; envelope = 0
 	xor a
-	ld [hli], a ; $ff13, $ff18, $ff1d, $ff22 ; frequency lo = 0
+	ld [hli], a ; rNR13, rNR23, rNR33, rNR43 ; frequency lo = 0
 	ld a, $80
-	ld [hli], a ; $ff14, $ff19, $ff1e, $ff23 ; restart sound (freq hi = 0)
+	ld [hli], a ; rNR14, rNR24, rNR34, rNR44 ; restart sound (freq hi = 0)
 	ret
 ; e900a
--- /dev/null
+++ b/battle/magikarp_length.asm
@@ -1,0 +1,220 @@
+CalcMagikarpLength: ; fbbfc
+; Return Magikarp's length (in mm) in MagikarpLength (big endian)
+;
+; input:
+;   de: EnemyMonDVs
+;   bc: PlayerID
+
+; This function is needlessly convoluted, and poorly commented.
+; Reading is discouraged.
+
+; In short, it generates a value between 190 and 1786 using
+; a Magikarp's DVs and its trainer ID. This value is further
+; scrutinized in GetEnemyMon to make longer Magikarp even rarer.
+
+; This is done by calculating the value using operands from
+; a conversion lookup table.
+
+; Our index is calculated by xoring DVs with the trainer ID:
+
+; bc = rrc(rrc(dvs)) xor rrc(id)
+
+; if bc < $a:     MagikarpLength = c + 190
+; if bc >= $ff00: MagikarpLength = c + 1370
+; else:           MagikarpLength = z*100 + (bc-x)/y
+
+; X, Y, and Z depend on the value of b as follows:
+
+; if b = 0:        x =   310,  y =   2,  z =  3
+; if b = 1:        x =   710,  y =   4,  z =  4
+; if b = 2-9:      x =  2710,  y =  20,  z =  5
+; if b = 10-29:    x =  7710,  y =  50,  z =  6
+; if b = 30-68:    x = 17710,  y = 100,  z =  7
+; if b = 69-126:   x = 32710,  y = 150,  z =  8
+; if b = 127-185:  x = 47710,  y = 150,  z =  9
+; if b = 186-224:  x = 57710,  y = 100,  z = 10
+; if b = 225-243:  x = 62710,  y =  50,  z = 11
+; if b = 244-251:  x = 64710,  y =  20,  z = 12
+; if b = 252-253:  x = 65210,  y =   5,  z = 13
+; if b = 254:      x = 65410,  y =   2,  z = 14
+
+; These values represent arbitrary conversion points.
+
+
+; b = rrcrrc(atkdefdv) xor rrc(id[0])
+	
+; id
+	ld h, b
+	ld l, c
+	ld a, [hli]
+	ld b, a
+	ld c, [hl]
+	rrc b
+	rrc c
+	
+; dvs
+	ld a, [de]
+	inc de
+	rrca
+	rrca
+	xor b
+	ld b, a
+	
+; c = rrcrrc(spdspcdv) xor rrc(id[1])
+	
+	ld a, [de]
+	rrca
+	rrca
+	xor c
+	ld c, a
+	
+; if bc < $000a:
+	ld a, b
+	and a
+	jr nz, .loadtable
+	ld a, c
+	cp a, $a
+	jr nc, .loadtable
+	
+; de = hl = bc + $be
+	ld hl, $be
+	add hl, bc
+	ld d, h
+	ld e, l
+	jr .endtable
+	
+.loadtable
+	ld hl, .MagikarpLengthTable
+	ld a, $02
+	ld [$d265], a
+	
+.readtable
+	ld a, [hli]
+	ld e, a
+	ld a, [hli]
+	ld d, a
+	call .BLessThanD
+	jr nc, .advancetable
+	
+; c = bc / [hl]
+	call .BCMinusDE
+	ld a, b
+	ld [$ffb3], a
+	ld a, c
+	ld [$ffb4], a
+	ld a, [hl]
+	ld [$ffb7], a
+	ld b, $02
+	call Divide
+	ld a, [$ffb6]
+	ld c, a
+	
+; de = c + 100 * (2 + number of rows down the table)
+	xor a
+	ld [$ffb4], a
+	ld [$ffb5], a
+	ld a, $64
+	ld [$ffb6], a
+	ld a, [$d265]
+	ld [$ffb7], a
+	call Multiply
+	ld b, $00
+	ld a, [$ffb6]
+	add c
+	ld e, a
+	ld a, [$ffb5]
+	adc b
+	ld d, a
+	jr .endtable
+	
+.advancetable
+	inc hl ; align to next triplet
+	ld a, [$d265]
+	inc a
+	ld [$d265], a
+	cp a, $10
+	jr c, .readtable
+	
+	call .BCMinusDE
+	ld hl, $0640
+	add hl, bc
+	ld d, h
+	ld e, l
+	
+.endtable
+	ld h, d
+	ld l, e
+	add hl, hl
+	add hl, hl
+	add hl, de
+	add hl, hl ; hl = de * 10
+	
+	ld de, $ff02
+	ld a, $ff
+.loop
+	inc a
+	add hl, de ; - 254
+	jr c, .loop
+	
+	ld d, $00
+	
+; mod $0c
+.modloop
+	cp a, $0c
+	jr c, .done
+	sub a, $0c
+	inc d
+	jr .modloop
+	
+.done
+	ld e, a
+	ld hl, MagikarpLength
+	ld [hl], d
+	inc hl
+	ld [hl], e
+	ret
+; fbc9a
+
+.BLessThanD ; fbc9a
+; return carry if b < d
+	ld a, b
+	cp d
+	ret c
+	ret nc
+; fbc9e
+
+.CLessThanE ; fbc9e
+; unused
+	ld a, c
+	cp e
+	ret
+; fbca1
+
+.BCMinusDE ; fbca1
+; bc -= de
+	ld a, c
+	sub e
+	ld c, a
+	ld a, b
+	sbc d
+	ld b, a
+	ret
+; fbca8
+
+.MagikarpLengthTable ; fbca8
+;	     ????, divisor
+	dwb $006e, $01
+	dwb $0136, $02
+	dwb $02c6, $04
+	dwb $0a96, $14
+	dwb $1e1e, $32
+	dwb $452e, $64
+	dwb $7fc6, $96
+	dwb $ba5e, $96
+	dwb $e16e, $64
+	dwb $f4f6, $32
+	dwb $fcc6, $14
+	dwb $feba, $05
+	dwb $ff82, $02
+; fbccf
+
--- a/constants.asm
+++ b/constants.asm
@@ -3417,15 +3417,20 @@
 
 
 ; joypad
-NO_INPUT EQU %00000000
-BUTTON_A EQU %00000001
-BUTTON_B EQU %00000010
-SELECT   EQU %00000100
-START    EQU %00001000
-D_RIGHT  EQU %00010000
-D_LEFT   EQU %00100000
-D_UP     EQU %01000000
-D_DOWN   EQU %10000000
+BUTTONS    EQU %00010000
+D_PAD      EQU %00100000
+
+AUTO_INPUT EQU $ff
+
+NO_INPUT   EQU %00000000
+BUTTON_A   EQU %00000001
+BUTTON_B   EQU %00000010
+SELECT     EQU %00000100
+START      EQU %00001000
+D_RIGHT    EQU %00010000
+D_LEFT     EQU %00100000
+D_UP       EQU %01000000
+D_DOWN     EQU %10000000
 
 ; mbc
 NUM_SRAM_BANKS EQU 4
--- /dev/null
+++ b/gbhw.asm
@@ -1,0 +1,65 @@
+; Graciously aped from http://nocash.emubase.de/pandocs.htm .
+
+rJOYP       EQU $ff00 ; Joypad (R/W)
+rSB         EQU $ff01 ; Serial transfer data (R/W)
+rSC         EQU $ff02 ; Serial Transfer Control (R/W)
+rDIV        EQU $ff04 ; Divider Register (R/W)
+rTIMA       EQU $ff05 ; Timer counter (R/W)
+rTMA        EQU $ff06 ; Timer Modulo (R/W)
+rTAC        EQU $ff07 ; Timer Control (R/W)
+rIF         EQU $ff0f ; Interrupt Flag (R/W)
+rNR10       EQU $ff10 ; Channel 1 Sweep register (R/W)
+rNR11       EQU $ff11 ; Channel 1 Sound length/Wave pattern duty (R/W)
+rNR12       EQU $ff12 ; Channel 1 Volume Envelope (R/W)
+rNR13       EQU $ff13 ; Channel 1 Frequency lo (Write Only)
+rNR14       EQU $ff14 ; Channel 1 Frequency hi (R/W)
+rNR21       EQU $ff16 ; Channel 2 Sound Length/Wave Pattern Duty (R/W)
+rNR22       EQU $ff17 ; Channel 2 Volume Envelope (R/W)
+rNR23       EQU $ff18 ; Channel 2 Frequency lo data (W)
+rNR24       EQU $ff19 ; Channel 2 Frequency hi data (R/W)
+rNR30       EQU $ff1a ; Channel 3 Sound on/off (R/W)
+rNR31       EQU $ff1b ; Channel 3 Sound Length
+rNR32       EQU $ff1c ; Channel 3 Select output level (R/W)
+rNR33       EQU $ff1d ; Channel 3 Frequency's lower data (W)
+rNR34       EQU $ff1e ; Channel 3 Frequency's higher data (R/W)
+rNR41       EQU $ff20 ; Channel 4 Sound Length (R/W)
+rNR42       EQU $ff21 ; Channel 4 Volume Envelope (R/W)
+rNR43       EQU $ff22 ; Channel 4 Polynomial Counter (R/W)
+rNR44       EQU $ff23 ; Channel 4 Counter/consecutive; Inital (R/W)
+rNR50       EQU $ff24 ; Channel control / ON-OFF / Volume (R/W)
+rNR51       EQU $ff25 ; Selection of Sound output terminal (R/W)
+rNR52       EQU $ff26 ; Sound on/off
+rLCDC       EQU $ff40 ; LCD Control (R/W)
+rSTAT       EQU $ff41 ; LCDC Status (R/W)
+rSCY        EQU $ff42 ; Scroll Y (R/W)
+rSCX        EQU $ff43 ; Scroll X (R/W)
+rLY         EQU $ff44 ; LCDC Y-Coordinate (R)
+rLYC        EQU $ff45 ; LY Compare (R/W)
+rDMA        EQU $ff46 ; DMA Transfer and Start Address (W)
+rBGP        EQU $ff47 ; BG Palette Data (R/W) - Non CGB Mode Only
+rOBP0       EQU $ff48 ; Object Palette 0 Data (R/W) - Non CGB Mode Only
+rOBP1       EQU $ff49 ; Object Palette 1 Data (R/W) - Non CGB Mode Only
+rWY         EQU $ff4a ; Window Y Position (R/W)
+rWX         EQU $ff4b ; Window X Position minus 7 (R/W)
+rKEY1       EQU $ff4d ; CGB Mode Only - Prepare Speed Switch
+rVBK        EQU $ff4f ; CGB Mode Only - VRAM Bank
+rHDMA1      EQU $ff51 ; CGB Mode Only - New DMA Source, High
+rHDMA2      EQU $ff52 ; CGB Mode Only - New DMA Source, Low
+rHDMA3      EQU $ff53 ; CGB Mode Only - New DMA Destination, High
+rHDMA4      EQU $ff54 ; CGB Mode Only - New DMA Destination, Low
+rHDMA5      EQU $ff55 ; CGB Mode Only - New DMA Length/Mode/Start
+rRP         EQU $ff56 ; CGB Mode Only - Infrared Communications Port
+rBGPI       EQU $ff68 ; CGB Mode Only - Background Palette Index
+rBGPD       EQU $ff69 ; CGB Mode Only - Background Palette Data
+rOBPI       EQU $ff6a ; CGB Mode Only - Sprite Palette Index
+rOBPD       EQU $ff6b ; CGB Mode Only - Sprite Palette Data
+rUNKNOWN1   EQU $ff6c ; (FEh) Bit 0 (Read/Write) - CGB Mode Only
+rSVBK       EQU $ff70 ; CGB Mode Only - WRAM Bank
+rUNKNOWN2   EQU $ff72 ; (00h) - Bit 0-7 (Read/Write)
+rUNKNOWN3   EQU $ff73 ; (00h) - Bit 0-7 (Read/Write)
+rUNKNOWN4   EQU $ff74 ; (00h) - Bit 0-7 (Read/Write) - CGB Mode Only
+rUNKNOWN5   EQU $ff75 ; (8Fh) - Bit 4-6 (Read/Write)
+rUNKNOWN6   EQU $ff76 ; (00h) - Always 00h (Read Only)
+rUNKNOWN7   EQU $ff77 ; (00h) - Always 00h (Read Only)
+rIE         EQU $ffff ; Interrupt Enable (R/W)
+
binary files a/gfx/font.1bpp /dev/null differ
binary files a/gfx/font_battle_extra.2bpp /dev/null differ
binary files a/gfx/font_extra.2bpp /dev/null differ
--- a/gfx/font_inversed.1bpp
+++ /dev/null
@@ -1,1 +1,0 @@
-��׻�}}�{{}}�ý���{}}}{���ýa}���}}}}}}������������www��{woO7{}��}9Um}}}�}=]muy}�ǻ}}}���}}�ǻ}}u���}}w{}��{��}���������}}}}}���}}������}}mU99}�9���׻9�}����������߿�����������������������������������������������������û����������������������������ý��������������������������������������������������������������mmmm�����������ý������������������������������ÿ������������������������������}mmU����;��׹��������������߁���������������������������������������������������׻�}}��ǻ}}����}}}}�������û����ý��������������������������������������������������������������������������������������������=�}�����7�w�����?�i�����?�l�����?�a�����?�A�����?�]�������������������������������������������������������������������������������������ouu���'Www�����������������������������1���������������������ϗ�ͥ3���?ý�����������������������������������ǫmǻ�����ߏߏ������׻�������������߿���������ǻ�������dz99�������������9��������9����Ó3����9����?99���9�������9�99����99�
\ No newline at end of file
binary files /dev/null b/gfx/misc/font.1bpp differ
binary files /dev/null b/gfx/misc/font_battle_extra.2bpp differ
binary files /dev/null b/gfx/misc/font_extra.2bpp differ
--- /dev/null
+++ b/gfx/misc/font_inversed.1bpp
@@ -1,0 +1,1 @@
+��׻�}}�{{}}�ý���{}}}{���ýa}���}}}}}}������������www��{woO7{}��}9Um}}}�}=]muy}�ǻ}}}���}}�ǻ}}u���}}w{}��{��}���������}}}}}���}}������}}mU99}�9���׻9�}����������߿�����������������������������������������������������û����������������������������ý��������������������������������������������������������������mmmm�����������ý������������������������������ÿ������������������������������}mmU����;��׹��������������߁���������������������������������������������������׻�}}��ǻ}}����}}}}�������û����ý��������������������������������������������������������������������������������������������=�}�����7�w�����?�i�����?�l�����?�a�����?�A�����?�]�������������������������������������������������������������������������������������ouu���'Www�����������������������������1���������������������ϗ�ͥ3���?ý�����������������������������������ǫmǻ�����ߏߏ������׻�������������߿���������ǻ�������dz99�������������9��������9����Ó3����9����?99���9�������9�99����99�
\ No newline at end of file
--- /dev/null
+++ b/joypad.asm
@@ -1,0 +1,275 @@
+JoypadInt: ; 92e
+; Replaced by Joypad, called from VBlank instead of the useless
+; joypad interrupt.
+
+; This is a placeholder in case the interrupt is somehow enabled.
+	reti
+; 92f
+
+ClearJoypadPublic: ; 92f
+	xor a
+; Pressed this frame (delta)
+	ld [$ffa7], a
+; Currently pressed
+	ld [$ffa8], a
+	ret
+; 935
+
+Joypad: ; 935
+; Read the joypad register and translate it to something more
+; workable for use in-game. There are 8 buttons, so we can use
+; one byte to contain all player input.
+
+; Updates:
+
+; $ffa2: released this frame (delta)
+; $ffa3: pressed this frame (delta)
+; $ffa4: currently pressed
+; $ffa5: pressed so far
+
+; Any of these three bits can be used to disable input.
+	ld a, [$cfbe]
+	and %11010000
+	ret nz
+	
+; If we're saving, input is disabled.
+	ld a, [$c2cd]
+	and a
+	ret nz
+	
+; We can only get four inputs at a time.
+; We take d-pad first for no particular reason.
+	ld a, D_PAD
+	ld [rJOYP], a
+; Read twice to give the request time to take.
+	ld a, [rJOYP]
+	ld a, [rJOYP]
+	
+; The Joypad register output is in the lo nybble (inversed).
+; We make the hi nybble of our new container d-pad input.
+	cpl
+	and $f
+	swap a
+	
+; We'll keep this in b for now.
+	ld b, a
+	
+; Buttons make 8 total inputs (A, B, Select, Start).
+; We can fit this into one byte.
+	ld a, BUTTONS
+	ld [rJOYP], a
+; Wait for input to stabilize.
+	ld a, [rJOYP]
+	ld a, [rJOYP]
+	ld a, [rJOYP]
+	ld a, [rJOYP]
+	ld a, [rJOYP]
+	ld a, [rJOYP]
+; Buttons take the lo nybble.
+	cpl
+	and $f
+	or b
+	ld b, a
+	
+; Reset the joypad register since we're done with it.
+	ld a, $30
+	ld [rJOYP], a
+	
+; To get the delta we xor the last frame's input with the new one.
+	ld a, [$ffa4] ; last frame
+	ld e, a
+	xor b
+	ld d, a
+; Released this frame:
+	and e
+	ld [$ffa2], a
+; Pressed this frame:
+	ld a, d
+	and b
+	ld [$ffa3], a
+	
+; Add any new presses to the list of collective presses:
+	ld c, a
+	ld a, [$ffa5]
+	or c
+	ld [$ffa5], a
+	
+; Currently pressed:
+	ld a, b
+	ld [$ffa4], a
+	
+; Now that we have the input, we can do stuff with it.
+
+; For example, soft reset:
+	and BUTTON_A | BUTTON_B | SELECT | START
+	cp  BUTTON_A | BUTTON_B | SELECT | START
+	jp z, $0150 ; reset
+	
+	ret
+; 984
+
+
+GetJoypadPublic: ; 984
+; Update mirror joypad input from $ffa4 (real input)
+
+; $ffa6: released this frame (delta)
+; $ffa7: pressed this frame (delta)
+; $ffa8: currently pressed
+
+; bit 0 A
+;     1 B
+;     2 SELECT
+;     3 START
+;     4 RIGHT
+;     5 LEFT
+;     6 UP
+;     7 DOWN
+
+	push af
+	push hl
+	push de
+	push bc
+	
+; The player input can be automated using an input stream.
+; See more below.
+	ld a, [InputType]
+	cp a, AUTO_INPUT
+	jr z, .auto
+
+; To get deltas, take this and last frame's input.
+	ld a, [$ffa4] ; real input
+	ld b, a
+	ld a, [$ffa8] ; last frame mirror
+	ld e, a
+	
+; Released this frame:
+	xor b
+	ld d, a
+	and e
+	ld [$ffa6], a
+	
+; Pressed this frame:
+	ld a, d
+	and b
+	ld [$ffa7], a
+	
+; It looks like the collective presses got commented out here.
+	ld c, a
+	
+; Currently pressed:
+	ld a, b
+	ld [$ffa8], a ; frame input
+	
+.quit
+	pop bc
+	pop de
+	pop hl
+	pop af
+	ret	
+
+.auto
+; Use a predetermined input stream (used in the catching tutorial).
+
+; Stream format: [input][duration]
+; A value of $ff will immediately end the stream.
+
+; Read from the input stream.
+	ld a, [$ff9d]
+	push af
+	ld a, [AutoInputBank]
+	rst Bankswitch
+	
+	ld hl, AutoInputAddress
+	ld a, [hli]
+	ld h, [hl]
+	ld l, a
+	
+; We only update when the input duration has expired.
+	ld a, [AutoInputLength]
+	and a
+	jr z, .updateauto
+	
+; Until then, don't change anything.
+	dec a
+	ld [AutoInputLength], a
+	pop af
+	rst Bankswitch
+	jr .quit
+	
+	
+.updateauto
+; An input of $ff will end the stream.
+	ld a, [hli]
+	cp a, $ff
+	jr z, .stopauto
+	ld b, a
+	
+; A duration of $ff will end the stream indefinitely.
+	ld a, [hli]
+	ld [AutoInputLength], a
+	cp a, $ff
+	jr nz, .next
+	
+; The current input is overwritten.
+	dec hl
+	dec hl
+	ld b, NO_INPUT
+	jr .finishauto
+	
+.next
+; On to the next input...
+	ld a, l
+	ld [AutoInputAddress], a
+	ld a, h
+	ld [AutoInputAddress+1], a
+	jr .finishauto
+	
+.stopauto
+	call StopAutoInput
+	ld b, NO_INPUT
+	
+.finishauto
+	pop af
+	rst Bankswitch
+	ld a, b
+	ld [$ffa7], a ; pressed
+	ld [$ffa8], a ; input
+	jr .quit
+; 9ee
+
+
+StartAutoInput: ; 9ee
+; Start reading automated input stream at a:hl.
+	
+	ld [AutoInputBank], a
+	ld a, l
+	ld [AutoInputAddress], a
+	ld a, h
+	ld [AutoInputAddress+1], a
+; Start reading the stream immediately.
+	xor a
+	ld [AutoInputLength], a
+; Reset input mirrors.
+	xor a
+	ld [$ffa7], a ; pressed this frame
+	ld [$ffa6], a ; released this frame
+	ld [$ffa8], a ; currently pressed
+	
+	ld a, AUTO_INPUT
+	ld [InputType], a
+	ret
+; a0a
+
+
+StopAutoInput: ; a0a
+; Clear variables related to automated input.
+	xor a
+	ld [AutoInputBank], a
+	ld [AutoInputAddress], a
+	ld [AutoInputAddress+1], a
+	ld [AutoInputLength], a
+; Back to normal input.
+	ld [InputType], a
+	ret
+; a1b
+
--- a/main.asm
+++ b/main.asm
@@ -47,7 +47,7 @@
 	jp $06ef
 
 SECTION "joypad",HOME[$60] ; joypad interrupt
-	jp $092e
+	jp JoypadInt
 
 SECTION "romheader",HOME[$100]
 Start:
@@ -150,47 +150,47 @@
 ; Most of this is just going through the motions
 
 ; don't need to do anything if lcd is already off
-	ld a, [$ff40] ; LCDC
+	ld a, [rLCDC]
 	bit 7, a ; lcd enable
 	ret z
 	
 ; reset ints
 	xor a
-	ld [$ff0f], a ; IF
+	ld [rIF], a
 	
 ; save enabled ints
-	ld a, [$ffff] ; IE
+	ld a, [rIE]
 	ld b, a
 	
 ; disable vblank
 	res 0, a ; vblank
-	ld [$ffff], a ; IE
+	ld [rIE], a
 	
 .wait
 ; wait until vblank
-	ld a, [$ff44] ; LY
+	ld a, [rLY]
 	cp 145 ; >144 (ensure beginning of vblank)
 	jr nz, .wait
 	
 ; turn lcd off
-	ld a, [$ff40] ; LCDC
+	ld a, [rLCDC]
 	and %01111111 ; lcd enable off
-	ld [$ff40], a ; LCDC
+	ld [rLCDC], a
 	
 ; reset ints
 	xor a
-	ld [$ff0f], a ; IF
+	ld [rIF], a
 	
 ; restore enabled ints
 	ld a, b
-	ld [$ffff], a ; IE
+	ld [rIE], a
 	ret
 ; 58a
 
 EnableLCD: ; 58a
-	ld a, [$ff40] ; LCDC
+	ld a, [rLCDC]
 	set 7, a ; lcd enable
-	ld [$ff40], a ; LCDC
+	ld [rLCDC], a
 	ret
 ; 591
 
@@ -425,253 +425,12 @@
 	ret
 ; 6c4
 
-INCBIN "baserom.gbc",$6c4,$935 - $6c4
+INCBIN "baserom.gbc",$6c4,$92e - $6c4
 
-Joypad: ; 935
-; update joypad state
-; $ffa2: released
-; $ffa3: pressed
-; $ffa4: input
-; $ffa5: total pressed
 
-; 
-	ld a, [$cfbe]
-	and $d0
-	ret nz
-	
-; pause game update?
-	ld a, [$c2cd]
-	and a
-	ret nz
-	
-; d-pad
-	ld a, $20
-	ld [$ff00], a
-	ld a, [$ff00]
-	ld a, [$ff00]
-; hi nybble
-	cpl
-	and $f
-	swap a
-	ld b, a
-	
-; buttons
-	ld a, $10
-	ld [$ff00], a
-; wait to stabilize
-	ld a, [$ff00]
-	ld a, [$ff00]
-	ld a, [$ff00]
-	ld a, [$ff00]
-	ld a, [$ff00]
-	ld a, [$ff00]
-; lo nybble
-	cpl
-	and $f
-	or b
-	ld b, a
-	
-; reset joypad
-	ld a, $30
-	ld [$ff00], a
-	
-; get change in input
-	ld a, [$ffa4] ; last frame's input
-	ld e, a
-	xor b ; current frame input
-	ld d, a
-; released
-	and e
-	ld [$ffa2], a
-; pressed
-	ld a, d
-	and b
-	ld [$ffa3], a
-	
-; total pressed
-	ld c, a
-	ld a, [$ffa5]
-	or c
-	ld [$ffa5], a
-	
-; original input
-	ld a, b
-	ld [$ffa4], a
-	
-; A+B+SELECT+START
-	and $f
-	cp $f
-	jp z, $0150 ; reset
-	
-	ret
-; 984
+INCLUDE "joypad.asm"
 
 
-GetJoypadPublic: ; 984
-; update mirror joypad input from $ffa4 (real input)
-
-; $ffa6: released
-; $ffa7: pressed
-; $ffa8: input
-
-; bit 0 A
-;     1 B
-;     2 SELECT
-;     3 START
-;     4 RIGHT
-;     5 LEFT
-;     6 UP
-;     7 DOWN
-
-	push af
-	push hl
-	push de
-	push bc
-	
-; automated input?
-	ld a, [InputType]
-	cp a, $ff ; INPUT_AUTO
-	jr z, .auto
-
-; get input
-	ld a, [$ffa4] ; real input
-	ld b, a
-	ld a, [$ffa8] ; last frame mirror
-	ld e, a
-	
-; released
-	xor b
-	ld d, a
-	and e
-	ld [$ffa6], a
-	
-; pressed
-	ld a, d
-	and b
-	ld [$ffa7], a
-	
-; leftover from pasted code
-	ld c, a
-	
-;
-	ld a, b
-	ld [$ffa8], a ; frame input
-.quit
-	pop bc
-	pop de
-	pop hl
-	pop af
-	ret	
-
-.auto
-; use predetermined input feed (used in catch tutorial)
-; struct: [input][duration]
-
-; save bank
-	ld a, [$ff9d]
-	push af
-;
-	ld a, [AutoInputBank]
-	rst Bankswitch
-;
-	ld hl, AutoInputAddress ; AutoInputAddress-9
-	ld a, [hli]
-	ld h, [hl]
-	ld l, a
-	
-; update when frame count hits 0
-	ld a, [AutoInputLength]
-	and a
-	jr z, .updateauto
-	
-; until then, do nothing
-	dec a
-	ld [AutoInputLength], a
-; restore bank
-	pop af
-	rst Bankswitch
-; we're done
-	jr .quit
-	
-.updateauto
-; get input
-	ld a, [hli]
-; stop?
-	cp a, $ff
-	jr z, .stopinput
-	ld b, a
-	
-; duration
-	ld a, [hli]
-	ld [AutoInputLength], a
-; duration $ff = end at input
-	cp a, $ff
-	jr nz, .next
-	
-; no input
-	dec hl
-	dec hl
-	ld b, $00 ; no input
-	jr .finishauto
-	
-.next
-; output recorded
-	ld a, l
-	ld [AutoInputAddress], a
-	ld a, h
-	ld [AutoInputAddress+1], a
-	jr .finishauto
-	
-.stopinput
-	call StopAutoInput
-	ld b, $00 ; no input
-	
-.finishauto
-; restore bank
-	pop af
-	rst Bankswitch
-; update mirrors
-	ld a, b
-	ld [$ffa7], a ; pressed
-	ld [$ffa8], a ; input
-	jr .quit
-; 9ee
-
-StartAutoInput: ; 9ee
-; start auto input stream at a:hl
-; bank
-	ld [AutoInputBank], a
-; address
-	ld a, l
-	ld [AutoInputAddress], a
-	ld a, h
-	ld [AutoInputAddress+1], a
-; don't wait to update
-	xor a
-	ld [AutoInputLength], a
-; clear input mirrors
-	xor a
-	ld [$ffa7], a ; pressed
-	ld [$ffa6], a ; released
-	ld [$ffa8], a ; input
-; start reading input stream instead of player input
-	ld a, $ff ; INPUT_AUTO
-	ld [InputType], a
-	ret
-; a0a
-
-StopAutoInput: ; a0a
-; clear autoinput ram
-	xor a
-	ld [AutoInputBank], a
-	ld [AutoInputAddress], a
-	ld [AutoInputAddress+1], a
-	ld [AutoInputLength], a
-; normal input
-	ld [InputType], a
-	ret
-; a1b
-
 INCBIN "baserom.gbc",$a1b,$b40 - $a1b
 
 FarDecompress: ; b40
@@ -1063,18 +822,18 @@
 	
 ForceUpdateCGBPals: ; c37
 ; save wram bank
-	ld a, [$ff70] ; wram bank
+	ld a, [rSVBK]
 	push af
 ; bankswitch
 	ld a, 5 ; BANK(BGPals)
-	ld [$ff70], a ; wram bank
+	ld [rSVBK], a
 ; get bg pal buffer
 	ld hl, BGPals ; 5:d080
 	
 ; update bg pals
 	ld a, %10000000 ; auto increment, index 0
-	ld [$ff68], a ; BGPI
-	ld c, $69 ; $ff69
+	ld [rBGPI], a
+	ld c, rBGPD - rJOYP
 	ld b, 4 ; NUM_PALS / 2
 	
 .bgp
@@ -1119,8 +878,8 @@
 	
 ; update obj pals
 	ld a, %10000000 ; auto increment, index 0
-	ld [$ff6a], a
-	ld c, $6b ; $ff6b - $ff00
+	ld [rOBPI], a
+	ld c, rOBPD - rJOYP
 	ld b, 4 ; NUM_PALS / 2
 	
 .obp
@@ -1163,7 +922,7 @@
 	
 ; restore wram bank
 	pop af
-	ld [$ff70], a ; wram bank
+	ld [rSVBK], a
 ; clear pal update queue
 	xor a
 	ld [$ffe5], a
@@ -1177,7 +936,7 @@
 ; exists to forego reinserting cgb-converted image data
 
 ; input: a -> bgp
-	ld [$ff47], a ; bgp
+	ld [rBGP], a
 	push af
 	
 ; check cgb
@@ -1199,7 +958,7 @@
 	ld hl, BGPals ; to
 	ld de, Unkn1Pals ; from
 ; order
-	ld a, [$ff47] ; bgp
+	ld a, [rBGP]
 	ld b, a
 ; # pals
 	ld c, 8 ; all pals
@@ -1225,9 +984,9 @@
 ; input: d -> obp1
 ;		 e -> obp2
 	ld a, e
-	ld [$ff48], a ; obp0
+	ld [rOBP0], a
 	ld a, d
-	ld [$ff49], a ; obp1
+	ld [rOBP1], a
 	
 ; check cgb
 	ld a, [$ffe6]
@@ -1250,7 +1009,7 @@
 	; from
 	ld de, Unkn2Pals
 ; order
-	ld a, [$ff48] ; obp0
+	ld a, [rOBP0]
 	ld b, a
 ; # pals
 	ld c, 8 ; all pals
@@ -1378,7 +1137,7 @@
 	call ByteFill
 	
 ; We aren't done if the LCD is on
-	ld a, [$ff40] ; LCDC
+	ld a, [rLCDC]
 	bit 7, a
 	ret z
 	jp WaitBGMap
@@ -1668,7 +1427,7 @@
 	and a
 	ret z
 ; start transfer
-	ld [$ff55], a ; hdma5
+	ld [rHDMA5], a
 ; indicate that transfer has occurred
 	xor a
 	ld [$ffe8], a
@@ -1689,7 +1448,7 @@
 	and a
 	ret z
 ; save wram bank
-	ld a, [$ff4f] ; vram bank
+	ld a, [rVBK]
 	push af
 ; save sp
 	ld [$ffd9], sp
@@ -1712,7 +1471,7 @@
 	pop bc
 ; update palettes
 	ld a, $1
-	ld [$ff4f], a ; vram bank
+	ld [rVBK], a
 ; tile 1
 	ld a, [hli]
 	ld [bc], a
@@ -1723,7 +1482,7 @@
 	dec c
 ; update tiles
 	ld a, $0
-	ld [$ff4f], a ; vram bank
+	ld [rVBK], a
 ; tile 1
 	ld a, [de]
 	inc de
@@ -1740,7 +1499,7 @@
 	pop bc
 ; update palettes
 	ld a, $1
-	ld [$ff4f], a ; vram bank
+	ld [rVBK], a
 ; tile 1
 	ld a, [hli]
 	ld [bc], a
@@ -1751,7 +1510,7 @@
 	dec c
 ; update tiles
 	ld a, $0
-	ld [$ff4f], a ; vram bank
+	ld [rVBK], a
 ; tile 1
 	ld a, [de]
 	inc de
@@ -1781,7 +1540,7 @@
 	
 ; restore vram bank
 	pop af
-	ld [$ff4f], a ; vram bank
+	ld [rVBK], a
 	
 ; we don't need to update bg map until new tiles are loaded
 	xor a
@@ -1859,13 +1618,13 @@
 .attr
 ; switch vram banks
 	ld a, 1
-	ld [$ff4f], a ; vram bank
+	ld [rVBK], a
 ; bg map 1
 	ld hl, AttrMap
 	call .getthird
 ; restore vram bank
 	ld a, 0
-	ld [$ff4f], a ; vram bank
+	ld [rVBK], a
 	ret
 	
 .tiles
@@ -2012,7 +1771,7 @@
 	and a
 	ret z
 ; abort if too far into vblank
-	ld a, [$ff44] ; LY
+	ld a, [rLY]
 ; ly = 144-145?
 	cp 144
 	ret c
@@ -2114,7 +1873,7 @@
 	and a
 	ret z
 ; abort if too far into vblank
-	ld a, [$ff44] ; LY
+	ld a, [rLY]
 ; ly = 144-145?
 	cp 144
 	ret c
@@ -2230,7 +1989,7 @@
 	ret z
 	
 ; abort if too far into vblank
-	ld a, [$ff44] ; LY
+	ld a, [rLY]
 ; ret unless ly = 144-150
 	cp 144
 	ret c
@@ -2244,15 +2003,15 @@
 	ld a, BANK(DoTileAnimation)
 	rst Bankswitch ; bankswitch
 
-	ld a, [$ff70] ; wram bank
+	ld a, [rSVBK]
 	push af ; save wram bank
 	ld a, $1 ; wram bank 1
-	ld [$ff70], a ; wram bank
+	ld [rSVBK], a
 
-	ld a, [$ff4f] ; vram bank
+	ld a, [rVBK]
 	push af ; save vram bank
 	ld a, $0 ; vram bank 0
-	ld [$ff4f], a ; vram bank
+	ld [rVBK], a
 	
 ; take care of tile animation queue
 	call DoTileAnimation
@@ -2259,9 +2018,9 @@
 	
 ; restore affected banks
 	pop af
-	ld [$ff4f], a ; vram bank
+	ld [rVBK], a
 	pop af
-	ld [$ff70], a ; wram bank
+	ld [rSVBK], a
 	pop af
 	rst Bankswitch ; bankswitch
 	ret
@@ -2319,15 +2078,15 @@
 	
 ; handshake
 	ld a, $88
-	ld [$ff01], a
+	ld [rSB], a
 	
 ; switch to internal clock
 	ld a, %00000001
-	ld [$ff02], a
+	ld [rSC], a
 	
 ; start transfer
 	ld a, %10000001
-	ld [$ff02], a
+	ld [rSC], a
 	
 	ret
 ; 208a
@@ -2339,17 +2098,17 @@
 	nop
 	
 ; save wram bank
-	ld a, [$ff70] ; wram bank
+	ld a, [rSVBK]
 	push af
 	
 	ld a, $1
-	ld [$ff70], a ; wram bank
+	ld [rSVBK], a
 	
 	call UpdateGameTimer
 	
 ; restore wram bank
 	pop af
-	ld [$ff70], a ; wram bank
+	ld [rSVBK], a
 	ret
 ; 20ad
 
@@ -2764,13 +2523,13 @@
 
 	push bc
 ; Added value
-	ld a, [$ff04] ; divider
+	ld a, [rDIV]
 	ld b, a
 	ld a, [$ffe1]
 	adc b
 	ld [$ffe1], a
 ; Subtracted value
-	ld a, [$ff04] ; divider
+	ld a, [rDIV]
 	ld b, a
 	ld a, [$ffe2]
 	sbc b
@@ -3216,9 +2975,9 @@
 	
 ; In DMG mode, we can just change palettes to 0 (white)
 	xor a
-	ld [$ff47], a ; BGP
-	ld [$ff48], a ; OBP0
-	ld [$ff49], a ; OBP1
+	ld [rBGP], a
+	ld [rOBP0], a
+	ld [rOBP1], a
 	ret
 	
 .cgb
@@ -5761,7 +5520,7 @@
 	callab CalcMagikarpLength
 	
 ; We're clear if the length is < 1536
-	ld a, [MagikarpLengthHi]
+	ld a, [MagikarpLength]
 	cp a, $06 ; $600 = 1536
 	jr nz, .CheckMagikarpArea
 	
@@ -5770,7 +5529,7 @@
 	cp a, $0c ; / $100
 	jr c, .CheckMagikarpArea
 ; Try again if > 1614
-	ld a, [MagikarpLengthLo]
+	ld a, [MagikarpLength + 1]
 	cp a, $50
 	jr nc, .GenerateDVs
 	
@@ -5779,7 +5538,7 @@
 	cp a, $32 ; / $100
 	jr c, .CheckMagikarpArea
 ; Try again if > 1598
-	ld a, [MagikarpLengthLo]
+	ld a, [MagikarpLength + 1]
 	cp a, $40
 	jr nc, .GenerateDVs
 	
@@ -5804,7 +5563,7 @@
 	cp a, $64 ; / $100
 	jr c, .Happiness
 ; Floor at length 1024
-	ld a, [MagikarpLengthHi]
+	ld a, [MagikarpLength]
 	cp a, $04 ; $400 = 1024
 	jr c, .GenerateDVs ; try again
 	
@@ -6081,42 +5840,47 @@
 
 CheckUnownLetter: ; 3eb75
 ; Return carry if the Unown letter hasn't been unlocked yet
-	ld a, [$def3] ; UnownLetter
+	
+	ld a, [UnlockedUnowns]
 	ld c, a
-	ld de, $0000
+	ld de, 0
+	
 .loop
-; Has this set been unlocked?
+	
+; Don't check this set unless it's been unlocked
 	srl c
 	jr nc, .next
-; Check out the set
+	
+; Is our letter in the set?
 	ld hl, .LetterSets
 	add hl, de
 	ld a, [hli]
 	ld h, [hl]
 	ld l, a
-; Is our letter in the set?
+	
 	push de
-	ld a, [$d234]
-	ld de, $0001
+	ld a, [UnownLetter]
+	ld de, 1
 	push bc
 	call IsInArray
 	pop bc
 	pop de
-	jr c, .Match
+	
+	jr c, .match
+	
 .next
-; Next set
+; Make sure we haven't gone past the end of the table
 	inc e
 	inc e
 	ld a, e
-; Gone past the end of the table?
-	cp a, 4*2 ; 4 sets with 2-byte pointers
+	cp a, .Set1 - .LetterSets
 	jr c, .loop
 	
-; Didn't find the letter (not unlocked)
+; Hasn't been unlocked, or the letter is invalid
 	scf
 	ret
 	
-.Match
+.match
 ; Valid letter
 	and a
 	ret
@@ -6128,26 +5892,21 @@
 	dw .Set4
 	
 .Set1
-	;   A    B    C    D    E    F    G    H    I    J    K
-	db $01, $02, $03, $04, $05, $06, $07, $08, $09, $0a, $0b
-	db $ff ; end
-	
+	;  A   B   C   D   E   F   G   H   I   J   K
+	db 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, $ff
 .Set2
-	;   L    M    N    O    P    Q    R
-	db $0c, $0d, $0e, $0f, $10, $11, $12
-	db $ff ; end
-	
+	;  L   M   N   O   P   Q   R
+	db 12, 13, 14, 15, 16, 17, 18, $ff
 .Set3
-	;   S    T    U    V    W
-	db $13, $14, $15, $16, $17
-	db $ff ; end
-	
+	;  S   T   U   V   W
+	db 19, 20, 21, 22, 23, $ff
 .Set4
-	;   X    Y    Z
-	db $18, $19, $1a
-	db $ff ; end
+	;  X   Y   Z
+	db 24, 25, 26, $ff
+	
 ; 3ebc7
 
+
 INCBIN "baserom.gbc", $3ebc7, $3edd8 - $3ebc7
 
 BattleRNG: ; 3edd8
@@ -9068,11 +8827,11 @@
 	ld hl, $d038 ; Unkn1Pals + 7 pals
 	
 ; save wram bank
-	ld a, [$ff70] ; wram bank
+	ld a, [rSVBK]
 	ld b, a
 ; wram bank 5
 	ld a, 5
-	ld [$ff70], a ; wram bank
+	ld [rSVBK], a
 	
 ; push palette
 	ld c, 4 ; NUM_PAL_COLORS
@@ -9087,7 +8846,7 @@
 	
 ; restore wram bank
 	ld a, b
-	ld [$ff70], a ; wram bank
+	ld [rSVBK], a
 	
 	
 ; update sgb pals
@@ -9099,11 +8858,11 @@
 	ld hl, $d03f ; last byte in Unkn1Pals
 	
 ; save wram bank
-	ld a, [$ff70] ; wram bank
+	ld a, [rSVBK]
 	ld d, a
 ; wram bank 5
 	ld a, 5
-	ld [$ff70], a ; wram bank
+	ld [rSVBK], a
 	
 ; pop palette
 	ld e, 4 ; NUM_PAL_COLORS
@@ -9118,7 +8877,7 @@
 	
 ; restore wram bank
 	ld a, d
-	ld [$ff70], a ; wram bank
+	ld [rSVBK], a
 	
 ; update palettes
 	call UpdateTimePals
@@ -12324,7 +12083,7 @@
 
 SECTION "bank36",DATA,BANK[$36]
 
-FontInversed: INCBIN "gfx/font_inversed.1bpp"
+FontInversed: INCBIN "gfx/misc/font_inversed.1bpp"
 
 ; Johto frame definitions
 INCLUDE "gfx/pics/johto_frames.asm"
@@ -12677,13 +12436,13 @@
 SECTION "bank3E",DATA,BANK[$3E]
 
 FontExtra:
-INCBIN "gfx/font_extra.2bpp",$0,$200
+INCBIN "gfx/misc/font_extra.2bpp",$0,$200
 
 Font:
-INCBIN "gfx/font.1bpp",$0,$400
+INCBIN "gfx/misc/font.1bpp",$0,$400
 
 FontBattleExtra:
-INCBIN "gfx/font_battle_extra.2bpp",$0,$200
+INCBIN "gfx/misc/font_battle_extra.2bpp",$0,$200
 
 INCBIN "baserom.gbc", $f8800, $f8ba0 - $f8800
 
@@ -12693,191 +12452,8 @@
 
 INCBIN "baserom.gbc", $f8ea3, $fbbfc - $f8ea3
 
-CalcMagikarpLength: ; fbbfc
-; Stores Magikarp's length at $d1ea-$d1eb in big endian
-;
-; input:
-;   de: EnemyMonDVs
-;   bc: PlayerID
-; output:
-;   $d1ea-$d1eb: length
-;
-; does a whole bunch of arbitrary nonsense
-; cycles through a table of arbitrary values
-; http://web.archive.org/web/20110628181718/http://upokecenter.com/games/gs/guides/magikarp.php
+INCLUDE "battle/magikarp_length.asm"
 
-; b = rrcrrc(atkdefdv) xor rrc(pidhi)
-	ld h, b
-	ld l, c
-	ld a, [hli]
-	ld b, a
-	ld c, [hl] ; ld bc, [PlayerID]
-	rrc b
-	rrc c
-	ld a, [de]
-	inc de
-	rrca
-	rrca
-	xor b
-	ld b, a
-	
-; c = rrcrrc(spdspcdv) xor rrc(pidlo)
-	ld a, [de]
-	rrca
-	rrca
-	xor c
-	ld c, a
-	
-; if bc < $000a:
-	ld a, b
-	and a
-	jr nz, .loadtable
-	ld a, c
-	cp a, $0a
-	jr nc, .loadtable
-	
-; de = hl = bc + $be
-	ld hl, $00be
-	add hl, bc
-	ld d, h
-	ld e, l
-	jr .endtable
-	
-.loadtable
-	ld hl, .MagikarpLengthTable
-	ld a, $02
-	ld [$d265], a
-	
-.readtable
-	ld a, [hli]
-	ld e, a
-	ld a, [hli]
-	ld d, a
-	call .BLessThanD
-	jr nc, .advancetable
-	
-; c = bc / [hl]
-	call .BCMinusDE
-	ld a, b
-	ld [$ffb3], a
-	ld a, c
-	ld [$ffb4], a
-	ld a, [hl]
-	ld [$ffb7], a
-	ld b, $02
-	call Divide
-	ld a, [$ffb6]
-	ld c, a
-	
-; de = c + $64 * (2 + number of rows down the table)
-	xor a
-	ld [$ffb4], a
-	ld [$ffb5], a
-	ld a, $64
-	ld [$ffb6], a
-	ld a, [$d265]
-	ld [$ffb7], a
-	call Multiply
-	ld b, $00
-	ld a, [$ffb6]
-	add c
-	ld e, a
-	ld a, [$ffb5]
-	adc b
-	ld d, a
-	jr .endtable
-	
-.advancetable
-	inc hl ; align to next triplet
-	ld a, [$d265]
-	inc a
-	ld [$d265], a
-	cp a, $10
-	jr c, .readtable
-	
-	call .BCMinusDE
-	ld hl, $0640
-	add hl, bc
-	ld d, h
-	ld e, l
-	
-.endtable
-	ld h, d
-	ld l, e
-	add hl, hl
-	add hl, hl
-	add hl, de
-	add hl, hl ; hl = de * 10
-	
-	ld de, $ff02
-	ld a, $ff
-.loop
-	inc a
-	add hl, de ; - 254
-	jr c, .loop
-	
-	ld d, $00
-	
-; mod $0c
-.modloop
-	cp a, $0c
-	jr c, .done
-	sub a, $0c
-	inc d
-	jr .modloop
-	
-.done
-	ld e, a
-	ld hl, $d1ea
-	ld [hl], d
-	inc hl
-	ld [hl], e
-	ret
-; fbc9a
-
-.BLessThanD ; fbc9a
-; return carry if b < d
-	ld a, b
-	cp d
-	ret c
-	ret nc
-; fbc9e
-
-.CLessThanE ; fbc9e
-; unused
-	ld a, c
-	cp e
-	ret
-; fbca1
-
-.BCMinusDE ; fbca1
-; bc -= de
-	ld a, c
-	sub e
-	ld c, a
-	ld a, b
-	sbc d
-	ld b, a
-	ret
-; fbca8
-
-.MagikarpLengthTable ; fbca8
-;		????, divisor
-	dwb $006e, $01
-	dwb $0136, $02
-	dwb $02c6, $04
-	dwb $0a96, $14
-	dwb $1e1e, $32
-	dwb $452e, $64
-	dwb $7fc6, $96
-	dwb $ba5e, $96
-	dwb $e16e, $64
-	dwb $f4f6, $32
-	dwb $fcc6, $14
-	dwb $feba, $05
-	dwb $ff82, $02
-; fbccf
-
 INCBIN "baserom.gbc",$FBCCF,$fc000-$fbccf
 
 
@@ -13107,7 +12683,7 @@
 	
 ; VRAM bank 1
 	ld a, 1
-	ld [$ff4f], a
+	ld [rVBK], a
 	
 	
 ; Decompress running Suicune gfx
@@ -13180,7 +12756,7 @@
 	
 ; Back to VRAM bank 0
 	ld a, $0
-	ld [$ff4f], a
+	ld [rVBK], a
 	
 	
 ; Decompress logo
@@ -13276,7 +12852,7 @@
 	call ByteFill
 	
 ; Let LCD Stat know we're messing around with SCX
-	ld a, $43 ; ff43 ; SCX
+	ld a, rSCX - rJOYP
 	ld [$ffc6], a
 	
 ; Restore WRAM bank
@@ -13289,9 +12865,9 @@
 	call $058a
 	
 ; Set sprite size to 8x16
-	ld a, [$ff40] ; LCDC
+	ld a, [rLCDC]
 	set 2, a
-	ld [$ff40], a ; LCDC
+	ld [rLCDC], a
 	
 ;
 	ld a, $70
--- a/pokecrystal.asm
+++ b/pokecrystal.asm
@@ -1,3 +1,4 @@
 INCLUDE "wram.asm"
 INCLUDE "constants.asm"
+INCLUDE "gbhw.asm"
 INCLUDE "main.tx"
--- a/vblank.asm
+++ b/vblank.asm
@@ -69,13 +69,13 @@
 	inc [hl]
 	
 ; advance rng
-	ld a, [$ff04] ; divider
+	ld a, [rDIV]
 	ld b, a
 	ld a, [$ffe1]
 	adc b
 	ld [$ffe1], a
 	
-	ld a, [$ff04] ; divider
+	ld a, [rDIV]
 	ld b, a
 	ld a, [$ffe2]
 	sbc b
@@ -87,16 +87,16 @@
 	
 ; scroll x
 	ld a, [$ffcf]
-	ld [$ff43], a ; scx
+	ld [rSCX], a
 ; scroll y
 	ld a, [$ffd0]
-	ld [$ff42], a ; scy
+	ld [rSCY], a
 ; window y
 	ld a, [$ffd2]
-	ld [$ff4a], a ; wy
+	ld [rWY], a
 ; window x + 7
 	ld a, [$ffd1]
-	ld [$ff4b], a ; wx
+	ld [rWX], a
 	
 ; some time management is in order
 ; only have time for one of these during vblank
@@ -131,7 +131,7 @@
 	call $ff80
 ;	403f:
 ;		ld a, $c4
-;		ld [$ff46], a ; oam dma
+;		ld [rDMA], a
 ;		ld a, $28
 ;	.loop
 ;		dec a
@@ -216,11 +216,11 @@
 	
 ; scroll x
 	ld a, [$ffcf]
-	ld [$ff43], a ; scx
+	ld [rSCX], a
 	
 ; scroll y
 	ld a, [$ffd0]
-	ld [$ff42], a ; scy
+	ld [rSCY], a
 	
 ; time-sensitive fns
 	call UpdatePals
@@ -233,7 +233,7 @@
 	call $ff80
 ;	403f:
 ;		ld a, $c4
-;		ld [$ff46], a ; oam dma
+;		ld [rDMA], a
 ;		ld a, $28
 ;	.loop
 ;		dec a
@@ -246,20 +246,20 @@
 	ld [VBlankOccurred], a
 	
 ; get requested ints
-	ld a, [$ff0f] ; IF
+	ld a, [rIF]
 	ld b, a
 ; discard requested ints
 	xor a
-	ld [$ff0f], a ; IF
+	ld [rIF], a
 ; enable lcd stat
 	ld a, %10 ; lcd stat
-	ld [$ffff], a ; IE
+	ld [rIE], a
 ; rerequest serial int if applicable (still disabled)
 ; request lcd stat
 	ld a, b
 	and %1000 ; serial
 	or %10 ; lcd stat
-	ld [$ff0f], a ; IF
+	ld [rIF], a
 	
 	ei
 ; update sound
@@ -272,17 +272,17 @@
 	di
 	
 ; get requested ints
-	ld a, [$ff0f] ; IF
+	ld a, [rIF]
 	ld b, a
 ; discard requested ints
 	xor a
-	ld [$ff0f], a ; IF
+	ld [rIF], a
 ; enable ints besides joypad
 	ld a, %1111 ; serial timer lcdstat vblank
-	ld [$ffff], a ; IE
+	ld [rIE], a
 ; rerequest ints
 	ld a, b
-	ld [$ff0f], a ; IF
+	ld [rIF], a
 	ret
 ; 37f
 
@@ -297,13 +297,13 @@
 	
 ; update gb pals
 	ld a, [$cfc7]
-	ld [$ff47], a ; BGP
+	ld [rBGP], a
 	
 	ld a, [$cfc8]
-	ld [$ff48], a ; OBP0
+	ld [rOBP0], a
 	
 	ld a, [$cfc9]
-	ld [$ff49], a ; 0BP1
+	ld [rOBP1], a
 	
 	and a
 	ret
@@ -324,10 +324,10 @@
 	
 ; scroll x
 	ld a, [$ffcf]
-	ld [$ff43], a ; scx
+	ld [rSCX], a
 ; scroll y
 	ld a, [$ffd0]
-	ld [$ff42], a ; scy
+	ld [rSCY], a
 	
 ; any pals to update?
 	ld a, [$ffe5]
@@ -342,7 +342,7 @@
 	call $ff80
 ;	403f:
 ;		ld a, $c4 ; Sprites / $100
-;		ld [$ff46], a ; oam dma
+;		ld [rDMA], a
 ;		ld a, $28
 ;	.loop
 ;		dec a
@@ -355,15 +355,15 @@
 	ld [VBlankOccurred], a
 	
 ; save int flag
-	ld a, [$ff0f] ; IF
+	ld a, [rIF]
 	push af
 ; reset ints
 	xor a
-	ld [$ff0f], a ; IF
+	ld [rIF], a
 ; force lcdstat int during sound update
 	ld a, %10 ; lcd stat
-	ld [$ffff], a ; IE
-	ld [$ff0f], a ; IF
+	ld [rIE], a
+	ld [rIF], a
 	
 	ei
 ; update sound
@@ -376,7 +376,7 @@
 	di
 	
 ; request lcdstat
-	ld a, [$ff0f] ; IF
+	ld a, [rIF]
 	ld b, a
 ; and any other ints
 	pop af
@@ -384,13 +384,13 @@
 	ld b, a
 ; reset ints
 	xor a
-	ld [$ff0f], a ; IF
+	ld [rIF], a
 ; enable ints besides joypad
 	ld a, %1111 ; serial timer lcdstat vblank
-	ld [$ffff], a ; IE
+	ld [rIE], a
 ; request ints
 	ld a, b
-	ld [$ff0f], a ; IF
+	ld [rIF], a
 	ret
 ; 3df
 
@@ -414,7 +414,7 @@
 	call $ff80
 ;	403f:
 ;		ld a, $c4
-;		ld [$ff46], a ; oam dma
+;		ld [rDMA], a
 ;		ld a, $28
 ;	.loop
 ;		dec a
@@ -456,7 +456,7 @@
 	
 ; scroll x
 	ld a, [$ffcf]
-	ld [$ff43], a ; scx
+	ld [rSCX], a
 	
 ; if we can update pals, skip this part
 	call UpdatePalsIfCGB
@@ -475,12 +475,12 @@
 	
 ; discard requested ints
 	xor a
-	ld [$ff0f], a ; IF
+	ld [rIF], a
 ; enable lcd stat
 	ld a, %10 ; lcd stat
-	ld [$ffff], a ; IE
+	ld [rIE], a
 ; request lcd stat
-	ld [$ff0f], a ; IF
+	ld [rIF], a
 	
 	ei
 ; update sound
@@ -494,10 +494,10 @@
 	
 ; discard requested ints
 	xor a
-	ld [$ff0f], a ; IF
+	ld [rIF], a
 ; enable ints besides joypad
 	ld a, %1111 ; serial timer lcdstat vblank
-	ld [$ffff], a ; IE
+	ld [rIE], a
 	ret
 ; 436
 
--- a/wram.asm
+++ b/wram.asm
@@ -837,11 +837,9 @@
 	ds 2
 
 Buffer1:
-MagikarpLength:
-MagikarpLengthHi: ; d1ea
+MagikarpLength: ; d1ea
 	ds 1
-Buffer2:
-MagikarpLengthLo: ; d1eb
+Buffer2: ; d1eb
 	ds 1
 
 SECTION "prng2",BSS[$d1fa]