summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile5
-rw-r--r--berry_fix/Makefile160
-rw-r--r--berry_fix/asm/berry_fix_header.inc35
-rw-r--r--berry_fix/asm/loader.s119
-rw-r--r--berry_fix/asm/macros/asm.inc12
-rw-r--r--berry_fix/asm/macros/function.inc29
-rw-r--r--berry_fix/asmdiff.sh7
-rw-r--r--berry_fix/build_tools.sh10
-rw-r--r--berry_fix/charmap.txt1067
-rw-r--r--berry_fix/constants/gba_constants.inc490
-rw-r--r--berry_fix/data/data.s4
-rw-r--r--berry_fix/ld_script.sed14
-rw-r--r--berry_fix/ld_script.txt31
-rw-r--r--berry_fix/payload/Makefile159
-rw-r--r--berry_fix/payload/asm/crt0.s83
-rw-r--r--berry_fix/payload/asm/macros/asm.inc12
-rw-r--r--berry_fix/payload/asm/macros/function.inc29
-rw-r--r--berry_fix/payload/asmdiff.sh7
-rw-r--r--berry_fix/payload/charmap.txt1067
-rw-r--r--berry_fix/payload/common_syms/agb_flash.txt10
-rw-r--r--berry_fix/payload/common_syms/main.txt9
-rw-r--r--berry_fix/payload/common_syms/rtc.txt2
-rw-r--r--berry_fix/payload/constants/gba_constants.inc490
-rw-r--r--berry_fix/payload/graphics/debug_digits.pngbin0 -> 166 bytes
-rw-r--r--berry_fix/payload/graphics/msg_box.pngbin0 -> 2631 bytes
-rw-r--r--berry_fix/payload/graphics/msg_box.tilemapbin0 -> 8192 bytes
-rw-r--r--berry_fix/payload/include/constants/game_stat.h56
-rw-r--r--berry_fix/payload/include/constants/vars.h196
-rw-r--r--berry_fix/payload/include/flash.h55
-rw-r--r--berry_fix/payload/include/global.berry.h62
-rw-r--r--berry_fix/payload/include/global.fieldmap.h317
-rw-r--r--berry_fix/payload/include/global.h875
-rw-r--r--berry_fix/payload/include/main.h45
-rw-r--r--berry_fix/payload/include/pokemon.h154
-rw-r--r--berry_fix/payload/include/rtc.h15
-rw-r--r--berry_fix/payload/ld_script.sed14
-rw-r--r--berry_fix/payload/ld_script.txt122
-rw-r--r--berry_fix/payload/rom.sha11
-rw-r--r--berry_fix/payload/src/flash.c752
-rw-r--r--berry_fix/payload/src/main.c289
-rw-r--r--berry_fix/payload/src/rtc.c346
-rw-r--r--berry_fix/payload/sym_bss.txt5
-rw-r--r--berry_fix/payload/sym_common.txt29
-rw-r--r--berry_fix/payload/sym_ewram.txt3
-rw-r--r--berry_fix/rom.sha11
-rw-r--r--data/berry_fix.mbbin15348 -> 0 bytes
-rw-r--r--data/multiboot_berry_glitch_fix.s2
47 files changed, 7189 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 9f8b13141..431475026 100644
--- a/Makefile
+++ b/Makefile
@@ -84,10 +84,12 @@ clean: tidy
rm -f sound/direct_sound_samples/*.bin
rm -f $(SONG_OBJS)
find . \( -iname '*.1bpp' -o -iname '*.4bpp' -o -iname '*.8bpp' -o -iname '*.gbapal' -o -iname '*.lz' -o -iname '*.latfont' -o -iname '*.hwjpnfont' -o -iname '*.fwjpnfont' \) -exec rm {} +
+ @$(MAKE) -C berry_fix clean
tidy:
rm -f $(ROM) $(ELF) $(MAP)
rm -r build/*
+ @$(MAKE) -C berry_fix tidy
include graphics_file_rules.mk
@@ -169,3 +171,6 @@ $(ELF): $(OBJ_DIR)/ld_script.ld $(OBJS)
$(ROM): $(ELF)
$(OBJCOPY) -O binary $< $@
$(FIX) $@ -p -t"$(TITLE)" -c$(GAME_CODE) -m$(MAKER_CODE) -r$(REVISION) --silent
+
+berry_fix/berry_fix.gba:
+ @$(MAKE) -C berry_fix
diff --git a/berry_fix/Makefile b/berry_fix/Makefile
new file mode 100644
index 000000000..ffe0cf251
--- /dev/null
+++ b/berry_fix/Makefile
@@ -0,0 +1,160 @@
+include $(DEVKITARM)/base_tools
+export CPP := $(PREFIX)cpp
+export LD := $(PREFIX)ld
+
+ifeq ($(OS),Windows_NT)
+EXE := .exe
+else
+EXE :=
+endif
+
+GAME_CODE := AGBJ
+MAKER_CODE := 01
+REVISION := 0
+
+SHELL := /bin/bash -o pipefail
+
+CPPFLAGS := -I ../tools/agbcc/include -I ../tools/agbcc -iquote include -nostdinc -undef
+
+ROM := berry_fix.gba
+OBJ_DIR := build
+CC1 := ../tools/agbcc/bin/agbcc$(EXE)
+override CFLAGS += -mthumb-interwork -Wimplicit -Wparentheses -Werror -O2 -fhex-asm
+
+
+ELF = $(ROM:.gba=.elf)
+MAP = $(ROM:.gba=.map)
+
+C_SUBDIR = src
+ASM_SUBDIR = asm
+DATA_ASM_SUBDIR = data
+
+C_BUILDDIR = $(OBJ_DIR)/$(C_SUBDIR)
+ASM_BUILDDIR = $(OBJ_DIR)/$(ASM_SUBDIR)
+DATA_ASM_BUILDDIR = $(OBJ_DIR)/$(DATA_ASM_SUBDIR)
+
+ASFLAGS := -mcpu=arm7tdmi
+
+LDFLAGS = -Map ../$(MAP)
+
+SHA1 := $(shell { command -v sha1sum || command -v shasum; } 2>/dev/null) -c
+GFX := ../tools/gbagfx/gbagfx$(EXE)
+AIF := ../tools/aif2pcm/aif2pcm$(EXE)
+MID := ../tools/mid2agb/mid2agb$(EXE)
+SCANINC := ../tools/scaninc/scaninc$(EXE)
+PREPROC := ../tools/preproc/preproc$(EXE)
+RAMSCRGEN := ../tools/ramscrgen/ramscrgen$(EXE)
+FIX := ../tools/gbafix/gbafix$(EXE)
+
+# Clear the default suffixes
+.SUFFIXES:
+# Don't delete intermediate files
+.SECONDARY:
+# Delete files that weren't built properly
+.DELETE_ON_ERROR:
+
+# Secondary expansion is required for dependency variables in object rules.
+.SECONDEXPANSION:
+
+.PHONY: rom clean compare tidy
+
+C_SRCS := $(wildcard $(C_SUBDIR)/*.c $(C_SUBDIR)/*/*.c $(C_SUBDIR)/*/*/*.c)
+C_OBJS := $(patsubst $(C_SUBDIR)/%.c,$(C_BUILDDIR)/%.o,$(C_SRCS))
+
+ASM_SRCS := $(wildcard $(ASM_SUBDIR)/*.s)
+ASM_OBJS := $(patsubst $(ASM_SUBDIR)/%.s,$(ASM_BUILDDIR)/%.o,$(ASM_SRCS))
+
+DATA_ASM_SRCS := $(wildcard $(DATA_ASM_SUBDIR)/*.s)
+DATA_ASM_OBJS := $(patsubst $(DATA_ASM_SUBDIR)/%.s,$(DATA_ASM_BUILDDIR)/%.o,$(DATA_ASM_SRCS))
+
+SONG_SRCS := $(wildcard $(SONG_SUBDIR)/*.s)
+SONG_OBJS := $(patsubst $(SONG_SUBDIR)/%.s,$(SONG_BUILDDIR)/%.o,$(SONG_SRCS))
+
+MID_SRCS := $(wildcard $(MID_SUBDIR)/*.mid)
+MID_OBJS := $(patsubst $(MID_SUBDIR)/%.mid,$(MID_BUILDDIR)/%.o,$(MID_SRCS))
+
+OBJS := $(C_OBJS) $(ASM_OBJS) $(DATA_ASM_OBJS) $(SONG_OBJS) $(MID_OBJS)
+# OBJS_REL := $(patsubst $(OBJ_DIR)/%,%,$(OBJS))
+
+SUBDIRS := $(sort $(dir $(OBJS)))
+
+$(shell mkdir -p $(SUBDIRS))
+
+rom: $(ROM)
+
+# For contributors to make sure a change didn't affect the contents of the ROM.
+compare: $(ROM)
+ @$(SHA1) rom.sha1
+
+clean: tidy
+ rm -f sound/direct_sound_samples/*.bin
+ rm -f $(SONG_OBJS) $(MID_OBJS) $(MID_SUBDIR)/*.s
+ find . \( -iname '*.1bpp' -o -iname '*.4bpp' -o -iname '*.8bpp' -o -iname '*.gbapal' -o -iname '*.lz' -o -iname '*.latfont' -o -iname '*.hwjpnfont' -o -iname '*.fwjpnfont' \) -exec rm {} +
+ make -C payload clean
+
+tidy:
+ rm -f $(ROM) $(ELF) $(MAP)
+ rm -r build/*
+ make -C payload tidy
+
+%.s: ;
+%.png: ;
+%.pal: ;
+%.aif: ;
+
+%.1bpp: %.png ; $(GFX) $< $@
+%.4bpp: %.png ; $(GFX) $< $@
+%.8bpp: %.png ; $(GFX) $< $@
+%.gbapal: %.pal ; $(GFX) $< $@
+%.gbapal: %.png ; $(GFX) $< $@
+%.lz: % ; $(GFX) $< $@
+%.rl: % ; $(GFX) $< $@
+
+
+ifeq ($(NODEP),1)
+$(C_BUILDDIR)/%.o: c_dep :=
+else
+$(C_BUILDDIR)/%.o: c_dep = $(shell $(SCANINC) -I include $(C_SUBDIR)/$*.c)
+endif
+
+$(C_BUILDDIR)/%.o : $(C_SUBDIR)/%.c $$(c_dep)
+ @$(CPP) $(CPPFLAGS) $< -o $(C_BUILDDIR)/$*.i
+ @$(PREPROC) $(C_BUILDDIR)/$*.i charmap.txt | $(CC1) $(CFLAGS) -o $(C_BUILDDIR)/$*.s
+ $(AS) $(ASFLAGS) -o $@ $(C_BUILDDIR)/$*.s
+
+ifeq ($(NODEP),1)
+$(ASM_BUILDDIR)/%.o: asm_dep :=
+else
+$(ASM_BUILDDIR)/%.o: asm_dep = $(shell $(SCANINC) $(ASM_SUBDIR)/$*.s)
+endif
+
+$(ASM_BUILDDIR)/%.o: $(ASM_SUBDIR)/%.s $$(asm_dep)
+ $(AS) $(ASFLAGS) -o $@ $<
+
+ifeq ($(NODEP),1)
+$(DATA_ASM_BUILDDIR)/%.o: data_dep :=
+else
+$(DATA_ASM_BUILDDIR)/%.o: data_dep = $(shell $(SCANINC) $(DATA_ASM_SUBDIR)/$*.s)
+endif
+
+payload: data/payload.gba.lz
+
+payload/payload.gba:
+ $(MAKE) -C payload/
+
+data/payload.gba.lz: payload/payload.gba
+ $(GFX) $< $@ -search 1
+
+$(DATA_ASM_BUILDDIR)/%.o: $(DATA_ASM_SUBDIR)/%.s $$(data_dep)
+ $(PREPROC) $< charmap.txt | $(CPP) -I include | $(AS) $(ASFLAGS) -o $@
+
+$(SONG_BUILDDIR)/%.o: $(SONG_SUBDIR)/%.s
+ $(AS) $(ASFLAGS) -I sound -o $@ $<
+
+$(ELF): ld_script.txt $(OBJS)
+ cd $(OBJ_DIR) && $(LD) $(LDFLAGS) -T ../ld_script.txt -o ../$@
+
+$(ROM): $(ELF)
+ $(OBJCOPY) -O binary $< $@
+ $(FIX) $@ -c$(GAME_CODE) -m$(MAKER_CODE) -r$(REVISION) --silent
+
diff --git a/berry_fix/asm/berry_fix_header.inc b/berry_fix/asm/berry_fix_header.inc
new file mode 100644
index 000000000..5167d2ff0
--- /dev/null
+++ b/berry_fix/asm/berry_fix_header.inc
@@ -0,0 +1,35 @@
+ .global BerryFixMBHeaderNintendoLogo
+BerryFixMBHeaderNintendoLogo:
+ .space 156
+
+BerryFixMBHeaderGameTitle:
+ .space 12
+
+ .global BerryFixMBHeaderGameCode
+BerryFixMBHeaderGameCode:
+ .space 4
+
+BerryFixMBHeaderMakerCode:
+ .space 2
+
+BerryFixMBHeaderMagic:
+ .byte 0
+
+BerryFixMBHeaderMainUnitCode:
+ .byte 0
+
+BerryFixMBHeaderDeviceType:
+ .byte 0
+
+BerryFixMBHeaderReserved1:
+ .space 7
+
+ .global BerryFixMBHeaderSoftwareVersion
+BerryFixMBHeaderSoftwareVersion:
+ .byte 0
+
+BerryFixMBHeaderChecksum:
+ .byte 0
+
+BerryFixMBHeaderReserved2:
+ .space 2
diff --git a/berry_fix/asm/loader.s b/berry_fix/asm/loader.s
new file mode 100644
index 000000000..c342e100f
--- /dev/null
+++ b/berry_fix/asm/loader.s
@@ -0,0 +1,119 @@
+ .include "asm/macros/asm.inc"
+ .include "asm/macros/function.inc"
+ .include "constants/gba_constants.inc"
+
+ .set SIO_ERROR, 0x0040
+ .set SIO_MULTI_BUSY, 0x0080
+
+ .set EWRAM_ORIG, 0x02000000
+ .set gCode, 0x02010000
+ .set PROG_ORIG, 0x00008000
+
+ .syntax unified
+
+ .text
+
+ arm_func_start _start
+_start: @ 0
+ b _entry
+ arm_func_end _start
+
+ .include "asm/berry_fix_header.inc"
+
+@ C0
+ .word 0
+
+ .global _GPIOPortData
+_GPIOPortData: @ C4
+ .2byte 0
+
+ .global _GPIOPortDirection
+_GPIOPortDirection: @ C6
+ .2byte 0
+
+ .global _GPIOPortReadEnable
+_GPIOPortReadEnable: @ C8
+ .2byte 0
+
+@ CA
+ .2byte 0
+
+@ CC
+ .space 0x34
+
+ arm_func_start _entry
+_entry: @ 100
+ b _send
+ arm_func_end _entry
+
+ .space 0x1C
+
+ arm_func_start _recv
+_recv:
+ @ Waits until link cable is no longer busy.
+ @ Returns nz if an error has occurred
+ @ Otherwise, returns the received short in r1.
+ @ Preserves r0
+_120:
+ ldrh r1, [r0, 0x8] @ SIOCNT
+ tst r1, SIO_MULTI_BUSY
+ beq _120
+_12c:
+ ldrh r1, [r0, 0x8] @ SIOCNT
+ tst r1, SIO_MULTI_BUSY
+ bne _12c
+ ldrh r1, [r0, 0x8] @ SIOCNT
+ tst r1, SIO_ERROR
+ bxne lr
+ ldrh r1, [r0] @ SIOMULTI0
+ bx lr
+ arm_func_end _recv
+
+ arm_func_start _send
+_send: @ 14c
+ ldr r0, =REG_SIOMULTI0
+_150:
+ bl _recv
+ bne _150
+ mov r2, 0
+ strh r2, [r0, 0xa] @ SIOMLT_SEND
+ cmp r1, 0
+ bne _150
+ mov r2, 0x8000
+_16c:
+ mov r1, 0
+_170:
+ strh r1, [r0, 0xa] @ SIOMLT_SEND
+ bl _recv
+ bne _150
+ cmp r1, r2
+ bne _16c
+ lsr r2, 5
+ cmp r1, 0
+ bne _170
+ ldr r3, =BerryFixMBHeaderGameCode
+ ldrh r2, [r3]
+ strh r2, [r0, 0xa] @ SIOMLT_SEND
+ bl _recv
+_1a0:
+ bne _1a0
+ cmp r1, r2
+ bne _1a0
+ ldrh r2, [r3, 0x2]
+ strh r2, [r0, 0xa] @ SIOMLT_SEND
+ bl _recv
+ bne _1a0
+ cmp r1, r2
+ bne _1a0
+ mov r1, 0
+ strh r1, [r0, 0xa] @ SIOMLT_SEND
+ ldr r0, =_data_2f0
+ ldr r1, =gCode
+ swi 0x11 << 16
+ ldr lr, =gCode
+ bx lr
+ .pool
+ arm_func_end _send
+ @ 1f0
+
+ .align 2, 0 @ don't pad with nop
diff --git a/berry_fix/asm/macros/asm.inc b/berry_fix/asm/macros/asm.inc
new file mode 100644
index 000000000..4ac003fab
--- /dev/null
+++ b/berry_fix/asm/macros/asm.inc
@@ -0,0 +1,12 @@
+ .macro inc x
+ .set \x, \x + 1
+ .endm
+
+ .macro enum_start x=0
+ .set __enum__, \x
+ .endm
+
+ .macro enum constant
+ .equiv \constant, __enum__
+ inc __enum__
+ .endm
diff --git a/berry_fix/asm/macros/function.inc b/berry_fix/asm/macros/function.inc
new file mode 100644
index 000000000..b109595df
--- /dev/null
+++ b/berry_fix/asm/macros/function.inc
@@ -0,0 +1,29 @@
+ .macro arm_func_start name
+ .align 2, 0
+ .global \name
+ .arm
+ .type \name, %function
+ .endm
+
+ .macro arm_func_end name
+ .size \name, .-\name
+ .endm
+
+ .macro thumb_func_start name
+ .align 2, 0
+ .global \name
+ .thumb
+ .thumb_func
+ .type \name, %function
+ .endm
+
+ .macro non_word_aligned_thumb_func_start name
+ .global \name
+ .thumb
+ .thumb_func
+ .type \name, %function
+ .endm
+
+ .macro thumb_func_end name
+ .size \name, .-\name
+ .endm
diff --git a/berry_fix/asmdiff.sh b/berry_fix/asmdiff.sh
new file mode 100644
index 000000000..4e14e106a
--- /dev/null
+++ b/berry_fix/asmdiff.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+OBJDUMP="$DEVKITARM/bin/arm-none-eabi-objdump -D -bbinary -marmv4t -Mforce-thumb"
+OPTIONS="--start-address=$(($1)) --stop-address=$(($1 + $2))"
+$OBJDUMP $OPTIONS baserom.gba > baserom.dump
+$OBJDUMP $OPTIONS berry_fix.gba > berry_fix.dump
+diff -c baserom.dump berry_fix.dump
diff --git a/berry_fix/build_tools.sh b/berry_fix/build_tools.sh
new file mode 100644
index 000000000..d9eebf05c
--- /dev/null
+++ b/berry_fix/build_tools.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+make -C tools/gbagfx CXX=${1:-g++}
+make -C tools/scaninc CXX=${1:-g++}
+make -C tools/preproc CXX=${1:-g++}
+make -C tools/bin2c CXX=${1:-g++}
+make -C tools/rsfont CXX=${1:-g++}
+make -C tools/aif2pcm CXX=${1:-g++}
+make -C tools/ramscrgen CXX=${1:-g++}
+make -C tools/gbafix CXX=${1:-g++}
+make -C tools/mid2agb CXX=${1:-g++}
diff --git a/berry_fix/charmap.txt b/berry_fix/charmap.txt
new file mode 100644
index 000000000..a736b40f2
--- /dev/null
+++ b/berry_fix/charmap.txt
@@ -0,0 +1,1067 @@
+' ' = 00
+'À' = 01
+'Á' = 02
+'Â' = 03
+'Ç' = 04
+'È' = 05
+'É' = 06
+'Ê' = 07
+'Ë' = 08
+'Ì' = 09
+'Î' = 0B
+'Ï' = 0C
+'Ò' = 0D
+'Ó' = 0E
+'Ô' = 0F
+'Œ' = 10
+'Ù' = 11
+'Ú' = 12
+'Û' = 13
+'Ñ' = 14
+'ß' = 15
+'à' = 16
+'á' = 17
+'ç' = 19
+'è' = 1A
+'é' = 1B
+'ê' = 1C
+'ë' = 1D
+'ì' = 1E
+'î' = 20
+'ï' = 21
+'ò' = 22
+'ó' = 23
+'ô' = 24
+'œ' = 25
+'ù' = 26
+'ú' = 27
+'û' = 28
+'ñ' = 29
+'º' = 2A
+'ª' = 2B
+SUPER_ER = 2C
+'&' = 2D
+'+' = 2E
+LV = 34
+'=' = 35
+';' = 36
+'¿' = 51
+'¡' = 52
+PK = 53
+PKMN = 53 54
+POKEBLOCK = 55 56 57 58 59
+'Í' = 5A
+'%' = 5B
+'(' = 5C
+')' = 5D
+'â' = 68
+'í' = 6F
+UNK_SPACER = 77
+UP_ARROW = 79
+DOWN_ARROW = 7A
+LEFT_ARROW = 7B
+RIGHT_ARROW = 7C
+'0' = A1
+'1' = A2
+'2' = A3
+'3' = A4
+'4' = A5
+'5' = A6
+'6' = A7
+'7' = A8
+'8' = A9
+'9' = AA
+'!' = AB
+'?' = AC
+'.' = AD
+'-' = AE
+'·' = AF
+'…' = B0
+'“' = B1
+'”' = B2
+'‘' = B3
+'’' = B4
+'♂' = B5
+'♀' = B6
+'¥' = B7
+',' = B8
+'×' = B9
+'/' = BA
+'A' = BB
+'B' = BC
+'C' = BD
+'D' = BE
+'E' = BF
+'F' = C0
+'G' = C1
+'H' = C2
+'I' = C3
+'J' = C4
+'K' = C5
+'L' = C6
+'M' = C7
+'N' = C8
+'O' = C9
+'P' = CA
+'Q' = CB
+'R' = CC
+'S' = CD
+'T' = CE
+'U' = CF
+'V' = D0
+'W' = D1
+'X' = D2
+'Y' = D3
+'Z' = D4
+'a' = D5
+'b' = D6
+'c' = D7
+'d' = D8
+'e' = D9
+'f' = DA
+'g' = DB
+'h' = DC
+'i' = DD
+'j' = DE
+'k' = DF
+'l' = E0
+'m' = E1
+'n' = E2
+'o' = E3
+'p' = E4
+'q' = E5
+'r' = E6
+'s' = E7
+'t' = E8
+'u' = E9
+'v' = EA
+'w' = EB
+'x' = EC
+'y' = ED
+'z' = EE
+'▶' = EF
+':' = F0
+'Ä' = F1
+'Ö' = F2
+'Ü' = F3
+'ä' = F4
+'ö' = F5
+'ü' = F6
+TALL_PLUS = FC 0C FB
+'$' = FF
+
+@ Hiragana
+'あ' = 01
+'い' = 02
+'う' = 03
+'え' = 04
+'お' = 05
+'か' = 06
+'き' = 07
+'く' = 08
+'け' = 09
+'こ' = 0A
+'さ' = 0B
+'し' = 0C
+'す' = 0D
+'せ' = 0E
+'そ' = 0F
+'た' = 10
+'ち' = 11
+'つ' = 12
+'て' = 13
+'と' = 14
+'な' = 15
+'に' = 16
+'ぬ' = 17
+'ね' = 18
+'の' = 19
+'は' = 1A
+'ひ' = 1B
+'ふ' = 1C
+'へ' = 1D
+'ほ' = 1E
+'ま' = 1F
+'み' = 20
+'む' = 21
+'め' = 22
+'も' = 23
+'や' = 24
+'ゆ' = 25
+'よ' = 26
+'ら' = 27
+'り' = 28
+'る' = 29
+'れ' = 2A
+'ろ' = 2B
+'わ' = 2C
+'を' = 2D
+'ん' = 2E
+'ぁ' = 2F
+'ぃ' = 30
+'ぅ' = 31
+'ぇ' = 32
+'ぉ' = 33
+'ゃ' = 34
+'ゅ' = 35
+'ょ' = 36
+'が' = 37
+'ぎ' = 38
+'ぐ' = 39
+'げ' = 3A
+'ご' = 3B
+'ざ' = 3C
+'じ' = 3D
+'ず' = 3E
+'ぜ' = 3F
+'ぞ' = 40
+'だ' = 41
+'ぢ' = 42
+'づ' = 43
+'で' = 44
+'ど' = 45
+'ば' = 46
+'び' = 47
+'ぶ' = 48
+'べ' = 49
+'ぼ' = 4A
+'ぱ' = 4B
+'ぴ' = 4C
+'ぷ' = 4D
+'ぺ' = 4E
+'ぽ' = 4F
+'っ' = 50
+
+@ Katakana
+'ア' = 51
+'イ' = 52
+'ウ' = 53
+'エ' = 54
+'オ' = 55
+'カ' = 56
+'キ' = 57
+'ク' = 58
+'ケ' = 59
+'コ' = 5A
+'サ' = 5B
+'シ' = 5C
+'ス' = 5D
+'セ' = 5E
+'ソ' = 5F
+'タ' = 60
+'チ' = 61
+'ツ' = 62
+'テ' = 63
+'ト' = 64
+'ナ' = 65
+'ニ' = 66
+'ヌ' = 67
+'ネ' = 68
+'ノ' = 69
+'ハ' = 6A
+'ヒ' = 6B
+'フ' = 6C
+'ヘ' = 6D
+'ホ' = 6E
+'マ' = 6F
+'ミ' = 70
+'ム' = 71
+'メ' = 72
+'モ' = 73
+'ヤ' = 74
+'ユ' = 75
+'ヨ' = 76
+'ラ' = 77
+'リ' = 78
+'ル' = 79
+'レ' = 7A
+'ロ' = 7B
+'ワ' = 7C
+'ヲ' = 7D
+'ン' = 7E
+'ァ' = 7F
+'ィ' = 80
+'ゥ' = 81
+'ェ' = 82
+'ォ' = 83
+'ャ' = 84
+'ュ' = 85
+'ョ' = 86
+'ガ' = 87
+'ギ' = 88
+'グ' = 89
+'ゲ' = 8A
+'ゴ' = 8B
+'ザ' = 8C
+'ジ' = 8D
+'ズ' = 8E
+'ゼ' = 8F
+'ゾ' = 90
+'ダ' = 91
+'ヂ' = 92
+'ヅ' = 93
+'デ' = 94
+'ド' = 95
+'バ' = 96
+'ビ' = 97
+'ブ' = 98
+'ベ' = 99
+'ボ' = 9A
+'パ' = 9B
+'ピ' = 9C
+'プ' = 9D
+'ペ' = 9E
+'ポ' = 9F
+'ッ' = A0
+
+@ Japanese punctuation
+' ' = 00
+'!' = AB
+'?' = AC
+'。' = AD
+'ー' = AE
+'⋯' = B0
+
+STRING = FD
+
+@ string placeholders
+PLAYER = FD 01
+STR_VAR_1 = FD 02
+STR_VAR_2 = FD 03
+STR_VAR_3 = FD 04
+KUN = FD 05
+RIVAL = FD 06
+@ version-dependent strings (originally made for Ruby/Sapphire differences)
+@ Emerald uses the Sapphire strings (except for VERSION).
+VERSION = FD 07 @ "EMERALD"
+AQUA = FD 08
+MAGMA = FD 09
+ARCHIE = FD 0A
+MAXIE = FD 0B
+KYOGRE = FD 0C
+GROUDON = FD 0D
+
+@ battle string placeholders
+
+B_BUFF1 = FD 00
+B_BUFF2 = FD 01
+B_COPY_VAR_1 = FD 02
+B_COPY_VAR_2 = FD 03
+B_COPY_VAR_3 = FD 04
+B_PLAYER_MON1_NAME = FD 05
+B_OPPONENT_MON1_NAME = FD 06
+B_PLAYER_MON2_NAME = FD 07
+B_OPPONENT_MON2_NAME = FD 08
+B_LINK_PLAYER_MON1_NAME = FD 09
+B_LINK_OPPONENT_MON1_NAME = FD 0A
+B_LINK_PLAYER_MON2_NAME = FD 0B
+B_LINK_OPPONENT_MON2_NAME = FD 0C
+B_ATK_NAME_WITH_PREFIX_MON1 = FD 0D
+B_ATK_PARTNER_NAME = FD 0E
+B_ATK_NAME_WITH_PREFIX = FD 0F
+B_DEF_NAME_WITH_PREFIX = FD 10
+B_EFF_NAME_WITH_PREFIX = FD 11 @ EFF = short for gEffectBattler
+B_ACTIVE_NAME_WITH_PREFIX = FD 12
+B_SCR_ACTIVE_NAME_WITH_PREFIX = FD 13
+B_CURRENT_MOVE = FD 14
+B_LAST_MOVE = FD 15
+B_LAST_ITEM = FD 16
+B_LAST_ABILITY = FD 17
+B_ATK_ABILITY = FD 18
+B_DEF_ABILITY = FD 19
+B_SCR_ACTIVE_ABILITY = FD 1A
+B_EFF_ABILITY = FD 1B
+B_TRAINER1_CLASS = FD 1C
+B_TRAINER1_NAME = FD 1D
+B_LINK_PLAYER_NAME = FD 1E
+B_LINK_PARTNER_NAME = FD 1F
+B_LINK_OPPONENT1_NAME = FD 20
+B_LINK_OPPONENT2_NAME = FD 21
+B_LINK_SCR_TRAINER_NAME = FD 22
+B_PLAYER_NAME = FD 23
+B_TRAINER1_LOSE_TEXT = FD 24
+B_TRAINER1_WIN_TEXT = FD 25
+B_26 = FD 26
+B_PC_CREATOR_NAME = FD 27
+B_ATK_PREFIX1 = FD 28
+B_DEF_PREFIX1 = FD 29
+B_ATK_PREFIX2 = FD 2A
+B_DEF_PREFIX2 = FD 2B
+B_ATK_PREFIX3 = FD 2C
+B_DEF_PREFIX3 = FD 2D
+B_TRAINER2_CLASS = FD 2E
+B_TRAINER2_NAME = FD 2F
+B_TRAINER2_LOSE_TEXT = FD 30
+B_TRAINER2_WIN_TEXT = FD 31
+B_PARTNER_CLASS = FD 32
+B_PARTNER_NAME = FD 33
+B_BUFF3 = FD 34
+
+@ indicates the end of a town/city name (before " TOWN" or " CITY")
+NAME_END = FC 00
+
+@ special 0xF7 character
+SPECIAL_F7 = F7
+
+@ more text functions
+
+COLOR = FC 01 @ use a color listed below right after
+HIGHLIGHT = FC 02 @ same as fc 01
+SHADOW = FC 03 @ same as fc 01
+COLOR_HIGHLIGHT_SHADOW = FC 04 @ takes 3 bytes
+PALETTE = FC 05 @ used in credits
+SIZE = FC 06 @ note that anything other than "SMALL" is invalid
+UNKNOWN_7 = FC 07
+PAUSE = FC 08 @ manually print the wait byte after this, havent mapped them
+PAUSE_UNTIL_PRESS = FC 09
+UNKNOWN_A = FC 0A
+PLAY_BGM = FC 0B
+ESCAPE = FC 0C
+SHIFT_TEXT = FC 0D
+UNKNOWN_E = FC 0E
+UNKNOWN_F = FC 0F
+PLAY_SE = FC 10
+CLEAR = FC 11
+SKIP = FC 12
+CLEAR_TO = FC 13
+UNKNOWN_14 = FC 14
+JPN = FC 15
+ENG = FC 16
+PAUSE_MUSIC = FC 17
+RESUME_MUSIC = FC 18
+
+@ colors
+
+TRANSPARENT = 00
+WHITE = 01
+DARK_GREY = 02
+LIGHT_GREY = 03
+RED = 04
+LIGHT_RED = 05
+GREEN = 06
+LIGHT_GREEN = 07
+BLUE = 08
+LIGHT_BLUE = 09
+@ these next colors can be set to anything arbitrary at runtime
+@ usually though they'll have the textbox border colors as described below
+DYNAMIC_COLOR1 = 0A @ white
+DYNAMIC_COLOR2 = 0B @ white with a tinge of green
+DYNAMIC_COLOR3 = 0C @ white 2
+DYNAMIC_COLOR4 = 0D @ aquamarine
+DYNAMIC_COLOR5 = 0E @ blue-green
+DYNAMIC_COLOR6 = 0F @ cerulean
+
+@ sound and music
+
+MUS_DUMMY = 00 00
+SE_KAIFUKU = 01 00
+SE_PC_LOGIN = 02 00
+SE_PC_OFF = 03 00
+SE_PC_ON = 04 00
+SE_SELECT = 05 00
+SE_WIN_OPEN = 06 00
+SE_WALL_HIT = 07 00
+SE_DOOR = 08 00
+SE_KAIDAN = 09 00
+SE_DANSA = 0A 00
+SE_JITENSYA = 0B 00
+SE_KOUKA_L = 0C 00
+SE_KOUKA_M = 0D 00
+SE_KOUKA_H = 0E 00
+SE_BOWA2 = 0F 00
+SE_POKE_DEAD = 10 00
+SE_NIGERU = 11 00
+SE_JIDO_DOA = 12 00
+SE_NAMINORI = 13 00
+SE_BAN = 14 00
+SE_PIN = 15 00
+SE_BOO = 16 00
+SE_BOWA = 17 00
+SE_JYUNI = 18 00
+SE_A = 19 00
+SE_I = 1A 00
+SE_U = 1B 00
+SE_E = 1C 00
+SE_O = 1D 00
+SE_N = 1E 00
+SE_SEIKAI = 1F 00
+SE_HAZURE = 20 00
+SE_EXP = 21 00
+SE_JITE_PYOKO = 22 00
+SE_MU_PACHI = 23 00
+SE_TK_KASYA = 24 00
+SE_FU_ZAKU = 25 00
+SE_FU_ZAKU2 = 26 00
+SE_FU_ZUZUZU = 27 00
+SE_RU_GASHIN = 28 00
+SE_RU_GASYAN = 29 00
+SE_RU_BARI = 2A 00
+SE_RU_HYUU = 2B 00
+SE_KI_GASYAN = 2C 00
+SE_TK_WARPIN = 2D 00
+SE_TK_WARPOUT = 2E 00
+SE_TU_SAA = 2F 00
+SE_HI_TURUN = 30 00
+SE_TRACK_MOVE = 31 00
+SE_TRACK_STOP = 32 00
+SE_TRACK_HAIKI = 33 00
+SE_TRACK_DOOR = 34 00
+SE_MOTER = 35 00
+SE_CARD = 36 00
+SE_SAVE = 37 00
+SE_KON = 38 00
+SE_KON2 = 39 00
+SE_KON3 = 3A 00
+SE_KON4 = 3B 00
+SE_SUIKOMU = 3C 00
+SE_NAGERU = 3D 00
+SE_TOY_C = 3E 00
+SE_TOY_D = 3F 00
+SE_TOY_E = 40 00
+SE_TOY_F = 41 00
+SE_TOY_G = 42 00
+SE_TOY_A = 43 00
+SE_TOY_B = 44 00
+SE_TOY_C1 = 45 00
+SE_MIZU = 46 00
+SE_HASHI = 47 00
+SE_DAUGI = 48 00
+SE_PINPON = 49 00
+SE_FUUSEN1 = 4A 00
+SE_FUUSEN2 = 4B 00
+SE_FUUSEN3 = 4C 00
+SE_TOY_KABE = 4D 00
+SE_TOY_DANGO = 4E 00
+SE_DOKU = 4F 00
+SE_ESUKA = 50 00
+SE_T_AME = 51 00
+SE_T_AME_E = 52 00
+SE_T_OOAME = 53 00
+SE_T_OOAME_E = 54 00
+SE_T_KOAME = 55 00
+SE_T_KOAME_E = 56 00
+SE_T_KAMI = 57 00
+SE_T_KAMI2 = 58 00
+SE_ELEBETA = 59 00
+SE_HINSI = 5A 00
+SE_EXPMAX = 5B 00
+SE_TAMAKORO = 5C 00
+SE_TAMAKORO_E = 5D 00
+SE_BASABASA = 5E 00
+SE_REGI = 5F 00
+SE_C_GAJI = 60 00
+SE_C_MAKU_U = 61 00
+SE_C_MAKU_D = 62 00
+SE_C_PASI = 63 00
+SE_C_SYU = 64 00
+SE_C_PIKON = 65 00
+SE_REAPOKE = 66 00
+SE_OP_BASYU = 67 00
+SE_BT_START = 68 00
+SE_DENDOU = 69 00
+SE_JIHANKI = 6A 00
+SE_TAMA = 6B 00
+SE_Z_SCROLL = 6C 00
+SE_Z_PAGE = 6D 00
+SE_PN_ON = 6E 00
+SE_PN_OFF = 6F 00
+SE_Z_SEARCH = 70 00
+SE_TAMAGO = 71 00
+SE_TB_START = 72 00
+SE_TB_KON = 73 00
+SE_TB_KARA = 74 00
+SE_BIDORO = 75 00
+SE_W085 = 76 00
+SE_W085B = 77 00
+SE_W231 = 78 00
+SE_W171 = 79 00
+SE_W233 = 7A 00
+SE_W233B = 7B 00
+SE_W145 = 7C 00
+SE_W145B = 7D 00
+SE_W145C = 7E 00
+SE_W240 = 7F 00
+SE_W015 = 80 00
+SE_W081 = 81 00
+SE_W081B = 82 00
+SE_W088 = 83 00
+SE_W016 = 84 00
+SE_W016B = 85 00
+SE_W003 = 86 00
+SE_W104 = 87 00
+SE_W013 = 88 00
+SE_W196 = 89 00
+SE_W086 = 8A 00
+SE_W004 = 8B 00
+SE_W025 = 8C 00
+SE_W025B = 8D 00
+SE_W152 = 8E 00
+SE_W026 = 8F 00
+SE_W172 = 90 00
+SE_W172B = 91 00
+SE_W053 = 92 00
+SE_W007 = 93 00
+SE_W092 = 94 00
+SE_W221 = 95 00
+SE_W221B = 96 00
+SE_W052 = 97 00
+SE_W036 = 98 00
+SE_W059 = 99 00
+SE_W059B = 9A 00
+SE_W010 = 9B 00
+SE_W011 = 9C 00
+SE_W017 = 9D 00
+SE_W019 = 9E 00
+SE_W028 = 9F 00
+SE_W013B = A0 00
+SE_W044 = A1 00
+SE_W029 = A2 00
+SE_W057 = A3 00
+SE_W056 = A4 00
+SE_W250 = A5 00
+SE_W030 = A6 00
+SE_W039 = A7 00
+SE_W054 = A8 00
+SE_W077 = A9 00
+SE_W020 = AA 00
+SE_W082 = AB 00
+SE_W047 = AC 00
+SE_W195 = AD 00
+SE_W006 = AE 00
+SE_W091 = AF 00
+SE_W146 = B0 00
+SE_W120 = B1 00
+SE_W153 = B2 00
+SE_W071B = B3 00
+SE_W071 = B4 00
+SE_W103 = B5 00
+SE_W062 = B6 00
+SE_W062B = B7 00
+SE_W048 = B8 00
+SE_W187 = B9 00
+SE_W118 = BA 00
+SE_W155 = BB 00
+SE_W122 = BC 00
+SE_W060 = BD 00
+SE_W185 = BE 00
+SE_W014 = BF 00
+SE_W043 = C0 00
+SE_W207 = C1 00
+SE_W207B = C2 00
+SE_W215 = C3 00
+SE_W109 = C4 00
+SE_W173 = C5 00
+SE_W280 = C6 00
+SE_W202 = C7 00
+SE_W060B = C8 00
+SE_W076 = C9 00
+SE_W080 = CA 00
+SE_W100 = CB 00
+SE_W107 = CC 00
+SE_W166 = CD 00
+SE_W129 = CE 00
+SE_W115 = CF 00
+SE_W112 = D0 00
+SE_W197 = D1 00
+SE_W199 = D2 00
+SE_W236 = D3 00
+SE_W204 = D4 00
+SE_W268 = D5 00
+SE_W070 = D6 00
+SE_W063 = D7 00
+SE_W127 = D8 00
+SE_W179 = D9 00
+SE_W151 = DA 00
+SE_W201 = DB 00
+SE_W161 = DC 00
+SE_W161B = DD 00
+SE_W227 = DE 00
+SE_W227B = DF 00
+SE_W226 = E0 00
+SE_W208 = E1 00
+SE_W213 = E2 00
+SE_W213B = E3 00
+SE_W234 = E4 00
+SE_W260 = E5 00
+SE_W328 = E6 00
+SE_W320 = E7 00
+SE_W255 = E8 00
+SE_W291 = E9 00
+SE_W089 = EA 00
+SE_W239 = EB 00
+SE_W230 = EC 00
+SE_W281 = ED 00
+SE_W327 = EE 00
+SE_W287 = EF 00
+SE_W257 = F0 00
+SE_W253 = F1 00
+SE_W258 = F2 00
+SE_W322 = F3 00
+SE_W298 = F4 00
+SE_W287B = F5 00
+SE_W114 = F6 00
+SE_W063B = F7 00
+SE_RG_W_DOOR = F8 00
+SE_RG_CARD1 = F9 00
+SE_RG_CARD2 = FA 00
+SE_RG_CARD3 = FB 00
+SE_RG_BAG1 = FC 00
+SE_RG_BAG2 = FD 00
+SE_RG_GETTING = FE 00
+SE_RG_SHOP = FF 00
+SE_RG_KITEKI = 00 01
+SE_RG_HELP_OP = 01 01
+SE_RG_HELP_CL = 02 01
+SE_RG_HELP_NG = 03 01
+SE_RG_DEOMOV = 04 01
+SE_RG_EXCELLENT = 05 01
+SE_RG_NAWAMISS = 06 01
+SE_TOREEYE = 07 01
+SE_TOREOFF = 08 01
+SE_HANTEI1 = 09 01
+SE_HANTEI2 = 0A 01
+SE_CURTAIN = 0B 01
+SE_CURTAIN1 = 0C 01
+SE_USSOKI = 0D 01
+MUS_TETSUJI = 5E 01
+MUS_FIELD13 = 5F 01
+MUS_KACHI22 = 60 01
+MUS_KACHI2 = 61 01
+MUS_KACHI3 = 62 01
+MUS_KACHI5 = 63 01
+MUS_PCC = 64 01
+MUS_NIBI = 65 01
+MUS_SUIKUN = 66 01
+MUS_DOORO1 = 67 01
+MUS_DOORO_X1 = 68 01
+MUS_DOORO_X3 = 69 01
+MUS_MACHI_S2 = 6A 01
+MUS_MACHI_S4 = 6B 01
+MUS_GIM = 6C 01
+MUS_NAMINORI = 6D 01
+MUS_DAN01 = 6E 01
+MUS_FANFA1 = 6F 01
+MUS_ME_ASA = 70 01
+MUS_ME_BACHI = 71 01
+MUS_FANFA4 = 72 01
+MUS_FANFA5 = 73 01
+MUS_ME_WAZA = 74 01
+MUS_BIJYUTU = 75 01
+MUS_DOORO_X4 = 76 01
+MUS_FUNE_KAN = 77 01
+MUS_ME_SHINKA = 78 01
+MUS_SHINKA = 79 01
+MUS_ME_WASURE = 7A 01
+MUS_SYOUJOEYE = 7B 01
+MUS_BOYEYE = 7C 01
+MUS_DAN02 = 7D 01
+MUS_MACHI_S3 = 7E 01
+MUS_ODAMAKI = 7F 01
+MUS_B_TOWER = 80 01
+MUS_SWIMEYE = 81 01
+MUS_DAN03 = 82 01
+MUS_ME_KINOMI = 83 01
+MUS_ME_TAMA = 84 01
+MUS_ME_B_BIG = 85 01
+MUS_ME_B_SMALL = 86 01
+MUS_ME_ZANNEN = 87 01
+MUS_BD_TIME = 88 01
+MUS_TEST1 = 89 01
+MUS_TEST2 = 8A 01
+MUS_TEST3 = 8B 01
+MUS_TEST4 = 8C 01
+MUS_TEST = 8D 01
+MUS_GOMACHI0 = 8E 01
+MUS_GOTOWN = 8F 01
+MUS_POKECEN = 90 01
+MUS_NEXTROAD = 91 01
+MUS_GRANROAD = 92 01
+MUS_CYCLING = 93 01
+MUS_FRIENDLY = 94 01
+MUS_MISHIRO = 95 01
+MUS_TOZAN = 96 01
+MUS_GIRLEYE = 97 01
+MUS_MINAMO = 98 01
+MUS_ASHROAD = 99 01
+MUS_EVENT0 = 9A 01
+MUS_DEEPDEEP = 9B 01
+MUS_KACHI1 = 9C 01
+MUS_TITLE3 = 9D 01
+MUS_DEMO1 = 9E 01
+MUS_GIRL_SUP = 9F 01
+MUS_HAGESHII = A0 01
+MUS_KAKKOII = A1 01
+MUS_KAZANBAI = A2 01
+MUS_AQA_0 = A3 01
+MUS_TSURETEK = A4 01
+MUS_BOY_SUP = A5 01
+MUS_RAINBOW = A6 01
+MUS_AYASII = A7 01
+MUS_KACHI4 = A8 01
+MUS_ROPEWAY = A9 01
+MUS_CASINO = AA 01
+MUS_HIGHTOWN = AB 01
+MUS_SAFARI = AC 01
+MUS_C_ROAD = AD 01
+MUS_AJITO = AE 01
+MUS_M_BOAT = AF 01
+MUS_M_DUNGON = B0 01
+MUS_FINECITY = B1 01
+MUS_MACHUPI = B2 01
+MUS_P_SCHOOL = B3 01
+MUS_DENDOU = B4 01
+MUS_TONEKUSA = B5 01
+MUS_MABOROSI = B6 01
+MUS_CON_FAN = B7 01
+MUS_CONTEST0 = B8 01
+MUS_MGM0 = B9 01
+MUS_T_BATTLE = BA 01
+MUS_OOAME = BB 01
+MUS_HIDERI = BC 01
+MUS_RUNECITY = BD 01
+MUS_CON_K = BE 01
+MUS_EIKOU_R = BF 01
+MUS_KARAKURI = C0 01
+MUS_HUTAGO = C1 01
+MUS_SITENNOU = C2 01
+MUS_YAMA_EYE = C3 01
+MUS_CONLOBBY = C4 01
+MUS_INTER_V = C5 01
+MUS_DAIGO = C6 01
+MUS_THANKFOR = C7 01
+MUS_END = C8 01
+MUS_B_FRONTIER = C9 01
+MUS_B_ARENA = CA 01
+MUS_ME_POINTGET = CB 01
+MUS_ME_TORE_EYE = CC 01
+MUS_PYRAMID = CD 01
+MUS_PYRAMID_TOP = CE 01
+MUS_B_PALACE = CF 01
+MUS_REKKUU_KOURIN = D0 01
+MUS_SATTOWER = D1 01
+MUS_ME_SYMBOLGET = D2 01
+MUS_B_DOME = D3 01
+MUS_B_TUBE = D4 01
+MUS_B_FACTORY = D5 01
+MUS_VS_REKKU = D6 01
+MUS_VS_FRONT = D7 01
+MUS_VS_MEW = D8 01
+MUS_B_DOME1 = D9 01
+MUS_BATTLE27 = DA 01
+MUS_BATTLE31 = DB 01
+MUS_BATTLE20 = DC 01
+MUS_BATTLE32 = DD 01
+MUS_BATTLE33 = DE 01
+MUS_BATTLE36 = DF 01
+MUS_BATTLE34 = E0 01
+MUS_BATTLE35 = E1 01
+MUS_BATTLE38 = E2 01
+MUS_BATTLE30 = E3 01
+MUS_RG_ANNAI = E4 01
+MUS_RG_SLOT = E5 01
+MUS_RG_AJITO = E6 01
+MUS_RG_GYM = E7 01
+MUS_RG_PURIN = E8 01
+MUS_RG_DEMO = E9 01
+MUS_RG_TITLE = EA 01
+MUS_RG_GUREN = EB 01
+MUS_RG_SHION = EC 01
+MUS_RG_KAIHUKU = ED 01
+MUS_RG_CYCLING = EE 01
+MUS_RG_ROCKET = EF 01
+MUS_RG_SHOUJO = F0 01
+MUS_RG_SHOUNEN = F1 01
+MUS_RG_DENDOU = F2 01
+MUS_RG_T_MORI = F3 01
+MUS_RG_OTSUKIMI = F4 01
+MUS_RG_POKEYASHI = F5 01
+MUS_RG_ENDING = F6 01
+MUS_RG_LOAD01 = F7 01
+MUS_RG_OPENING = F8 01
+MUS_RG_LOAD02 = F9 01
+MUS_RG_LOAD03 = FA 01
+MUS_RG_CHAMP_R = FB 01
+MUS_RG_VS_GYM = FC 01
+MUS_RG_VS_TORE = FD 01
+MUS_RG_VS_YASEI = FE 01
+MUS_RG_VS_LAST = FF 01
+MUS_RG_MASARA = 00 02
+MUS_RG_KENKYU = 01 02
+MUS_RG_OHKIDO = 02 02
+MUS_RG_POKECEN = 03 02
+MUS_RG_SANTOAN = 04 02
+MUS_RG_NAMINORI = 05 02
+MUS_RG_P_TOWER = 06 02
+MUS_RG_SHIRUHU = 07 02
+MUS_RG_HANADA = 08 02
+MUS_RG_TAMAMUSI = 09 02
+MUS_RG_WIN_TRE = 0A 02
+MUS_RG_WIN_YASEI = 0B 02
+MUS_RG_WIN_GYM = 0C 02
+MUS_RG_KUCHIBA = 0D 02
+MUS_RG_NIBI = 0E 02
+MUS_RG_RIVAL1 = 0F 02
+MUS_RG_RIVAL2 = 10 02
+MUS_RG_FAN2 = 11 02
+MUS_RG_FAN5 = 12 02
+MUS_RG_FAN6 = 13 02
+MUS_ME_RG_PHOTO = 14 02
+MUS_RG_TITLEROG = 15 02
+MUS_RG_GET_YASEI = 16 02
+MUS_RG_SOUSA = 17 02
+MUS_RG_SEKAIKAN = 18 02
+MUS_RG_SEIBETU = 19 02
+MUS_RG_JUMP = 1A 02
+MUS_RG_UNION = 1B 02
+MUS_RG_NETWORK = 1C 02
+MUS_RG_OKURIMONO = 1D 02
+MUS_RG_KINOMIKUI = 1E 02
+MUS_RG_NANADUNGEON = 1F 02
+MUS_RG_OSHIE_TV = 20 02
+MUS_RG_NANASHIMA = 21 02
+MUS_RG_NANAISEKI = 22 02
+MUS_RG_NANA123 = 23 02
+MUS_RG_NANA45 = 24 02
+MUS_RG_NANA67 = 25 02
+MUS_RG_POKEFUE = 26 02
+MUS_RG_VS_DEO = 27 02
+MUS_RG_VS_MYU2 = 28 02
+MUS_RG_VS_DEN = 29 02
+MUS_RG_EXEYE = 2A 02
+MUS_RG_DEOEYE = 2B 02
+MUS_RG_T_TOWER = 2C 02
+MUS_RG_SLOWMASARA = 2D 02
+MUS_RG_TVNOIZE = 2E 02
+PH_TRAP_BLEND = 2F 02
+PH_TRAP_HELD = 30 02
+PH_TRAP_SOLO = 31 02
+PH_FACE_BLEND = 32 02
+PH_FACE_HELD = 33 02
+PH_FACE_SOLO = 34 02
+PH_CLOTH_BLEND = 35 02
+PH_CLOTH_HELD = 36 02
+PH_CLOTH_SOLO = 37 02
+PH_DRESS_BLEND = 38 02
+PH_DRESS_HELD = 39 02
+PH_DRESS_SOLO = 3A 02
+PH_FLEECE_BLEND = 3B 02
+PH_FLEECE_HELD = 3C 02
+PH_FLEECE_SOLO = 3D 02
+PH_KIT_BLEND = 3E 02
+PH_KIT_HELD = 3F 02
+PH_KIT_SOLO = 40 02
+PH_PRICE_BLEND = 41 02
+PH_PRICE_HELD = 42 02
+PH_PRICE_SOLO = 43 02
+PH_LOT_BLEND = 44 02
+PH_LOT_HELD = 45 02
+PH_LOT_SOLO = 46 02
+PH_GOAT_BLEND = 47 02
+PH_GOAT_HELD = 48 02
+PH_GOAT_SOLO = 49 02
+PH_THOUGHT_BLEND = 4A 02
+PH_THOUGHT_HELD = 4B 02
+PH_THOUGHT_SOLO = 4C 02
+PH_CHOICE_BLEND = 4D 02
+PH_CHOICE_HELD = 4E 02
+PH_CHOICE_SOLO = 4F 02
+PH_MOUTH_BLEND = 50 02
+PH_MOUTH_HELD = 51 02
+PH_MOUTH_SOLO = 52 02
+PH_FOOT_BLEND = 53 02
+PH_FOOT_HELD = 54 02
+PH_FOOT_SOLO = 55 02
+PH_GOOSE_BLEND = 56 02
+PH_GOOSE_HELD = 57 02
+PH_GOOSE_SOLO = 58 02
+PH_STRUT_BLEND = 59 02
+PH_STRUT_HELD = 5A 02
+PH_STRUT_SOLO = 5B 02
+PH_CURE_BLEND = 5C 02
+PH_CURE_HELD = 5D 02
+PH_CURE_SOLO = 5E 02
+PH_NURSE_BLEND = 5F 02
+PH_NURSE_HELD = 60 02
+PH_NURSE_SOLO = 61 02
+
+A_BUTTON = F8 00
+B_BUTTON = F8 01
+DPAD_UPDOWN = F8 0A
+DPAD_NONE = F8 0C
+
+UP_ARROW_2 = F9 00
+DOWN_ARROW_2 = F9 01
+LEFT_ARROW_2 = F9 02
+RIGHT_ARROW_2 = F9 03
+PLUS = F9 04
+LV_2 = F9 05
+PP = F9 06
+ID = F9 07
+NO = F9 08
+UNDERSCORE = F9 09
+CIRCLE_1 = F9 0A
+CIRCLE_2 = F9 0B
+CIRCLE_3 = F9 0C
+CIRCLE_4 = F9 0D
+CIRCLE_5 = F9 0E
+CIRCLE_6 = F9 0F
+CIRCLE_7 = F9 10
+CIRCLE_8 = F9 11
+CIRCLE_9 = F9 12
+ROUND_LEFT_PAREN = F9 13
+ROUND_RIGHT_PAREN = F9 14
+CIRCLE_DOT = F9 15
+TRIANGLE = F9 16
+BIG_MULT_X = F9 17
+
+EMOJI_UNDERSCORE = F9 D0
+EMOJI_PIPE = F9 D1
+EMOJI_HIGHBAR = F9 D2
+EMOJI_TILDE = F9 D3
+EMOJI_LEFT_PAREN = F9 D4
+EMOJI_RIGHT_PAREN = F9 D5
+EMOJI_UNION = F9 D6 @ ⊂
+EMOJI_GREATER_THAN = F9 D7
+EMOJI_LEFT_EYE = F9 D8
+EMOJI_RIGHT_EYE = F9 D9
+EMOJI_AT = F9 DA
+EMOJI_SEMICOLON = F9 DB
+EMOJI_PLUS = F9 DC
+EMOJI_MINUS = F9 DD
+EMOJI_EQUALS = F9 DE
+EMOJI_SPIRAL = F9 DF
+EMOJI_TONGUE = F9 E0
+EMOJI_TRIANGLE_OUTLINE = F9 E1
+EMOJI_ACUTE = F9 E2
+EMOJI_GRAVE = F9 E3
+EMOJI_CIRCLE = F9 E4
+EMOJI_TRIANGLE = F9 E5
+EMOJI_SQUARE = F9 E6
+EMOJI_HEART = F9 E7
+EMOJI_MOON = F9 E8
+EMOJI_NOTE = F9 E9
+EMOJI_BALL = F9 EA
+EMOJI_BOLT = F9 EB
+EMOJI_LEAF = F9 EC
+EMOJI_FIRE = F9 ED
+EMOJI_WATER = F9 EE
+EMOJI_LEFT_FIST = F9 EF
+EMOJI_RIGHT_FIST = F9 F0
+EMOJI_BIGWHEEL = F9 F1
+EMOJI_SMALLWHEEL = F9 F2
+EMOJI_SPHERE = F9 F3
+EMOJI_IRRITATED = F9 F4
+EMOJI_MISCHIEVOUS = F9 F5
+EMOJI_HAPPY = F9 F6
+EMOJI_ANGRY = F9 F7
+EMOJI_SURPRISED = F9 F8
+EMOJI_BIGSMILE = F9 F9
+EMOJI_EVIL = F9 FA
+EMOJI_TIRED = F9 FB
+EMOJI_NEUTRAL = F9 FC
+EMOJI_SHOCKED = F9 FD
+EMOJI_BIGANGER = F9 FE
+
+'\l' = FA @ scroll up window text
+'\p' = FB @ new paragraph
+'\n' = FE @ new line
diff --git a/berry_fix/constants/gba_constants.inc b/berry_fix/constants/gba_constants.inc
new file mode 100644
index 000000000..9d59c8fcd
--- /dev/null
+++ b/berry_fix/constants/gba_constants.inc
@@ -0,0 +1,490 @@
+ .set PSR_USR_MODE, 0x00000010
+ .set PSR_FIQ_MODE, 0x00000011
+ .set PSR_IRQ_MODE, 0x00000012
+ .set PSR_SVC_MODE, 0x00000013
+ .set PSR_ABT_MODE, 0x00000017
+ .set PSR_UND_MODE, 0x0000001b
+ .set PSR_SYS_MODE, 0x0000001f
+ .set PSR_MODE_MASK, 0x0000001f
+ .set PSR_T_BIT, 0x00000020
+ .set PSR_F_BIT, 0x00000040
+ .set PSR_I_BIT, 0x00000080
+
+ .set EWRAM_START, 0x02000000
+ .set EWRAM_END, EWRAM_START + 0x40000
+ .set IWRAM_START, 0x03000000
+ .set IWRAM_END, IWRAM_START + 0x8000
+
+ .set PLTT, 0x5000000
+ .set BG_PLTT, PLTT
+ .set OBJ_PLTT, PLTT + 0x200
+
+ .set VRAM, 0x6000000
+ .set BG_VRAM, VRAM
+ .set OBJ_VRAM0, VRAM + 0x10000 @ text-mode BG
+ .set OBJ_VRAM1, VRAM + 0x14000 @ bitmap-mode BG
+
+ .set OAM, 0x7000000
+
+ .set SOUND_INFO_PTR, 0x3007FF0
+ .set INTR_CHECK, 0x3007FF8
+ .set INTR_VECTOR, 0x3007FFC
+
+ .set INTR_FLAG_VBLANK, 1 << 0
+ .set INTR_FLAG_HBLANK, 1 << 1
+ .set INTR_FLAG_VCOUNT, 1 << 2
+ .set INTR_FLAG_TIMER0, 1 << 3
+ .set INTR_FLAG_TIMER1, 1 << 4
+ .set INTR_FLAG_TIMER2, 1 << 5
+ .set INTR_FLAG_TIMER3, 1 << 6
+ .set INTR_FLAG_SERIAL, 1 << 7
+ .set INTR_FLAG_DMA0, 1 << 8
+ .set INTR_FLAG_DMA1, 1 << 9
+ .set INTR_FLAG_DMA2, 1 << 10
+ .set INTR_FLAG_DMA3, 1 << 11
+ .set INTR_FLAG_KEYPAD, 1 << 12
+ .set INTR_FLAG_GAMEPAK, 1 << 13
+
+ .set VCOUNT_VBLANK, 160
+ .set TOTAL_SCANLINES, 228
+
+ .set REG_BASE, 0x4000000 @ I/O register base address
+
+@ I/O register offsets
+ .set OFFSET_REG_DISPCNT, 0x0
+ .set OFFSET_REG_DISPSTAT, 0x4
+ .set OFFSET_REG_VCOUNT, 0x6
+ .set OFFSET_REG_BG0CNT, 0x8
+ .set OFFSET_REG_BG1CNT, 0xa
+ .set OFFSET_REG_BG2CNT, 0xc
+ .set OFFSET_REG_BG3CNT, 0xe
+ .set OFFSET_REG_BG0HOFS, 0x10
+ .set OFFSET_REG_BG0VOFS, 0x12
+ .set OFFSET_REG_BG1HOFS, 0x14
+ .set OFFSET_REG_BG1VOFS, 0x16
+ .set OFFSET_REG_BG2HOFS, 0x18
+ .set OFFSET_REG_BG2VOFS, 0x1a
+ .set OFFSET_REG_BG3HOFS, 0x1c
+ .set OFFSET_REG_BG3VOFS, 0x1e
+ .set OFFSET_REG_BG2PA, 0x20
+ .set OFFSET_REG_BG2PB, 0x22
+ .set OFFSET_REG_BG2PC, 0x24
+ .set OFFSET_REG_BG2PD, 0x26
+ .set OFFSET_REG_BG2X_L, 0x28
+ .set OFFSET_REG_BG2X_H, 0x2a
+ .set OFFSET_REG_BG2Y_L, 0x2c
+ .set OFFSET_REG_BG2Y_H, 0x2e
+ .set OFFSET_REG_BG3PA, 0x30
+ .set OFFSET_REG_BG3PB, 0x32
+ .set OFFSET_REG_BG3PC, 0x34
+ .set OFFSET_REG_BG3PD, 0x36
+ .set OFFSET_REG_BG3X_L, 0x38
+ .set OFFSET_REG_BG3X_H, 0x3a
+ .set OFFSET_REG_BG3Y_L, 0x3c
+ .set OFFSET_REG_BG3Y_H, 0x3e
+ .set OFFSET_REG_WIN0H, 0x40
+ .set OFFSET_REG_WIN1H, 0x42
+ .set OFFSET_REG_WIN0V, 0x44
+ .set OFFSET_REG_WIN1V, 0x46
+ .set OFFSET_REG_WININ, 0x48
+ .set OFFSET_REG_WINOUT, 0x4a
+ .set OFFSET_REG_MOSAIC, 0x4c
+ .set OFFSET_REG_BLDCNT, 0x50
+ .set OFFSET_REG_BLDALPHA, 0x52
+ .set OFFSET_REG_BLDY, 0x54
+
+ .set OFFSET_REG_SOUND1CNT, 0x60
+ .set OFFSET_REG_SOUND1CNT_L, 0x60
+ .set OFFSET_REG_NR10, 0x60
+ .set OFFSET_REG_SOUND1CNT_H, 0x62
+ .set OFFSET_REG_NR11, 0x62
+ .set OFFSET_REG_NR12, 0x63
+ .set OFFSET_REG_SOUND1CNT_X, 0x64
+ .set OFFSET_REG_NR13, 0x64
+ .set OFFSET_REG_NR14, 0x65
+ .set OFFSET_REG_SOUND2CNT, 0x68
+ .set OFFSET_REG_SOUND2CNT_L, 0x68
+ .set OFFSET_REG_NR21, 0x68
+ .set OFFSET_REG_NR22, 0x69
+ .set OFFSET_REG_SOUND2CNT_H, 0x6c
+ .set OFFSET_REG_NR23, 0x6c
+ .set OFFSET_REG_NR24, 0x6d
+ .set OFFSET_REG_SOUND3CNT, 0x70
+ .set OFFSET_REG_SOUND3CNT_L, 0x70
+ .set OFFSET_REG_NR30, 0x70
+ .set OFFSET_REG_SOUND3CNT_H, 0x72
+ .set OFFSET_REG_NR31, 0x72
+ .set OFFSET_REG_NR32, 0x73
+ .set OFFSET_REG_SOUND3CNT_X, 0x74
+ .set OFFSET_REG_NR33, 0x74
+ .set OFFSET_REG_NR34, 0x75
+ .set OFFSET_REG_SOUND4CNT, 0x78
+ .set OFFSET_REG_SOUND4CNT_L, 0x78
+ .set OFFSET_REG_NR41, 0x78
+ .set OFFSET_REG_NR42, 0x79
+ .set OFFSET_REG_SOUND4CNT_H, 0x7c
+ .set OFFSET_REG_NR43, 0x7c
+ .set OFFSET_REG_NR44, 0x7d
+ .set OFFSET_REG_SOUNDCNT, 0x80
+ .set OFFSET_REG_SOUNDCNT_L, 0x80
+ .set OFFSET_REG_NR50, 0x80
+ .set OFFSET_REG_NR51, 0x81
+ .set OFFSET_REG_SOUNDCNT_H, 0x82
+ .set OFFSET_REG_SOUNDCNT_X, 0x84
+ .set OFFSET_REG_NR52, 0x84
+ .set OFFSET_REG_SOUNDBIAS, 0x88
+ .set OFFSET_REG_WAVE_RAM, 0x90
+ .set OFFSET_REG_WAVE_RAM0, 0x90
+ .set OFFSET_REG_WAVE_RAM0_L, 0x90
+ .set OFFSET_REG_WAVE_RAM0_H, 0x92
+ .set OFFSET_REG_WAVE_RAM1, 0x94
+ .set OFFSET_REG_WAVE_RAM1_L, 0x94
+ .set OFFSET_REG_WAVE_RAM1_H, 0x96
+ .set OFFSET_REG_WAVE_RAM2, 0x98
+ .set OFFSET_REG_WAVE_RAM2_L, 0x98
+ .set OFFSET_REG_WAVE_RAM2_H, 0x9a
+ .set OFFSET_REG_WAVE_RAM3, 0x9c
+ .set OFFSET_REG_WAVE_RAM3_L, 0x9c
+ .set OFFSET_REG_WAVE_RAM3_H, 0x9e
+ .set OFFSET_REG_FIFO, 0xa0
+ .set OFFSET_REG_FIFO_A, 0xa0
+ .set OFFSET_REG_FIFO_A_L, 0xa0
+ .set OFFSET_REG_FIFO_A_H, 0xa2
+ .set OFFSET_REG_FIFO_B, 0xa4
+ .set OFFSET_REG_FIFO_B_L, 0xa4
+ .set OFFSET_REG_FIFO_B_H, 0xa6
+
+ .set OFFSET_REG_DMA0, 0xb0
+ .set OFFSET_REG_DMA0SAD, 0xb0
+ .set OFFSET_REG_DMA0SAD_L, 0xb0
+ .set OFFSET_REG_DMA0SAD_H, 0xb2
+ .set OFFSET_REG_DMA0DAD, 0xb4
+ .set OFFSET_REG_DMA0DAD_L, 0xb4
+ .set OFFSET_REG_DMA0DAD_H, 0xb6
+ .set OFFSET_REG_DMA0CNT, 0xb8
+ .set OFFSET_REG_DMA0CNT_L, 0xb8
+ .set OFFSET_REG_DMA0CNT_H, 0xba
+ .set OFFSET_REG_DMA1, 0xbc
+ .set OFFSET_REG_DMA1SAD, 0xbc
+ .set OFFSET_REG_DMA1SAD_L, 0xbc
+ .set OFFSET_REG_DMA1SAD_H, 0xbe
+ .set OFFSET_REG_DMA1DAD, 0xc0
+ .set OFFSET_REG_DMA1DAD_L, 0xc0
+ .set OFFSET_REG_DMA1DAD_H, 0xc2
+ .set OFFSET_REG_DMA1CNT, 0xc4
+ .set OFFSET_REG_DMA1CNT_L, 0xc4
+ .set OFFSET_REG_DMA1CNT_H, 0xc6
+ .set OFFSET_REG_DMA2, 0xc8
+ .set OFFSET_REG_DMA2SAD, 0xc8
+ .set OFFSET_REG_DMA2SAD_L, 0xc8
+ .set OFFSET_REG_DMA2SAD_H, 0xca
+ .set OFFSET_REG_DMA2DAD, 0xcc
+ .set OFFSET_REG_DMA2DAD_L, 0xcc
+ .set OFFSET_REG_DMA2DAD_H, 0xce
+ .set OFFSET_REG_DMA2CNT, 0xd0
+ .set OFFSET_REG_DMA2CNT_L, 0xd0
+ .set OFFSET_REG_DMA2CNT_H, 0xd2
+ .set OFFSET_REG_DMA3, 0xd4
+ .set OFFSET_REG_DMA3SAD, 0xd4
+ .set OFFSET_REG_DMA3SAD_L, 0xd4
+ .set OFFSET_REG_DMA3SAD_H, 0xd6
+ .set OFFSET_REG_DMA3DAD, 0xd8
+ .set OFFSET_REG_DMA3DAD_L, 0xd8
+ .set OFFSET_REG_DMA3DAD_H, 0xda
+ .set OFFSET_REG_DMA3CNT, 0xdc
+ .set OFFSET_REG_DMA3CNT_L, 0xdc
+ .set OFFSET_REG_DMA3CNT_H, 0xde
+
+ .set OFFSET_REG_TM0CNT, 0x100
+ .set OFFSET_REG_TM0CNT_L, 0x100
+ .set OFFSET_REG_TM0CNT_H, 0x102
+ .set OFFSET_REG_TM1CNT, 0x104
+ .set OFFSET_REG_TM1CNT_L, 0x104
+ .set OFFSET_REG_TM1CNT_H, 0x106
+ .set OFFSET_REG_TM2CNT, 0x108
+ .set OFFSET_REG_TM2CNT_L, 0x108
+ .set OFFSET_REG_TM2CNT_H, 0x10a
+ .set OFFSET_REG_TM3CNT, 0x10c
+ .set OFFSET_REG_TM3CNT_L, 0x10c
+ .set OFFSET_REG_TM3CNT_H, 0x10e
+
+ .set OFFSET_REG_SIOCNT, 0x128
+ .set OFFSET_REG_SIODATA8, 0x12a
+ .set OFFSET_REG_SIODATA32, 0x120
+ .set OFFSET_REG_SIOMLT_SEND, 0x12a
+ .set OFFSET_REG_SIOMLT_RECV, 0x120
+ .set OFFSET_REG_SIOMULTI0, 0x120
+ .set OFFSET_REG_SIOMULTI1, 0x122
+ .set OFFSET_REG_SIOMULTI2, 0x124
+ .set OFFSET_REG_SIOMULTI3, 0x126
+
+ .set OFFSET_REG_KEYINPUT, 0x130
+ .set OFFSET_REG_KEYCNT, 0x132
+
+ .set OFFSET_REG_RCNT, 0x134
+
+ .set OFFSET_REG_JOYCNT, 0x140
+ .set OFFSET_REG_JOYSTAT, 0x158
+ .set OFFSET_REG_JOY_RECV, 0x150
+ .set OFFSET_REG_JOY_RECV_L, 0x150
+ .set OFFSET_REG_JOY_RECV_H, 0x152
+ .set OFFSET_REG_JOY_TRANS, 0x154
+ .set OFFSET_REG_JOY_TRANS_L, 0x154
+ .set OFFSET_REG_JOY_TRANS_H, 0x156
+
+ .set OFFSET_REG_IME, 0x208
+ .set OFFSET_REG_IE, 0x200
+ .set OFFSET_REG_IF, 0x202
+
+ .set OFFSET_REG_WAITCNT, 0x204
+
+@ I/O register addresses
+ .set REG_DISPCNT, REG_BASE + OFFSET_REG_DISPCNT
+ .set REG_DISPSTAT, REG_BASE + OFFSET_REG_DISPSTAT
+ .set REG_VCOUNT, REG_BASE + OFFSET_REG_VCOUNT
+ .set REG_BG0CNT, REG_BASE + OFFSET_REG_BG0CNT
+ .set REG_BG1CNT, REG_BASE + OFFSET_REG_BG1CNT
+ .set REG_BG2CNT, REG_BASE + OFFSET_REG_BG2CNT
+ .set REG_BG3CNT, REG_BASE + OFFSET_REG_BG3CNT
+ .set REG_BG0HOFS, REG_BASE + OFFSET_REG_BG0HOFS
+ .set REG_BG0VOFS, REG_BASE + OFFSET_REG_BG0VOFS
+ .set REG_BG1HOFS, REG_BASE + OFFSET_REG_BG1HOFS
+ .set REG_BG1VOFS, REG_BASE + OFFSET_REG_BG1VOFS
+ .set REG_BG2HOFS, REG_BASE + OFFSET_REG_BG2HOFS
+ .set REG_BG2VOFS, REG_BASE + OFFSET_REG_BG2VOFS
+ .set REG_BG3HOFS, REG_BASE + OFFSET_REG_BG3HOFS
+ .set REG_BG3VOFS, REG_BASE + OFFSET_REG_BG3VOFS
+ .set REG_BG2PA, REG_BASE + OFFSET_REG_BG2PA
+ .set REG_BG2PB, REG_BASE + OFFSET_REG_BG2PB
+ .set REG_BG2PC, REG_BASE + OFFSET_REG_BG2PC
+ .set REG_BG2PD, REG_BASE + OFFSET_REG_BG2PD
+ .set REG_BG2X_L, REG_BASE + OFFSET_REG_BG2X_L
+ .set REG_BG2X_H, REG_BASE + OFFSET_REG_BG2X_H
+ .set REG_BG2Y_L, REG_BASE + OFFSET_REG_BG2Y_L
+ .set REG_BG2Y_H, REG_BASE + OFFSET_REG_BG2Y_H
+ .set REG_BG3PA, REG_BASE + OFFSET_REG_BG3PA
+ .set REG_BG3PB, REG_BASE + OFFSET_REG_BG3PB
+ .set REG_BG3PC, REG_BASE + OFFSET_REG_BG3PC
+ .set REG_BG3PD, REG_BASE + OFFSET_REG_BG3PD
+ .set REG_BG3X_L, REG_BASE + OFFSET_REG_BG3X_L
+ .set REG_BG3X_H, REG_BASE + OFFSET_REG_BG3X_H
+ .set REG_BG3Y_L, REG_BASE + OFFSET_REG_BG3Y_L
+ .set REG_BG3Y_H, REG_BASE + OFFSET_REG_BG3Y_H
+ .set REG_WIN0H, REG_BASE + OFFSET_REG_WIN0H
+ .set REG_WIN1H, REG_BASE + OFFSET_REG_WIN1H
+ .set REG_WIN0V, REG_BASE + OFFSET_REG_WIN0V
+ .set REG_WIN1V, REG_BASE + OFFSET_REG_WIN1V
+ .set REG_WININ, REG_BASE + OFFSET_REG_WININ
+ .set REG_WINOUT, REG_BASE + OFFSET_REG_WINOUT
+ .set REG_MOSAIC, REG_BASE + OFFSET_REG_MOSAIC
+ .set REG_BLDCNT, REG_BASE + OFFSET_REG_BLDCNT
+ .set REG_BLDALPHA, REG_BASE + OFFSET_REG_BLDALPHA
+ .set REG_BLDY, REG_BASE + OFFSET_REG_BLDY
+
+ .set REG_SOUND1CNT, REG_BASE + OFFSET_REG_SOUND1CNT
+ .set REG_SOUND1CNT_L, REG_BASE + OFFSET_REG_SOUND1CNT_L
+ .set REG_NR10, REG_BASE + OFFSET_REG_NR10
+ .set REG_SOUND1CNT_H, REG_BASE + OFFSET_REG_SOUND1CNT_H
+ .set REG_NR11, REG_BASE + OFFSET_REG_NR11
+ .set REG_NR12, REG_BASE + OFFSET_REG_NR12
+ .set REG_SOUND1CNT_X, REG_BASE + OFFSET_REG_SOUND1CNT_X
+ .set REG_NR13, REG_BASE + OFFSET_REG_NR13
+ .set REG_NR14, REG_BASE + OFFSET_REG_NR14
+ .set REG_SOUND2CNT, REG_BASE + OFFSET_REG_SOUND2CNT
+ .set REG_SOUND2CNT_L, REG_BASE + OFFSET_REG_SOUND2CNT_L
+ .set REG_NR21, REG_BASE + OFFSET_REG_NR21
+ .set REG_NR22, REG_BASE + OFFSET_REG_NR22
+ .set REG_SOUND2CNT_H, REG_BASE + OFFSET_REG_SOUND2CNT_H
+ .set REG_NR23, REG_BASE + OFFSET_REG_NR23
+ .set REG_NR24, REG_BASE + OFFSET_REG_NR24
+ .set REG_SOUND3CNT, REG_BASE + OFFSET_REG_SOUND3CNT
+ .set REG_SOUND3CNT_L, REG_BASE + OFFSET_REG_SOUND3CNT_L
+ .set REG_NR30, REG_BASE + OFFSET_REG_NR30
+ .set REG_SOUND3CNT_H, REG_BASE + OFFSET_REG_SOUND3CNT_H
+ .set REG_NR31, REG_BASE + OFFSET_REG_NR31
+ .set REG_NR32, REG_BASE + OFFSET_REG_NR32
+ .set REG_SOUND3CNT_X, REG_BASE + OFFSET_REG_SOUND3CNT_X
+ .set REG_NR33, REG_BASE + OFFSET_REG_NR33
+ .set REG_NR34, REG_BASE + OFFSET_REG_NR34
+ .set REG_SOUND4CNT, REG_BASE + OFFSET_REG_SOUND4CNT
+ .set REG_SOUND4CNT_L, REG_BASE + OFFSET_REG_SOUND4CNT_L
+ .set REG_NR41, REG_BASE + OFFSET_REG_NR41
+ .set REG_NR42, REG_BASE + OFFSET_REG_NR42
+ .set REG_SOUND4CNT_H, REG_BASE + OFFSET_REG_SOUND4CNT_H
+ .set REG_NR43, REG_BASE + OFFSET_REG_NR43
+ .set REG_NR44, REG_BASE + OFFSET_REG_NR44
+ .set REG_SOUNDCNT, REG_BASE + OFFSET_REG_SOUNDCNT
+ .set REG_SOUNDCNT_L, REG_BASE + OFFSET_REG_SOUNDCNT_L
+ .set REG_NR50, REG_BASE + OFFSET_REG_NR50
+ .set REG_NR51, REG_BASE + OFFSET_REG_NR51
+ .set REG_SOUNDCNT_H, REG_BASE + OFFSET_REG_SOUNDCNT_H
+ .set REG_SOUNDCNT_X, REG_BASE + OFFSET_REG_SOUNDCNT_X
+ .set REG_NR52, REG_BASE + OFFSET_REG_NR52
+ .set REG_SOUNDBIAS, REG_BASE + OFFSET_REG_SOUNDBIAS
+ .set REG_WAVE_RAM, REG_BASE + OFFSET_REG_WAVE_RAM
+ .set REG_WAVE_RAM0, REG_BASE + OFFSET_REG_WAVE_RAM0
+ .set REG_WAVE_RAM0_L, REG_BASE + OFFSET_REG_WAVE_RAM0_L
+ .set REG_WAVE_RAM0_H, REG_BASE + OFFSET_REG_WAVE_RAM0_H
+ .set REG_WAVE_RAM1, REG_BASE + OFFSET_REG_WAVE_RAM1
+ .set REG_WAVE_RAM1_L, REG_BASE + OFFSET_REG_WAVE_RAM1_L
+ .set REG_WAVE_RAM1_H, REG_BASE + OFFSET_REG_WAVE_RAM1_H
+ .set REG_WAVE_RAM2, REG_BASE + OFFSET_REG_WAVE_RAM2
+ .set REG_WAVE_RAM2_L, REG_BASE + OFFSET_REG_WAVE_RAM2_L
+ .set REG_WAVE_RAM2_H, REG_BASE + OFFSET_REG_WAVE_RAM2_H
+ .set REG_WAVE_RAM3, REG_BASE + OFFSET_REG_WAVE_RAM3
+ .set REG_WAVE_RAM3_L, REG_BASE + OFFSET_REG_WAVE_RAM3_L
+ .set REG_WAVE_RAM3_H, REG_BASE + OFFSET_REG_WAVE_RAM3_H
+ .set REG_FIFO, REG_BASE + OFFSET_REG_FIFO
+ .set REG_FIFO_A, REG_BASE + OFFSET_REG_FIFO_A
+ .set REG_FIFO_A_L, REG_BASE + OFFSET_REG_FIFO_A_L
+ .set REG_FIFO_A_H, REG_BASE + OFFSET_REG_FIFO_A_H
+ .set REG_FIFO_B, REG_BASE + OFFSET_REG_FIFO_B
+ .set REG_FIFO_B_L, REG_BASE + OFFSET_REG_FIFO_B_L
+ .set REG_FIFO_B_H, REG_BASE + OFFSET_REG_FIFO_B_H
+
+ .set REG_DMA0, REG_BASE + OFFSET_REG_DMA0
+ .set REG_DMA0SAD, REG_BASE + OFFSET_REG_DMA0SAD
+ .set REG_DMA0SAD_L, REG_BASE + OFFSET_REG_DMA0SAD_L
+ .set REG_DMA0SAD_H, REG_BASE + OFFSET_REG_DMA0SAD_H
+ .set REG_DMA0DAD, REG_BASE + OFFSET_REG_DMA0DAD
+ .set REG_DMA0DAD_L, REG_BASE + OFFSET_REG_DMA0DAD_L
+ .set REG_DMA0DAD_H, REG_BASE + OFFSET_REG_DMA0DAD_H
+ .set REG_DMA0CNT, REG_BASE + OFFSET_REG_DMA0CNT
+ .set REG_DMA0CNT_L, REG_BASE + OFFSET_REG_DMA0CNT_L
+ .set REG_DMA0CNT_H, REG_BASE + OFFSET_REG_DMA0CNT_H
+ .set REG_DMA1, REG_BASE + OFFSET_REG_DMA1
+ .set REG_DMA1SAD, REG_BASE + OFFSET_REG_DMA1SAD
+ .set REG_DMA1SAD_L, REG_BASE + OFFSET_REG_DMA1SAD_L
+ .set REG_DMA1SAD_H, REG_BASE + OFFSET_REG_DMA1SAD_H
+ .set REG_DMA1DAD, REG_BASE + OFFSET_REG_DMA1DAD
+ .set REG_DMA1DAD_L, REG_BASE + OFFSET_REG_DMA1DAD_L
+ .set REG_DMA1DAD_H, REG_BASE + OFFSET_REG_DMA1DAD_H
+ .set REG_DMA1CNT, REG_BASE + OFFSET_REG_DMA1CNT
+ .set REG_DMA1CNT_L, REG_BASE + OFFSET_REG_DMA1CNT_L
+ .set REG_DMA1CNT_H, REG_BASE + OFFSET_REG_DMA1CNT_H
+ .set REG_DMA2, REG_BASE + OFFSET_REG_DMA2
+ .set REG_DMA2SAD, REG_BASE + OFFSET_REG_DMA2SAD
+ .set REG_DMA2SAD_L, REG_BASE + OFFSET_REG_DMA2SAD_L
+ .set REG_DMA2SAD_H, REG_BASE + OFFSET_REG_DMA2SAD_H
+ .set REG_DMA2DAD, REG_BASE + OFFSET_REG_DMA2DAD
+ .set REG_DMA2DAD_L, REG_BASE + OFFSET_REG_DMA2DAD_L
+ .set REG_DMA2DAD_H, REG_BASE + OFFSET_REG_DMA2DAD_H
+ .set REG_DMA2CNT, REG_BASE + OFFSET_REG_DMA2CNT
+ .set REG_DMA2CNT_L, REG_BASE + OFFSET_REG_DMA2CNT_L
+ .set REG_DMA2CNT_H, REG_BASE + OFFSET_REG_DMA2CNT_H
+ .set REG_DMA3, REG_BASE + OFFSET_REG_DMA3
+ .set REG_DMA3SAD, REG_BASE + OFFSET_REG_DMA3SAD
+ .set REG_DMA3SAD_L, REG_BASE + OFFSET_REG_DMA3SAD_L
+ .set REG_DMA3SAD_H, REG_BASE + OFFSET_REG_DMA3SAD_H
+ .set REG_DMA3DAD, REG_BASE + OFFSET_REG_DMA3DAD
+ .set REG_DMA3DAD_L, REG_BASE + OFFSET_REG_DMA3DAD_L
+ .set REG_DMA3DAD_H, REG_BASE + OFFSET_REG_DMA3DAD_H
+ .set REG_DMA3CNT, REG_BASE + OFFSET_REG_DMA3CNT
+ .set REG_DMA3CNT_L, REG_BASE + OFFSET_REG_DMA3CNT_L
+ .set REG_DMA3CNT_H, REG_BASE + OFFSET_REG_DMA3CNT_H
+
+ .set REG_TM0CNT, REG_BASE + OFFSET_REG_TM0CNT
+ .set REG_TM0CNT_L, REG_BASE + OFFSET_REG_TM0CNT_L
+ .set REG_TM0CNT_H, REG_BASE + OFFSET_REG_TM0CNT_H
+ .set REG_TM1CNT, REG_BASE + OFFSET_REG_TM1CNT
+ .set REG_TM1CNT_L, REG_BASE + OFFSET_REG_TM1CNT_L
+ .set REG_TM1CNT_H, REG_BASE + OFFSET_REG_TM1CNT_H
+ .set REG_TM2CNT, REG_BASE + OFFSET_REG_TM2CNT
+ .set REG_TM2CNT_L, REG_BASE + OFFSET_REG_TM2CNT_L
+ .set REG_TM2CNT_H, REG_BASE + OFFSET_REG_TM2CNT_H
+ .set REG_TM3CNT, REG_BASE + OFFSET_REG_TM3CNT
+ .set REG_TM3CNT_L, REG_BASE + OFFSET_REG_TM3CNT_L
+ .set REG_TM3CNT_H, REG_BASE + OFFSET_REG_TM3CNT_H
+
+ .set REG_SIOCNT, REG_BASE + OFFSET_REG_SIOCNT
+ .set REG_SIODATA8, REG_BASE + OFFSET_REG_SIODATA8
+ .set REG_SIODATA32, REG_BASE + OFFSET_REG_SIODATA32
+ .set REG_SIOMLT_SEND, REG_BASE + OFFSET_REG_SIOMLT_SEND
+ .set REG_SIOMLT_RECV, REG_BASE + OFFSET_REG_SIOMLT_RECV
+ .set REG_SIOMULTI0, REG_BASE + OFFSET_REG_SIOMULTI0
+ .set REG_SIOMULTI1, REG_BASE + OFFSET_REG_SIOMULTI1
+ .set REG_SIOMULTI2, REG_BASE + OFFSET_REG_SIOMULTI2
+ .set REG_SIOMULTI3, REG_BASE + OFFSET_REG_SIOMULTI3
+
+ .set REG_KEYINPUT, REG_BASE + OFFSET_REG_KEYINPUT
+ .set REG_KEYCNT, REG_BASE + OFFSET_REG_KEYCNT
+
+ .set REG_RCNT, REG_BASE + OFFSET_REG_RCNT
+
+ .set REG_JOYCNT, REG_BASE + OFFSET_REG_JOYCNT
+ .set REG_JOYSTAT, REG_BASE + OFFSET_REG_JOYSTAT
+ .set REG_JOY_RECV, REG_BASE + OFFSET_REG_JOY_RECV
+ .set REG_JOY_RECV_L, REG_BASE + OFFSET_REG_JOY_RECV_L
+ .set REG_JOY_RECV_H, REG_BASE + OFFSET_REG_JOY_RECV_H
+ .set REG_JOY_TRANS, REG_BASE + OFFSET_REG_JOY_TRANS
+ .set REG_JOY_TRANS_L, REG_BASE + OFFSET_REG_JOY_TRANS_L
+ .set REG_JOY_TRANS_H, REG_BASE + OFFSET_REG_JOY_TRANS_H
+
+ .set REG_IME, REG_BASE + OFFSET_REG_IME
+ .set REG_IE, REG_BASE + OFFSET_REG_IE
+ .set REG_IF, REG_BASE + OFFSET_REG_IF
+
+ .set REG_WAITCNT, REG_BASE + OFFSET_REG_WAITCNT
+
+@ DMA register constants
+
+ .set DMA_DEST_INC, 0x0000
+ .set DMA_DEST_DEC, 0x0020
+ .set DMA_DEST_FIXED, 0x0040
+ .set DMA_DEST_RELOAD, 0x0060
+ .set DMA_SRC_INC, 0x0000
+ .set DMA_SRC_DEC, 0x0080
+ .set DMA_SRC_FIXED, 0x0100
+ .set DMA_REPEAT, 0x0200
+ .set DMA_16BIT, 0x0000
+ .set DMA_32BIT, 0x0400
+ .set DMA_DREQ_ON, 0x0800
+ .set DMA_START_NOW, 0x0000
+ .set DMA_START_VBLANK, 0x1000
+ .set DMA_START_HBLANK, 0x2000
+ .set DMA_START_SPECIAL, 0x3000
+ .set DMA_INTR_ENABLE, 0x4000
+ .set DMA_ENABLE, 0x8000
+
+@ OAM attribute constants
+
+ .set OAM_OBJ_NORMAL, 0x00000000
+ .set OAM_OBJ_BLEND, 0x00000400
+ .set OAM_OBJ_WINDOW, 0x00000800
+
+ .set OAM_AFFINE_NONE, 0x00000000
+ .set OAM_AFFINE_NORMAL_SIZE, 0x00000100
+ .set OAM_OBJ_DISABLED, 0x00000200
+ .set OAM_AFFINE_DOUBLE_SIZE, 0x00000300
+
+ .set OAM_MOSAIC_OFF, 0x00000000
+ .set OAM_MOSAIC_ON, 0x00001000
+
+ .set OAM_4BPP, 0x00000000
+ .set OAM_8BPP, 0x00002000
+
+ .set OAM_H_FLIP, 0x10000000
+ .set OAM_V_FLIP, 0x20000000
+
+ .set OAM_SQUARE, 0x00000000
+ .set OAM_H_RECTANGLE, 0x00004000
+ .set OAM_V_RECTANGLE, 0x00008000
+ .set OAM_SIZE_0, 0x00000000
+ .set OAM_SIZE_1, 0x40000000
+ .set OAM_SIZE_2, 0x80000000
+ .set OAM_SIZE_3, 0xc0000000
+
+ .set OAM_SIZE_8x8, OAM_SIZE_0 | OAM_SQUARE
+ .set OAM_SIZE_16x16, OAM_SIZE_1 | OAM_SQUARE
+ .set OAM_SIZE_32x32, OAM_SIZE_2 | OAM_SQUARE
+ .set OAM_SIZE_64x64, OAM_SIZE_3 | OAM_SQUARE
+
+ .set OAM_SIZE_16x8, OAM_SIZE_0 | OAM_H_RECTANGLE
+ .set OAM_SIZE_32x8, OAM_SIZE_1 | OAM_H_RECTANGLE
+ .set OAM_SIZE_32x16, OAM_SIZE_2 | OAM_H_RECTANGLE
+ .set OAM_SIZE_64x32, OAM_SIZE_3 | OAM_H_RECTANGLE
+
+ .set OAM_SIZE_8x16, OAM_SIZE_0 | OAM_V_RECTANGLE
+ .set OAM_SIZE_8x32, OAM_SIZE_1 | OAM_V_RECTANGLE
+ .set OAM_SIZE_16x32, OAM_SIZE_2 | OAM_V_RECTANGLE
+ .set OAM_SIZE_32x64, OAM_SIZE_3 | OAM_V_RECTANGLE
diff --git a/berry_fix/data/data.s b/berry_fix/data/data.s
new file mode 100644
index 000000000..dbb86b13b
--- /dev/null
+++ b/berry_fix/data/data.s
@@ -0,0 +1,4 @@
+ .section .rodata
+
+_data_2f0::
+ .incbin "data/payload.gba.lz"
diff --git a/berry_fix/ld_script.sed b/berry_fix/ld_script.sed
new file mode 100644
index 000000000..b91542b6f
--- /dev/null
+++ b/berry_fix/ld_script.sed
@@ -0,0 +1,14 @@
+/<EWRAM>/ {
+ r sym_ewram.ld
+ d
+}
+
+/<BSS>/ {
+ r sym_bss.ld
+ d
+}
+
+/<COMMON>/ {
+ r sym_common.ld
+ d
+}
diff --git a/berry_fix/ld_script.txt b/berry_fix/ld_script.txt
new file mode 100644
index 000000000..2edeaef7c
--- /dev/null
+++ b/berry_fix/ld_script.txt
@@ -0,0 +1,31 @@
+ENTRY(_start)
+
+SECTIONS {
+ . = 0x2000000;
+
+ .text :
+ ALIGN(4)
+ {
+ asm/loader.o(.text);
+ } =0
+
+ . += 0x100;
+ .rodata :
+ ALIGN(4)
+ {
+ data/data.o(.rodata);
+ } =0
+
+ . = 0x2010000;
+
+ ewram (NOLOAD) :
+ ALIGN(4)
+ {
+ gCode = .;
+ }
+
+ /DISCARD/ :
+ {
+ *(*);
+ }
+}
diff --git a/berry_fix/payload/Makefile b/berry_fix/payload/Makefile
new file mode 100644
index 000000000..e63d74234
--- /dev/null
+++ b/berry_fix/payload/Makefile
@@ -0,0 +1,159 @@
+include $(DEVKITARM)/base_tools
+export CPP := $(PREFIX)cpp
+export LD := $(PREFIX)ld
+
+ifeq ($(OS),Windows_NT)
+EXE := .exe
+else
+EXE :=
+endif
+
+SHELL := /bin/bash -o pipefail
+
+CPPFLAGS := -I ../../tools/agbcc/include -I ../../tools/agbcc -iquote include -nostdinc -undef
+
+ROM := payload.gba
+OBJ_DIR := build
+CC1 := ../../tools/agbcc/bin/agbcc$(EXE)
+override CFLAGS += -mthumb-interwork -Wimplicit -Wparentheses -Werror -O2 -fhex-asm
+
+
+ELF = $(ROM:.gba=.elf)
+MAP = $(ROM:.gba=.map)
+
+C_SUBDIR = src
+ASM_SUBDIR = asm
+DATA_ASM_SUBDIR = data
+
+C_BUILDDIR = $(OBJ_DIR)/$(C_SUBDIR)
+ASM_BUILDDIR = $(OBJ_DIR)/$(ASM_SUBDIR)
+DATA_ASM_BUILDDIR = $(OBJ_DIR)/$(DATA_ASM_SUBDIR)
+
+ASFLAGS := -mcpu=arm7tdmi
+
+LDFLAGS = -Map ../$(MAP)
+
+LIB := -L ../../../tools/agbcc/lib -lagb_flash -lsiirtc -lagbsyscall -lgcc
+
+SHA1 := $(shell { command -v sha1sum || command -v shasum; } 2>/dev/null) -c
+GFX := ../../tools/gbagfx/gbagfx$(EXE)
+AIF := ../../tools/aif2pcm/aif2pcm$(EXE)
+MID := ../../tools/mid2agb/mid2agb$(EXE)
+SCANINC := ../../tools/scaninc/scaninc$(EXE)
+PREPROC := ../../tools/preproc/preproc$(EXE)
+RAMSCRGEN := ../../tools/ramscrgen/ramscrgen$(EXE)
+FIX := ../../tools/gbafix/gbafix$(EXE)
+
+# Clear the default suffixes
+.SUFFIXES:
+# Don't delete intermediate files
+.SECONDARY:
+# Delete files that weren't built properly
+.DELETE_ON_ERROR:
+
+# Secondary expansion is required for dependency variables in object rules.
+.SECONDEXPANSION:
+
+.PHONY: rom clean compare tidy
+
+C_SRCS := $(wildcard $(C_SUBDIR)/*.c $(C_SUBDIR)/*/*.c $(C_SUBDIR)/*/*/*.c)
+C_OBJS := $(patsubst $(C_SUBDIR)/%.c,$(C_BUILDDIR)/%.o,$(C_SRCS))
+
+ASM_SRCS := $(wildcard $(ASM_SUBDIR)/*.s)
+ASM_OBJS := $(patsubst $(ASM_SUBDIR)/%.s,$(ASM_BUILDDIR)/%.o,$(ASM_SRCS))
+
+DATA_ASM_SRCS := $(wildcard $(DATA_ASM_SUBDIR)/*.s)
+DATA_ASM_OBJS := $(patsubst $(DATA_ASM_SUBDIR)/%.s,$(DATA_ASM_BUILDDIR)/%.o,$(DATA_ASM_SRCS))
+
+SONG_SRCS := $(wildcard $(SONG_SUBDIR)/*.s)
+SONG_OBJS := $(patsubst $(SONG_SUBDIR)/%.s,$(SONG_BUILDDIR)/%.o,$(SONG_SRCS))
+
+MID_SRCS := $(wildcard $(MID_SUBDIR)/*.mid)
+MID_OBJS := $(patsubst $(MID_SUBDIR)/%.mid,$(MID_BUILDDIR)/%.o,$(MID_SRCS))
+
+OBJS := $(C_OBJS) $(ASM_OBJS) $(DATA_ASM_OBJS) $(SONG_OBJS) $(MID_OBJS)
+# OBJS_REL := $(patsubst $(OBJ_DIR)/%,%,$(OBJS))
+
+SUBDIRS := $(sort $(dir $(OBJS)))
+
+$(shell mkdir -p $(SUBDIRS))
+
+rom: $(ROM)
+
+# For contributors to make sure a change didn't affect the contents of the ROM.
+compare: $(ROM)
+ @$(SHA1) rom.sha1
+
+clean: tidy
+ rm -f sound/direct_sound_samples/*.bin
+ rm -f $(SONG_OBJS) $(MID_OBJS) $(MID_SUBDIR)/*.s
+ find . \( -iname '*.1bpp' -o -iname '*.4bpp' -o -iname '*.8bpp' -o -iname '*.gbapal' -o -iname '*.lz' -o -iname '*.latfont' -o -iname '*.hwjpnfont' -o -iname '*.fwjpnfont' \) -exec rm {} +
+
+tidy:
+ rm -f $(ROM) $(ELF) $(MAP)
+ rm -r build/*
+
+%.s: ;
+%.png: ;
+%.pal: ;
+%.aif: ;
+
+%.1bpp: %.png ; $(GFX) $< $@
+%.4bpp: %.png ; $(GFX) $< $@
+%.8bpp: %.png ; $(GFX) $< $@
+%.gbapal: %.pal ; $(GFX) $< $@
+%.gbapal: %.png ; $(GFX) $< $@
+%.lz: % ; $(GFX) $< $@
+%.rl: % ; $(GFX) $< $@
+
+
+ifeq ($(NODEP),1)
+$(C_BUILDDIR)/%.o: c_dep :=
+else
+$(C_BUILDDIR)/%.o: c_dep = $(shell $(SCANINC) -I include $(C_SUBDIR)/$*.c)
+endif
+
+$(C_BUILDDIR)/%.o : $(C_SUBDIR)/%.c $$(c_dep)
+ @$(CPP) $(CPPFLAGS) $< -o $(C_BUILDDIR)/$*.i
+ @$(PREPROC) $(C_BUILDDIR)/$*.i charmap.txt | $(CC1) $(CFLAGS) -o $(C_BUILDDIR)/$*.s
+ $(AS) $(ASFLAGS) -o $@ $(C_BUILDDIR)/$*.s
+
+ifeq ($(NODEP),1)
+$(ASM_BUILDDIR)/%.o: asm_dep :=
+else
+$(ASM_BUILDDIR)/%.o: asm_dep = $(shell $(SCANINC) $(ASM_SUBDIR)/$*.s)
+endif
+
+$(ASM_BUILDDIR)/%.o: $(ASM_SUBDIR)/%.s $$(asm_dep)
+ $(AS) $(ASFLAGS) -o $@ $<
+
+ifeq ($(NODEP),1)
+$(DATA_ASM_BUILDDIR)/%.o: data_dep :=
+else
+$(DATA_ASM_BUILDDIR)/%.o: data_dep = $(shell $(SCANINC) $(DATA_ASM_SUBDIR)/$*.s)
+endif
+
+$(DATA_ASM_BUILDDIR)/%.o: $(DATA_ASM_SUBDIR)/%.s $$(data_dep)
+ $(PREPROC) $< charmap.txt | $(CPP) -I include | $(AS) $(ASFLAGS) -o $@
+
+$(SONG_BUILDDIR)/%.o: $(SONG_SUBDIR)/%.s
+ $(AS) $(ASFLAGS) -I sound -o $@ $<
+
+$(OBJ_DIR)/sym_bss.ld: sym_bss.txt
+ $(RAMSCRGEN) .bss $< ENGLISH > $@
+
+$(OBJ_DIR)/sym_common.ld: sym_common.txt $(C_OBJS) $(wildcard common_syms/*.txt)
+ $(RAMSCRGEN) COMMON $< ENGLISH -c $(C_BUILDDIR),common_syms,../../tools/agbcc/lib > $@
+
+$(OBJ_DIR)/sym_ewram.ld: sym_ewram.txt
+ $(RAMSCRGEN) ewram_data $< ENGLISH > $@
+
+$(OBJ_DIR)/ld_script.ld: ld_script.txt $(OBJ_DIR)/sym_bss.ld $(OBJ_DIR)/sym_common.ld $(OBJ_DIR)/sym_ewram.ld
+ cd $(OBJ_DIR) && sed -f ../../ld_script.sed ../$< | sed "s#tools/#../tools/#g" > ld_script.ld
+
+$(ELF): $(OBJ_DIR)/ld_script.ld $(OBJS)
+ cd $(OBJ_DIR) && $(LD) $(LDFLAGS) -T ld_script.ld -o ../$@ $(LIB)
+
+$(ROM): $(ELF)
+ $(OBJCOPY) -O binary $< $@
+
diff --git a/berry_fix/payload/asm/crt0.s b/berry_fix/payload/asm/crt0.s
new file mode 100644
index 000000000..66536914a
--- /dev/null
+++ b/berry_fix/payload/asm/crt0.s
@@ -0,0 +1,83 @@
+ .include "asm/macros/asm.inc"
+ .include "asm/macros/function.inc"
+ .include "constants/gba_constants.inc"
+
+ .syntax unified
+
+ .text
+
+ .arm
+ .align 2, 0
+ .global Init
+Init:
+ mov r0, PSR_IRQ_MODE
+ msr cpsr_cf, r0
+ ldr sp, sp_irq
+ mov r0, PSR_SYS_MODE
+ msr cpsr_cf, r0
+ ldr sp, sp_sys
+ ldr r1, =INTR_VECTOR
+ ldr r0, =IntrMain
+ str r0, [r1]
+ ldr r1, =AgbMain + 1
+ mov lr, pc
+ bx r1
+ b Init
+
+ .align 2, 0
+sp_sys: .word IWRAM_END - 0x100
+sp_irq: .word IWRAM_END - 0x60
+
+ .pool
+ .size Init, .-Init
+
+ .arm
+ .align 2, 0
+ .global IntrMain
+IntrMain: @ 0x2010048
+ mov ip, REG_BASE
+ add r3, ip, OFFSET_REG_IE
+ ldr r2, [r3]
+ and r1, r2, r2, lsr #16
+ mov r2, #0
+ ands r0, r1, #0x2000
+ strbne r0, [r3, #-0x17c]
+_02010064:
+ bne _02010064
+ ands r0, r1, #0xc0
+ bne _020100DC
+ add r2, r2, #4
+ ands r0, r1, #1
+ strhne r0, [ip, #-8]
+ bne _020100DC
+ add r2, r2, #4
+ ands r0, r1, #2
+ bne _020100DC
+ add r2, r2, #4
+ ands r0, r1, #4
+ bne _020100DC
+ add r2, r2, #4
+ ands r0, r1, #0x100
+ bne _020100DC
+ add r2, r2, #4
+ ands r0, r1, #0x200
+ bne _020100DC
+ add r2, r2, #4
+ ands r0, r1, #0x400
+ bne _020100DC
+ add r2, r2, #4
+ ands r0, r1, #0x800
+ bne _020100DC
+ add r2, r2, #4
+ ands r0, r1, #0x1000
+ bne _020100DC
+ add r2, r2, #4
+ ands r0, r1, #8
+_020100DC:
+ strh r0, [r3, #2]
+ ldr r1, =gIntrTable
+ add r1, r1, r2
+ ldr r0, [r1]
+ bx r0
+ .pool
+ .size IntrMain, .-IntrMain
diff --git a/berry_fix/payload/asm/macros/asm.inc b/berry_fix/payload/asm/macros/asm.inc
new file mode 100644
index 000000000..4ac003fab
--- /dev/null
+++ b/berry_fix/payload/asm/macros/asm.inc
@@ -0,0 +1,12 @@
+ .macro inc x
+ .set \x, \x + 1
+ .endm
+
+ .macro enum_start x=0
+ .set __enum__, \x
+ .endm
+
+ .macro enum constant
+ .equiv \constant, __enum__
+ inc __enum__
+ .endm
diff --git a/berry_fix/payload/asm/macros/function.inc b/berry_fix/payload/asm/macros/function.inc
new file mode 100644
index 000000000..b109595df
--- /dev/null
+++ b/berry_fix/payload/asm/macros/function.inc
@@ -0,0 +1,29 @@
+ .macro arm_func_start name
+ .align 2, 0
+ .global \name
+ .arm
+ .type \name, %function
+ .endm
+
+ .macro arm_func_end name
+ .size \name, .-\name
+ .endm
+
+ .macro thumb_func_start name
+ .align 2, 0
+ .global \name
+ .thumb
+ .thumb_func
+ .type \name, %function
+ .endm
+
+ .macro non_word_aligned_thumb_func_start name
+ .global \name
+ .thumb
+ .thumb_func
+ .type \name, %function
+ .endm
+
+ .macro thumb_func_end name
+ .size \name, .-\name
+ .endm
diff --git a/berry_fix/payload/asmdiff.sh b/berry_fix/payload/asmdiff.sh
new file mode 100644
index 000000000..5f86ac620
--- /dev/null
+++ b/berry_fix/payload/asmdiff.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+OBJDUMP="$DEVKITARM/bin/arm-none-eabi-objdump -D -bbinary -marmv4t -Mforce-thumb"
+OPTIONS="--start-address=$(($1)) --stop-address=$(($1 + $2))"
+$OBJDUMP $OPTIONS baserom.gba > baserom.dump
+$OBJDUMP $OPTIONS payload.gba > payload.dump
+diff baserom.dump payload.dump
diff --git a/berry_fix/payload/charmap.txt b/berry_fix/payload/charmap.txt
new file mode 100644
index 000000000..a736b40f2
--- /dev/null
+++ b/berry_fix/payload/charmap.txt
@@ -0,0 +1,1067 @@
+' ' = 00
+'À' = 01
+'Á' = 02
+'Â' = 03
+'Ç' = 04
+'È' = 05
+'É' = 06
+'Ê' = 07
+'Ë' = 08
+'Ì' = 09
+'Î' = 0B
+'Ï' = 0C
+'Ò' = 0D
+'Ó' = 0E
+'Ô' = 0F
+'Œ' = 10
+'Ù' = 11
+'Ú' = 12
+'Û' = 13
+'Ñ' = 14
+'ß' = 15
+'à' = 16
+'á' = 17
+'ç' = 19
+'è' = 1A
+'é' = 1B
+'ê' = 1C
+'ë' = 1D
+'ì' = 1E
+'î' = 20
+'ï' = 21
+'ò' = 22
+'ó' = 23
+'ô' = 24
+'œ' = 25
+'ù' = 26
+'ú' = 27
+'û' = 28
+'ñ' = 29
+'º' = 2A
+'ª' = 2B
+SUPER_ER = 2C
+'&' = 2D
+'+' = 2E
+LV = 34
+'=' = 35
+';' = 36
+'¿' = 51
+'¡' = 52
+PK = 53
+PKMN = 53 54
+POKEBLOCK = 55 56 57 58 59
+'Í' = 5A
+'%' = 5B
+'(' = 5C
+')' = 5D
+'â' = 68
+'í' = 6F
+UNK_SPACER = 77
+UP_ARROW = 79
+DOWN_ARROW = 7A
+LEFT_ARROW = 7B
+RIGHT_ARROW = 7C
+'0' = A1
+'1' = A2
+'2' = A3
+'3' = A4
+'4' = A5
+'5' = A6
+'6' = A7
+'7' = A8
+'8' = A9
+'9' = AA
+'!' = AB
+'?' = AC
+'.' = AD
+'-' = AE
+'·' = AF
+'…' = B0
+'“' = B1
+'”' = B2
+'‘' = B3
+'’' = B4
+'♂' = B5
+'♀' = B6
+'¥' = B7
+',' = B8
+'×' = B9
+'/' = BA
+'A' = BB
+'B' = BC
+'C' = BD
+'D' = BE
+'E' = BF
+'F' = C0
+'G' = C1
+'H' = C2
+'I' = C3
+'J' = C4
+'K' = C5
+'L' = C6
+'M' = C7
+'N' = C8
+'O' = C9
+'P' = CA
+'Q' = CB
+'R' = CC
+'S' = CD
+'T' = CE
+'U' = CF
+'V' = D0
+'W' = D1
+'X' = D2
+'Y' = D3
+'Z' = D4
+'a' = D5
+'b' = D6
+'c' = D7
+'d' = D8
+'e' = D9
+'f' = DA
+'g' = DB
+'h' = DC
+'i' = DD
+'j' = DE
+'k' = DF
+'l' = E0
+'m' = E1
+'n' = E2
+'o' = E3
+'p' = E4
+'q' = E5
+'r' = E6
+'s' = E7
+'t' = E8
+'u' = E9
+'v' = EA
+'w' = EB
+'x' = EC
+'y' = ED
+'z' = EE
+'▶' = EF
+':' = F0
+'Ä' = F1
+'Ö' = F2
+'Ü' = F3
+'ä' = F4
+'ö' = F5
+'ü' = F6
+TALL_PLUS = FC 0C FB
+'$' = FF
+
+@ Hiragana
+'あ' = 01
+'い' = 02
+'う' = 03
+'え' = 04
+'お' = 05
+'か' = 06
+'き' = 07
+'く' = 08
+'け' = 09
+'こ' = 0A
+'さ' = 0B
+'し' = 0C
+'す' = 0D
+'せ' = 0E
+'そ' = 0F
+'た' = 10
+'ち' = 11
+'つ' = 12
+'て' = 13
+'と' = 14
+'な' = 15
+'に' = 16
+'ぬ' = 17
+'ね' = 18
+'の' = 19
+'は' = 1A
+'ひ' = 1B
+'ふ' = 1C
+'へ' = 1D
+'ほ' = 1E
+'ま' = 1F
+'み' = 20
+'む' = 21
+'め' = 22
+'も' = 23
+'や' = 24
+'ゆ' = 25
+'よ' = 26
+'ら' = 27
+'り' = 28
+'る' = 29
+'れ' = 2A
+'ろ' = 2B
+'わ' = 2C
+'を' = 2D
+'ん' = 2E
+'ぁ' = 2F
+'ぃ' = 30
+'ぅ' = 31
+'ぇ' = 32
+'ぉ' = 33
+'ゃ' = 34
+'ゅ' = 35
+'ょ' = 36
+'が' = 37
+'ぎ' = 38
+'ぐ' = 39
+'げ' = 3A
+'ご' = 3B
+'ざ' = 3C
+'じ' = 3D
+'ず' = 3E
+'ぜ' = 3F
+'ぞ' = 40
+'だ' = 41
+'ぢ' = 42
+'づ' = 43
+'で' = 44
+'ど' = 45
+'ば' = 46
+'び' = 47
+'ぶ' = 48
+'べ' = 49
+'ぼ' = 4A
+'ぱ' = 4B
+'ぴ' = 4C
+'ぷ' = 4D
+'ぺ' = 4E
+'ぽ' = 4F
+'っ' = 50
+
+@ Katakana
+'ア' = 51
+'イ' = 52
+'ウ' = 53
+'エ' = 54
+'オ' = 55
+'カ' = 56
+'キ' = 57
+'ク' = 58
+'ケ' = 59
+'コ' = 5A
+'サ' = 5B
+'シ' = 5C
+'ス' = 5D
+'セ' = 5E
+'ソ' = 5F
+'タ' = 60
+'チ' = 61
+'ツ' = 62
+'テ' = 63
+'ト' = 64
+'ナ' = 65
+'ニ' = 66
+'ヌ' = 67
+'ネ' = 68
+'ノ' = 69
+'ハ' = 6A
+'ヒ' = 6B
+'フ' = 6C
+'ヘ' = 6D
+'ホ' = 6E
+'マ' = 6F
+'ミ' = 70
+'ム' = 71
+'メ' = 72
+'モ' = 73
+'ヤ' = 74
+'ユ' = 75
+'ヨ' = 76
+'ラ' = 77
+'リ' = 78
+'ル' = 79
+'レ' = 7A
+'ロ' = 7B
+'ワ' = 7C
+'ヲ' = 7D
+'ン' = 7E
+'ァ' = 7F
+'ィ' = 80
+'ゥ' = 81
+'ェ' = 82
+'ォ' = 83
+'ャ' = 84
+'ュ' = 85
+'ョ' = 86
+'ガ' = 87
+'ギ' = 88
+'グ' = 89
+'ゲ' = 8A
+'ゴ' = 8B
+'ザ' = 8C
+'ジ' = 8D
+'ズ' = 8E
+'ゼ' = 8F
+'ゾ' = 90
+'ダ' = 91
+'ヂ' = 92
+'ヅ' = 93
+'デ' = 94
+'ド' = 95
+'バ' = 96
+'ビ' = 97
+'ブ' = 98
+'ベ' = 99
+'ボ' = 9A
+'パ' = 9B
+'ピ' = 9C
+'プ' = 9D
+'ペ' = 9E
+'ポ' = 9F
+'ッ' = A0
+
+@ Japanese punctuation
+' ' = 00
+'!' = AB
+'?' = AC
+'。' = AD
+'ー' = AE
+'⋯' = B0
+
+STRING = FD
+
+@ string placeholders
+PLAYER = FD 01
+STR_VAR_1 = FD 02
+STR_VAR_2 = FD 03
+STR_VAR_3 = FD 04
+KUN = FD 05
+RIVAL = FD 06
+@ version-dependent strings (originally made for Ruby/Sapphire differences)
+@ Emerald uses the Sapphire strings (except for VERSION).
+VERSION = FD 07 @ "EMERALD"
+AQUA = FD 08
+MAGMA = FD 09
+ARCHIE = FD 0A
+MAXIE = FD 0B
+KYOGRE = FD 0C
+GROUDON = FD 0D
+
+@ battle string placeholders
+
+B_BUFF1 = FD 00
+B_BUFF2 = FD 01
+B_COPY_VAR_1 = FD 02
+B_COPY_VAR_2 = FD 03
+B_COPY_VAR_3 = FD 04
+B_PLAYER_MON1_NAME = FD 05
+B_OPPONENT_MON1_NAME = FD 06
+B_PLAYER_MON2_NAME = FD 07
+B_OPPONENT_MON2_NAME = FD 08
+B_LINK_PLAYER_MON1_NAME = FD 09
+B_LINK_OPPONENT_MON1_NAME = FD 0A
+B_LINK_PLAYER_MON2_NAME = FD 0B
+B_LINK_OPPONENT_MON2_NAME = FD 0C
+B_ATK_NAME_WITH_PREFIX_MON1 = FD 0D
+B_ATK_PARTNER_NAME = FD 0E
+B_ATK_NAME_WITH_PREFIX = FD 0F
+B_DEF_NAME_WITH_PREFIX = FD 10
+B_EFF_NAME_WITH_PREFIX = FD 11 @ EFF = short for gEffectBattler
+B_ACTIVE_NAME_WITH_PREFIX = FD 12
+B_SCR_ACTIVE_NAME_WITH_PREFIX = FD 13
+B_CURRENT_MOVE = FD 14
+B_LAST_MOVE = FD 15
+B_LAST_ITEM = FD 16
+B_LAST_ABILITY = FD 17
+B_ATK_ABILITY = FD 18
+B_DEF_ABILITY = FD 19
+B_SCR_ACTIVE_ABILITY = FD 1A
+B_EFF_ABILITY = FD 1B
+B_TRAINER1_CLASS = FD 1C
+B_TRAINER1_NAME = FD 1D
+B_LINK_PLAYER_NAME = FD 1E
+B_LINK_PARTNER_NAME = FD 1F
+B_LINK_OPPONENT1_NAME = FD 20
+B_LINK_OPPONENT2_NAME = FD 21
+B_LINK_SCR_TRAINER_NAME = FD 22
+B_PLAYER_NAME = FD 23
+B_TRAINER1_LOSE_TEXT = FD 24
+B_TRAINER1_WIN_TEXT = FD 25
+B_26 = FD 26
+B_PC_CREATOR_NAME = FD 27
+B_ATK_PREFIX1 = FD 28
+B_DEF_PREFIX1 = FD 29
+B_ATK_PREFIX2 = FD 2A
+B_DEF_PREFIX2 = FD 2B
+B_ATK_PREFIX3 = FD 2C
+B_DEF_PREFIX3 = FD 2D
+B_TRAINER2_CLASS = FD 2E
+B_TRAINER2_NAME = FD 2F
+B_TRAINER2_LOSE_TEXT = FD 30
+B_TRAINER2_WIN_TEXT = FD 31
+B_PARTNER_CLASS = FD 32
+B_PARTNER_NAME = FD 33
+B_BUFF3 = FD 34
+
+@ indicates the end of a town/city name (before " TOWN" or " CITY")
+NAME_END = FC 00
+
+@ special 0xF7 character
+SPECIAL_F7 = F7
+
+@ more text functions
+
+COLOR = FC 01 @ use a color listed below right after
+HIGHLIGHT = FC 02 @ same as fc 01
+SHADOW = FC 03 @ same as fc 01
+COLOR_HIGHLIGHT_SHADOW = FC 04 @ takes 3 bytes
+PALETTE = FC 05 @ used in credits
+SIZE = FC 06 @ note that anything other than "SMALL" is invalid
+UNKNOWN_7 = FC 07
+PAUSE = FC 08 @ manually print the wait byte after this, havent mapped them
+PAUSE_UNTIL_PRESS = FC 09
+UNKNOWN_A = FC 0A
+PLAY_BGM = FC 0B
+ESCAPE = FC 0C
+SHIFT_TEXT = FC 0D
+UNKNOWN_E = FC 0E
+UNKNOWN_F = FC 0F
+PLAY_SE = FC 10
+CLEAR = FC 11
+SKIP = FC 12
+CLEAR_TO = FC 13
+UNKNOWN_14 = FC 14
+JPN = FC 15
+ENG = FC 16
+PAUSE_MUSIC = FC 17
+RESUME_MUSIC = FC 18
+
+@ colors
+
+TRANSPARENT = 00
+WHITE = 01
+DARK_GREY = 02
+LIGHT_GREY = 03
+RED = 04
+LIGHT_RED = 05
+GREEN = 06
+LIGHT_GREEN = 07
+BLUE = 08
+LIGHT_BLUE = 09
+@ these next colors can be set to anything arbitrary at runtime
+@ usually though they'll have the textbox border colors as described below
+DYNAMIC_COLOR1 = 0A @ white
+DYNAMIC_COLOR2 = 0B @ white with a tinge of green
+DYNAMIC_COLOR3 = 0C @ white 2
+DYNAMIC_COLOR4 = 0D @ aquamarine
+DYNAMIC_COLOR5 = 0E @ blue-green
+DYNAMIC_COLOR6 = 0F @ cerulean
+
+@ sound and music
+
+MUS_DUMMY = 00 00
+SE_KAIFUKU = 01 00
+SE_PC_LOGIN = 02 00
+SE_PC_OFF = 03 00
+SE_PC_ON = 04 00
+SE_SELECT = 05 00
+SE_WIN_OPEN = 06 00
+SE_WALL_HIT = 07 00
+SE_DOOR = 08 00
+SE_KAIDAN = 09 00
+SE_DANSA = 0A 00
+SE_JITENSYA = 0B 00
+SE_KOUKA_L = 0C 00
+SE_KOUKA_M = 0D 00
+SE_KOUKA_H = 0E 00
+SE_BOWA2 = 0F 00
+SE_POKE_DEAD = 10 00
+SE_NIGERU = 11 00
+SE_JIDO_DOA = 12 00
+SE_NAMINORI = 13 00
+SE_BAN = 14 00
+SE_PIN = 15 00
+SE_BOO = 16 00
+SE_BOWA = 17 00
+SE_JYUNI = 18 00
+SE_A = 19 00
+SE_I = 1A 00
+SE_U = 1B 00
+SE_E = 1C 00
+SE_O = 1D 00
+SE_N = 1E 00
+SE_SEIKAI = 1F 00
+SE_HAZURE = 20 00
+SE_EXP = 21 00
+SE_JITE_PYOKO = 22 00
+SE_MU_PACHI = 23 00
+SE_TK_KASYA = 24 00
+SE_FU_ZAKU = 25 00
+SE_FU_ZAKU2 = 26 00
+SE_FU_ZUZUZU = 27 00
+SE_RU_GASHIN = 28 00
+SE_RU_GASYAN = 29 00
+SE_RU_BARI = 2A 00
+SE_RU_HYUU = 2B 00
+SE_KI_GASYAN = 2C 00
+SE_TK_WARPIN = 2D 00
+SE_TK_WARPOUT = 2E 00
+SE_TU_SAA = 2F 00
+SE_HI_TURUN = 30 00
+SE_TRACK_MOVE = 31 00
+SE_TRACK_STOP = 32 00
+SE_TRACK_HAIKI = 33 00
+SE_TRACK_DOOR = 34 00
+SE_MOTER = 35 00
+SE_CARD = 36 00
+SE_SAVE = 37 00
+SE_KON = 38 00
+SE_KON2 = 39 00
+SE_KON3 = 3A 00
+SE_KON4 = 3B 00
+SE_SUIKOMU = 3C 00
+SE_NAGERU = 3D 00
+SE_TOY_C = 3E 00
+SE_TOY_D = 3F 00
+SE_TOY_E = 40 00
+SE_TOY_F = 41 00
+SE_TOY_G = 42 00
+SE_TOY_A = 43 00
+SE_TOY_B = 44 00
+SE_TOY_C1 = 45 00
+SE_MIZU = 46 00
+SE_HASHI = 47 00
+SE_DAUGI = 48 00
+SE_PINPON = 49 00
+SE_FUUSEN1 = 4A 00
+SE_FUUSEN2 = 4B 00
+SE_FUUSEN3 = 4C 00
+SE_TOY_KABE = 4D 00
+SE_TOY_DANGO = 4E 00
+SE_DOKU = 4F 00
+SE_ESUKA = 50 00
+SE_T_AME = 51 00
+SE_T_AME_E = 52 00
+SE_T_OOAME = 53 00
+SE_T_OOAME_E = 54 00
+SE_T_KOAME = 55 00
+SE_T_KOAME_E = 56 00
+SE_T_KAMI = 57 00
+SE_T_KAMI2 = 58 00
+SE_ELEBETA = 59 00
+SE_HINSI = 5A 00
+SE_EXPMAX = 5B 00
+SE_TAMAKORO = 5C 00
+SE_TAMAKORO_E = 5D 00
+SE_BASABASA = 5E 00
+SE_REGI = 5F 00
+SE_C_GAJI = 60 00
+SE_C_MAKU_U = 61 00
+SE_C_MAKU_D = 62 00
+SE_C_PASI = 63 00
+SE_C_SYU = 64 00
+SE_C_PIKON = 65 00
+SE_REAPOKE = 66 00
+SE_OP_BASYU = 67 00
+SE_BT_START = 68 00
+SE_DENDOU = 69 00
+SE_JIHANKI = 6A 00
+SE_TAMA = 6B 00
+SE_Z_SCROLL = 6C 00
+SE_Z_PAGE = 6D 00
+SE_PN_ON = 6E 00
+SE_PN_OFF = 6F 00
+SE_Z_SEARCH = 70 00
+SE_TAMAGO = 71 00
+SE_TB_START = 72 00
+SE_TB_KON = 73 00
+SE_TB_KARA = 74 00
+SE_BIDORO = 75 00
+SE_W085 = 76 00
+SE_W085B = 77 00
+SE_W231 = 78 00
+SE_W171 = 79 00
+SE_W233 = 7A 00
+SE_W233B = 7B 00
+SE_W145 = 7C 00
+SE_W145B = 7D 00
+SE_W145C = 7E 00
+SE_W240 = 7F 00
+SE_W015 = 80 00
+SE_W081 = 81 00
+SE_W081B = 82 00
+SE_W088 = 83 00
+SE_W016 = 84 00
+SE_W016B = 85 00
+SE_W003 = 86 00
+SE_W104 = 87 00
+SE_W013 = 88 00
+SE_W196 = 89 00
+SE_W086 = 8A 00
+SE_W004 = 8B 00
+SE_W025 = 8C 00
+SE_W025B = 8D 00
+SE_W152 = 8E 00
+SE_W026 = 8F 00
+SE_W172 = 90 00
+SE_W172B = 91 00
+SE_W053 = 92 00
+SE_W007 = 93 00
+SE_W092 = 94 00
+SE_W221 = 95 00
+SE_W221B = 96 00
+SE_W052 = 97 00
+SE_W036 = 98 00
+SE_W059 = 99 00
+SE_W059B = 9A 00
+SE_W010 = 9B 00
+SE_W011 = 9C 00
+SE_W017 = 9D 00
+SE_W019 = 9E 00
+SE_W028 = 9F 00
+SE_W013B = A0 00
+SE_W044 = A1 00
+SE_W029 = A2 00
+SE_W057 = A3 00
+SE_W056 = A4 00
+SE_W250 = A5 00
+SE_W030 = A6 00
+SE_W039 = A7 00
+SE_W054 = A8 00
+SE_W077 = A9 00
+SE_W020 = AA 00
+SE_W082 = AB 00
+SE_W047 = AC 00
+SE_W195 = AD 00
+SE_W006 = AE 00
+SE_W091 = AF 00
+SE_W146 = B0 00
+SE_W120 = B1 00
+SE_W153 = B2 00
+SE_W071B = B3 00
+SE_W071 = B4 00
+SE_W103 = B5 00
+SE_W062 = B6 00
+SE_W062B = B7 00
+SE_W048 = B8 00
+SE_W187 = B9 00
+SE_W118 = BA 00
+SE_W155 = BB 00
+SE_W122 = BC 00
+SE_W060 = BD 00
+SE_W185 = BE 00
+SE_W014 = BF 00
+SE_W043 = C0 00
+SE_W207 = C1 00
+SE_W207B = C2 00
+SE_W215 = C3 00
+SE_W109 = C4 00
+SE_W173 = C5 00
+SE_W280 = C6 00
+SE_W202 = C7 00
+SE_W060B = C8 00
+SE_W076 = C9 00
+SE_W080 = CA 00
+SE_W100 = CB 00
+SE_W107 = CC 00
+SE_W166 = CD 00
+SE_W129 = CE 00
+SE_W115 = CF 00
+SE_W112 = D0 00
+SE_W197 = D1 00
+SE_W199 = D2 00
+SE_W236 = D3 00
+SE_W204 = D4 00
+SE_W268 = D5 00
+SE_W070 = D6 00
+SE_W063 = D7 00
+SE_W127 = D8 00
+SE_W179 = D9 00
+SE_W151 = DA 00
+SE_W201 = DB 00
+SE_W161 = DC 00
+SE_W161B = DD 00
+SE_W227 = DE 00
+SE_W227B = DF 00
+SE_W226 = E0 00
+SE_W208 = E1 00
+SE_W213 = E2 00
+SE_W213B = E3 00
+SE_W234 = E4 00
+SE_W260 = E5 00
+SE_W328 = E6 00
+SE_W320 = E7 00
+SE_W255 = E8 00
+SE_W291 = E9 00
+SE_W089 = EA 00
+SE_W239 = EB 00
+SE_W230 = EC 00
+SE_W281 = ED 00
+SE_W327 = EE 00
+SE_W287 = EF 00
+SE_W257 = F0 00
+SE_W253 = F1 00
+SE_W258 = F2 00
+SE_W322 = F3 00
+SE_W298 = F4 00
+SE_W287B = F5 00
+SE_W114 = F6 00
+SE_W063B = F7 00
+SE_RG_W_DOOR = F8 00
+SE_RG_CARD1 = F9 00
+SE_RG_CARD2 = FA 00
+SE_RG_CARD3 = FB 00
+SE_RG_BAG1 = FC 00
+SE_RG_BAG2 = FD 00
+SE_RG_GETTING = FE 00
+SE_RG_SHOP = FF 00
+SE_RG_KITEKI = 00 01
+SE_RG_HELP_OP = 01 01
+SE_RG_HELP_CL = 02 01
+SE_RG_HELP_NG = 03 01
+SE_RG_DEOMOV = 04 01
+SE_RG_EXCELLENT = 05 01
+SE_RG_NAWAMISS = 06 01
+SE_TOREEYE = 07 01
+SE_TOREOFF = 08 01
+SE_HANTEI1 = 09 01
+SE_HANTEI2 = 0A 01
+SE_CURTAIN = 0B 01
+SE_CURTAIN1 = 0C 01
+SE_USSOKI = 0D 01
+MUS_TETSUJI = 5E 01
+MUS_FIELD13 = 5F 01
+MUS_KACHI22 = 60 01
+MUS_KACHI2 = 61 01
+MUS_KACHI3 = 62 01
+MUS_KACHI5 = 63 01
+MUS_PCC = 64 01
+MUS_NIBI = 65 01
+MUS_SUIKUN = 66 01
+MUS_DOORO1 = 67 01
+MUS_DOORO_X1 = 68 01
+MUS_DOORO_X3 = 69 01
+MUS_MACHI_S2 = 6A 01
+MUS_MACHI_S4 = 6B 01
+MUS_GIM = 6C 01
+MUS_NAMINORI = 6D 01
+MUS_DAN01 = 6E 01
+MUS_FANFA1 = 6F 01
+MUS_ME_ASA = 70 01
+MUS_ME_BACHI = 71 01
+MUS_FANFA4 = 72 01
+MUS_FANFA5 = 73 01
+MUS_ME_WAZA = 74 01
+MUS_BIJYUTU = 75 01
+MUS_DOORO_X4 = 76 01
+MUS_FUNE_KAN = 77 01
+MUS_ME_SHINKA = 78 01
+MUS_SHINKA = 79 01
+MUS_ME_WASURE = 7A 01
+MUS_SYOUJOEYE = 7B 01
+MUS_BOYEYE = 7C 01
+MUS_DAN02 = 7D 01
+MUS_MACHI_S3 = 7E 01
+MUS_ODAMAKI = 7F 01
+MUS_B_TOWER = 80 01
+MUS_SWIMEYE = 81 01
+MUS_DAN03 = 82 01
+MUS_ME_KINOMI = 83 01
+MUS_ME_TAMA = 84 01
+MUS_ME_B_BIG = 85 01
+MUS_ME_B_SMALL = 86 01
+MUS_ME_ZANNEN = 87 01
+MUS_BD_TIME = 88 01
+MUS_TEST1 = 89 01
+MUS_TEST2 = 8A 01
+MUS_TEST3 = 8B 01
+MUS_TEST4 = 8C 01
+MUS_TEST = 8D 01
+MUS_GOMACHI0 = 8E 01
+MUS_GOTOWN = 8F 01
+MUS_POKECEN = 90 01
+MUS_NEXTROAD = 91 01
+MUS_GRANROAD = 92 01
+MUS_CYCLING = 93 01
+MUS_FRIENDLY = 94 01
+MUS_MISHIRO = 95 01
+MUS_TOZAN = 96 01
+MUS_GIRLEYE = 97 01
+MUS_MINAMO = 98 01
+MUS_ASHROAD = 99 01
+MUS_EVENT0 = 9A 01
+MUS_DEEPDEEP = 9B 01
+MUS_KACHI1 = 9C 01
+MUS_TITLE3 = 9D 01
+MUS_DEMO1 = 9E 01
+MUS_GIRL_SUP = 9F 01
+MUS_HAGESHII = A0 01
+MUS_KAKKOII = A1 01
+MUS_KAZANBAI = A2 01
+MUS_AQA_0 = A3 01
+MUS_TSURETEK = A4 01
+MUS_BOY_SUP = A5 01
+MUS_RAINBOW = A6 01
+MUS_AYASII = A7 01
+MUS_KACHI4 = A8 01
+MUS_ROPEWAY = A9 01
+MUS_CASINO = AA 01
+MUS_HIGHTOWN = AB 01
+MUS_SAFARI = AC 01
+MUS_C_ROAD = AD 01
+MUS_AJITO = AE 01
+MUS_M_BOAT = AF 01
+MUS_M_DUNGON = B0 01
+MUS_FINECITY = B1 01
+MUS_MACHUPI = B2 01
+MUS_P_SCHOOL = B3 01
+MUS_DENDOU = B4 01
+MUS_TONEKUSA = B5 01
+MUS_MABOROSI = B6 01
+MUS_CON_FAN = B7 01
+MUS_CONTEST0 = B8 01
+MUS_MGM0 = B9 01
+MUS_T_BATTLE = BA 01
+MUS_OOAME = BB 01
+MUS_HIDERI = BC 01
+MUS_RUNECITY = BD 01
+MUS_CON_K = BE 01
+MUS_EIKOU_R = BF 01
+MUS_KARAKURI = C0 01
+MUS_HUTAGO = C1 01
+MUS_SITENNOU = C2 01
+MUS_YAMA_EYE = C3 01
+MUS_CONLOBBY = C4 01
+MUS_INTER_V = C5 01
+MUS_DAIGO = C6 01
+MUS_THANKFOR = C7 01
+MUS_END = C8 01
+MUS_B_FRONTIER = C9 01
+MUS_B_ARENA = CA 01
+MUS_ME_POINTGET = CB 01
+MUS_ME_TORE_EYE = CC 01
+MUS_PYRAMID = CD 01
+MUS_PYRAMID_TOP = CE 01
+MUS_B_PALACE = CF 01
+MUS_REKKUU_KOURIN = D0 01
+MUS_SATTOWER = D1 01
+MUS_ME_SYMBOLGET = D2 01
+MUS_B_DOME = D3 01
+MUS_B_TUBE = D4 01
+MUS_B_FACTORY = D5 01
+MUS_VS_REKKU = D6 01
+MUS_VS_FRONT = D7 01
+MUS_VS_MEW = D8 01
+MUS_B_DOME1 = D9 01
+MUS_BATTLE27 = DA 01
+MUS_BATTLE31 = DB 01
+MUS_BATTLE20 = DC 01
+MUS_BATTLE32 = DD 01
+MUS_BATTLE33 = DE 01
+MUS_BATTLE36 = DF 01
+MUS_BATTLE34 = E0 01
+MUS_BATTLE35 = E1 01
+MUS_BATTLE38 = E2 01
+MUS_BATTLE30 = E3 01
+MUS_RG_ANNAI = E4 01
+MUS_RG_SLOT = E5 01
+MUS_RG_AJITO = E6 01
+MUS_RG_GYM = E7 01
+MUS_RG_PURIN = E8 01
+MUS_RG_DEMO = E9 01
+MUS_RG_TITLE = EA 01
+MUS_RG_GUREN = EB 01
+MUS_RG_SHION = EC 01
+MUS_RG_KAIHUKU = ED 01
+MUS_RG_CYCLING = EE 01
+MUS_RG_ROCKET = EF 01
+MUS_RG_SHOUJO = F0 01
+MUS_RG_SHOUNEN = F1 01
+MUS_RG_DENDOU = F2 01
+MUS_RG_T_MORI = F3 01
+MUS_RG_OTSUKIMI = F4 01
+MUS_RG_POKEYASHI = F5 01
+MUS_RG_ENDING = F6 01
+MUS_RG_LOAD01 = F7 01
+MUS_RG_OPENING = F8 01
+MUS_RG_LOAD02 = F9 01
+MUS_RG_LOAD03 = FA 01
+MUS_RG_CHAMP_R = FB 01
+MUS_RG_VS_GYM = FC 01
+MUS_RG_VS_TORE = FD 01
+MUS_RG_VS_YASEI = FE 01
+MUS_RG_VS_LAST = FF 01
+MUS_RG_MASARA = 00 02
+MUS_RG_KENKYU = 01 02
+MUS_RG_OHKIDO = 02 02
+MUS_RG_POKECEN = 03 02
+MUS_RG_SANTOAN = 04 02
+MUS_RG_NAMINORI = 05 02
+MUS_RG_P_TOWER = 06 02
+MUS_RG_SHIRUHU = 07 02
+MUS_RG_HANADA = 08 02
+MUS_RG_TAMAMUSI = 09 02
+MUS_RG_WIN_TRE = 0A 02
+MUS_RG_WIN_YASEI = 0B 02
+MUS_RG_WIN_GYM = 0C 02
+MUS_RG_KUCHIBA = 0D 02
+MUS_RG_NIBI = 0E 02
+MUS_RG_RIVAL1 = 0F 02
+MUS_RG_RIVAL2 = 10 02
+MUS_RG_FAN2 = 11 02
+MUS_RG_FAN5 = 12 02
+MUS_RG_FAN6 = 13 02
+MUS_ME_RG_PHOTO = 14 02
+MUS_RG_TITLEROG = 15 02
+MUS_RG_GET_YASEI = 16 02
+MUS_RG_SOUSA = 17 02
+MUS_RG_SEKAIKAN = 18 02
+MUS_RG_SEIBETU = 19 02
+MUS_RG_JUMP = 1A 02
+MUS_RG_UNION = 1B 02
+MUS_RG_NETWORK = 1C 02
+MUS_RG_OKURIMONO = 1D 02
+MUS_RG_KINOMIKUI = 1E 02
+MUS_RG_NANADUNGEON = 1F 02
+MUS_RG_OSHIE_TV = 20 02
+MUS_RG_NANASHIMA = 21 02
+MUS_RG_NANAISEKI = 22 02
+MUS_RG_NANA123 = 23 02
+MUS_RG_NANA45 = 24 02
+MUS_RG_NANA67 = 25 02
+MUS_RG_POKEFUE = 26 02
+MUS_RG_VS_DEO = 27 02
+MUS_RG_VS_MYU2 = 28 02
+MUS_RG_VS_DEN = 29 02
+MUS_RG_EXEYE = 2A 02
+MUS_RG_DEOEYE = 2B 02
+MUS_RG_T_TOWER = 2C 02
+MUS_RG_SLOWMASARA = 2D 02
+MUS_RG_TVNOIZE = 2E 02
+PH_TRAP_BLEND = 2F 02
+PH_TRAP_HELD = 30 02
+PH_TRAP_SOLO = 31 02
+PH_FACE_BLEND = 32 02
+PH_FACE_HELD = 33 02
+PH_FACE_SOLO = 34 02
+PH_CLOTH_BLEND = 35 02
+PH_CLOTH_HELD = 36 02
+PH_CLOTH_SOLO = 37 02
+PH_DRESS_BLEND = 38 02
+PH_DRESS_HELD = 39 02
+PH_DRESS_SOLO = 3A 02
+PH_FLEECE_BLEND = 3B 02
+PH_FLEECE_HELD = 3C 02
+PH_FLEECE_SOLO = 3D 02
+PH_KIT_BLEND = 3E 02
+PH_KIT_HELD = 3F 02
+PH_KIT_SOLO = 40 02
+PH_PRICE_BLEND = 41 02
+PH_PRICE_HELD = 42 02
+PH_PRICE_SOLO = 43 02
+PH_LOT_BLEND = 44 02
+PH_LOT_HELD = 45 02
+PH_LOT_SOLO = 46 02
+PH_GOAT_BLEND = 47 02
+PH_GOAT_HELD = 48 02
+PH_GOAT_SOLO = 49 02
+PH_THOUGHT_BLEND = 4A 02
+PH_THOUGHT_HELD = 4B 02
+PH_THOUGHT_SOLO = 4C 02
+PH_CHOICE_BLEND = 4D 02
+PH_CHOICE_HELD = 4E 02
+PH_CHOICE_SOLO = 4F 02
+PH_MOUTH_BLEND = 50 02
+PH_MOUTH_HELD = 51 02
+PH_MOUTH_SOLO = 52 02
+PH_FOOT_BLEND = 53 02
+PH_FOOT_HELD = 54 02
+PH_FOOT_SOLO = 55 02
+PH_GOOSE_BLEND = 56 02
+PH_GOOSE_HELD = 57 02
+PH_GOOSE_SOLO = 58 02
+PH_STRUT_BLEND = 59 02
+PH_STRUT_HELD = 5A 02
+PH_STRUT_SOLO = 5B 02
+PH_CURE_BLEND = 5C 02
+PH_CURE_HELD = 5D 02
+PH_CURE_SOLO = 5E 02
+PH_NURSE_BLEND = 5F 02
+PH_NURSE_HELD = 60 02
+PH_NURSE_SOLO = 61 02
+
+A_BUTTON = F8 00
+B_BUTTON = F8 01
+DPAD_UPDOWN = F8 0A
+DPAD_NONE = F8 0C
+
+UP_ARROW_2 = F9 00
+DOWN_ARROW_2 = F9 01
+LEFT_ARROW_2 = F9 02
+RIGHT_ARROW_2 = F9 03
+PLUS = F9 04
+LV_2 = F9 05
+PP = F9 06
+ID = F9 07
+NO = F9 08
+UNDERSCORE = F9 09
+CIRCLE_1 = F9 0A
+CIRCLE_2 = F9 0B
+CIRCLE_3 = F9 0C
+CIRCLE_4 = F9 0D
+CIRCLE_5 = F9 0E
+CIRCLE_6 = F9 0F
+CIRCLE_7 = F9 10
+CIRCLE_8 = F9 11
+CIRCLE_9 = F9 12
+ROUND_LEFT_PAREN = F9 13
+ROUND_RIGHT_PAREN = F9 14
+CIRCLE_DOT = F9 15
+TRIANGLE = F9 16
+BIG_MULT_X = F9 17
+
+EMOJI_UNDERSCORE = F9 D0
+EMOJI_PIPE = F9 D1
+EMOJI_HIGHBAR = F9 D2
+EMOJI_TILDE = F9 D3
+EMOJI_LEFT_PAREN = F9 D4
+EMOJI_RIGHT_PAREN = F9 D5
+EMOJI_UNION = F9 D6 @ ⊂
+EMOJI_GREATER_THAN = F9 D7
+EMOJI_LEFT_EYE = F9 D8
+EMOJI_RIGHT_EYE = F9 D9
+EMOJI_AT = F9 DA
+EMOJI_SEMICOLON = F9 DB
+EMOJI_PLUS = F9 DC
+EMOJI_MINUS = F9 DD
+EMOJI_EQUALS = F9 DE
+EMOJI_SPIRAL = F9 DF
+EMOJI_TONGUE = F9 E0
+EMOJI_TRIANGLE_OUTLINE = F9 E1
+EMOJI_ACUTE = F9 E2
+EMOJI_GRAVE = F9 E3
+EMOJI_CIRCLE = F9 E4
+EMOJI_TRIANGLE = F9 E5
+EMOJI_SQUARE = F9 E6
+EMOJI_HEART = F9 E7
+EMOJI_MOON = F9 E8
+EMOJI_NOTE = F9 E9
+EMOJI_BALL = F9 EA
+EMOJI_BOLT = F9 EB
+EMOJI_LEAF = F9 EC
+EMOJI_FIRE = F9 ED
+EMOJI_WATER = F9 EE
+EMOJI_LEFT_FIST = F9 EF
+EMOJI_RIGHT_FIST = F9 F0
+EMOJI_BIGWHEEL = F9 F1
+EMOJI_SMALLWHEEL = F9 F2
+EMOJI_SPHERE = F9 F3
+EMOJI_IRRITATED = F9 F4
+EMOJI_MISCHIEVOUS = F9 F5
+EMOJI_HAPPY = F9 F6
+EMOJI_ANGRY = F9 F7
+EMOJI_SURPRISED = F9 F8
+EMOJI_BIGSMILE = F9 F9
+EMOJI_EVIL = F9 FA
+EMOJI_TIRED = F9 FB
+EMOJI_NEUTRAL = F9 FC
+EMOJI_SHOCKED = F9 FD
+EMOJI_BIGANGER = F9 FE
+
+'\l' = FA @ scroll up window text
+'\p' = FB @ new paragraph
+'\n' = FE @ new line
diff --git a/berry_fix/payload/common_syms/agb_flash.txt b/berry_fix/payload/common_syms/agb_flash.txt
new file mode 100644
index 000000000..cb421ec80
--- /dev/null
+++ b/berry_fix/payload/common_syms/agb_flash.txt
@@ -0,0 +1,10 @@
+gFlashTimeoutFlag
+PollFlashStatus
+WaitForFlashWrite
+ProgramFlashSector
+gFlash
+ProgramFlashByte
+gFlashNumRemainingBytes
+EraseFlashChip
+EraseFlashSector
+gFlashMaxTime
diff --git a/berry_fix/payload/common_syms/main.txt b/berry_fix/payload/common_syms/main.txt
new file mode 100644
index 000000000..b62c72124
--- /dev/null
+++ b/berry_fix/payload/common_syms/main.txt
@@ -0,0 +1,9 @@
+gIntrTable
+gHeldKeys
+gNewKeys
+gIntrVector
+gUpdateSuccessful
+gUnknown_3001194
+gUnknown_30011A0
+gMainCallbackState
+gGameVersion
diff --git a/berry_fix/payload/common_syms/rtc.txt b/berry_fix/payload/common_syms/rtc.txt
new file mode 100644
index 000000000..7aafbe65d
--- /dev/null
+++ b/berry_fix/payload/common_syms/rtc.txt
@@ -0,0 +1,2 @@
+gTimeSinceBerryUpdate
+gRtcUTCTime
diff --git a/berry_fix/payload/constants/gba_constants.inc b/berry_fix/payload/constants/gba_constants.inc
new file mode 100644
index 000000000..9d59c8fcd
--- /dev/null
+++ b/berry_fix/payload/constants/gba_constants.inc
@@ -0,0 +1,490 @@
+ .set PSR_USR_MODE, 0x00000010
+ .set PSR_FIQ_MODE, 0x00000011
+ .set PSR_IRQ_MODE, 0x00000012
+ .set PSR_SVC_MODE, 0x00000013
+ .set PSR_ABT_MODE, 0x00000017
+ .set PSR_UND_MODE, 0x0000001b
+ .set PSR_SYS_MODE, 0x0000001f
+ .set PSR_MODE_MASK, 0x0000001f
+ .set PSR_T_BIT, 0x00000020
+ .set PSR_F_BIT, 0x00000040
+ .set PSR_I_BIT, 0x00000080
+
+ .set EWRAM_START, 0x02000000
+ .set EWRAM_END, EWRAM_START + 0x40000
+ .set IWRAM_START, 0x03000000
+ .set IWRAM_END, IWRAM_START + 0x8000
+
+ .set PLTT, 0x5000000
+ .set BG_PLTT, PLTT
+ .set OBJ_PLTT, PLTT + 0x200
+
+ .set VRAM, 0x6000000
+ .set BG_VRAM, VRAM
+ .set OBJ_VRAM0, VRAM + 0x10000 @ text-mode BG
+ .set OBJ_VRAM1, VRAM + 0x14000 @ bitmap-mode BG
+
+ .set OAM, 0x7000000
+
+ .set SOUND_INFO_PTR, 0x3007FF0
+ .set INTR_CHECK, 0x3007FF8
+ .set INTR_VECTOR, 0x3007FFC
+
+ .set INTR_FLAG_VBLANK, 1 << 0
+ .set INTR_FLAG_HBLANK, 1 << 1
+ .set INTR_FLAG_VCOUNT, 1 << 2
+ .set INTR_FLAG_TIMER0, 1 << 3
+ .set INTR_FLAG_TIMER1, 1 << 4
+ .set INTR_FLAG_TIMER2, 1 << 5
+ .set INTR_FLAG_TIMER3, 1 << 6
+ .set INTR_FLAG_SERIAL, 1 << 7
+ .set INTR_FLAG_DMA0, 1 << 8
+ .set INTR_FLAG_DMA1, 1 << 9
+ .set INTR_FLAG_DMA2, 1 << 10
+ .set INTR_FLAG_DMA3, 1 << 11
+ .set INTR_FLAG_KEYPAD, 1 << 12
+ .set INTR_FLAG_GAMEPAK, 1 << 13
+
+ .set VCOUNT_VBLANK, 160
+ .set TOTAL_SCANLINES, 228
+
+ .set REG_BASE, 0x4000000 @ I/O register base address
+
+@ I/O register offsets
+ .set OFFSET_REG_DISPCNT, 0x0
+ .set OFFSET_REG_DISPSTAT, 0x4
+ .set OFFSET_REG_VCOUNT, 0x6
+ .set OFFSET_REG_BG0CNT, 0x8
+ .set OFFSET_REG_BG1CNT, 0xa
+ .set OFFSET_REG_BG2CNT, 0xc
+ .set OFFSET_REG_BG3CNT, 0xe
+ .set OFFSET_REG_BG0HOFS, 0x10
+ .set OFFSET_REG_BG0VOFS, 0x12
+ .set OFFSET_REG_BG1HOFS, 0x14
+ .set OFFSET_REG_BG1VOFS, 0x16
+ .set OFFSET_REG_BG2HOFS, 0x18
+ .set OFFSET_REG_BG2VOFS, 0x1a
+ .set OFFSET_REG_BG3HOFS, 0x1c
+ .set OFFSET_REG_BG3VOFS, 0x1e
+ .set OFFSET_REG_BG2PA, 0x20
+ .set OFFSET_REG_BG2PB, 0x22
+ .set OFFSET_REG_BG2PC, 0x24
+ .set OFFSET_REG_BG2PD, 0x26
+ .set OFFSET_REG_BG2X_L, 0x28
+ .set OFFSET_REG_BG2X_H, 0x2a
+ .set OFFSET_REG_BG2Y_L, 0x2c
+ .set OFFSET_REG_BG2Y_H, 0x2e
+ .set OFFSET_REG_BG3PA, 0x30
+ .set OFFSET_REG_BG3PB, 0x32
+ .set OFFSET_REG_BG3PC, 0x34
+ .set OFFSET_REG_BG3PD, 0x36
+ .set OFFSET_REG_BG3X_L, 0x38
+ .set OFFSET_REG_BG3X_H, 0x3a
+ .set OFFSET_REG_BG3Y_L, 0x3c
+ .set OFFSET_REG_BG3Y_H, 0x3e
+ .set OFFSET_REG_WIN0H, 0x40
+ .set OFFSET_REG_WIN1H, 0x42
+ .set OFFSET_REG_WIN0V, 0x44
+ .set OFFSET_REG_WIN1V, 0x46
+ .set OFFSET_REG_WININ, 0x48
+ .set OFFSET_REG_WINOUT, 0x4a
+ .set OFFSET_REG_MOSAIC, 0x4c
+ .set OFFSET_REG_BLDCNT, 0x50
+ .set OFFSET_REG_BLDALPHA, 0x52
+ .set OFFSET_REG_BLDY, 0x54
+
+ .set OFFSET_REG_SOUND1CNT, 0x60
+ .set OFFSET_REG_SOUND1CNT_L, 0x60
+ .set OFFSET_REG_NR10, 0x60
+ .set OFFSET_REG_SOUND1CNT_H, 0x62
+ .set OFFSET_REG_NR11, 0x62
+ .set OFFSET_REG_NR12, 0x63
+ .set OFFSET_REG_SOUND1CNT_X, 0x64
+ .set OFFSET_REG_NR13, 0x64
+ .set OFFSET_REG_NR14, 0x65
+ .set OFFSET_REG_SOUND2CNT, 0x68
+ .set OFFSET_REG_SOUND2CNT_L, 0x68
+ .set OFFSET_REG_NR21, 0x68
+ .set OFFSET_REG_NR22, 0x69
+ .set OFFSET_REG_SOUND2CNT_H, 0x6c
+ .set OFFSET_REG_NR23, 0x6c
+ .set OFFSET_REG_NR24, 0x6d
+ .set OFFSET_REG_SOUND3CNT, 0x70
+ .set OFFSET_REG_SOUND3CNT_L, 0x70
+ .set OFFSET_REG_NR30, 0x70
+ .set OFFSET_REG_SOUND3CNT_H, 0x72
+ .set OFFSET_REG_NR31, 0x72
+ .set OFFSET_REG_NR32, 0x73
+ .set OFFSET_REG_SOUND3CNT_X, 0x74
+ .set OFFSET_REG_NR33, 0x74
+ .set OFFSET_REG_NR34, 0x75
+ .set OFFSET_REG_SOUND4CNT, 0x78
+ .set OFFSET_REG_SOUND4CNT_L, 0x78
+ .set OFFSET_REG_NR41, 0x78
+ .set OFFSET_REG_NR42, 0x79
+ .set OFFSET_REG_SOUND4CNT_H, 0x7c
+ .set OFFSET_REG_NR43, 0x7c
+ .set OFFSET_REG_NR44, 0x7d
+ .set OFFSET_REG_SOUNDCNT, 0x80
+ .set OFFSET_REG_SOUNDCNT_L, 0x80
+ .set OFFSET_REG_NR50, 0x80
+ .set OFFSET_REG_NR51, 0x81
+ .set OFFSET_REG_SOUNDCNT_H, 0x82
+ .set OFFSET_REG_SOUNDCNT_X, 0x84
+ .set OFFSET_REG_NR52, 0x84
+ .set OFFSET_REG_SOUNDBIAS, 0x88
+ .set OFFSET_REG_WAVE_RAM, 0x90
+ .set OFFSET_REG_WAVE_RAM0, 0x90
+ .set OFFSET_REG_WAVE_RAM0_L, 0x90
+ .set OFFSET_REG_WAVE_RAM0_H, 0x92
+ .set OFFSET_REG_WAVE_RAM1, 0x94
+ .set OFFSET_REG_WAVE_RAM1_L, 0x94
+ .set OFFSET_REG_WAVE_RAM1_H, 0x96
+ .set OFFSET_REG_WAVE_RAM2, 0x98
+ .set OFFSET_REG_WAVE_RAM2_L, 0x98
+ .set OFFSET_REG_WAVE_RAM2_H, 0x9a
+ .set OFFSET_REG_WAVE_RAM3, 0x9c
+ .set OFFSET_REG_WAVE_RAM3_L, 0x9c
+ .set OFFSET_REG_WAVE_RAM3_H, 0x9e
+ .set OFFSET_REG_FIFO, 0xa0
+ .set OFFSET_REG_FIFO_A, 0xa0
+ .set OFFSET_REG_FIFO_A_L, 0xa0
+ .set OFFSET_REG_FIFO_A_H, 0xa2
+ .set OFFSET_REG_FIFO_B, 0xa4
+ .set OFFSET_REG_FIFO_B_L, 0xa4
+ .set OFFSET_REG_FIFO_B_H, 0xa6
+
+ .set OFFSET_REG_DMA0, 0xb0
+ .set OFFSET_REG_DMA0SAD, 0xb0
+ .set OFFSET_REG_DMA0SAD_L, 0xb0
+ .set OFFSET_REG_DMA0SAD_H, 0xb2
+ .set OFFSET_REG_DMA0DAD, 0xb4
+ .set OFFSET_REG_DMA0DAD_L, 0xb4
+ .set OFFSET_REG_DMA0DAD_H, 0xb6
+ .set OFFSET_REG_DMA0CNT, 0xb8
+ .set OFFSET_REG_DMA0CNT_L, 0xb8
+ .set OFFSET_REG_DMA0CNT_H, 0xba
+ .set OFFSET_REG_DMA1, 0xbc
+ .set OFFSET_REG_DMA1SAD, 0xbc
+ .set OFFSET_REG_DMA1SAD_L, 0xbc
+ .set OFFSET_REG_DMA1SAD_H, 0xbe
+ .set OFFSET_REG_DMA1DAD, 0xc0
+ .set OFFSET_REG_DMA1DAD_L, 0xc0
+ .set OFFSET_REG_DMA1DAD_H, 0xc2
+ .set OFFSET_REG_DMA1CNT, 0xc4
+ .set OFFSET_REG_DMA1CNT_L, 0xc4
+ .set OFFSET_REG_DMA1CNT_H, 0xc6
+ .set OFFSET_REG_DMA2, 0xc8
+ .set OFFSET_REG_DMA2SAD, 0xc8
+ .set OFFSET_REG_DMA2SAD_L, 0xc8
+ .set OFFSET_REG_DMA2SAD_H, 0xca
+ .set OFFSET_REG_DMA2DAD, 0xcc
+ .set OFFSET_REG_DMA2DAD_L, 0xcc
+ .set OFFSET_REG_DMA2DAD_H, 0xce
+ .set OFFSET_REG_DMA2CNT, 0xd0
+ .set OFFSET_REG_DMA2CNT_L, 0xd0
+ .set OFFSET_REG_DMA2CNT_H, 0xd2
+ .set OFFSET_REG_DMA3, 0xd4
+ .set OFFSET_REG_DMA3SAD, 0xd4
+ .set OFFSET_REG_DMA3SAD_L, 0xd4
+ .set OFFSET_REG_DMA3SAD_H, 0xd6
+ .set OFFSET_REG_DMA3DAD, 0xd8
+ .set OFFSET_REG_DMA3DAD_L, 0xd8
+ .set OFFSET_REG_DMA3DAD_H, 0xda
+ .set OFFSET_REG_DMA3CNT, 0xdc
+ .set OFFSET_REG_DMA3CNT_L, 0xdc
+ .set OFFSET_REG_DMA3CNT_H, 0xde
+
+ .set OFFSET_REG_TM0CNT, 0x100
+ .set OFFSET_REG_TM0CNT_L, 0x100
+ .set OFFSET_REG_TM0CNT_H, 0x102
+ .set OFFSET_REG_TM1CNT, 0x104
+ .set OFFSET_REG_TM1CNT_L, 0x104
+ .set OFFSET_REG_TM1CNT_H, 0x106
+ .set OFFSET_REG_TM2CNT, 0x108
+ .set OFFSET_REG_TM2CNT_L, 0x108
+ .set OFFSET_REG_TM2CNT_H, 0x10a
+ .set OFFSET_REG_TM3CNT, 0x10c
+ .set OFFSET_REG_TM3CNT_L, 0x10c
+ .set OFFSET_REG_TM3CNT_H, 0x10e
+
+ .set OFFSET_REG_SIOCNT, 0x128
+ .set OFFSET_REG_SIODATA8, 0x12a
+ .set OFFSET_REG_SIODATA32, 0x120
+ .set OFFSET_REG_SIOMLT_SEND, 0x12a
+ .set OFFSET_REG_SIOMLT_RECV, 0x120
+ .set OFFSET_REG_SIOMULTI0, 0x120
+ .set OFFSET_REG_SIOMULTI1, 0x122
+ .set OFFSET_REG_SIOMULTI2, 0x124
+ .set OFFSET_REG_SIOMULTI3, 0x126
+
+ .set OFFSET_REG_KEYINPUT, 0x130
+ .set OFFSET_REG_KEYCNT, 0x132
+
+ .set OFFSET_REG_RCNT, 0x134
+
+ .set OFFSET_REG_JOYCNT, 0x140
+ .set OFFSET_REG_JOYSTAT, 0x158
+ .set OFFSET_REG_JOY_RECV, 0x150
+ .set OFFSET_REG_JOY_RECV_L, 0x150
+ .set OFFSET_REG_JOY_RECV_H, 0x152
+ .set OFFSET_REG_JOY_TRANS, 0x154
+ .set OFFSET_REG_JOY_TRANS_L, 0x154
+ .set OFFSET_REG_JOY_TRANS_H, 0x156
+
+ .set OFFSET_REG_IME, 0x208
+ .set OFFSET_REG_IE, 0x200
+ .set OFFSET_REG_IF, 0x202
+
+ .set OFFSET_REG_WAITCNT, 0x204
+
+@ I/O register addresses
+ .set REG_DISPCNT, REG_BASE + OFFSET_REG_DISPCNT
+ .set REG_DISPSTAT, REG_BASE + OFFSET_REG_DISPSTAT
+ .set REG_VCOUNT, REG_BASE + OFFSET_REG_VCOUNT
+ .set REG_BG0CNT, REG_BASE + OFFSET_REG_BG0CNT
+ .set REG_BG1CNT, REG_BASE + OFFSET_REG_BG1CNT
+ .set REG_BG2CNT, REG_BASE + OFFSET_REG_BG2CNT
+ .set REG_BG3CNT, REG_BASE + OFFSET_REG_BG3CNT
+ .set REG_BG0HOFS, REG_BASE + OFFSET_REG_BG0HOFS
+ .set REG_BG0VOFS, REG_BASE + OFFSET_REG_BG0VOFS
+ .set REG_BG1HOFS, REG_BASE + OFFSET_REG_BG1HOFS
+ .set REG_BG1VOFS, REG_BASE + OFFSET_REG_BG1VOFS
+ .set REG_BG2HOFS, REG_BASE + OFFSET_REG_BG2HOFS
+ .set REG_BG2VOFS, REG_BASE + OFFSET_REG_BG2VOFS
+ .set REG_BG3HOFS, REG_BASE + OFFSET_REG_BG3HOFS
+ .set REG_BG3VOFS, REG_BASE + OFFSET_REG_BG3VOFS
+ .set REG_BG2PA, REG_BASE + OFFSET_REG_BG2PA
+ .set REG_BG2PB, REG_BASE + OFFSET_REG_BG2PB
+ .set REG_BG2PC, REG_BASE + OFFSET_REG_BG2PC
+ .set REG_BG2PD, REG_BASE + OFFSET_REG_BG2PD
+ .set REG_BG2X_L, REG_BASE + OFFSET_REG_BG2X_L
+ .set REG_BG2X_H, REG_BASE + OFFSET_REG_BG2X_H
+ .set REG_BG2Y_L, REG_BASE + OFFSET_REG_BG2Y_L
+ .set REG_BG2Y_H, REG_BASE + OFFSET_REG_BG2Y_H
+ .set REG_BG3PA, REG_BASE + OFFSET_REG_BG3PA
+ .set REG_BG3PB, REG_BASE + OFFSET_REG_BG3PB
+ .set REG_BG3PC, REG_BASE + OFFSET_REG_BG3PC
+ .set REG_BG3PD, REG_BASE + OFFSET_REG_BG3PD
+ .set REG_BG3X_L, REG_BASE + OFFSET_REG_BG3X_L
+ .set REG_BG3X_H, REG_BASE + OFFSET_REG_BG3X_H
+ .set REG_BG3Y_L, REG_BASE + OFFSET_REG_BG3Y_L
+ .set REG_BG3Y_H, REG_BASE + OFFSET_REG_BG3Y_H
+ .set REG_WIN0H, REG_BASE + OFFSET_REG_WIN0H
+ .set REG_WIN1H, REG_BASE + OFFSET_REG_WIN1H
+ .set REG_WIN0V, REG_BASE + OFFSET_REG_WIN0V
+ .set REG_WIN1V, REG_BASE + OFFSET_REG_WIN1V
+ .set REG_WININ, REG_BASE + OFFSET_REG_WININ
+ .set REG_WINOUT, REG_BASE + OFFSET_REG_WINOUT
+ .set REG_MOSAIC, REG_BASE + OFFSET_REG_MOSAIC
+ .set REG_BLDCNT, REG_BASE + OFFSET_REG_BLDCNT
+ .set REG_BLDALPHA, REG_BASE + OFFSET_REG_BLDALPHA
+ .set REG_BLDY, REG_BASE + OFFSET_REG_BLDY
+
+ .set REG_SOUND1CNT, REG_BASE + OFFSET_REG_SOUND1CNT
+ .set REG_SOUND1CNT_L, REG_BASE + OFFSET_REG_SOUND1CNT_L
+ .set REG_NR10, REG_BASE + OFFSET_REG_NR10
+ .set REG_SOUND1CNT_H, REG_BASE + OFFSET_REG_SOUND1CNT_H
+ .set REG_NR11, REG_BASE + OFFSET_REG_NR11
+ .set REG_NR12, REG_BASE + OFFSET_REG_NR12
+ .set REG_SOUND1CNT_X, REG_BASE + OFFSET_REG_SOUND1CNT_X
+ .set REG_NR13, REG_BASE + OFFSET_REG_NR13
+ .set REG_NR14, REG_BASE + OFFSET_REG_NR14
+ .set REG_SOUND2CNT, REG_BASE + OFFSET_REG_SOUND2CNT
+ .set REG_SOUND2CNT_L, REG_BASE + OFFSET_REG_SOUND2CNT_L
+ .set REG_NR21, REG_BASE + OFFSET_REG_NR21
+ .set REG_NR22, REG_BASE + OFFSET_REG_NR22
+ .set REG_SOUND2CNT_H, REG_BASE + OFFSET_REG_SOUND2CNT_H
+ .set REG_NR23, REG_BASE + OFFSET_REG_NR23
+ .set REG_NR24, REG_BASE + OFFSET_REG_NR24
+ .set REG_SOUND3CNT, REG_BASE + OFFSET_REG_SOUND3CNT
+ .set REG_SOUND3CNT_L, REG_BASE + OFFSET_REG_SOUND3CNT_L
+ .set REG_NR30, REG_BASE + OFFSET_REG_NR30
+ .set REG_SOUND3CNT_H, REG_BASE + OFFSET_REG_SOUND3CNT_H
+ .set REG_NR31, REG_BASE + OFFSET_REG_NR31
+ .set REG_NR32, REG_BASE + OFFSET_REG_NR32
+ .set REG_SOUND3CNT_X, REG_BASE + OFFSET_REG_SOUND3CNT_X
+ .set REG_NR33, REG_BASE + OFFSET_REG_NR33
+ .set REG_NR34, REG_BASE + OFFSET_REG_NR34
+ .set REG_SOUND4CNT, REG_BASE + OFFSET_REG_SOUND4CNT
+ .set REG_SOUND4CNT_L, REG_BASE + OFFSET_REG_SOUND4CNT_L
+ .set REG_NR41, REG_BASE + OFFSET_REG_NR41
+ .set REG_NR42, REG_BASE + OFFSET_REG_NR42
+ .set REG_SOUND4CNT_H, REG_BASE + OFFSET_REG_SOUND4CNT_H
+ .set REG_NR43, REG_BASE + OFFSET_REG_NR43
+ .set REG_NR44, REG_BASE + OFFSET_REG_NR44
+ .set REG_SOUNDCNT, REG_BASE + OFFSET_REG_SOUNDCNT
+ .set REG_SOUNDCNT_L, REG_BASE + OFFSET_REG_SOUNDCNT_L
+ .set REG_NR50, REG_BASE + OFFSET_REG_NR50
+ .set REG_NR51, REG_BASE + OFFSET_REG_NR51
+ .set REG_SOUNDCNT_H, REG_BASE + OFFSET_REG_SOUNDCNT_H
+ .set REG_SOUNDCNT_X, REG_BASE + OFFSET_REG_SOUNDCNT_X
+ .set REG_NR52, REG_BASE + OFFSET_REG_NR52
+ .set REG_SOUNDBIAS, REG_BASE + OFFSET_REG_SOUNDBIAS
+ .set REG_WAVE_RAM, REG_BASE + OFFSET_REG_WAVE_RAM
+ .set REG_WAVE_RAM0, REG_BASE + OFFSET_REG_WAVE_RAM0
+ .set REG_WAVE_RAM0_L, REG_BASE + OFFSET_REG_WAVE_RAM0_L
+ .set REG_WAVE_RAM0_H, REG_BASE + OFFSET_REG_WAVE_RAM0_H
+ .set REG_WAVE_RAM1, REG_BASE + OFFSET_REG_WAVE_RAM1
+ .set REG_WAVE_RAM1_L, REG_BASE + OFFSET_REG_WAVE_RAM1_L
+ .set REG_WAVE_RAM1_H, REG_BASE + OFFSET_REG_WAVE_RAM1_H
+ .set REG_WAVE_RAM2, REG_BASE + OFFSET_REG_WAVE_RAM2
+ .set REG_WAVE_RAM2_L, REG_BASE + OFFSET_REG_WAVE_RAM2_L
+ .set REG_WAVE_RAM2_H, REG_BASE + OFFSET_REG_WAVE_RAM2_H
+ .set REG_WAVE_RAM3, REG_BASE + OFFSET_REG_WAVE_RAM3
+ .set REG_WAVE_RAM3_L, REG_BASE + OFFSET_REG_WAVE_RAM3_L
+ .set REG_WAVE_RAM3_H, REG_BASE + OFFSET_REG_WAVE_RAM3_H
+ .set REG_FIFO, REG_BASE + OFFSET_REG_FIFO
+ .set REG_FIFO_A, REG_BASE + OFFSET_REG_FIFO_A
+ .set REG_FIFO_A_L, REG_BASE + OFFSET_REG_FIFO_A_L
+ .set REG_FIFO_A_H, REG_BASE + OFFSET_REG_FIFO_A_H
+ .set REG_FIFO_B, REG_BASE + OFFSET_REG_FIFO_B
+ .set REG_FIFO_B_L, REG_BASE + OFFSET_REG_FIFO_B_L
+ .set REG_FIFO_B_H, REG_BASE + OFFSET_REG_FIFO_B_H
+
+ .set REG_DMA0, REG_BASE + OFFSET_REG_DMA0
+ .set REG_DMA0SAD, REG_BASE + OFFSET_REG_DMA0SAD
+ .set REG_DMA0SAD_L, REG_BASE + OFFSET_REG_DMA0SAD_L
+ .set REG_DMA0SAD_H, REG_BASE + OFFSET_REG_DMA0SAD_H
+ .set REG_DMA0DAD, REG_BASE + OFFSET_REG_DMA0DAD
+ .set REG_DMA0DAD_L, REG_BASE + OFFSET_REG_DMA0DAD_L
+ .set REG_DMA0DAD_H, REG_BASE + OFFSET_REG_DMA0DAD_H
+ .set REG_DMA0CNT, REG_BASE + OFFSET_REG_DMA0CNT
+ .set REG_DMA0CNT_L, REG_BASE + OFFSET_REG_DMA0CNT_L
+ .set REG_DMA0CNT_H, REG_BASE + OFFSET_REG_DMA0CNT_H
+ .set REG_DMA1, REG_BASE + OFFSET_REG_DMA1
+ .set REG_DMA1SAD, REG_BASE + OFFSET_REG_DMA1SAD
+ .set REG_DMA1SAD_L, REG_BASE + OFFSET_REG_DMA1SAD_L
+ .set REG_DMA1SAD_H, REG_BASE + OFFSET_REG_DMA1SAD_H
+ .set REG_DMA1DAD, REG_BASE + OFFSET_REG_DMA1DAD
+ .set REG_DMA1DAD_L, REG_BASE + OFFSET_REG_DMA1DAD_L
+ .set REG_DMA1DAD_H, REG_BASE + OFFSET_REG_DMA1DAD_H
+ .set REG_DMA1CNT, REG_BASE + OFFSET_REG_DMA1CNT
+ .set REG_DMA1CNT_L, REG_BASE + OFFSET_REG_DMA1CNT_L
+ .set REG_DMA1CNT_H, REG_BASE + OFFSET_REG_DMA1CNT_H
+ .set REG_DMA2, REG_BASE + OFFSET_REG_DMA2
+ .set REG_DMA2SAD, REG_BASE + OFFSET_REG_DMA2SAD
+ .set REG_DMA2SAD_L, REG_BASE + OFFSET_REG_DMA2SAD_L
+ .set REG_DMA2SAD_H, REG_BASE + OFFSET_REG_DMA2SAD_H
+ .set REG_DMA2DAD, REG_BASE + OFFSET_REG_DMA2DAD
+ .set REG_DMA2DAD_L, REG_BASE + OFFSET_REG_DMA2DAD_L
+ .set REG_DMA2DAD_H, REG_BASE + OFFSET_REG_DMA2DAD_H
+ .set REG_DMA2CNT, REG_BASE + OFFSET_REG_DMA2CNT
+ .set REG_DMA2CNT_L, REG_BASE + OFFSET_REG_DMA2CNT_L
+ .set REG_DMA2CNT_H, REG_BASE + OFFSET_REG_DMA2CNT_H
+ .set REG_DMA3, REG_BASE + OFFSET_REG_DMA3
+ .set REG_DMA3SAD, REG_BASE + OFFSET_REG_DMA3SAD
+ .set REG_DMA3SAD_L, REG_BASE + OFFSET_REG_DMA3SAD_L
+ .set REG_DMA3SAD_H, REG_BASE + OFFSET_REG_DMA3SAD_H
+ .set REG_DMA3DAD, REG_BASE + OFFSET_REG_DMA3DAD
+ .set REG_DMA3DAD_L, REG_BASE + OFFSET_REG_DMA3DAD_L
+ .set REG_DMA3DAD_H, REG_BASE + OFFSET_REG_DMA3DAD_H
+ .set REG_DMA3CNT, REG_BASE + OFFSET_REG_DMA3CNT
+ .set REG_DMA3CNT_L, REG_BASE + OFFSET_REG_DMA3CNT_L
+ .set REG_DMA3CNT_H, REG_BASE + OFFSET_REG_DMA3CNT_H
+
+ .set REG_TM0CNT, REG_BASE + OFFSET_REG_TM0CNT
+ .set REG_TM0CNT_L, REG_BASE + OFFSET_REG_TM0CNT_L
+ .set REG_TM0CNT_H, REG_BASE + OFFSET_REG_TM0CNT_H
+ .set REG_TM1CNT, REG_BASE + OFFSET_REG_TM1CNT
+ .set REG_TM1CNT_L, REG_BASE + OFFSET_REG_TM1CNT_L
+ .set REG_TM1CNT_H, REG_BASE + OFFSET_REG_TM1CNT_H
+ .set REG_TM2CNT, REG_BASE + OFFSET_REG_TM2CNT
+ .set REG_TM2CNT_L, REG_BASE + OFFSET_REG_TM2CNT_L
+ .set REG_TM2CNT_H, REG_BASE + OFFSET_REG_TM2CNT_H
+ .set REG_TM3CNT, REG_BASE + OFFSET_REG_TM3CNT
+ .set REG_TM3CNT_L, REG_BASE + OFFSET_REG_TM3CNT_L
+ .set REG_TM3CNT_H, REG_BASE + OFFSET_REG_TM3CNT_H
+
+ .set REG_SIOCNT, REG_BASE + OFFSET_REG_SIOCNT
+ .set REG_SIODATA8, REG_BASE + OFFSET_REG_SIODATA8
+ .set REG_SIODATA32, REG_BASE + OFFSET_REG_SIODATA32
+ .set REG_SIOMLT_SEND, REG_BASE + OFFSET_REG_SIOMLT_SEND
+ .set REG_SIOMLT_RECV, REG_BASE + OFFSET_REG_SIOMLT_RECV
+ .set REG_SIOMULTI0, REG_BASE + OFFSET_REG_SIOMULTI0
+ .set REG_SIOMULTI1, REG_BASE + OFFSET_REG_SIOMULTI1
+ .set REG_SIOMULTI2, REG_BASE + OFFSET_REG_SIOMULTI2
+ .set REG_SIOMULTI3, REG_BASE + OFFSET_REG_SIOMULTI3
+
+ .set REG_KEYINPUT, REG_BASE + OFFSET_REG_KEYINPUT
+ .set REG_KEYCNT, REG_BASE + OFFSET_REG_KEYCNT
+
+ .set REG_RCNT, REG_BASE + OFFSET_REG_RCNT
+
+ .set REG_JOYCNT, REG_BASE + OFFSET_REG_JOYCNT
+ .set REG_JOYSTAT, REG_BASE + OFFSET_REG_JOYSTAT
+ .set REG_JOY_RECV, REG_BASE + OFFSET_REG_JOY_RECV
+ .set REG_JOY_RECV_L, REG_BASE + OFFSET_REG_JOY_RECV_L
+ .set REG_JOY_RECV_H, REG_BASE + OFFSET_REG_JOY_RECV_H
+ .set REG_JOY_TRANS, REG_BASE + OFFSET_REG_JOY_TRANS
+ .set REG_JOY_TRANS_L, REG_BASE + OFFSET_REG_JOY_TRANS_L
+ .set REG_JOY_TRANS_H, REG_BASE + OFFSET_REG_JOY_TRANS_H
+
+ .set REG_IME, REG_BASE + OFFSET_REG_IME
+ .set REG_IE, REG_BASE + OFFSET_REG_IE
+ .set REG_IF, REG_BASE + OFFSET_REG_IF
+
+ .set REG_WAITCNT, REG_BASE + OFFSET_REG_WAITCNT
+
+@ DMA register constants
+
+ .set DMA_DEST_INC, 0x0000
+ .set DMA_DEST_DEC, 0x0020
+ .set DMA_DEST_FIXED, 0x0040
+ .set DMA_DEST_RELOAD, 0x0060
+ .set DMA_SRC_INC, 0x0000
+ .set DMA_SRC_DEC, 0x0080
+ .set DMA_SRC_FIXED, 0x0100
+ .set DMA_REPEAT, 0x0200
+ .set DMA_16BIT, 0x0000
+ .set DMA_32BIT, 0x0400
+ .set DMA_DREQ_ON, 0x0800
+ .set DMA_START_NOW, 0x0000
+ .set DMA_START_VBLANK, 0x1000
+ .set DMA_START_HBLANK, 0x2000
+ .set DMA_START_SPECIAL, 0x3000
+ .set DMA_INTR_ENABLE, 0x4000
+ .set DMA_ENABLE, 0x8000
+
+@ OAM attribute constants
+
+ .set OAM_OBJ_NORMAL, 0x00000000
+ .set OAM_OBJ_BLEND, 0x00000400
+ .set OAM_OBJ_WINDOW, 0x00000800
+
+ .set OAM_AFFINE_NONE, 0x00000000
+ .set OAM_AFFINE_NORMAL_SIZE, 0x00000100
+ .set OAM_OBJ_DISABLED, 0x00000200
+ .set OAM_AFFINE_DOUBLE_SIZE, 0x00000300
+
+ .set OAM_MOSAIC_OFF, 0x00000000
+ .set OAM_MOSAIC_ON, 0x00001000
+
+ .set OAM_4BPP, 0x00000000
+ .set OAM_8BPP, 0x00002000
+
+ .set OAM_H_FLIP, 0x10000000
+ .set OAM_V_FLIP, 0x20000000
+
+ .set OAM_SQUARE, 0x00000000
+ .set OAM_H_RECTANGLE, 0x00004000
+ .set OAM_V_RECTANGLE, 0x00008000
+ .set OAM_SIZE_0, 0x00000000
+ .set OAM_SIZE_1, 0x40000000
+ .set OAM_SIZE_2, 0x80000000
+ .set OAM_SIZE_3, 0xc0000000
+
+ .set OAM_SIZE_8x8, OAM_SIZE_0 | OAM_SQUARE
+ .set OAM_SIZE_16x16, OAM_SIZE_1 | OAM_SQUARE
+ .set OAM_SIZE_32x32, OAM_SIZE_2 | OAM_SQUARE
+ .set OAM_SIZE_64x64, OAM_SIZE_3 | OAM_SQUARE
+
+ .set OAM_SIZE_16x8, OAM_SIZE_0 | OAM_H_RECTANGLE
+ .set OAM_SIZE_32x8, OAM_SIZE_1 | OAM_H_RECTANGLE
+ .set OAM_SIZE_32x16, OAM_SIZE_2 | OAM_H_RECTANGLE
+ .set OAM_SIZE_64x32, OAM_SIZE_3 | OAM_H_RECTANGLE
+
+ .set OAM_SIZE_8x16, OAM_SIZE_0 | OAM_V_RECTANGLE
+ .set OAM_SIZE_8x32, OAM_SIZE_1 | OAM_V_RECTANGLE
+ .set OAM_SIZE_16x32, OAM_SIZE_2 | OAM_V_RECTANGLE
+ .set OAM_SIZE_32x64, OAM_SIZE_3 | OAM_V_RECTANGLE
diff --git a/berry_fix/payload/graphics/debug_digits.png b/berry_fix/payload/graphics/debug_digits.png
new file mode 100644
index 000000000..edf0d36c9
--- /dev/null
+++ b/berry_fix/payload/graphics/debug_digits.png
Binary files differ
diff --git a/berry_fix/payload/graphics/msg_box.png b/berry_fix/payload/graphics/msg_box.png
new file mode 100644
index 000000000..00d1bbe37
--- /dev/null
+++ b/berry_fix/payload/graphics/msg_box.png
Binary files differ
diff --git a/berry_fix/payload/graphics/msg_box.tilemap b/berry_fix/payload/graphics/msg_box.tilemap
new file mode 100644
index 000000000..5b82401ba
--- /dev/null
+++ b/berry_fix/payload/graphics/msg_box.tilemap
Binary files differ
diff --git a/berry_fix/payload/include/constants/game_stat.h b/berry_fix/payload/include/constants/game_stat.h
new file mode 100644
index 000000000..47d703d85
--- /dev/null
+++ b/berry_fix/payload/include/constants/game_stat.h
@@ -0,0 +1,56 @@
+#ifndef GUARD_CONSTANTS_GAME_STAT_H
+#define GUARD_CONSTANTS_GAME_STAT_H
+
+#define GAME_STAT_SAVED_GAME 0
+#define GAME_STAT_FIRST_HOF_PLAY_TIME 1
+#define GAME_STAT_STARTED_TRENDS 2
+#define GAME_STAT_PLANTED_BERRIES 3
+#define GAME_STAT_TRADED_BIKES 4
+#define GAME_STAT_STEPS 5
+#define GAME_STAT_GOT_INTERVIEWED 6
+#define GAME_STAT_TOTAL_BATTLES 7
+#define GAME_STAT_WILD_BATTLES 8
+#define GAME_STAT_TRAINER_BATTLES 9
+#define GAME_STAT_ENTERED_HOF 10
+#define GAME_STAT_POKEMON_CAPTURES 11
+#define GAME_STAT_FISHING_CAPTURES 12
+#define GAME_STAT_HATCHED_EGGS 13
+#define GAME_STAT_EVOLVED_POKEMON 14
+#define GAME_STAT_USED_POKECENTER 15
+#define GAME_STAT_RESTED_AT_HOME 16
+#define GAME_STAT_ENTERED_SAFARI_ZONE 17
+#define GAME_STAT_USED_CUT 18
+#define GAME_STAT_USED_ROCK_SMASH 19
+#define GAME_STAT_MOVED_SECRET_BASE 20
+#define GAME_STAT_POKEMON_TRADES 21
+#define GAME_STAT_UNKNOWN_22 22
+#define GAME_STAT_LINK_BATTLE_WINS 23
+#define GAME_STAT_LINK_BATTLE_LOSSES 24
+#define GAME_STAT_LINK_BATTLE_DRAWS 25
+#define GAME_STAT_USED_SPLASH 26
+#define GAME_STAT_USED_STRUGGLE 27
+#define GAME_STAT_SLOT_JACKPOTS 28
+#define GAME_STAT_CONSECUTIVE_ROULETTE_WINS 29
+#define GAME_STAT_ENTERED_BATTLE_TOWER 30
+#define GAME_STAT_UNKNOWN_31 31
+#define GAME_STAT_BATTLE_TOWER_BEST_STREAK 32
+#define GAME_STAT_POKEBLOCKS 33
+#define GAME_STAT_POKEBLOCKS_WITH_FRIENDS 34
+#define GAME_STAT_WON_LINK_CONTEST 35
+#define GAME_STAT_ENTERED_CONTEST 36
+#define GAME_STAT_WON_CONTEST 37
+#define GAME_STAT_SHOPPED 38
+#define GAME_STAT_USED_ITEMFINDER 39
+#define GAME_STAT_GOT_RAINED_ON 40
+#define GAME_STAT_CHECKED_POKEDEX 41
+#define GAME_STAT_RECEIVED_RIBBONS 42
+#define GAME_STAT_JUMPED_DOWN_LEDGES 43
+#define GAME_STAT_WATCHED_TV 44
+#define GAME_STAT_CHECKED_CLOCK 45
+#define GAME_STAT_WON_POKEMON_LOTTERY 46
+#define GAME_STAT_USED_DAYCARE 47
+#define GAME_STAT_RODE_CABLE_CAR 48
+#define GAME_STAT_ENTERED_HOT_SPRINGS 49
+#define NUM_GAME_STATS 50
+
+#endif // GUARD_CONSTANTS_GAME_STAT_H
diff --git a/berry_fix/payload/include/constants/vars.h b/berry_fix/payload/include/constants/vars.h
new file mode 100644
index 000000000..856aba069
--- /dev/null
+++ b/berry_fix/payload/include/constants/vars.h
@@ -0,0 +1,196 @@
+#ifndef GUARD_CONSTANTS_VARS_H
+#define GUARD_CONSTANTS_VARS_H
+
+#define VAR_0x3F20 0x3F20
+
+#define VARS_START 0x4000
+
+// temporary vars
+// The first 0x10 vars are are temporary--they are cleared every time a map is loaded.
+#define VAR_TEMP_0 0x4000
+#define VAR_TEMP_1 0x4001
+#define VAR_TEMP_2 0x4002
+#define VAR_TEMP_3 0x4003
+#define VAR_TEMP_4 0x4004
+#define VAR_TEMP_5 0x4005
+#define VAR_TEMP_6 0x4006
+#define VAR_TEMP_7 0x4007
+#define VAR_TEMP_8 0x4008
+#define VAR_TEMP_9 0x4009
+#define VAR_TEMP_A 0x400A
+#define VAR_TEMP_B 0x400B
+#define VAR_TEMP_C 0x400C
+#define VAR_TEMP_D 0x400D
+#define VAR_TEMP_E 0x400E
+#define VAR_TEMP_F 0x400F
+
+// object gfx id vars
+// These 0x10 vars are used to dynamically control a event object's sprite.
+// For example, the rival's sprite id is dynamically set based on the player's gender.
+// See VarGetEventObjectGraphicsId().
+#define VAR_OBJ_GFX_ID_0 0x4010
+#define VAR_OBJ_GFX_ID_1 0x4011
+#define VAR_OBJ_GFX_ID_2 0x4012
+#define VAR_OBJ_GFX_ID_3 0x4013
+#define VAR_OBJ_GFX_ID_4 0x4014
+#define VAR_OBJ_GFX_ID_5 0x4015
+#define VAR_OBJ_GFX_ID_6 0x4016
+#define VAR_OBJ_GFX_ID_7 0x4017
+#define VAR_OBJ_GFX_ID_8 0x4018
+#define VAR_OBJ_GFX_ID_9 0x4019
+#define VAR_OBJ_GFX_ID_A 0x401A
+#define VAR_OBJ_GFX_ID_B 0x401B
+#define VAR_OBJ_GFX_ID_C 0x401C
+#define VAR_OBJ_GFX_ID_D 0x401D
+#define VAR_OBJ_GFX_ID_E 0x401E
+#define VAR_OBJ_GFX_ID_F 0x401F
+
+// general purpose vars
+#define VAR_RECYCLE_GOODS 0x4020
+#define VAR_REPEL_STEP_COUNT 0x4021
+#define VAR_ICE_STEP_COUNT 0x4022
+#define VAR_STARTER_MON 0x4023 // 0=Treecko, 1=Torchic, 2=Mudkip
+#define VAR_MIRAGE_RND_H 0x4024
+#define VAR_MIRAGE_RND_L 0x4025
+#define VAR_SECRET_BASE_MAP 0x4026
+#define VAR_CYCLING_ROAD_RECORD_COLLISIONS 0x4027
+#define VAR_CYCLING_ROAD_RECORD_TIME_L 0x4028
+#define VAR_CYCLING_ROAD_RECORD_TIME_H 0x4029
+#define VAR_HAPPINESS_STEP_COUNTER 0x402A
+#define VAR_POISON_STEP_COUNTER 0x402B
+#define VAR_RESET_RTC_ENABLE 0x402C
+#define VAR_ENIGMA_BERRY_AVAILABLE 0x402D
+
+#define VAR_DAYS 0x4040
+#define VAR_FANCLUB_UNKNOWN_1 0x4041 // TODO: document these two fanclub vars
+#define VAR_FANCLUB_UNKNOWN_2 0x4042
+#define VAR_DEPT_STORE_FLOOR 0x4043
+#define VAR_TRICK_HOUSE_ROOMS_COMPLETED 0x4044
+#define VAR_LOTTERY_PRIZE 0x4045
+#define VAR_NATIONAL_DEX 0x4046
+#define VAR_SHROOMISH_SIZE_RECORD 0x4047
+#define VAR_ASH_GATHER_COUNT 0x4048
+#define VAR_BIRCH_STATE 0x4049
+#define VAR_CRUISE_STEP_COUNT 0x404A
+#define VAR_LOTTERY_RND_L 0x404B
+#define VAR_LOTTERY_RND_H 0x404C
+
+#define VAR_BARBOACH_SIZE_RECORD 0x404F
+#define VAR_LITTLEROOT_STATE 0x4050
+#define VAR_ROUTE102_ACCESSIBLE 0x4051
+
+#define VAR_LAVARIDGE_RIVAL_STATE 0x4053
+#define VAR_CURRENT_SECRET_BASE 0x4054
+
+#define VAR_PETALBURG_STATE 0x4057
+#define VAR_SLATEPORT_STATE 0x4058
+
+#define VAR_RUSTBORO_STATE 0x405A
+
+#define VAR_SOOTOPOLIS_STATE 0x405E
+
+#define VAR_ROUTE101_STATE 0x4060
+
+#define VAR_ROUTE103_STATE 0x4062
+
+#define VAR_ROUTE110_STATE 0x4069
+
+#define VAR_ROUTE116_STATE 0x406F
+
+#define VAR_ROUTE118_STATE 0x4071
+#define VAR_ROUTE119_STATE 0x4072
+
+#define VAR_ROUTE121_STATE 0x4074
+#define VAR_ROUTE128_STATE 0x407B
+
+#define VAR_LITTLEROOT_HOUSES_STATE 0x4082 // TODO: needs more investigation
+
+#define VAR_BIRCH_LAB_STATE 0x4084
+#define VAR_PETALBURG_GYM_STATE 0x4085
+#define VAR_LINK_CONTEST_ROOM_STATE 0x4086
+#define VAR_CABLE_CLUB_STATE 0x4087
+#define VAR_CONTEST_LOCATION 0x4088
+#define VAR_0x4089 0x4089 // TODO: related to decorations
+#define VAR_CONTEST_PRIZE_PICKUP 0x408A
+
+#define VAR_LITTLEROOT_HOUSES_STATE_2 0x408C // TODO: needs more investigation
+#define VAR_LITTLEROOT_RIVAL_STATE 0x408D
+#define VAR_BOARD_BRINEY_BOAT_ROUTE104_STATE 0x408E
+#define VAR_DEVON_CORP_3F_STATE 0x408F
+#define VAR_BRINEY_HOUSE_STATE 0x4090
+
+#define VAR_LITTLEROOT_INTRO_STATE 0x4092
+#define VAR_MAUVILLE_GYM_STATE 0x4093
+#define VAR_LILYCOVE_MUSEUM_2F_STATE 0x4094
+#define VAR_LILYCOVE_FAN_CLUB_STATE 0x4095
+#define VAR_BRINEY_LOCATION 0x4096
+#define VAR_0x4097 0x4097 // TODO: related to creating new secret base
+#define VAR_PETALBURG_WOODS_STATE 0x4098
+#define VAR_LILYCOVE_CONTEST_LOBBY_STATE 0x4099
+#define VAR_RUSTURF_TUNNEL_STATE 0x409a
+#define VAR_CAVE_OF_ORIGIN_B4F_STATE 0x409B
+#define VAR_ELITE_4_STATE 0x409C
+
+#define VAR_SLATEPORT_HARBOR_STATE 0x40A0
+
+#define VAR_SEAFLOOR_CAVERN_STATE 0x40A2
+#define VAR_CABLE_CAR_STATION_STATE 0x40A3
+#define VAR_SAFARI_ZONE_STATE 0x40A4
+#define VAR_TRICK_HOUSE_ENTRANCE_STATE 0x40A5
+#define VAR_TRICK_HOUSE_ENTRANCE_STATE_2 0x40A6
+#define VAR_TRICK_HOUSE_ENTRANCE_STATE_3 0x40A7
+
+#define VAR_CYCLING_CHALLENGE_STATE 0x40A9
+#define VAR_SLATEPORT_MUSEUM_1F_STATE 0x40AA
+#define VAR_TRICK_HOUSE_PUZZLE_1_STATE 0x40AB
+#define VAR_TRICK_HOUSE_PUZZLE_2_STATE 0x40AC
+#define VAR_TRICK_HOUSE_PUZZLE_3_STATE 0x40AD
+#define VAR_TRICK_HOUSE_PUZZLE_4_STATE 0x40AE
+#define VAR_TRICK_HOUSE_PUZZLE_5_STATE 0x40AF
+#define VAR_TRICK_HOUSE_PUZZLE_6_STATE 0x40B0
+#define VAR_TRICK_HOUSE_PUZZLE_7_STATE 0x40B1
+#define VAR_TRICK_HOUSE_PUZZLE_8_STATE 0x40B2
+#define VAR_WEATHER_INSTITUTE_STATE 0x40B3
+#define VAR_PORTHOLE_STATE 0x40B4
+#define VAR_TRICK_HOUSE_STATE 0x40B5 // TODO: needs some further investigation
+#define VAR_TRICK_HOUSE_PUZZLE_7_STATE_2 0x40B6
+#define VAR_SLATEPORT_FAN_CLUB_STATE 0x40B7
+
+#define VAR_MT_PYRE_STATE 0x40B9
+#define VAR_NEW_MAUVILLE_STATE 0x40BA
+
+#define VAR_BRAVO_TRAINER_BATTLE_TOWER_ON 0x40BC
+#define VAR_JAGGED_PASS_ASH_WEATHER 0x40BD
+#define VAR_GLASS_WORKSHOP_STATE 0x40BE
+#define VAR_METEOR_FALLS_STATE 0x40BF
+#define VAR_GAME_CORNER_STATE 0x40C0
+#define VAR_TRICK_HOUSE_PRIZE_PICKUP 0x40C1
+#define VAR_PACIFIDLOG_TM_RECEIVED_DAY 0x40C2
+#define VAR_VICTORY_ROAD_1F_STATE 0x40C3
+#define VAR_FOSSIL_RESURRECTION_STATE 0x40C4
+#define VAR_WHICH_FOSSIL_REVIVED 0x40C5
+#define VAR_STEVENS_HOUSE_STATE 0x40C6
+#define VAR_OLDALE_STATE 0x40C7
+
+// special vars
+// They are commonly used as parameters to commands, or return values from commands.
+#define VAR_SPECIAL_0 0x8000
+#define VAR_SPECIAL_1 0x8001
+#define VAR_SPECIAL_2 0x8002
+#define VAR_SPECIAL_3 0x8003
+#define VAR_SPECIAL_4 0x8004
+#define VAR_SPECIAL_5 0x8005
+#define VAR_SPECIAL_6 0x8006
+#define VAR_SPECIAL_7 0x8007
+#define VAR_SPECIAL_8 0x8008
+#define VAR_SPECIAL_9 0x8009
+#define VAR_SPECIAL_A 0x800A
+#define VAR_SPECIAL_B 0x800B
+#define FACING 0x800C
+#define RESULT 0x800D
+#define ITEM_ID 0x800E
+#define LAST_TALKED 0x800F
+#define CONTEST_RANK 0x8010
+#define CONTEST_CATEGORY 0x8011
+
+#endif // GUARD_CONSTANTS_VARS_H
diff --git a/berry_fix/payload/include/flash.h b/berry_fix/payload/include/flash.h
new file mode 100644
index 000000000..26de88216
--- /dev/null
+++ b/berry_fix/payload/include/flash.h
@@ -0,0 +1,55 @@
+#ifndef GUARD_FLASH_H
+#define GUARD_FLASH_H
+
+#include <gba/gba.h>
+
+enum
+{
+ SECTOR_DAMAGED,
+ SECTOR_OK,
+ SECTOR_CHECK, // unused
+};
+
+enum MsgBoxUpdateMessage
+{
+ MSGBOX_WILL_NOW_UPDATE = 0,
+ MSGBOX_HAS_BEEN_UPDATED,
+ MSGBOX_UNABLE_TO_UPDATE,
+ MSGBOX_NO_NEED_TO_UPDATE,
+ MSGBOX_UPDATING
+};
+
+struct SaveSector
+{
+ u8 data[0xFF4];
+ u16 id;
+ u16 checksum;
+ u32 signature;
+ u32 counter;
+}; // size is 0x1000
+
+// headless save section?
+struct UnkSaveSection
+{
+ u8 data[0xFF4];
+ u32 signature;
+}; // size is 0xFF8
+
+#define eSaveSection ((struct SaveSector *)0x2020000)
+
+#define NUM_SECTORS_PER_SAVE_SLOT 14 // Number of sectors occupied by a save slot
+#define FILE_SIGNATURE 0x08012025
+
+#define SAVE_STATUS_EMPTY 0
+#define SAVE_STATUS_OK 1
+#define SAVE_STATUS_NO_FLASH 4
+#define SAVE_STATUS_ERROR 0xFF
+
+bool32 flash_maincb_ident_is_valid(void);
+bool8 flash_maincb_read_save(u32);
+void msg_load_gfx(void);
+void msg_display(enum MsgBoxUpdateMessage);
+bool32 flash_maincb_check_need_reset_pacifidlog_tm(void);
+bool32 flash_maincb_reset_pacifidlog_tm(void);
+
+#endif //GUARD_FLASH_H
diff --git a/berry_fix/payload/include/global.berry.h b/berry_fix/payload/include/global.berry.h
new file mode 100644
index 000000000..8f185c8f9
--- /dev/null
+++ b/berry_fix/payload/include/global.berry.h
@@ -0,0 +1,62 @@
+#ifndef GUARD_GLOBAL_BERRY_H
+#define GUARD_GLOBAL_BERRY_H
+
+struct Berry
+{
+ /*0x00*/ u8 name[7];
+ /*0x07*/ u8 firmness;
+ /*0x08*/ u16 size;
+ /*0x0A*/ u8 maxYield;
+ /*0x0B*/ u8 minYield;
+ /*0x0C*/ const u8 *description1;
+ /*0x10*/ const u8 *description2;
+ /*0x14*/ u8 stageDuration;
+ /*0x15*/ u8 spicy;
+ /*0x16*/ u8 dry;
+ /*0x17*/ u8 sweet;
+ /*0x18*/ u8 bitter;
+ /*0x19*/ u8 sour;
+ /*0x1A*/ u8 smoothness;
+};
+
+struct EnigmaBerry
+{
+ /*0x000*/ struct Berry berry;
+ /*0x01B*/ u8 pic[(6 * 6) * TILE_SIZE_4BPP];
+ /*0x49C*/ u16 palette[16];
+ /*0x4BC*/ u8 description1[45];
+ /*0x4E9*/ u8 description2[45];
+ /*0x516*/ u8 itemEffect[18];
+ /*0x528*/ u8 holdEffect;
+ /*0x529*/ u8 holdEffectParam;
+ /*0x52C*/ u32 checksum;
+};
+
+struct BattleEnigmaBerry
+{
+ /*0x00*/ u8 name[7];
+ /*0x07*/ u8 holdEffect;
+ /*0x08*/ u8 itemEffect[18];
+ /*0x1A*/ u8 holdEffectParam;
+};
+
+struct BerryTree
+{
+ /*0x00*/ u8 berry;
+ /*0x01*/ u8 stage:7;
+ /*
+ A berry sparkle is a state that a berry tree
+ can be in after growing within the player's
+ viewport.
+ */
+ /*0x01*/ bool8 growthSparkle:1;
+ /*0x02*/ u16 minutesUntilNextStage;
+ /*0x04*/ u8 berryYield;
+ /*0x05*/ u8 regrowthCount:4;
+ /*0x05*/ u8 watered1:1;
+ /*0x05*/ u8 watered2:1;
+ /*0x05*/ u8 watered3:1;
+ /*0x05*/ u8 watered4:1;
+};
+
+#endif // GUARD_GLOBAL_BERRY_H
diff --git a/berry_fix/payload/include/global.fieldmap.h b/berry_fix/payload/include/global.fieldmap.h
new file mode 100644
index 000000000..81f805ee2
--- /dev/null
+++ b/berry_fix/payload/include/global.fieldmap.h
@@ -0,0 +1,317 @@
+#ifndef GUARD_GLOBAL_FIELDMAP_H
+#define GUARD_GLOBAL_FIELDMAP_H
+
+enum
+{
+ CONNECTION_SOUTH = 1,
+ CONNECTION_NORTH,
+ CONNECTION_WEST,
+ CONNECTION_EAST,
+ CONNECTION_DIVE,
+ CONNECTION_EMERGE
+};
+
+typedef void (*TilesetCB)(void);
+
+struct Tileset
+{
+ /*0x00*/ bool8 isCompressed;
+ /*0x01*/ bool8 isSecondary;
+ /*0x04*/ void *tiles;
+ /*0x08*/ void *palettes;
+ /*0x0c*/ void *metatiles;
+ /*0x10*/ void *metatileAttributes;
+ /*0x14*/ TilesetCB callback;
+};
+
+struct MapLayout
+{
+ /*0x00*/ s32 width;
+ /*0x04*/ s32 height;
+ /*0x08*/ u16 *border;
+ /*0x0c*/ u16 *map;
+ /*0x10*/ struct Tileset *primaryTileset;
+ /*0x14*/ struct Tileset *secondaryTileset;
+};
+
+struct BackupMapLayout
+{
+ s32 width;
+ s32 height;
+ u16 *map;
+};
+
+struct EventObjectTemplate
+{
+ /*0x00*/ u8 localId;
+ /*0x01*/ u8 graphicsId;
+ /*0x02*/ u8 unk2;
+ /*0x04*/ s16 x;
+ /*0x06*/ s16 y;
+ /*0x08*/ u8 elevation;
+ /*0x09*/ u8 movementType;
+ /*0x0A*/ u8 movementRangeX:4;
+ u8 movementRangeY:4;
+ /*0x0C*/ u16 trainerType;
+ /*0x0E*/ u16 trainerRange_berryTreeId;
+ /*0x10*/ u8 *script;
+ /*0x14*/ u16 flagId;
+};
+
+struct WarpEvent
+{
+ s16 x, y;
+ u8 elevation;
+ u8 warpId;
+ u8 mapNum;
+ u8 mapGroup;
+};
+
+struct CoordEvent
+{
+ s16 x, y;
+ u8 elevation;
+ u16 trigger;
+ u16 index;
+ u8 filler_A[0x2];
+ u8 *script;
+};
+
+struct BgEvent
+{
+ /*0x00*/u16 x;
+ /*0x02*/u16 y;
+ /*0x04*/u8 elevation;
+ /*0x05*/u8 kind;
+ /*0x08*/union { // carried over from diego's FR/LG work, seems to be the same struct
+ // in gen 3, "kind" (0x3 in BgEvent struct) determines the method to read the union.
+ u8 *script;
+
+ // hidden item type
+ struct {
+ u16 item;
+ u16 hiddenItemId; // flag offset to determine flag lookup
+ } hiddenItem;
+
+ // secret base type
+ u32 secretBaseId;
+
+ } bgUnion;
+};
+
+struct MapEvents
+{
+ u8 eventObjectCount;
+ u8 warpCount;
+ u8 coordEventCount;
+ u8 bgEventCount;
+
+ struct EventObjectTemplate *eventObjects;
+ struct WarpEvent *warps;
+ struct CoordEvent *coordEvents;
+ struct BgEvent *bgEvents;
+};
+
+struct MapConnection
+{
+ /*0x00*/ u8 direction;
+ /*0x01*/ u32 offset;
+ /*0x05*/ u8 mapGroup;
+ /*0x06*/ u8 mapNum;
+};
+
+struct MapConnections
+{
+ s32 count;
+ struct MapConnection *connections;
+};
+
+struct MapHeader
+{
+ /* 0x00 */ struct MapLayout *mapLayout;
+ /* 0x04 */ struct MapEvents *events;
+ /* 0x08 */ u8 *mapScripts;
+ /* 0x0C */ struct MapConnections *connections;
+ /* 0x10 */ u16 music;
+ /* 0x12 */ u16 mapLayoutId;
+ /* 0x14 */ u8 regionMapSectionId;
+ /* 0x15 */ u8 cave;
+ /* 0x16 */ u8 weather;
+ /* 0x17 */ u8 mapType;
+ /* 0x18 */ u8 filler_18;
+ /* 0x19 */ u8 escapeRope;
+ /* 0x1A */ u8 flags;
+ /* 0x1B */ u8 battleType;
+};
+
+struct EventObject
+{
+ /*0x00*/ u32 active:1;
+ u32 singleMovementActive:1;
+ u32 triggerGroundEffectsOnMove:1;
+ u32 triggerGroundEffectsOnStop:1;
+ u32 disableCoveringGroundEffects:1; // disables ground effects that cover parts of the object's sprite
+ u32 landingJump:1;
+ u32 heldMovementActive:1;
+ u32 heldMovementFinished:1;
+ /*0x01*/ u32 frozen:1;
+ u32 facingDirectionLocked:1;
+ u32 disableAnim:1; // used to disable forced movement sliding animations (like on ice)
+ u32 enableAnim:1;
+ u32 inanimate:1;
+ u32 invisible:1;
+ u32 offScreen:1;
+ u32 trackedByCamera:1; // only set for the player object
+ /*0x02*/ u32 isPlayer:1;
+ u32 hasReflection:1;
+ u32 inShortGrass:1;
+ u32 inShallowFlowingWater:1;
+ u32 inSandPile:1;
+ u32 inHotSprings:1;
+ u32 hasShadow:1;
+ u32 spriteAnimPausedBackup:1;
+ /*0x03*/ u32 spriteAffineAnimPausedBackup:1;
+ u32 disableJumpLandingGroundEffect:1;
+ u32 fixedPriority:1;
+ /*0x04*/ u8 spriteId;
+ /*0x05*/ u8 graphicsId;
+ /*0x06*/ u8 movementType;
+ /*0x07*/ u8 trainerType;
+ /*0x08*/ u8 localId;
+ /*0x09*/ u8 mapNum;
+ /*0x0A*/ u8 mapGroup;
+ /*0x0B*/ u8 currentElevation:4;
+ u8 previousElevation:4;
+ /*0x0C*/ struct Coords16 initialCoords;
+ /*0x10*/ struct Coords16 currentCoords;
+ /*0x14*/ struct Coords16 previousCoords;
+ /*0x18*/ u8 facingDirection:4;
+ /*0x18*/ u8 movementDirection:4;
+ /*0x19*/ union __attribute__((packed)) {
+ u8 as_byte;
+ struct __attribute__((packed)) {
+ u16 x:4;
+ u16 y:4;
+ } as_nybbles;
+ } range;
+ /*0x1A*/ u8 fieldEffectSpriteId;
+ /*0x1B*/ u8 warpArrowSpriteId;
+ /*0x1C*/ u8 movementActionId;
+ /*0x1D*/ u8 trainerRange_berryTreeId;
+ /*0x1E*/ u8 currentMetatileBehavior;
+ /*0x1F*/ u8 previousMetatileBehavior;
+ /*0x20*/ u8 previousMovementDirection;
+ /*0x21*/ u8 directionSequenceIndex;
+ /*0x22*/ u8 playerCopyableMovement; // used as an index to gCopyPlayerMovementFuncs for the "copy player" movement types
+ /*size = 0x24*/
+};
+
+struct EventObjectGraphicsInfo
+{
+ /*0x00*/ u16 tileTag;
+ /*0x02*/ u16 paletteTag;
+ /*0x04*/ u16 bridgeReflectionPaletteTag;
+ /*0x06*/ u16 size;
+ /*0x08*/ s16 width;
+ /*0x0A*/ s16 height;
+ /*0x0C*/ u8 paletteSlot:4;
+ u8 shadowSize:2;
+ u8 inanimate:1;
+ u8 disableReflectionPaletteLoad:1;
+ /*0x0D*/ u8 tracks;
+ /*0x10*/ const struct OamData *oam;
+ /*0x14*/ const struct SubspriteTable *subspriteTables;
+ /*0x18*/ const union AnimCmd *const *anims;
+ /*0x1C*/ const struct SpriteFrameImage *images;
+ /*0x20*/ const union AffineAnimCmd *const *affineAnims;
+};
+
+#define PLAYER_AVATAR_FLAG_ON_FOOT (1 << 0)
+#define PLAYER_AVATAR_FLAG_MACH_BIKE (1 << 1)
+#define PLAYER_AVATAR_FLAG_ACRO_BIKE (1 << 2)
+#define PLAYER_AVATAR_FLAG_SURFING (1 << 3)
+#define PLAYER_AVATAR_FLAG_UNDERWATER (1 << 4)
+#define PLAYER_AVATAR_FLAG_5 (1 << 5)
+#define PLAYER_AVATAR_FLAG_6 (1 << 6)
+#define PLAYER_AVATAR_FLAG_DASH (1 << 7)
+
+enum
+{
+ ACRO_BIKE_NORMAL,
+ ACRO_BIKE_TURNING,
+ ACRO_BIKE_WHEELIE_STANDING,
+ ACRO_BIKE_BUNNY_HOP,
+ ACRO_BIKE_WHEELIE_MOVING,
+ ACRO_BIKE_STATE5,
+ ACRO_BIKE_STATE6,
+};
+
+enum
+{
+ DIR_NONE,
+ DIR_SOUTH,
+ DIR_NORTH,
+ DIR_WEST,
+ DIR_EAST,
+ DIR_SOUTHWEST,
+ DIR_SOUTHEAST,
+ DIR_NORTHWEST,
+ DIR_NORTHEAST,
+};
+
+enum
+{
+ COLLISION_LEDGE_JUMP = 6
+};
+
+// player running states
+enum
+{
+ NOT_MOVING,
+ TURN_DIRECTION, // not the same as turning! turns your avatar without moving. also known as a turn frame in some circles
+ MOVING,
+};
+
+// player tile transition states
+enum
+{
+ T_NOT_MOVING,
+ T_TILE_TRANSITION,
+ T_TILE_CENTER, // player is on a frame in which they are centered on a tile during which the player either stops or keeps their momentum and keeps going, changing direction if necessary.
+};
+
+struct PlayerAvatar /* 0x202E858 */
+{
+ /*0x00*/ u8 flags;
+ /*0x01*/ u8 unk1; // used to be named bike, but its definitely not that. seems to be some transition flags
+ /*0x02*/ u8 runningState; // this is a static running state. 00 is not moving, 01 is turn direction, 02 is moving.
+ /*0x03*/ u8 tileTransitionState; // this is a transition running state: 00 is not moving, 01 is transition between tiles, 02 means you are on the frame in which you have centered on a tile but are about to keep moving, even if changing directions. 2 is also used for a ledge hop, since you are transitioning.
+ /*0x04*/ u8 spriteId;
+ /*0x05*/ u8 eventObjectId;
+ /*0x06*/ bool8 preventStep;
+ /*0x07*/ u8 gender;
+ /*0x08*/ u8 acroBikeState; // 00 is normal, 01 is turning, 02 is standing wheelie, 03 is hopping wheelie
+ /*0x09*/ u8 newDirBackup; // during bike movement, the new direction as opposed to player's direction is backed up here.
+ /*0x0A*/ u8 bikeFrameCounter; // on the mach bike, when this value is 1, the bike is moving but not accelerating yet for 1 tile. on the acro bike, this acts as a timer for acro bike.
+ /*0x0B*/ u8 bikeSpeed;
+ // acro bike only
+ /*0x0C*/ u32 directionHistory; // up/down/left/right history is stored in each nybble, but using the field directions and not the io inputs.
+ /*0x10*/ u32 abStartSelectHistory; // same as above but for A + B + start + select only
+ // these two are timer history arrays which [0] is the active timer for acro bike. every element is backed up to the next element upon update.
+ /*0x14*/ u8 dirTimerHistory[8];
+ /*0x1C*/ u8 abStartSelectTimerHistory[8];
+};
+
+struct Camera
+{
+ bool8 active:1;
+ s32 x;
+ s32 y;
+};
+
+extern struct EventObject gEventObjects[];
+extern u8 gSelectedEventObject;
+extern struct MapHeader gMapHeader;
+extern struct PlayerAvatar gPlayerAvatar;
+
+#endif // GUARD_GLOBAL_FIELDMAP_H
diff --git a/berry_fix/payload/include/global.h b/berry_fix/payload/include/global.h
new file mode 100644
index 000000000..ad83b544c
--- /dev/null
+++ b/berry_fix/payload/include/global.h
@@ -0,0 +1,875 @@
+#ifndef GUARD_GLOBAL_H
+#define GUARD_GLOBAL_H
+
+#include <gba/gba.h>
+
+// global.h from pokemon ruby
+
+// IDE support
+#if defined(__APPLE__) || defined(__CYGWIN__)
+#define _(x) x
+#define __(x) x
+#define INCBIN(x) {0}
+#define INCBIN_U8 INCBIN
+#define INCBIN_U16 INCBIN
+#define INCBIN_U32 INCBIN
+#define INCBIN_S8 INCBIN
+#define INCBIN_S16 INCBIN
+#define INCBIN_S32 INCBIN
+#endif
+
+// Prevent cross-jump optimization.
+#define BLOCK_CROSS_JUMP asm("");
+
+// to help in decompiling
+#define asm_comment(x) asm volatile("@ -- " x " -- ")
+
+#define asm_unified(x) asm(".syntax unified\n" x "\n.syntax divided\n")
+
+#define ARRAY_COUNT(array) (sizeof(array) / sizeof((array)[0]))
+
+
+#define POKEMON_SLOTS_NUMBER 412
+#define POKEMON_NAME_LENGTH 10
+#define OT_NAME_LENGTH 7
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#define max(a, b) ((a) >= (b) ? (a) : (b))
+
+// why does GF hate 2d arrays
+#define MULTI_DIM_ARR(x, dim, y) ((x) * dim + (y))
+
+// dim access enums
+enum
+{
+ B_8 = 1,
+ B_16 = 2,
+ B_32 = 4
+};
+
+// There are many quirks in the source code which have overarching behavioral differences from
+// a number of other files. For example, diploma.c seems to declare rodata before each use while
+// other files declare out of order and must be at the beginning. There are also a number of
+// macros which differ from one file to the next due to the method of obtaining the result, such
+// as these below. Because of this, there is a theory (Two Team Theory) that states that these
+// programming projects had more than 1 "programming team" which utilized different macros for
+// each of the files that were worked on.
+#define T1_READ_8(ptr) ((ptr)[0])
+#define T1_READ_16(ptr) ((ptr)[0] | ((ptr)[1] << 8))
+#define T1_READ_32(ptr) ((ptr)[0] | ((ptr)[1] << 8) | ((ptr)[2] << 16) | ((ptr)[3] << 24))
+#define T1_READ_PTR(ptr) (u8*) T1_READ_32(ptr)
+
+// T2_READ_8 is a duplicate to remain consistent with each group.
+#define T2_READ_8(ptr) ((ptr)[0])
+#define T2_READ_16(ptr) ((ptr)[0] + ((ptr)[1] << 8))
+#define T2_READ_32(ptr) ((ptr)[0] + ((ptr)[1] << 8) + ((ptr)[2] << 16) + ((ptr)[3] << 24))
+#define T2_READ_PTR(ptr) (void*) T2_READ_32(ptr)
+
+// Credits to Made (dolphin emoji)
+#define S16TOPOSFLOAT(val) \
+({ \
+ s16 v = (val); \
+ float f = (float)v; \
+ if(v < 0) f += 65536.0f; \
+ f; \
+})
+
+enum
+{
+ VERSION_SAPPHIRE = 1,
+ VERSION_RUBY = 2,
+ VERSION_EMERALD = 3,
+};
+
+enum LanguageId
+{
+ LANGUAGE_JAPANESE = 1,
+ LANGUAGE_ENGLISH = 2,
+ LANGUAGE_GERMAN = 5,
+};
+
+// capacities of various saveblock objects
+#define DAYCARE_MON_COUNT 2
+#define POKEBLOCKS_COUNT 40
+#define PARTY_SIZE 6
+#define EVENT_OBJECTS_COUNT 16
+#define BERRY_TREES_COUNT 128
+#define FLAGS_COUNT 288
+#define VARS_COUNT 256
+#define MAIL_COUNT 16
+#define SECRET_BASES_COUNT 20
+#define TV_SHOWS_COUNT 25
+#define POKE_NEWS_COUNT 16
+#define PC_ITEMS_COUNT 50
+#define BAG_ITEMS_COUNT 20
+#define BAG_KEYITEMS_COUNT 20
+#define BAG_POKEBALLS_COUNT 16
+#define BAG_TMHM_COUNT 64
+#define BAG_BERRIES_COUNT 46
+
+enum
+{
+ MALE,
+ FEMALE
+};
+
+enum
+{
+ OPTIONS_BUTTON_MODE_NORMAL,
+ OPTIONS_BUTTON_MODE_LR,
+ OPTIONS_BUTTON_MODE_L_EQUALS_A
+};
+
+enum
+{
+ OPTIONS_TEXT_SPEED_SLOW,
+ OPTIONS_TEXT_SPEED_MID,
+ OPTIONS_TEXT_SPEED_FAST
+};
+
+enum
+{
+ OPTIONS_SOUND_MONO,
+ OPTIONS_SOUND_STEREO
+};
+
+enum
+{
+ OPTIONS_BATTLE_STYLE_SHIFT,
+ OPTIONS_BATTLE_STYLE_SET
+};
+
+enum
+{
+ BAG_ITEMS = 1,
+ BAG_POKEBALLS,
+ BAG_TMsHMs,
+ BAG_BERRIES,
+ BAG_KEYITEMS
+};
+
+struct Coords16
+{
+ s16 x;
+ s16 y;
+};
+
+struct UCoords16
+{
+ u16 x;
+ u16 y;
+};
+
+struct SecretBaseRecord
+{
+ /*0x1A08*/ u8 secretBaseId;
+ /*0x1A09*/ u8 sbr_field_1_0:4;
+ /*0x1A09*/ u8 gender:1;
+ /*0x1A09*/ u8 sbr_field_1_5:1;
+ /*0x1A09*/ u8 sbr_field_1_6:2;
+ /*0x1A0A*/ u8 playerName[OT_NAME_LENGTH];
+ /*0x1A11*/ u8 trainerId[4]; // byte 0 is used for determining trainer class
+ /*0x1A16*/ u16 sbr_field_e;
+ /*0x1A18*/ u8 sbr_field_10;
+ /*0x1A19*/ u8 sbr_field_11;
+ /*0x1A1A*/ u8 decorations[16];
+ /*0x1A2A*/ u8 decorationPos[16];
+ /*0x1A3C*/ u32 partyPersonality[6];
+ /*0x1A54*/ u16 partyMoves[6 * 4];
+ /*0x1A84*/ u16 partySpecies[6];
+ /*0x1A90*/ u16 partyHeldItems[6];
+ /*0x1A9C*/ u8 partyLevels[6];
+ /*0x1AA2*/ u8 partyEVs[6];
+};
+
+#include "constants/game_stat.h"
+#include "global.fieldmap.h"
+#include "global.berry.h"
+#include "pokemon.h"
+
+struct WarpData
+{
+ s8 mapGroup;
+ s8 mapNum;
+ s8 warpId;
+ s16 x, y;
+};
+
+struct ItemSlot
+{
+ u16 itemId;
+ u16 quantity;
+};
+
+struct Pokeblock
+{
+ u8 color;
+ u8 spicy;
+ u8 dry;
+ u8 sweet;
+ u8 bitter;
+ u8 sour;
+ u8 feel;
+};
+
+struct Roamer
+{
+ /*0x00*/ u32 ivs;
+ /*0x04*/ u32 personality;
+ /*0x08*/ u16 species;
+ /*0x0A*/ u16 hp;
+ /*0x0C*/ u8 level;
+ /*0x0D*/ u8 status;
+ /*0x0E*/ u8 cool;
+ /*0x0F*/ u8 beauty;
+ /*0x10*/ u8 cute;
+ /*0x11*/ u8 smart;
+ /*0x12*/ u8 tough;
+ /*0x13*/ bool8 active;
+ /*0x14*/ u8 filler[0x8];
+};
+
+struct RamScriptData
+{
+ u8 magic;
+ u8 mapGroup;
+ u8 mapNum;
+ u8 objectId;
+ u8 script[995];
+};
+
+struct RamScript
+{
+ u32 checksum;
+ struct RamScriptData data;
+};
+
+struct EasyChatPair
+{
+ u16 unk0_0:7;
+ u16 unk0_7:7;
+ u16 unk1_6:1;
+ u16 unk2;
+ u16 words[2];
+}; /*size = 0x8*/
+
+struct TVShowCommon
+{
+ /*0x00*/ u8 kind;
+ /*0x01*/ bool8 active;
+ /*0x02*/ u8 pad02[20];
+ /*0x16*/ u16 var16[3];
+ /*0x1C*/ u8 srcTrainerId3Lo;
+ /*0x1D*/ u8 srcTrainerId3Hi;
+ /*0x1E*/ u8 srcTrainerId2Lo;
+ /*0x1F*/ u8 srcTrainerId2Hi;
+ /*0x20*/ u8 srcTrainerIdLo;
+ /*0x21*/ u8 srcTrainerIdHi;
+ /*0x22*/ u8 trainerIdLo;
+ /*0x23*/ u8 trainerIdHi;
+};
+
+struct TVShowFanClubLetter
+{
+ /*0x00*/ u8 kind;
+ /*0x01*/ bool8 active;
+ /*0x02*/ u16 species;
+ /*0x04*/ u16 pad04[6];
+ /*0x10*/ u8 playerName[8];
+ /*0x18*/ u8 language;
+};
+
+struct TVShowRecentHappenings
+{
+ /*0x00*/ u8 kind;
+ /*0x01*/ bool8 active;
+ /*0x02*/ u16 var02;
+ /*0x04*/ u16 var04[6];
+ /*0x10*/ u8 playerName[8];
+ /*0x18*/ u8 language;
+ /*0x19*/ u8 pad19[10];
+};
+
+struct TVShowFanclubOpinions
+{
+ /*0x00*/ u8 kind;
+ /*0x01*/ bool8 active;
+ /*0x02*/ u16 var02;
+ /*0x04*/ u8 var04A:4;
+ /*0x04*/ u8 var04B:4;
+ /*0x05*/ u8 playerName[8];
+ /*0x0D*/ u8 language;
+ /*0x0E*/ u8 var0E;
+ /*0x0F*/ u8 var0F;
+ /*0x10*/ u8 var10[8];
+ /*0x18*/ u16 var18[2];
+ /*0x1C*/ u16 var1C[4];
+};
+
+struct TVShowUnknownType04
+{
+ /*0x00*/ u8 kind;
+ /*0x01*/ bool8 active;
+ /*0x02*/ u8 pad02[4];
+ /*0x06*/ u16 var06;
+};
+
+struct TVShowNameRaterShow
+{
+ /*0x00*/ u8 kind;
+ /*0x01*/ bool8 active;
+ /*0x02*/ u16 species;
+ /*0x04*/ u8 pokemonName[11];
+ /*0x0F*/ u8 trainerName[11];
+ /*0x1A*/ u8 random;
+ /*0x1B*/ u8 random2;
+ /*0x1C*/ u16 var1C;
+ /*0x1E*/ u8 language;
+ /*0x1F*/ u8 pokemonNameLanguage;
+};
+
+struct TVShowBravoTrainerPokemonProfiles
+{
+ /*0x00*/ u8 kind;
+ /*0x01*/ bool8 active;
+ /*0x02*/ u16 species;
+ /*0x04*/ u16 var04[2];
+ /*0x08*/ u8 pokemonNickname[11];
+ /*0x13*/ u8 contestCategory:3;
+ /*0x13*/ u8 contestRank:2;
+ /*0x13*/ u8 contestResult:2;
+ /*0x13*/ u8 var13_7:1;
+ /*0x14*/ u16 var14;
+ /*0x16*/ u8 playerName[8];
+ /*0x1E*/ u8 language;
+ /*0x1F*/ u8 var1f;
+};
+
+struct TVShowBravoTrainerBattleTowerSpotlight
+{
+ /*0x00*/ u8 kind;
+ /*0x01*/ bool8 active;
+ /*0x02*/ u8 trainerName[8];
+ /*0x0A*/ u16 species;
+ /*0x0C*/ u8 enemyTrainerName[8];
+ /*0x14*/ u16 defeatedSpecies;
+ /*0x16*/ u16 var16;
+ /*0x18*/ u16 var18[1];
+ /*0x1A*/ u8 btLevel;
+ /*0x1B*/ u8 var1b;
+ /*0x1C*/ u8 var1c;
+ /*0x1D*/ u8 language;
+};
+
+struct TVShowPokemonToday
+{
+ /*0x00*/ u8 kind;
+ /*0x01*/ bool8 active;
+ /*0x02*/ u8 language;
+ /*0x03*/ u8 language2;
+ /*0x04*/ u8 nickname[11];
+ /*0x0F*/ u8 ball;
+ /*0x10*/ u16 species;
+ /*0x12*/ u8 var12;
+ /*0x13*/ u8 playerName[8];
+};
+
+struct TVShowSmartShopper
+{
+ /*0x00*/ u8 kind;
+ /*0x01*/ bool8 active;
+ /*0x02*/ u8 priceReduced;
+ /*0x03*/ u8 language;
+ /*0x04*/ u8 pad04[2];
+ /*0x06*/ u16 itemIds[3];
+ /*0x0C*/ u16 itemAmounts[3];
+ /*0x12*/ u8 shopLocation;
+ /*0x13*/ u8 playerName[8];
+};
+
+struct TVShowPokemonTodayFailed
+{
+ /*0x00*/ u8 kind;
+ /*0x01*/ bool8 active;
+ /*0x02*/ u8 language;
+ /*0x03*/ u8 pad03[9];
+ /*0x0c*/ u16 species;
+ /*0x0e*/ u16 species2;
+ /*0x10*/ u8 var10;
+ /*0x11*/ u8 var11;
+ /*0x12*/ u8 var12;
+ /*0x13*/ u8 playerName[8];
+};
+
+struct TVShowPokemonAngler
+{
+ /*0x00*/ u8 kind;
+ /*0x01*/ bool8 active;
+ /*0x02*/ u8 var02;
+ /*0x03*/ u8 var03;
+ /*0x04*/ u16 var04;
+ /*0x06*/ u8 language;
+ u8 pad07[12];
+ /*0x13*/ u8 playerName[8];
+};
+
+struct TVShowWorldOfMasters
+{
+ /*0x00*/ u8 kind;
+ /*0x01*/ bool8 active;
+ /*0x02*/ u16 var02;
+ /*0x04*/ u16 var04;
+ /*0x06*/ u16 var06;
+ /*0x08*/ u16 var08;
+ /*0x0a*/ u8 var0a;
+ /*0x0b*/ u8 language;
+ u8 pad0c[7];
+ /*0x13*/ u8 playerName[8];
+};
+
+struct TVShowMassOutbreak
+{
+ /*0x00*/ u8 kind;
+ /*0x01*/ bool8 active;
+ /*0x02*/ u8 var02;
+ /*0x03*/ u8 var03;
+ /*0x04*/ u16 moves[4];
+ /*0x0C*/ u16 species;
+ /*0x0E*/ u16 var0E;
+ /*0x10*/ u8 locationMapNum;
+ /*0x11*/ u8 locationMapGroup;
+ /*0x12*/ u8 var12;
+ /*0x13*/ u8 probability;
+ /*0x14*/ u8 level;
+ /*0x15*/ u8 var15;
+ /*0x16*/ u16 daysLeft;
+ /*0x18*/ u8 language;
+ u8 pad19[11];
+};
+
+typedef union TVShow
+{
+ struct TVShowCommon common;
+ struct TVShowFanClubLetter fanclubLetter;
+ struct TVShowRecentHappenings recentHappenings;
+ struct TVShowFanclubOpinions fanclubOpinions;
+ struct TVShowUnknownType04 unkShow04;
+ struct TVShowNameRaterShow nameRaterShow;
+ struct TVShowBravoTrainerPokemonProfiles bravoTrainer;
+ struct TVShowBravoTrainerBattleTowerSpotlight bravoTrainerTower;
+ struct TVShowPokemonToday pokemonToday;
+ struct TVShowSmartShopper smartshopperShow;
+ struct TVShowPokemonTodayFailed pokemonTodayFailed;
+ struct TVShowPokemonAngler pokemonAngler;
+ struct TVShowWorldOfMasters worldOfMasters;
+ struct TVShowMassOutbreak massOutbreak;
+} TVShow;
+
+struct MailStruct
+{
+ /*0x00*/ u16 words[9];
+ /*0x12*/ u8 playerName[8];
+ /*0x1A*/ u8 trainerId[4];
+ /*0x1E*/ u16 species;
+ /*0x20*/ u16 itemId;
+};
+
+
+// Mauville Pokemon Center men
+
+struct MauvilleManCommon
+{
+ u8 id;
+};
+
+struct MauvilleManBard
+{
+ /*0x00*/ u8 id;
+ /*0x02*/ u16 songLyrics[6];
+ /*0x0E*/ u16 temporaryLyrics[6];
+ /*0x1A*/ u8 playerName[8];
+ /*0x22*/ u8 filler_2DB6[0x3];
+ /*0x25*/ u8 playerTrainerId[4];
+ /*0x29*/ bool8 hasChangedSong;
+}; /*size = 0x2C*/
+
+struct MauvilleManHipster
+{
+ u8 id;
+ bool8 alreadySpoken;
+};
+
+struct MauvilleManTrader
+{
+ u8 id;
+ u8 unk1[4];
+ u8 unk5[4][11];
+ bool8 alreadyTraded;
+};
+
+struct MauvilleManStoryteller
+{
+ u8 id;
+ bool8 alreadyRecorded;
+ u8 filler2[2];
+ u8 gameStatIDs[4];
+ u8 trainerNames[4][7];
+ u8 statValues[4][4];
+};
+
+struct MauvilleManGiddy
+{
+ /*0x00*/ u8 id;
+ /*0x01*/ u8 taleCounter;
+ /*0x02*/ u8 questionNum;
+ /*0x04*/ u16 randomWords[10];
+ /*0x18*/ u8 questionList[12];
+}; /*size = 0x2C*/
+
+
+union MauvilleMan
+{
+ struct MauvilleManCommon common;
+ struct MauvilleManBard bard;
+ struct MauvilleManHipster hipster;
+ struct MauvilleManTrader trader;
+ struct MauvilleManStoryteller storyteller;
+ struct MauvilleManGiddy giddy;
+ u8 filler[0x40]; // needed to pad out the struct
+};
+
+struct PokeNews
+{
+ u8 kind;
+ u8 state;
+ u16 days;
+};
+
+struct GabbyAndTyData
+{
+ /*2b10*/ u16 mon1;
+ /*2b12*/ u16 mon2;
+ /*2b14*/ u16 lastMove;
+ /*2b16*/ u16 quote;
+ /*2b18*/ u8 mapnum;
+ /*2b19*/ u8 battleNum;
+ /*2b1a*/ u8 valA_0:1;
+ /*2b1a*/ u8 valA_1:1;
+ /*2b1a*/ u8 valA_2:1;
+ /*2b1a*/ u8 valA_3:1;
+ /*2b1a*/ u8 valA_4:1;
+ /*2b1a*/ u8 valA_5:3;
+ /*2b1b*/ u8 valB_0:1;
+ /*2b1b*/ u8 valB_1:1;
+ /*2b1b*/ u8 valB_2:1;
+ /*2b1b*/ u8 valB_3:1;
+ /*2b1b*/ u8 valB_4:1;
+ /*2b1b*/ u8 valB_5:3;
+};
+
+struct DayCareMail
+{
+ /*0x00*/ struct MailStruct message;
+ /*0x24*/ u8 names[19];
+};
+
+struct DayCareStepCountersEtc {
+ u32 steps[DAYCARE_MON_COUNT];
+ u16 pendingEggPersonality;
+ u8 eggCycleStepsRemaining;
+};
+
+struct RecordMixingDayCareMail
+{
+ struct DayCareMail mail[DAYCARE_MON_COUNT];
+ u32 numDaycareMons;
+ u16 itemsHeld[DAYCARE_MON_COUNT]; // marks whether or not each daycare mon is currently holding an item.
+};
+
+struct DayCareMisc
+{
+ struct DayCareMail mail[DAYCARE_MON_COUNT];
+ struct DayCareStepCountersEtc countersEtc;
+};
+
+struct DayCare {
+ struct BoxPokemon mons[DAYCARE_MON_COUNT];
+ struct DayCareMisc misc;
+};
+
+struct LinkBattleRecord
+{
+ u8 name[8];
+ u16 trainerId;
+ u16 wins;
+ u16 losses;
+ u16 draws;
+};
+
+struct RecordMixingGiftData
+{
+ u8 unk0;
+ u8 quantity;
+ u16 itemId;
+ u8 filler4[8];
+};
+
+struct RecordMixingGift
+{
+ int checksum;
+ struct RecordMixingGiftData data;
+};
+
+struct ContestWinner
+{
+ /*0x00*/ u32 personality; // personality
+ /*0x04*/ u32 otId; // otId
+ /*0x08*/ u16 species; // species
+ /*0x0A*/ u8 contestCategory;
+ /*0x0B*/ u8 nickname[11];
+ /*0x16*/ u8 trainerName[8];
+};
+
+// there should be enough flags for all 412 slots
+// each slot takes up 8 flags
+// if the value is not divisible by 8, we need to account for the reminder as well
+#define DEX_FLAGS_NO ((POKEMON_SLOTS_NUMBER / 8) + ((POKEMON_SLOTS_NUMBER % 8) ? 1 : 0))
+
+struct SaveBlock1 /* 0x02025734 */
+{
+ /*0x00*/ struct Coords16 pos;
+ /*0x04*/ struct WarpData location;
+ /*0x0C*/ struct WarpData warp1;
+ /*0x14*/ struct WarpData warp2;
+ /*0x1C*/ struct WarpData lastHealLocation;
+ /*0x24*/ struct WarpData warp4;
+ /*0x2C*/ u16 savedMusic;
+ /*0x2E*/ u8 weather;
+ /*0x2F*/ u8 weatherCycleStage;
+ /*0x30*/ u8 flashLevel; // flash level on current map, 0 being normal and 4 being the darkest
+ /*0x32*/ u16 mapLayoutId;
+ /*0x34*/ u16 mapView[0x100];
+ /*0x234*/ u8 playerPartyCount;
+ /*0x238*/ struct Pokemon playerParty[6];
+ /*0x490*/ u32 money;
+ /*0x494*/ u16 coins;
+ /*0x496*/ u16 registeredItem; // registered for use with SELECT button
+ /*0x498*/ struct ItemSlot pcItems[PC_ITEMS_COUNT];
+ /*0x560*/ struct ItemSlot bagPocket_Items[BAG_ITEMS_COUNT];
+ /*0x5B0*/ struct ItemSlot bagPocket_KeyItems[BAG_KEYITEMS_COUNT];
+ /*0x600*/ struct ItemSlot bagPocket_PokeBalls[BAG_POKEBALLS_COUNT];
+ /*0x640*/ struct ItemSlot bagPocket_TMHM[BAG_TMHM_COUNT];
+ /*0x740*/ struct ItemSlot bagPocket_Berries[BAG_BERRIES_COUNT];
+ /*0x7F8*/ struct Pokeblock pokeblocks[POKEBLOCKS_COUNT];
+ /*0x938*/ u8 dexSeen2[DEX_FLAGS_NO];
+ /*0x96C*/ u16 berryBlenderRecords[3];
+ /*0x972*/ u8 filler_972[0x6];
+ /*0x978*/ u16 trainerRematchStepCounter;
+ /*0x97A*/ u8 trainerRematches[100];
+ /*0x9E0*/ struct EventObject eventObjects[EVENT_OBJECTS_COUNT];
+ /*0xC20*/ struct EventObjectTemplate eventObjectTemplates[64];
+ /*0x1220*/ u8 flags[FLAGS_COUNT];
+ /*0x1340*/ u16 vars[VARS_COUNT];
+ /*0x1540*/ u32 gameStats[NUM_GAME_STATS];
+ /*0x1608*/ struct BerryTree berryTrees[BERRY_TREES_COUNT];
+ /*0x1A08*/ struct SecretBaseRecord secretBases[SECRET_BASES_COUNT];
+ /*0x2688*/ u8 playerRoomDecor[12];
+ /*0x2694*/ u8 playerRoomDecorPos[12];
+ /*0x26A0*/ u8 decorDesk[10];
+ /*0x26AA*/ u8 decorChair[10];
+ /*0x26B4*/ u8 decorPlant[10];
+ /*0x26BE*/ u8 decorOrnament[30];
+ /*0x26DC*/ u8 decorMat[30];
+ /*0x26FA*/ u8 decorPoster[10];
+ /*0x2704*/ u8 decorDoll[40];
+ /*0x272C*/ u8 decorCushion[10];
+ /*0x2736*/ u8 padding_2736[2];
+ /*0x2738*/ TVShow tvShows[TV_SHOWS_COUNT];
+ /*0x2ABC*/ struct PokeNews pokeNews[POKE_NEWS_COUNT];
+ /*0x2AFC*/ u16 outbreakPokemonSpecies;
+ /*0x2AFE*/ u8 outbreakLocationMapNum;
+ /*0x2AFF*/ u8 outbreakLocationMapGroup;
+ /*0x2B00*/ u8 outbreakPokemonLevel;
+ /*0x2B01*/ u8 outbreakUnk1;
+ /*0x2B02*/ u16 outbreakUnk2;
+ /*0x2B04*/ u16 outbreakPokemonMoves[4];
+ /*0x2B0C*/ u8 outbreakUnk4;
+ /*0x2B0D*/ u8 outbreakPokemonProbability;
+ /*0x2B0E*/ u16 outbreakUnk5;
+ /*0x2B10*/ struct GabbyAndTyData gabbyAndTyData;
+ /*0x2B1C*/ struct {
+ /*0x2B1C*/ u16 unk2B1C[6];
+ /*0x2B28*/ u16 unk2B28[6];
+ /*0x2B34*/ u16 unk2B34[6];
+ /*0x2B40*/ u16 unk2B40[6];
+ } easyChats;
+ /*0x2B4C*/ struct MailStruct mail[MAIL_COUNT];
+ /*0x2D8C*/ u8 unk2D8C[4]; // What is this? Apparently it's supposed to be 64 bytes in size.
+ /*0x2D90*/ u8 filler_2D90[0x4];
+ /*0x2D94*/ union MauvilleMan mauvilleMan;
+ /*0x2DD4*/ struct EasyChatPair easyChatPairs[5]; //Dewford trend [0] and some other stuff
+ /*0x2DFC*/ struct ContestWinner contestWinners[8];
+ /*0x2EFC*/ struct ContestWinner museumPortraits[5];
+ /*0x2F9C*/ struct DayCare daycare;
+ /*0x30B8*/ struct LinkBattleRecord linkBattleRecords[5];
+ struct {
+ /*0x3108*/ u8 unknown1[8];
+ /*0x3110*/ u8 giftRibbons[11];
+ /*0x311B*/ u8 unknown2[8];
+ /*0x3123*/ u32 currentPokeCoupons;
+ /*0x3127*/ u32 totalEarnedPokeCoupons;
+ /*0x312B*/ u8 unknown3[6];
+ /*0x3131*/ u8 receivedWishmakerJirachi;
+ /*0x3132*/ u8 unknown4[18];
+ } __attribute__((packed)) externalReservedData;
+ /*0x3144*/ struct Roamer roamer;
+ /*0x3160*/ struct EnigmaBerry enigmaBerry;
+ /*0x3690*/ struct RamScript ramScript;
+ /*0x3A7C*/ struct RecordMixingGift recordMixingGift;
+ /*0x3A8C*/ u8 dexSeen3[DEX_FLAGS_NO];
+};
+
+extern struct SaveBlock1 gSaveBlock1;
+
+struct Time
+{
+ /*0x00*/ s16 days;
+ /*0x02*/ s8 hours;
+ /*0x03*/ s8 minutes;
+ /*0x04*/ s8 seconds;
+};
+
+struct Pokedex
+{
+ /*0x00*/ u8 order;
+ /*0x01*/ u8 unknown1;
+ /*0x02*/ u8 nationalMagic; // must equal 0xDA in order to have National mode
+ /*0x03*/ u8 unknown2;
+ /*0x04*/ u32 unownPersonality; // set when you first see Unown
+ /*0x08*/ u32 spindaPersonality; // set when you first see Spinda
+ /*0x0C*/ u32 unknown3;
+ /*0x10*/ u8 owned[DEX_FLAGS_NO];
+ /*0x44*/ u8 seen[DEX_FLAGS_NO];
+};
+
+struct BattleTowerTrainer
+{
+ /*0x00*/ u8 trainerClass;
+ /*0x01*/ u8 name[8];
+ /*0x09*/ u8 teamFlags;
+ u8 filler0A[2];
+ /*0x0C*/ u16 greeting[6];
+};
+
+struct BattleTowerRecord // record mixing
+{
+ /*0x00*/ u8 battleTowerLevelType; // 0 = level 50, 1 = level 100
+ /*0x01*/ u8 trainerClass;
+ /*0x02*/ u16 winStreak;
+ /*0x04*/ u8 name[8];
+ /*0x0C*/ u8 trainerId[4];
+ /*0x10*/ u16 greeting[6];
+ /*0x1C*/ struct BattleTowerPokemon party[3];
+ /*0xA0*/ u32 checksum;
+};
+
+struct BattleTowerEReaderTrainer
+{
+ /*0x00*/ u8 unk0;
+ /*0x01*/ u8 trainerClass;
+ /*0x02*/ u16 winStreak;
+ /*0x04*/ u8 name[8];
+ /*0x0C*/ u8 trainerId[4];
+ /*0x10*/ u16 greeting[6];
+ /*0x1C*/ u16 farewellPlayerLost[6];
+ /*0x28*/ u16 farewellPlayerWon[6];
+ /*0x34*/ struct BattleTowerPokemon party[3];
+ /*0xB8*/ u32 checksum;
+};
+
+struct BattleTowerData
+{
+ /*0x0000, 0x00A8*/ struct BattleTowerRecord playerRecord;
+ /*0x00A4, 0x014C*/ struct BattleTowerRecord records[5]; // from record mixing
+ /*0x03D8, 0x0480*/ u16 firstMonSpecies; // species of the first pokemon in the player's battle tower party
+ /*0x03DA, 0x0482*/ u16 defeatedBySpecies; // species of the pokemon that defated the player
+ /*0x03DC, 0x0484*/ u8 defeatedByTrainerName[8];
+ /*0x03E4, 0x048C*/ u8 firstMonNickname[POKEMON_NAME_LENGTH]; // nickname of the first pokemon in the player's battle tower party
+ /*0x03F0, 0x0498*/ struct BattleTowerEReaderTrainer ereaderTrainer;
+ /*0x04AC, 0x0554*/ u8 battleTowerLevelType:1; // 0 = level 50; 1 = level 100
+ /*0x04AC, 0x0554*/ u8 unk_554:1;
+ /*0x04AD, 0x0555*/ u8 battleOutcome;
+ /*0x04AE, 0x0556*/ u8 var_4AE[2];
+ /*0x04B0, 0x0558*/ u16 curChallengeBattleNum[2]; // 1-based index of battle in the current challenge. (challenges consist of 7 battles)
+ /*0x04B4, 0x055C*/ u16 curStreakChallengesNum[2]; // 1-based index of the current challenge in the current streak.
+ /*0x04B8, 0x0560*/ u16 recordWinStreaks[2];
+ /*0x04BC, 0x0564*/ u8 battleTowerTrainerId; // index for gBattleTowerTrainers table
+ /*0x04BD, 0x0565*/ u8 selectedPartyMons[0x3]; // indices of the 3 selected player party mons.
+ /*0x04C0, 0x0568*/ u16 prizeItem;
+ /*0x04C2, 0x056A*/ u8 battledTrainerIds[6];
+ /*0x04C8, 0x0570*/ u16 totalBattleTowerWins;
+ /*0x04CA, 0x0572*/ u16 bestBattleTowerWinStreak;
+ /*0x04CC, 0x0574*/ u16 currentWinStreaks[2];
+ /*0x04D0, 0x0578*/ u8 lastStreakLevelType; // 0 = level 50, 1 = level 100. level type of the last streak. Used by tv to report the level mode.
+ /*0x04D1, 0x0579*/ u8 filler_4D1[0x317];
+};
+
+struct SaveBlock2 /* 0x02024EA4 */
+{
+ /*0x00*/ u8 playerName[8];
+ /*0x08*/ u8 playerGender; // MALE, FEMALE
+ /*0x09*/ u8 specialSaveWarp;
+ /*0x0A*/ u8 playerTrainerId[4];
+ /*0x0E*/ u16 playTimeHours;
+ /*0x10*/ u8 playTimeMinutes;
+ /*0x11*/ u8 playTimeSeconds;
+ /*0x12*/ u8 playTimeVBlanks;
+ /*0x13*/ u8 optionsButtonMode; // OPTIONS_BUTTON_MODE_[NORMAL/LR/L_EQUALS_A]
+ /*0x14*/ u16 optionsTextSpeed:3; // OPTIONS_TEXT_SPEED_[SLOW/MID/FAST]
+ u16 optionsWindowFrameType:5; // Specifies one of the 20 decorative borders for text boxes
+ u16 optionsSound:1; // OPTIONS_SOUND_[MONO/STEREO]
+ u16 optionsBattleStyle:1; // OPTIONS_BATTLE_STYLE_[SHIFT/SET]
+ u16 optionsBattleSceneOff:1; // whether battle animations are disabled
+ u16 regionMapZoom:1; // whether the map is zoomed in
+ /*0x18*/ struct Pokedex pokedex;
+ /*0x90*/ u8 filler_90[0x8];
+ /*0x98*/ struct Time localTimeOffset;
+ /*0xA0*/ struct Time lastBerryTreeUpdate;
+ /*0xA8*/ struct BattleTowerData battleTower;
+};
+
+struct MapPosition
+{
+ s16 x;
+ s16 y;
+ s8 height;
+};
+
+struct UnkStruct_8054FF8
+{
+ u8 a;
+ u8 b;
+ u8 c;
+ u8 d;
+ struct MapPosition sub;
+ u16 field_C;
+};
+
+// wasnt defined so I had to define it
+struct HallOfFame
+{
+ u8 filler[0x1F00];
+};
+
+extern struct SaveBlock2 gSaveBlock2;
+
+#define RomHeaderGameTitle ((const char *)0x080000A0)
+#define RomHeaderGameCode ((const char *)0x080000AC)
+#define RomHeaderMakerCode ((const char *)0x080000B0)
+#define RomHeaderMagic ((const u8 *) 0x080000B2)
+#define RomHeaderSoftwareVersion ((const u8 *) 0x080000BC)
+
+#define LocalTimeOffset ((struct Time *)0x02028098)
+#define LastBerryTreeUpdate ((struct Time *)0x020280A0)
+
+#endif //GUARD_GLOBAL_H
diff --git a/berry_fix/payload/include/main.h b/berry_fix/payload/include/main.h
new file mode 100644
index 000000000..8f7ef1a5a
--- /dev/null
+++ b/berry_fix/payload/include/main.h
@@ -0,0 +1,45 @@
+#ifndef GUARD_MAIN_H
+#define GUARD_MAIN_H
+
+#include <gba/gba.h>
+
+enum RomHeaderValidationResult
+{
+ SAPPHIRE_UPDATABLE = 2,
+ RUBY_UPDATABLE,
+ SAPPHIRE_NONEED,
+ RUBY_NONEED,
+ INVALID
+};
+
+enum MainCallbackState
+{
+ MAINCB_INIT = 0,
+ MAINCB_CHECK_RTC,
+ MAINCB_CHECK_FLASH,
+ MAINCB_READ_SAVE,
+ MAINCB_CHECK_TIME,
+ MAINCB_FIX_DATE,
+ MAINCB_NO_NEED_TO_FIX,
+ MAINCB_YEAR_MAKES_NO_SENSE,
+ MAINCB_FINISHED,
+ MAINCB_CHECK_PACIFIDLOG_TM,
+ MAINCB_FIX_PACIFIDLOG_TM,
+ MAINCB_ERROR
+};
+
+extern IntrFunc gIntrTable[];
+extern u16 gHeldKeys;
+extern u16 gNewKeys;
+extern u8 gIntrVector[];
+extern u32 gUpdateSuccessful;
+extern u32 gUnknown_3001194;
+extern u32 gUnknown_30011A0[];
+extern u32 gMainCallbackState;
+extern u32 gGameVersion;
+
+extern u8 gSharedMem[0x8000];
+
+extern const IntrFunc gIntrFuncPointers[];
+
+#endif //GUARD_MAIN_H
diff --git a/berry_fix/payload/include/pokemon.h b/berry_fix/payload/include/pokemon.h
new file mode 100644
index 000000000..d3a14ffff
--- /dev/null
+++ b/berry_fix/payload/include/pokemon.h
@@ -0,0 +1,154 @@
+#ifndef GUARD_POKEMON_H
+#define GUARD_POKEMON_H
+
+struct PokemonSubstruct0
+{
+ u16 species;
+ u16 heldItem;
+ u32 experience;
+ u8 ppBonuses;
+ u8 friendship;
+};
+
+struct PokemonSubstruct1
+{
+ u16 moves[4];
+ u8 pp[4];
+};
+
+struct PokemonSubstruct2
+{
+ u8 hpEV;
+ u8 attackEV;
+ u8 defenseEV;
+ u8 speedEV;
+ u8 spAttackEV;
+ u8 spDefenseEV;
+ u8 cool;
+ u8 beauty;
+ u8 cute;
+ u8 smart;
+ u8 tough;
+ u8 sheen;
+};
+
+struct PokemonSubstruct3
+{
+ /*0x00*/ u8 pokerus;
+ /*0x01*/ u8 metLocation;
+
+ /*0x02*/ u16 metLevel:7;
+ /*0x02*/ u16 metGame:4;
+ /*0x03*/ u16 pokeball:4;
+ /*0x03*/ u16 otGender:1;
+
+ /*0x04*/ u32 hpIV:5;
+ /*0x04*/ u32 attackIV:5;
+ /*0x05*/ u32 defenseIV:5;
+ /*0x05*/ u32 speedIV:5;
+ /*0x05*/ u32 spAttackIV:5;
+ /*0x06*/ u32 spDefenseIV:5;
+ /*0x07*/ u32 isEgg:1;
+ /*0x07*/ u32 altAbility:1;
+
+ /*0x08*/ u32 coolRibbon:3;
+ /*0x08*/ u32 beautyRibbon:3;
+ /*0x08*/ u32 cuteRibbon:3;
+ /*0x09*/ u32 smartRibbon:3;
+ /*0x09*/ u32 toughRibbon:3;
+ /*0x09*/ u32 championRibbon:1;
+ /*0x0A*/ u32 winningRibbon:1;
+ /*0x0A*/ u32 victoryRibbon:1;
+ /*0x0A*/ u32 artistRibbon:1;
+ /*0x0A*/ u32 effortRibbon:1;
+ /*0x0A*/ u32 giftRibbon1:1;
+ /*0x0A*/ u32 giftRibbon2:1;
+ /*0x0A*/ u32 giftRibbon3:1;
+ /*0x0A*/ u32 giftRibbon4:1;
+ /*0x0B*/ u32 giftRibbon5:1;
+ /*0x0B*/ u32 giftRibbon6:1;
+ /*0x0B*/ u32 giftRibbon7:1;
+ /*0x0B*/ u32 fatefulEncounter:5; // unused in Ruby/Sapphire, but the high bit must be set for Mew/Deoxys to obey in FR/LG/Emerald
+};
+
+union PokemonSubstruct
+{
+ struct PokemonSubstruct0 type0;
+ struct PokemonSubstruct1 type1;
+ struct PokemonSubstruct2 type2;
+ struct PokemonSubstruct3 type3;
+ u16 raw[6];
+};
+
+struct BoxPokemon
+{
+ /*0x00*/ u32 personality;
+ /*0x04*/ u32 otId;
+ /*0x08*/ u8 nickname[POKEMON_NAME_LENGTH];
+ /*0x12*/ u8 language;
+ /*0x13*/ u8 isBadEgg:1;
+ u8 hasSpecies:1;
+ u8 isEgg:1;
+ /*0x14*/ u8 otName[OT_NAME_LENGTH];
+ /*0x1B*/ u8 markings;
+ /*0x1C*/ u16 checksum;
+ /*0x1E*/ u16 unknown;
+
+ union
+ {
+ u32 raw[12];
+ union PokemonSubstruct substructs[4];
+ } secure;
+}; /*size = 0x50*/
+
+struct Pokemon
+{
+ /*0x00*/ struct BoxPokemon box;
+ /*0x50*/ u32 status;
+ /*0x54*/ u8 level;
+ /*0x55*/ u8 mail;
+ /*0x56*/ u16 hp;
+ /*0x58*/ u16 maxHP;
+ /*0x5A*/ u16 attack;
+ /*0x5C*/ u16 defense;
+ /*0x5E*/ u16 speed;
+ /*0x60*/ u16 spAttack;
+ /*0x62*/ u16 spDefense;
+};
+
+struct BattleTowerPokemon
+{
+ /*0x00*/u16 species;
+ /*0x02*/u16 heldItem;
+ /*0x04*/u16 moves[4];
+ /*0x0C*/u8 level;
+ /*0x0D*/u8 ppBonuses;
+ /*0x0E*/u8 hpEV;
+ /*0x0F*/u8 attackEV;
+ /*0x10*/u8 defenseEV;
+ /*0x11*/u8 speedEV;
+ /*0x12*/u8 spAttackEV;
+ /*0x13*/u8 spDefenseEV;
+ /*0x14*/u32 otId;
+ /*0x18*/u32 hpIV:5;
+ /*0x18*/u32 attackIV:5;
+ /*0x19*/u32 defenseIV:5;
+ /*0x19*/u32 speedIV:5;
+ /*0x1A*/u32 spAttackIV:5;
+ /*0x1A*/u32 spDefenseIV:5;
+ /*0x1B*/u32 gap:1;
+ /*0x1B*/u32 altAbility:1;
+ /*0x1C*/u32 personality;
+ /*0x20*/u8 nickname[POKEMON_NAME_LENGTH + 1];
+ /*0x2B*/u8 friendship;
+};
+
+struct PokemonStorage
+{
+ /*0x0000*/ u8 currentBox;
+ /*0x0004*/ struct BoxPokemon boxes[14][30];
+ /*0x8344*/ u8 boxNames[14][9];
+ /*0x83c2*/ u8 wallpaper[14];
+};
+
+#endif // GUARD_POKEMON_H
diff --git a/berry_fix/payload/include/rtc.h b/berry_fix/payload/include/rtc.h
new file mode 100644
index 000000000..64a1f2295
--- /dev/null
+++ b/berry_fix/payload/include/rtc.h
@@ -0,0 +1,15 @@
+#ifndef GUARD_RTC_H
+#define GUARD_RTC_H
+
+#include <gba/gba.h>
+#include <siirtc.h>
+#include "global.h"
+
+extern struct Time gTimeSinceBerryUpdate;
+extern struct Time gRtcUTCTime;
+
+bool32 rtc_maincb_is_rtc_working(void);
+bool32 rtc_maincb_is_time_since_last_berry_update_positive(u8 *);
+void rtc_maincb_fix_date(void);
+
+#endif //GUARD_RTC_H
diff --git a/berry_fix/payload/ld_script.sed b/berry_fix/payload/ld_script.sed
new file mode 100644
index 000000000..b91542b6f
--- /dev/null
+++ b/berry_fix/payload/ld_script.sed
@@ -0,0 +1,14 @@
+/<EWRAM>/ {
+ r sym_ewram.ld
+ d
+}
+
+/<BSS>/ {
+ r sym_bss.ld
+ d
+}
+
+/<COMMON>/ {
+ r sym_common.ld
+ d
+}
diff --git a/berry_fix/payload/ld_script.txt b/berry_fix/payload/ld_script.txt
new file mode 100644
index 000000000..a70ecac09
--- /dev/null
+++ b/berry_fix/payload/ld_script.txt
@@ -0,0 +1,122 @@
+ENTRY(Init)
+
+SECTIONS {
+ . = 0x2010000;
+
+ .text :
+ ALIGN(4)
+ {
+ asm/crt0.o(.text);
+ src/main.o(.text);
+ src/rtc.o(.text);
+ src/flash.o(.text);
+ } =0
+
+ lib_text :
+ ALIGN(4)
+ {
+ *libagb_flash.a:agb_flash.o(.text);
+ *libagb_flash.a:agb_flash_1m.o(.text);
+ *libagb_flash.a:agb_flash_mx.o(.text);
+ *libagbsyscall.a:ArcTan2.o(.text);
+ *libagbsyscall.a:BgAffineSet.o(.text);
+ *libagbsyscall.a:CpuFastSet.o(.text);
+ *libagbsyscall.a:CpuSet.o(.text);
+ *libagbsyscall.a:Div.o(.text);
+ *libagbsyscall.a:Mod.o(.text);
+ *libagbsyscall.a:LZ77UnCompVram.o(.text);
+ *libagbsyscall.a:LZ77UnCompWram.o(.text);
+ *libagbsyscall.a:MultiBoot.o(.text);
+ *libagbsyscall.a:ObjAffineSet.o(.text);
+ *libagbsyscall.a:RLUnCompVram.o(.text);
+ *libagbsyscall.a:RLUnCompWram.o(.text);
+ *libagbsyscall.a:RegisterRamReset.o(.text);
+ *libagbsyscall.a:SoftReset.o(.text);
+ *libagbsyscall.a:Sqrt.o(.text);
+ *libagbsyscall.a:VBlankIntrWait.o(.text);
+ *libsiirtc.a:siirtc.o(.text);
+ *libgcc.a:_call_via_rX.o(.text);
+ *libgcc.a:_modsi3.o(.text);
+ *libgcc.a:_umodsi3.o(.text);
+ *libgcc.a:_dvmd_tls.o(.text);
+ } =0
+
+ .rodata :
+ ALIGN(4)
+ {
+ src/main.o(.rodata);
+ src/rtc.o(.rodata);
+ src/flash.o(.rodata);
+ } =0
+
+ lib_rodata :
+ ALIGN(4)
+ {
+ *libagb_flash.a:agb_flash.o(.rodata);
+ *libagb_flash.a:agb_flash_1m.o(.rodata);
+ *libagb_flash.a:agb_flash_mx.o(.rodata);
+ *libagb_flash.a:agb_flash_le.o(.rodata);
+ *libsiirtc.a:siirtc.o(.rodata);
+ }
+
+ . = 0x2020000;
+
+ ewram (NOLOAD) :
+ ALIGN(4)
+ {
+<EWRAM>
+ }
+
+ . = 0x3001000;
+
+ iwram (NOLOAD) :
+ ALIGN(4)
+ {
+<BSS>
+ . = 0x40;
+<COMMON>
+ end = .;
+ }
+
+ . = 0x8000000;
+
+ RS_Rom (NOLOAD) :
+ ALIGN(4)
+ {
+ _start = .;
+ . += 4;
+ RomHeaderNintendoLogo = .;
+ . += 156;
+ RS_RomHeader = .;
+ RomHeaderGameTitle = .;
+ . += 12;
+ RomHeaderGameCode = .;
+ . += 4;
+ RomHeaderMakerCode = .;
+ . += 2;
+ RomHeaderMagic = .;
+ . += 1;
+ RomHeaderMainUnitCode = .;
+ . += 1;
+ RomHeaderDeviceType = .;
+ . += 1;
+ RomHeaderReserved1 = .;
+ . += 7;
+ RomHeaderSoftwareVersion = .;
+ . += 1;
+ RomHeaderChecksum = .;
+ . += 1;
+ RomHeaderReserved2 = .;
+ . += 6;
+ GPIOPortData = .;
+ . += 2;
+ GPIOPortDirection = .;
+ . += 2;
+ GPIOPortReadEnable = .;
+ } =0
+
+ /DISCARD/ :
+ {
+ *(*);
+ }
+}
diff --git a/berry_fix/payload/rom.sha1 b/berry_fix/payload/rom.sha1
new file mode 100644
index 000000000..92eee7e87
--- /dev/null
+++ b/berry_fix/payload/rom.sha1
@@ -0,0 +1 @@
+866991e2b5a8de02d12f53abe0ee9af03a2b6e01 payload.gba
diff --git a/berry_fix/payload/src/flash.c b/berry_fix/payload/src/flash.c
new file mode 100644
index 000000000..3a0369dda
--- /dev/null
+++ b/berry_fix/payload/src/flash.c
@@ -0,0 +1,752 @@
+#include <gba/gba.h>
+#include <agb_flash.h>
+#include "constants/vars.h"
+#include "global.h"
+#include "main.h"
+#include "flash.h"
+#include "rtc.h"
+
+struct SaveBlockChunk
+{
+ u8 * data;
+ u16 size;
+};
+
+u8 WriteSaveBlockChunks(u16 a0, const struct SaveBlockChunk * a1);
+u8 WriteSingleChunk(u16 a0, const struct SaveBlockChunk * a1);
+u8 TryWriteSector(u8, u8 *);
+u8 EraseCurrentChunk(u16 a0, const struct SaveBlockChunk * a1);
+u8 TryReadAllSaveSectorsCurrentSlot(u16 a0, const struct SaveBlockChunk * a1);
+u8 ReadAllSaveSectorsCurrentSlot(u16 a0, const struct SaveBlockChunk * a1);
+u8 GetSaveValidStatus(const struct SaveBlockChunk * a1);
+u32 DoReadFlashWholeSection(u8 a0, struct SaveSector * a1);
+u16 CalculateChecksum(const void *, u16);
+
+u16 gFirstSaveSector;
+u32 gPrevSaveCounter;
+u16 gLastKnownGoodSector;
+u32 gDamagedSaveSectors;
+u32 gSaveCounter;
+struct SaveSector * gFastSaveSection;
+u16 gCurSaveChunk;
+bool32 gFlashIdentIsValid;
+
+EWRAM_DATA struct SaveBlock2 gSaveBlock2 = {};
+EWRAM_DATA struct SaveBlock1 gSaveBlock1 = {};
+EWRAM_DATA struct PokemonStorage gPokemonStorage = {};
+
+// Each 4 KiB flash sector contains 3968 bytes of actual data followed by a 128 byte footer
+#define SECTOR_DATA_SIZE 3968
+#define SECTOR_FOOTER_SIZE 128
+
+#define SAVEBLOCK_CHUNK(structure, chunkNum) \
+{ \
+ (u8 *)&structure + chunkNum * SECTOR_DATA_SIZE, \
+ min(sizeof(structure) - chunkNum * SECTOR_DATA_SIZE, SECTOR_DATA_SIZE) \
+} \
+
+static const struct SaveBlockChunk sSaveBlockChunks[] =
+{
+ SAVEBLOCK_CHUNK(gSaveBlock2, 0),
+
+ SAVEBLOCK_CHUNK(gSaveBlock1, 0),
+ SAVEBLOCK_CHUNK(gSaveBlock1, 1),
+ SAVEBLOCK_CHUNK(gSaveBlock1, 2),
+ SAVEBLOCK_CHUNK(gSaveBlock1, 3),
+
+ SAVEBLOCK_CHUNK(gPokemonStorage, 0),
+ SAVEBLOCK_CHUNK(gPokemonStorage, 1),
+ SAVEBLOCK_CHUNK(gPokemonStorage, 2),
+ SAVEBLOCK_CHUNK(gPokemonStorage, 3),
+ SAVEBLOCK_CHUNK(gPokemonStorage, 4),
+ SAVEBLOCK_CHUNK(gPokemonStorage, 5),
+ SAVEBLOCK_CHUNK(gPokemonStorage, 6),
+ SAVEBLOCK_CHUNK(gPokemonStorage, 7),
+ SAVEBLOCK_CHUNK(gPokemonStorage, 8),
+};
+
+const u16 gInfoMessagesPal[] = INCBIN_U16("graphics/msg_box.gbapal");
+const u8 gInfoMessagesTilemap[] = INCBIN_U8("graphics/msg_box.tilemap.lz");
+const u8 gInfoMessagesGfx[] = INCBIN_U8("graphics/msg_box.4bpp.lz");
+
+bool32 flash_maincb_ident_is_valid(void)
+{
+ gFlashIdentIsValid = TRUE;
+ if (!IdentifyFlash())
+ {
+ SetFlashTimerIntr(0, &((IntrFunc *)gIntrFuncPointers)[9]);
+ return TRUE;
+ }
+ gFlashIdentIsValid = FALSE;
+ return FALSE;
+}
+
+void Call_ReadFlash(u16 sectorNum, ptrdiff_t offset, void * dest, size_t size)
+{
+ ReadFlash(sectorNum, offset, dest, size);
+}
+
+u8 Call_WriteSaveBlockChunks(u16 a0, const struct SaveBlockChunk * a1)
+{
+ return WriteSaveBlockChunks(a0, a1);
+}
+
+u8 Call_TryReadAllSaveSectorsCurrentSlot(u16 a0, const struct SaveBlockChunk * a1)
+{
+ return TryReadAllSaveSectorsCurrentSlot(a0, a1);
+}
+
+u32 * GetDamagedSaveSectorsPtr(void)
+{
+ return &gDamagedSaveSectors;
+}
+
+s32 flash_write_save_block_chunks(u8 a0)
+{
+ u8 i;
+
+ switch (a0)
+ {
+ case 0:
+ default:
+ Call_WriteSaveBlockChunks(0xFFFF, sSaveBlockChunks);
+ break;
+ case 1:
+ for (i = 0; i < 5; i++)
+ {
+ Call_WriteSaveBlockChunks(i, sSaveBlockChunks);
+ }
+ break;
+ case 2:
+ Call_WriteSaveBlockChunks(0, sSaveBlockChunks);
+ break;
+ }
+
+ return 0;
+}
+
+u8 flash_write_save_block_chunks_check_damage(u8 a0)
+{
+ flash_write_save_block_chunks(a0);
+ if (*GetDamagedSaveSectorsPtr() == 0)
+ return 1;
+ return 0xFF;
+}
+
+u8 flash_maincb_read_save(u32 unused)
+{
+ return Call_TryReadAllSaveSectorsCurrentSlot(0xFFFF, sSaveBlockChunks);
+}
+
+void msg_load_gfx(void)
+{
+ REG_DISPCNT = 0;
+ REG_BG0HOFS = 0;
+ REG_BG0VOFS = 0;
+ REG_BLDCNT = 0;
+ LZ77UnCompVram(gInfoMessagesGfx, (void *)BG_VRAM);
+ LZ77UnCompVram(gInfoMessagesTilemap, (void *)BG_SCREEN_ADDR(28));
+ CpuCopy16(gInfoMessagesPal, (void *)BG_PLTT, 0x200);
+ REG_BG0CNT = BGCNT_SCREENBASE(28) | BGCNT_TXT512x512;
+ REG_DISPCNT = DISPCNT_BG0_ON;
+}
+
+void msg_display(enum MsgBoxUpdateMessage a0)
+{
+ switch (a0)
+ {
+ case MSGBOX_WILL_NOW_UPDATE:
+ REG_BG0HOFS = 0;
+ REG_BG0VOFS = 0;
+ break;
+ case MSGBOX_HAS_BEEN_UPDATED:
+ REG_BG0HOFS = 0x100;
+ REG_BG0VOFS = 0;
+ break;
+ case MSGBOX_UNABLE_TO_UPDATE:
+ REG_BG0HOFS = 0x100;
+ REG_BG0VOFS = 0xB0;
+ break;
+ case MSGBOX_NO_NEED_TO_UPDATE:
+ REG_BG0HOFS = 0;
+ REG_BG0VOFS = 0xB0;
+ break;
+ case MSGBOX_UPDATING:
+ REG_BG0HOFS = 0;
+ REG_BG0VOFS = 0x160;
+ break;
+ }
+}
+
+void Save_EraseAllData(void)
+{
+ u16 i;
+ for (i = 0; i < 32; i++)
+ EraseFlashSector(i);
+}
+
+void Save_ResetSaveCounters(void)
+{
+ gSaveCounter = 0;
+ gFirstSaveSector = 0;
+ gDamagedSaveSectors = 0;
+}
+
+bool32 SetSectorDamagedStatus(u8 op, u8 sectorNum)
+{
+ bool32 retVal = FALSE;
+
+ switch (op)
+ {
+ case SECTOR_DAMAGED:
+ gDamagedSaveSectors |= (1 << sectorNum);
+ break;
+ case SECTOR_OK:
+ gDamagedSaveSectors &= ~(1 << sectorNum);
+ break;
+ case SECTOR_CHECK: // unused
+ if (gDamagedSaveSectors & (1 << sectorNum))
+ retVal = TRUE;
+ break;
+ }
+
+ return retVal;
+}
+
+u8 WriteSaveBlockChunks(u16 chunkId, const struct SaveBlockChunk *chunks)
+{
+ u32 retVal;
+ u16 i;
+
+ gFastSaveSection = eSaveSection;
+
+ if (chunkId != 0xFFFF) // write single chunk
+ {
+ retVal = WriteSingleChunk(chunkId, chunks);
+ }
+ else // write all chunks
+ {
+ gLastKnownGoodSector = gFirstSaveSector;
+ gPrevSaveCounter = gSaveCounter;
+ gFirstSaveSector++;
+ gFirstSaveSector %= NUM_SECTORS_PER_SAVE_SLOT;
+ gSaveCounter++;
+ retVal = SAVE_STATUS_OK;
+
+ for (i = 0; i < NUM_SECTORS_PER_SAVE_SLOT; i++)
+ WriteSingleChunk(i, chunks);
+
+ // Check for any bad sectors
+ if (gDamagedSaveSectors != 0) // skip the damaged sector.
+ {
+ retVal = SAVE_STATUS_ERROR;
+ gFirstSaveSector = gLastKnownGoodSector;
+ gSaveCounter = gPrevSaveCounter;
+ }
+ }
+
+ return retVal;
+}
+
+u8 WriteSingleChunk(u16 chunkId, const struct SaveBlockChunk * chunks)
+{
+ u16 i;
+ u16 sectorNum;
+ u8 *chunkData;
+ u16 chunkSize;
+
+ // select sector number
+ sectorNum = chunkId + gFirstSaveSector;
+ sectorNum %= NUM_SECTORS_PER_SAVE_SLOT;
+ // select save slot
+ sectorNum += NUM_SECTORS_PER_SAVE_SLOT * (gSaveCounter % 2);
+
+ chunkData = chunks[chunkId].data;
+ chunkSize = chunks[chunkId].size;
+
+ // clear save section.
+ for (i = 0; i < sizeof(struct SaveSector); i++)
+ ((u8 *)gFastSaveSection)[i] = 0;
+
+ gFastSaveSection->id = chunkId;
+ gFastSaveSection->signature = FILE_SIGNATURE;
+ gFastSaveSection->counter = gSaveCounter;
+ for (i = 0; i < chunkSize; i++)
+ gFastSaveSection->data[i] = chunkData[i];
+ gFastSaveSection->checksum = CalculateChecksum(chunkData, chunkSize);
+
+ return TryWriteSector(sectorNum, gFastSaveSection->data);
+}
+
+u8 HandleWriteSectorNBytes(u8 sectorNum, u8 *data, u16 size)
+{
+ u16 i;
+ struct SaveSector *section = eSaveSection;
+
+ for (i = 0; i < sizeof(struct SaveSector); i++)
+ ((char *)section)[i] = 0;
+
+ section->signature = FILE_SIGNATURE;
+ for (i = 0; i < size; i++)
+ section->data[i] = data[i];
+ section->id = CalculateChecksum(data, size); // though this appears to be incorrect, it might be some sector checksum instead of a whole save checksum and only appears to be relevent to HOF data, if used.
+
+ return TryWriteSector(sectorNum, section->data);
+}
+
+u8 TryWriteSector(u8 sectorNum, u8 *data)
+{
+ if (ProgramFlashSectorAndVerify(sectorNum, data) != 0) // is damaged?
+ {
+ SetSectorDamagedStatus(SECTOR_DAMAGED, sectorNum); // set damaged sector bits.
+ return SAVE_STATUS_ERROR;
+ }
+ else
+ {
+ SetSectorDamagedStatus(SECTOR_OK, sectorNum); // unset damaged sector bits. it's safe now.
+ return SAVE_STATUS_OK;
+ }
+}
+
+u32 RestoreSaveBackupVarsAndIncrement(const struct SaveBlockChunk *chunk) // chunk is unused
+{
+ gFastSaveSection = eSaveSection;
+ gLastKnownGoodSector = gFirstSaveSector;
+ gPrevSaveCounter = gSaveCounter;
+ gFirstSaveSector++;
+ gFirstSaveSector %= NUM_SECTORS_PER_SAVE_SLOT;
+ gSaveCounter++;
+ gCurSaveChunk = 0;
+ gDamagedSaveSectors = 0;
+ return 0;
+}
+
+u32 RestoreSaveBackupVars(const struct SaveBlockChunk *chunk)
+{
+ gFastSaveSection = eSaveSection;
+ gLastKnownGoodSector = gFirstSaveSector;
+ gPrevSaveCounter = gSaveCounter;
+ gCurSaveChunk = 0;
+ gDamagedSaveSectors = 0;
+ return 0;
+}
+
+u8 WriteSingleChunkAndIncrement(u16 a1, const struct SaveBlockChunk * chunk)
+{
+ u8 retVal;
+
+ if (gCurSaveChunk < a1 - 1)
+ {
+ retVal = SAVE_STATUS_OK;
+ WriteSingleChunk(gCurSaveChunk, chunk);
+ gCurSaveChunk++;
+ if (gDamagedSaveSectors)
+ {
+ retVal = SAVE_STATUS_ERROR;
+ gFirstSaveSector = gLastKnownGoodSector;
+ gSaveCounter = gPrevSaveCounter;
+ }
+ }
+ else
+ {
+ retVal = SAVE_STATUS_ERROR;
+ }
+
+ return retVal;
+}
+
+u8 ErasePreviousChunk(u16 a1, const struct SaveBlockChunk *chunk)
+{
+ u8 retVal = SAVE_STATUS_OK;
+
+ EraseCurrentChunk(a1 - 1, chunk);
+
+ if (gDamagedSaveSectors)
+ {
+ retVal = SAVE_STATUS_ERROR;
+ gFirstSaveSector = gLastKnownGoodSector;
+ gSaveCounter = gPrevSaveCounter;
+ }
+ return retVal;
+}
+
+u8 EraseCurrentChunk(u16 chunkId, const struct SaveBlockChunk *chunks)
+{
+ u16 i;
+ u16 sector;
+ u8 *data;
+ u16 size;
+ u8 status;
+
+ // select sector number
+ sector = chunkId + gFirstSaveSector;
+ sector %= NUM_SECTORS_PER_SAVE_SLOT;
+ // select save slot
+ sector += NUM_SECTORS_PER_SAVE_SLOT * (gSaveCounter % 2);
+
+ data = chunks[chunkId].data;
+ size = chunks[chunkId].size;
+
+ // clear temp save section.
+ for (i = 0; i < sizeof(struct SaveSector); i++)
+ ((char *)gFastSaveSection)[i] = 0;
+
+ gFastSaveSection->id = chunkId;
+ gFastSaveSection->signature = FILE_SIGNATURE;
+ gFastSaveSection->counter = gSaveCounter;
+
+ // set temp section's data.
+ for (i = 0; i < size; i++)
+ gFastSaveSection->data[i] = data[i];
+
+ // calculate checksum.
+ gFastSaveSection->checksum = CalculateChecksum(data, size);
+
+ EraseFlashSector(sector);
+
+ status = SAVE_STATUS_OK;
+
+ for (i = 0; i < sizeof(struct UnkSaveSection); i++)
+ {
+ if (ProgramFlashByte(sector, i, gFastSaveSection->data[i]))
+ {
+ status = SAVE_STATUS_ERROR;
+ break;
+ }
+ }
+
+ if (status == SAVE_STATUS_ERROR)
+ {
+ SetSectorDamagedStatus(SECTOR_DAMAGED, sector);
+ return SAVE_STATUS_ERROR;
+ }
+ else
+ {
+ status = SAVE_STATUS_OK;
+
+ for (i = 0; i < 7; i++)
+ {
+ if (ProgramFlashByte(sector, 0xFF9 + i, ((u8 *)gFastSaveSection)[0xFF9 + i]))
+ {
+ status = SAVE_STATUS_ERROR;
+ break;
+ }
+ }
+
+ if (status == SAVE_STATUS_ERROR)
+ {
+ SetSectorDamagedStatus(SECTOR_DAMAGED, sector);
+ return SAVE_STATUS_ERROR;
+ }
+ else
+ {
+ SetSectorDamagedStatus(SECTOR_OK, sector);
+ return SAVE_STATUS_OK;
+ }
+ }
+}
+
+u8 WriteSomeFlashByteToPrevSector(u16 a1, const struct SaveBlockChunk *chunk)
+{
+ u16 sector;
+
+ // select sector number
+ sector = a1 + gFirstSaveSector - 1;
+ sector %= NUM_SECTORS_PER_SAVE_SLOT;
+ // select save slot
+ sector += NUM_SECTORS_PER_SAVE_SLOT * (gSaveCounter % 2);
+
+ if (ProgramFlashByte(sector, sizeof(struct UnkSaveSection), ((u8 *)gFastSaveSection)[sizeof(struct UnkSaveSection)]))
+ {
+ // sector is damaged, so enable the bit in gDamagedSaveSectors and restore the last written sector and save counter.
+ SetSectorDamagedStatus(SECTOR_DAMAGED, sector);
+ gFirstSaveSector = gLastKnownGoodSector;
+ gSaveCounter = gPrevSaveCounter;
+ return SAVE_STATUS_ERROR;
+ }
+ else
+ {
+ SetSectorDamagedStatus(SECTOR_OK, sector);
+ return SAVE_STATUS_OK;
+ }
+}
+
+u8 WriteSomeFlashByte0x25ToPrevSector(u16 a1, const struct SaveBlockChunk *chunk)
+{
+ u16 sector;
+
+ sector = a1 + gFirstSaveSector - 1;
+ sector %= NUM_SECTORS_PER_SAVE_SLOT;
+ sector += NUM_SECTORS_PER_SAVE_SLOT * (gSaveCounter % 2);
+
+ if (ProgramFlashByte(sector, sizeof(struct UnkSaveSection), 0x25))
+ {
+ // sector is damaged, so enable the bit in gDamagedSaveSectors and restore the last written sector and save counter.
+ SetSectorDamagedStatus(SECTOR_DAMAGED, sector);
+ gFirstSaveSector = gLastKnownGoodSector;
+ gSaveCounter = gPrevSaveCounter;
+ return SAVE_STATUS_ERROR;
+ }
+ else
+ {
+ SetSectorDamagedStatus(SECTOR_OK, sector);
+ return SAVE_STATUS_OK;
+ }
+}
+
+u8 TryReadAllSaveSectorsCurrentSlot(u16 a1, const struct SaveBlockChunk *chunk)
+{
+ u8 retVal;
+ gFastSaveSection = eSaveSection;
+ if (a1 != 0xFFFF)
+ {
+ retVal = SAVE_STATUS_ERROR;
+ }
+ else
+ {
+ retVal = GetSaveValidStatus(chunk);
+ ReadAllSaveSectorsCurrentSlot(0xFFFF, chunk);
+ }
+
+ return retVal;
+}
+
+u8 ReadAllSaveSectorsCurrentSlot(u16 a1, const struct SaveBlockChunk *chunks)
+{
+ u16 i;
+ u16 checksum;
+ u16 sector = NUM_SECTORS_PER_SAVE_SLOT * (gSaveCounter % 2);
+ u16 id;
+
+ for (i = 0; i < NUM_SECTORS_PER_SAVE_SLOT; i++)
+ {
+ DoReadFlashWholeSection(i + sector, gFastSaveSection);
+ id = gFastSaveSection->id;
+ if (id == 0)
+ gFirstSaveSector = i;
+ checksum = CalculateChecksum(gFastSaveSection->data, chunks[id].size);
+ if (gFastSaveSection->signature == FILE_SIGNATURE
+ && gFastSaveSection->checksum == checksum)
+ {
+ u16 j;
+ for (j = 0; j < chunks[id].size; j++)
+ chunks[id].data[j] = gFastSaveSection->data[j];
+ }
+ }
+
+ return 1;
+}
+
+u8 GetSaveValidStatus(const struct SaveBlockChunk *chunks)
+{
+ u16 sector;
+ bool8 signatureValid;
+ u16 checksum;
+ u32 slot1saveCounter = 0;
+ u32 slot2saveCounter = 0;
+ u8 slot1Status;
+ u8 slot2Status;
+ u32 validSectors;
+ const u32 ALL_SECTORS = (1 << NUM_SECTORS_PER_SAVE_SLOT) - 1; // bitmask of all saveblock sectors
+
+ // check save slot 1.
+ validSectors = 0;
+ signatureValid = FALSE;
+ for (sector = 0; sector < NUM_SECTORS_PER_SAVE_SLOT; sector++)
+ {
+ DoReadFlashWholeSection(sector, gFastSaveSection);
+ if (gFastSaveSection->signature == FILE_SIGNATURE)
+ {
+ signatureValid = TRUE;
+ checksum = CalculateChecksum(gFastSaveSection->data, chunks[gFastSaveSection->id].size);
+ if (gFastSaveSection->checksum == checksum)
+ {
+ slot1saveCounter = gFastSaveSection->counter;
+ validSectors |= 1 << gFastSaveSection->id;
+ }
+ }
+ }
+
+ if (signatureValid)
+ {
+ if (validSectors == ALL_SECTORS)
+ slot1Status = SAVE_STATUS_OK;
+ else
+ slot1Status = SAVE_STATUS_ERROR;
+ }
+ else
+ {
+ slot1Status = SAVE_STATUS_EMPTY;
+ }
+
+ // check save slot 2.
+ validSectors = 0;
+ signatureValid = FALSE;
+ for (sector = 0; sector < NUM_SECTORS_PER_SAVE_SLOT; sector++)
+ {
+ DoReadFlashWholeSection(NUM_SECTORS_PER_SAVE_SLOT + sector, gFastSaveSection);
+ if (gFastSaveSection->signature == FILE_SIGNATURE)
+ {
+ signatureValid = TRUE;
+ checksum = CalculateChecksum(gFastSaveSection->data, chunks[gFastSaveSection->id].size);
+ if (gFastSaveSection->checksum == checksum)
+ {
+ slot2saveCounter = gFastSaveSection->counter;
+ validSectors |= 1 << gFastSaveSection->id;
+ }
+ }
+ }
+
+ if (signatureValid)
+ {
+ if (validSectors == ALL_SECTORS)
+ slot2Status = SAVE_STATUS_OK;
+ else
+ slot2Status = SAVE_STATUS_ERROR;
+ }
+ else
+ {
+ slot2Status = SAVE_STATUS_EMPTY;
+ }
+
+ if (slot1Status == SAVE_STATUS_OK && slot2Status == SAVE_STATUS_OK)
+ {
+ // Choose counter of the most recent save file
+ if ((slot1saveCounter == -1 && slot2saveCounter == 0) || (slot1saveCounter == 0 && slot2saveCounter == -1))
+ {
+ if ((unsigned)(slot1saveCounter + 1) < (unsigned)(slot2saveCounter + 1))
+ gSaveCounter = slot2saveCounter;
+ else
+ gSaveCounter = slot1saveCounter;
+ }
+ else
+ {
+ if (slot1saveCounter < slot2saveCounter)
+ gSaveCounter = slot2saveCounter;
+ else
+ gSaveCounter = slot1saveCounter;
+ }
+ return SAVE_STATUS_OK;
+ }
+
+ if (slot1Status == SAVE_STATUS_OK)
+ {
+ gSaveCounter = slot1saveCounter;
+ if (slot2Status == SAVE_STATUS_ERROR)
+ return SAVE_STATUS_ERROR;
+ else
+ return SAVE_STATUS_OK;
+ }
+
+ if (slot2Status == SAVE_STATUS_OK)
+ {
+ gSaveCounter = slot2saveCounter;
+ if (slot1Status == SAVE_STATUS_ERROR)
+ return SAVE_STATUS_ERROR;
+ else
+ return SAVE_STATUS_OK;
+ }
+
+ if (slot1Status == SAVE_STATUS_EMPTY && slot2Status == SAVE_STATUS_EMPTY)
+ {
+ gSaveCounter = 0;
+ gFirstSaveSector = 0;
+ return SAVE_STATUS_EMPTY;
+ }
+
+ gSaveCounter = 0;
+ gFirstSaveSector = 0;
+ return 2;
+}
+
+u8 ReadSomeUnknownSectorAndVerify(u8 sector, u8 *data, u16 size)
+{
+ u16 i;
+ struct SaveSector *section = eSaveSection;
+
+ DoReadFlashWholeSection(sector, section);
+ if (section->signature == FILE_SIGNATURE)
+ {
+ u16 checksum = CalculateChecksum(section->data, size);
+ if (section->id == checksum)
+ {
+ for (i = 0; i < size; i++)
+ data[i] = section->data[i];
+ return SAVE_STATUS_OK;
+ }
+ else
+ {
+ return 2;
+ }
+ }
+ else
+ {
+ return SAVE_STATUS_EMPTY;
+ }
+}
+
+u32 DoReadFlashWholeSection(u8 sector, struct SaveSector *section)
+{
+ ReadFlash(sector, 0, section->data, sizeof(struct SaveSector));
+ return 1;
+}
+
+u16 CalculateChecksum(const void *data, u16 size)
+{
+ u16 i;
+ u32 checksum = 0;
+
+ for (i = 0; i < (size / 4); i++)
+ {
+ checksum += *((u32 *)data);
+ data += sizeof(u32);
+ }
+
+ return ((checksum >> 16) + checksum);
+}
+
+void nullsub_0201182C()
+{
+}
+
+void nullsub_02011830()
+{
+}
+
+void nullsub_02011834()
+{
+}
+
+u16 * get_var_addr(u16 a0)
+{
+ if (a0 < VARS_START)
+ return NULL;
+ if (a0 < VAR_SPECIAL_0)
+ return &gSaveBlock1.vars[a0 - VARS_START];
+ return NULL;
+}
+
+bool32 flash_maincb_check_need_reset_pacifidlog_tm(void)
+{
+ u8 sp0;
+ u16 * data = get_var_addr(VAR_PACIFIDLOG_TM_RECEIVED_DAY);
+ rtc_maincb_is_time_since_last_berry_update_positive(&sp0);
+ if (*data <= gRtcUTCTime.days)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+bool32 flash_maincb_reset_pacifidlog_tm(void)
+{
+ u8 sp0;
+ if (flash_maincb_check_need_reset_pacifidlog_tm() == TRUE)
+ return TRUE;
+ rtc_maincb_is_time_since_last_berry_update_positive(&sp0);
+ if (gRtcUTCTime.days < 0)
+ return FALSE;
+ *get_var_addr(VAR_PACIFIDLOG_TM_RECEIVED_DAY) = 1;
+ if (flash_write_save_block_chunks_check_damage(0) != TRUE)
+ return FALSE;
+ return TRUE;
+}
diff --git a/berry_fix/payload/src/main.c b/berry_fix/payload/src/main.c
new file mode 100644
index 000000000..249150665
--- /dev/null
+++ b/berry_fix/payload/src/main.c
@@ -0,0 +1,289 @@
+#include <gba/gba.h>
+#include "global.h"
+#include "main.h"
+#include "rtc.h"
+#include "flash.h"
+
+static s32 gInitialWaitTimer;
+IntrFunc gIntrTable[16];
+u16 gHeldKeys;
+u16 gNewKeys;
+u8 gIntrVector[0x100];
+u32 gUpdateSuccessful;
+u32 gUnknown_3001194;
+u32 gUnknown_30011A0[0x19];
+u32 gMainCallbackState;
+u32 gGameVersion;
+
+EWRAM_DATA u8 gSharedMem[0x8000] = {};
+
+void IntrMain(void);
+void ReadKeys(void);
+void dummy_intr_0(void);
+void dummy_intr_1(void);
+void main_callback(u32 *, void *, void *);
+
+
+const char gBerryFixGameCode[] = "AGBJ";
+const IntrFunc gIntrFuncPointers[] = {
+ dummy_intr_0,
+ dummy_intr_1,
+ dummy_intr_0,
+ dummy_intr_0,
+ dummy_intr_0,
+ dummy_intr_0,
+ dummy_intr_0,
+ dummy_intr_0,
+ dummy_intr_0,
+ dummy_intr_0,
+ NULL,
+ NULL,
+ NULL
+};
+const char gVersionData[][2] = {
+ {'J', 1},
+ {'E', 2},
+ {'D', 1},
+ {'F', 1},
+ {'I', 1},
+ {'S', 1}
+};
+const char gRubyTitleAndCode[] = "POKEMON RUBYAXV";
+const char gSapphireTitleAndCode[] = "POKEMON SAPPAXP";
+const u16 sDebugPals[20] = {
+ RGB(00, 00, 00),
+ RGB(31, 00, 00),
+ RGB(00, 31, 00),
+ RGB(00, 00, 31)
+};
+const u16 sDebugDigitsGfx[] = INCBIN_U16("graphics/debug_digits.4bpp");
+
+void AgbMain(void)
+{
+ RegisterRamReset(0x1E);
+ DmaCopy32(3, gIntrFuncPointers, gIntrTable, sizeof gIntrFuncPointers);
+ DmaCopy32(3, IntrMain, gIntrVector, sizeof(gIntrVector));
+ INTR_VECTOR = gIntrVector;
+ REG_IE = INTR_FLAG_VBLANK;
+ if (*RomHeaderMagic == 0x96 && *(u32 *)RomHeaderGameCode == *(u32 *)gBerryFixGameCode)
+ REG_IE |= INTR_FLAG_GAMEPAK;
+ REG_DISPSTAT = DISPSTAT_VBLANK_INTR;
+ REG_IME = INTR_FLAG_VBLANK;
+ msg_load_gfx();
+ gMainCallbackState = MAINCB_INIT;
+ gUnknown_3001194 = 0;
+ for (;;)
+ {
+ VBlankIntrWait();
+ ReadKeys();
+ main_callback(&gMainCallbackState, gUnknown_30011A0, gSharedMem);
+ }
+}
+
+void dummy_intr_1(void)
+{}
+
+void dummy_intr_0(void)
+{}
+
+void ReadKeys(void)
+{
+ u16 keyInput = REG_KEYINPUT ^ KEYS_MASK;
+ gNewKeys = keyInput & ~gHeldKeys;
+ gHeldKeys = keyInput;
+}
+
+void fill_palette(const u8 * src, u16 * dest, u8 value)
+{
+ s32 i;
+ for (i = 0; src[i] != 0; i++)
+ dest[i] = src[i] | value << 12;
+}
+
+bool32 berry_fix_memcmp(const char * src1, const char * src2, size_t size)
+{
+ s32 i;
+ for (i = 0; i < size; i++)
+ {
+ if (src1[i] != src2[i])
+ return FALSE;
+ }
+ return TRUE;
+}
+
+s32 validate_rom_header_internal(void)
+{
+ char languageCode = *(RomHeaderGameCode + 3);
+ s32 softwareVersion = *RomHeaderSoftwareVersion;
+ s32 shouldUpdate = -1;
+ s32 i;
+ for (i = 0; i < ARRAY_COUNT(gVersionData); i++)
+ {
+ if (languageCode == gVersionData[i][0])
+ {
+ if (softwareVersion >= gVersionData[i][1])
+ {
+ shouldUpdate = 0;
+ }
+ else
+ {
+ shouldUpdate = 1;
+ }
+ break;
+ }
+ }
+ if (shouldUpdate != -1)
+ {
+ if (berry_fix_memcmp(RomHeaderGameTitle, gRubyTitleAndCode, 15) == TRUE)
+ {
+ if (shouldUpdate == 0)
+ return RUBY_NONEED;
+ else
+ {
+ gGameVersion = VERSION_RUBY;
+ return RUBY_UPDATABLE;
+ }
+ }
+ else if (berry_fix_memcmp(RomHeaderGameTitle, gSapphireTitleAndCode, 15) == TRUE)
+ {
+ if (shouldUpdate == 0)
+ return SAPPHIRE_NONEED;
+ else
+ {
+ gGameVersion = VERSION_SAPPHIRE;
+ return SAPPHIRE_UPDATABLE;
+ }
+ }
+ }
+ return INVALID;
+}
+
+s32 validate_rom_header(void)
+{
+ if (*RomHeaderMakerCode == '0' && *(RomHeaderMakerCode + 1) == '1' && *RomHeaderMagic == 0x96)
+ return validate_rom_header_internal();
+ else
+ return INVALID;
+}
+
+void main_callback(u32 * state, void * unused1, void * unused2)
+{
+ u8 year;
+ switch (*state)
+ {
+ case MAINCB_INIT:
+ msg_display(MSGBOX_WILL_NOW_UPDATE);
+ if (++gInitialWaitTimer >= 180)
+ {
+ gInitialWaitTimer = 0;
+ gUpdateSuccessful = 0;
+ switch (validate_rom_header())
+ {
+ case SAPPHIRE_UPDATABLE:
+ case RUBY_UPDATABLE: // Should Update Ruby
+ ++(*state); // MAINCB_CHECK_RTC
+ break;
+ case INVALID: // Invalid header
+ *state = MAINCB_ERROR;
+ break;
+ case SAPPHIRE_NONEED: // Should not update Sapphire
+ case RUBY_NONEED: // Should not update Ruby
+ *state = MAINCB_NO_NEED_TO_FIX;
+ break;
+ }
+ }
+ break;
+ case MAINCB_CHECK_RTC:
+ if (!rtc_maincb_is_rtc_working())
+ *state = MAINCB_ERROR;
+ else
+ ++(*state); // MAINCB_CHECK_FLASH
+ break;
+ case MAINCB_CHECK_FLASH:
+ if (flash_maincb_ident_is_valid() == TRUE)
+ ++(*state); // MAINCB_READ_SAVE
+ else
+ *state = MAINCB_ERROR;
+ break;
+ case MAINCB_READ_SAVE:
+ if (flash_maincb_read_save(0) == SAVE_STATUS_OK)
+ ++(*state); // MAINCB_CHECK_TIME
+ else
+ *state = MAINCB_ERROR;
+ break;
+ case MAINCB_CHECK_TIME:
+ if (rtc_maincb_is_time_since_last_berry_update_positive(&year) == TRUE)
+ {
+ if (year == 0)
+ ++(*state); // MAINCB_FIX_DATE
+ else
+ *state = MAINCB_CHECK_PACIFIDLOG_TM;
+ }
+ else
+ {
+ if (year != 1)
+ *state = MAINCB_YEAR_MAKES_NO_SENSE;
+ else
+ ++(*state); // MAINCB_FIX_DATE
+ }
+ break;
+ case MAINCB_FIX_DATE:
+ rtc_maincb_fix_date();
+ gUpdateSuccessful |= 1;
+ *state = MAINCB_CHECK_PACIFIDLOG_TM;
+ break;
+ case MAINCB_CHECK_PACIFIDLOG_TM:
+ if (flash_maincb_check_need_reset_pacifidlog_tm() == TRUE)
+ *state = MAINCB_FINISHED;
+ else
+ *state = MAINCB_FIX_PACIFIDLOG_TM;
+ break;
+ case MAINCB_FIX_PACIFIDLOG_TM:
+ msg_display(MSGBOX_UPDATING);
+ if (flash_maincb_reset_pacifidlog_tm() == TRUE)
+ {
+ gUpdateSuccessful |= 1;
+ *state = MAINCB_FINISHED;
+ }
+ else
+ *state = MAINCB_ERROR;
+ break;
+ case MAINCB_FINISHED:
+ if (gUpdateSuccessful == 0)
+ *state = MAINCB_NO_NEED_TO_FIX;
+ else
+ msg_display(MSGBOX_HAS_BEEN_UPDATED);
+ break;
+ case MAINCB_NO_NEED_TO_FIX:
+ msg_display(MSGBOX_NO_NEED_TO_UPDATE);
+ break;
+ case MAINCB_YEAR_MAKES_NO_SENSE:
+ msg_display(MSGBOX_UNABLE_TO_UPDATE);
+ break;
+ case MAINCB_ERROR:
+ msg_display(MSGBOX_UNABLE_TO_UPDATE);
+ break;
+ }
+}
+
+void DBG_LoadDigitsPal(void)
+{
+ const u16 * src;
+ s32 i;
+ register vu16 * dest asm("r3") = (vu16 *)BG_PLTT + 1;
+ DmaFill16(3, RGB(31, 31, 31), (vu16 *)BG_PLTT, BG_PLTT_SIZE);
+ src = sDebugPals;
+ for (i = 0; i < 4; i++)
+ {
+ *dest = *src;
+ dest += 16;
+ src++;
+ }
+}
+
+void DBG_LoadDigits(void)
+{
+ DmaFill16(3, 0x1111, (void *)VRAM + 0x8420, 0x1800);
+ DmaCopy32(3, sDebugDigitsGfx, (void *)VRAM + 0x8600, 0x200);
+ DBG_LoadDigitsPal();
+}
diff --git a/berry_fix/payload/src/rtc.c b/berry_fix/payload/src/rtc.c
new file mode 100644
index 000000000..97692e205
--- /dev/null
+++ b/berry_fix/payload/src/rtc.c
@@ -0,0 +1,346 @@
+#include <gba/gba.h>
+#include <siirtc.h>
+#include "global.h"
+#include "main.h"
+
+struct Time gTimeSinceBerryUpdate;
+struct Time gRtcUTCTime;
+
+static u16 sRtcProbeStatus;
+static struct SiiRtcInfo sRtcInfoBuffer;
+static u8 sRtcProbeCode;
+static u16 sImeBak;
+static struct SiiRtcInfo sRtcInfoWork;
+
+const struct SiiRtcInfo sDefaultRTC = {
+ .year = 0, // 2000
+ .month = 1, // January
+ .day = 1, // 01
+ .dayOfWeek = 0,
+ .hour = 0,
+ .minute = 0,
+ .second = 0,
+ .status = 0,
+ .alarmHour = 0,
+ .alarmMinute = 0
+};
+const s32 sDaysPerMonth[] = {
+ 31,
+ 28,
+ 31,
+ 30,
+ 31,
+ 30,
+ 31,
+ 31,
+ 30,
+ 31,
+ 30,
+ 31
+};
+
+void rtc_get_status_and_datetime(struct SiiRtcInfo *);
+u16 rtc_validate_datetime(struct SiiRtcInfo *);
+
+
+void rtc_intr_disable(void)
+{
+ sImeBak = REG_IME;
+ REG_IME = 0;
+}
+
+void rtc_intr_enable(void)
+{
+ REG_IME = sImeBak;
+}
+
+s32 bcd_to_hex(u8 a0)
+{
+ if (a0 >= 0xa0 || (a0 & 0xF) >= 10)
+ return 0xFF;
+ return ((a0 >> 4) & 0xF) * 10 + (a0 & 0xF);
+}
+
+bool8 is_leap_year(u8 year)
+{
+ if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
+ return TRUE;
+ return FALSE;
+}
+
+u16 rtc_count_days_parameterized(u8 year, u8 month, u8 day)
+{
+ u16 numDays = 0;
+ s32 i;
+ for (i = year - 1; i > 0; i--)
+ {
+ numDays += 365;
+ if (is_leap_year(i) == TRUE)
+ numDays++;
+ }
+ for (i = 0; i < month - 1; i++)
+ numDays += sDaysPerMonth[i];
+ if (month > MONTH_FEB && is_leap_year(year) == TRUE)
+ numDays++;
+ numDays += day;
+ return numDays;
+}
+
+u16 rtc_count_days_from_info(struct SiiRtcInfo *info)
+{
+ return rtc_count_days_parameterized(bcd_to_hex(info->year), bcd_to_hex(info->month), bcd_to_hex(info->day));
+}
+
+static void rtc_probe_status(void)
+{
+ sRtcProbeStatus = 0;
+ rtc_intr_disable();
+ SiiRtcUnprotect();
+ sRtcProbeCode = SiiRtcProbe();
+ rtc_intr_enable();
+ if ((sRtcProbeCode & 0xF) != 1)
+ sRtcProbeStatus = 1;
+ else
+ {
+ if (sRtcProbeCode & 0xF0)
+ sRtcProbeStatus = 2;
+ else
+ sRtcProbeStatus = 0;
+ rtc_get_status_and_datetime(&sRtcInfoBuffer);
+ sRtcProbeStatus = rtc_validate_datetime(&sRtcInfoBuffer);
+ }
+}
+
+u16 rtc_get_probe_status(void)
+{
+ return sRtcProbeStatus;
+}
+
+void sub_020106EC(struct SiiRtcInfo * info)
+{
+ if (sRtcProbeStatus & 0xFF0)
+ *info = sDefaultRTC;
+ else
+ rtc_get_status_and_datetime(info);
+}
+
+void rtc_get_datetime(struct SiiRtcInfo * info)
+{
+ rtc_intr_disable();
+ SiiRtcGetDateTime(info);
+ rtc_intr_enable();
+}
+
+void rtc_get_status(struct SiiRtcInfo * info)
+{
+ rtc_intr_disable();
+ SiiRtcGetStatus(info);
+ rtc_intr_enable();
+}
+
+void rtc_get_status_and_datetime(struct SiiRtcInfo * info)
+{
+ rtc_get_status(info);
+ rtc_get_datetime(info);
+}
+
+u16 rtc_validate_datetime(struct SiiRtcInfo * info)
+{
+ s32 year, month, day;
+ u16 r4 = (info->status & SIIRTCINFO_POWER) ? 0x20 : 0;
+ if (!(info->status & SIIRTCINFO_24HOUR))
+ r4 |= 0x10;
+ year = bcd_to_hex(info->year);
+ if (year == 0xFF)
+ r4 |= 0x40;
+ month = bcd_to_hex(info->month);
+ if (month == 0xFF || month == 0 || month > 12)
+ r4 |= 0x80;
+ day = bcd_to_hex(info->day);
+ if (day == 0xFF)
+ r4 |= 0x100;
+ if (month == MONTH_FEB)
+ {
+ if (day > is_leap_year(year) + sDaysPerMonth[1])
+ r4 |= 0x100;
+ }
+ else
+ {
+ if (day > sDaysPerMonth[month - 1])
+ r4 |= 0x100;
+ }
+ day = bcd_to_hex(info->hour);
+ if (day > 24)
+ r4 |= 0x200;
+ day = bcd_to_hex(info->minute);
+ if (day > 60)
+ r4 |= 0x400;
+ day = bcd_to_hex(info->second);
+ if (day > 60)
+ r4 |= 0x800;
+ return r4;
+}
+
+void rtc_reset(void)
+{
+ rtc_intr_disable();
+ SiiRtcReset();
+ rtc_intr_enable();
+}
+
+void rtc_sub_time_from_datetime(struct SiiRtcInfo * datetime, struct Time * dest, struct Time * timediff)
+{
+ u16 r4 = rtc_count_days_from_info(datetime);
+ dest->seconds = bcd_to_hex(datetime->second) - timediff->seconds;
+ dest->minutes = bcd_to_hex(datetime->minute) - timediff->minutes;
+ dest->hours = bcd_to_hex(datetime->hour) - timediff->hours;
+ dest->days = r4 - timediff->days;
+ if (dest->seconds < 0)
+ {
+ dest->seconds += 60;
+ dest->minutes--;
+ }
+ if (dest->minutes < 0)
+ {
+ dest->minutes += 60;
+ dest->hours--;
+ }
+ if (dest->hours < 0)
+ {
+ dest->hours += 24;
+ dest->days--;
+ }
+}
+
+void rtc_sub_time_from_time(struct Time * dest, struct Time * diff, struct Time * src)
+{
+ dest->seconds = src->seconds - diff->seconds;
+ dest->minutes = src->minutes - diff->minutes;
+ dest->hours = src->hours - diff->hours;
+ dest->days = src->days - diff->days;
+ if (dest->seconds < 0)
+ {
+ dest->seconds += 60;
+ dest->minutes--;
+ }
+ if (dest->minutes < 0)
+ {
+ dest->minutes += 60;
+ dest->hours--;
+ }
+ if (dest->hours < 0)
+ {
+ dest->hours += 24;
+ dest->days--;
+ }
+}
+
+bool32 rtc_maincb_is_rtc_working(void)
+{
+ rtc_probe_status();
+ if (rtc_get_probe_status() & 0xFF0)
+ return FALSE;
+ return TRUE;
+}
+
+void rtc_set_datetime(struct SiiRtcInfo * info)
+{
+ vu16 imeBak = REG_IME;
+ REG_IME = 0;
+ SiiRtcSetDateTime(info);
+ REG_IME = imeBak;
+}
+
+bool32 rtc_maincb_is_time_since_last_berry_update_positive(u8 * a0)
+{
+ rtc_get_status_and_datetime(&sRtcInfoWork);
+ *a0 = bcd_to_hex(sRtcInfoWork.year);
+ rtc_sub_time_from_datetime(&sRtcInfoWork, &gRtcUTCTime, LocalTimeOffset);
+ rtc_sub_time_from_time(&gTimeSinceBerryUpdate, LastBerryTreeUpdate, &gRtcUTCTime);
+ if (gTimeSinceBerryUpdate.days * 1440 + gTimeSinceBerryUpdate.hours * 60 + gTimeSinceBerryUpdate.minutes >= 0)
+ return TRUE;
+ return FALSE;
+}
+
+u32 hex_to_bcd(u8 a0)
+{
+ u32 r4;
+ if (a0 > 99)
+ return 0xFF;
+ r4 = Div(a0, 10) << 4;
+ r4 |= Mod(a0, 10);
+ return r4;
+}
+
+void sii_rtc_inc(u8 * a0)
+{
+ *a0 = hex_to_bcd(bcd_to_hex(*a0) + 1);
+}
+
+void sii_rtc_inc_month(struct SiiRtcInfo * a0)
+{
+ sii_rtc_inc(&a0->month);
+ if (bcd_to_hex(a0->month) > 12)
+ {
+ sii_rtc_inc(&a0->year);
+ a0->month = MONTH_JAN;
+ }
+}
+
+void sii_rtc_inc_day(struct SiiRtcInfo * a0)
+{
+ sii_rtc_inc(&a0->day);
+ if (bcd_to_hex(a0->day) > sDaysPerMonth[bcd_to_hex(a0->month) - 1])
+ {
+ if (!is_leap_year(bcd_to_hex(a0->year)) || bcd_to_hex(a0->month) != MONTH_FEB || bcd_to_hex(a0->day) != 29)
+ {
+ a0->day = 1;
+ sii_rtc_inc_month(a0);
+ }
+ }
+}
+
+bool32 rtc_is_past_feb_28_2000(struct SiiRtcInfo * a0)
+{
+ if (bcd_to_hex(a0->year) == 0)
+ {
+ if (bcd_to_hex(a0->month) == MONTH_JAN)
+ return FALSE;
+ if (bcd_to_hex(a0->month) > MONTH_FEB)
+ return TRUE;
+ if (bcd_to_hex(a0->day) == 29)
+ return TRUE;
+ return FALSE;
+ }
+ if (bcd_to_hex(a0->year) == 1)
+ return TRUE;
+ return FALSE;
+}
+
+void rtc_maincb_fix_date(void)
+{
+ rtc_get_status_and_datetime(&sRtcInfoWork);
+ if (bcd_to_hex(sRtcInfoWork.year) == 0 || bcd_to_hex(sRtcInfoWork.year) == 1)
+ {
+ if (bcd_to_hex(sRtcInfoWork.year) == 1)
+ {
+ sRtcInfoWork.year = 2;
+ sRtcInfoWork.month = MONTH_JAN;
+ sRtcInfoWork.day = 2;
+ rtc_set_datetime(&sRtcInfoWork);
+ }
+ else
+ {
+ if (rtc_is_past_feb_28_2000(&sRtcInfoWork) == TRUE)
+ {
+ sii_rtc_inc_day(&sRtcInfoWork);
+ sii_rtc_inc(&sRtcInfoWork.year);
+ }
+ else
+ {
+ sii_rtc_inc(&sRtcInfoWork.year);
+ }
+ rtc_set_datetime(&sRtcInfoWork);
+ }
+ }
+}
diff --git a/berry_fix/payload/sym_bss.txt b/berry_fix/payload/sym_bss.txt
new file mode 100644
index 000000000..17bb7f204
--- /dev/null
+++ b/berry_fix/payload/sym_bss.txt
@@ -0,0 +1,5 @@
+ .include "src/main.o"
+ .include "src/rtc.o"
+ .include "src/flash.o"
+ .include "*libagb_flash.a:agb_flash.o"
+ .include "*libsiirtc.a:siirtc.o"
diff --git a/berry_fix/payload/sym_common.txt b/berry_fix/payload/sym_common.txt
new file mode 100644
index 000000000..e284737fc
--- /dev/null
+++ b/berry_fix/payload/sym_common.txt
@@ -0,0 +1,29 @@
+ .include "main.o"
+ .include "rtc.o"
+
+ .align 4
+gFirstSaveSector: @ 0x03001220
+ .space 0x4
+
+gPrevSaveCounter: @ 0x03001224
+ .space 0x4
+
+gLastKnownGoodSector: @ 0x03001228
+ .space 0x4
+
+gDamagedSaveSectors: @ 0x0300122C
+ .space 0x4
+
+gSaveCounter: @ 0x03001230
+ .space 0x4
+
+gFastSaveSection: @ 0x03001234
+ .space 0x4
+
+gCurSaveChunk:
+ .space 0x4
+
+gFlashIdentIsValid: @ 0x0300123C
+ .space 0x4
+
+ .include "*libagb_flash.a:agb_flash.o"
diff --git a/berry_fix/payload/sym_ewram.txt b/berry_fix/payload/sym_ewram.txt
new file mode 100644
index 000000000..2c61f5e7e
--- /dev/null
+++ b/berry_fix/payload/sym_ewram.txt
@@ -0,0 +1,3 @@
+ .include "src/main.o"
+ .include "src/rtc.o"
+ .include "src/flash.o"
diff --git a/berry_fix/rom.sha1 b/berry_fix/rom.sha1
new file mode 100644
index 000000000..145b083b2
--- /dev/null
+++ b/berry_fix/rom.sha1
@@ -0,0 +1 @@
+2eb0a94a913bebfb4cb59ceb57f3f965da55ef6d berry_fix.gba
diff --git a/data/berry_fix.mb b/data/berry_fix.mb
deleted file mode 100644
index 0afff07f5..000000000
--- a/data/berry_fix.mb
+++ /dev/null
Binary files differ
diff --git a/data/multiboot_berry_glitch_fix.s b/data/multiboot_berry_glitch_fix.s
index bc417a8ba..1eb843d3f 100644
--- a/data/multiboot_berry_glitch_fix.s
+++ b/data/multiboot_berry_glitch_fix.s
@@ -1,5 +1,5 @@
.section .rodata
gMultiBootProgram_BerryGlitchFix_Start:: @ 86FFC6C
- .incbin "data/berry_fix.mb"
+ .incbin "berry_fix/berry_fix.gba"
gMultiBootProgram_BerryGlitchFix_End::